esxlib/client/inventory_vms.go

285 lines
6.3 KiB
Go
Raw Normal View History

2023-06-22 05:16:40 +00:00
package client
import (
"bufio"
"bytes"
"context"
"encoding/base64"
"errors"
"fmt"
"text/template"
"esxlib/pkg/sshutil"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/view"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/soap"
)
type VirtualMachines struct {
ClientRef
sshAuth *sshutil.Auth
}
func (vms *VirtualMachines) List(ctx context.Context) ([]*VirtualMachine, error) {
m := view.NewManager(vms.VIM())
v, err := m.CreateContainerView(ctx, vms.VIM().ServiceContent.RootFolder, []string{"VirtualMachine"}, true)
if err != nil {
return nil, err
}
defer v.Destroy(ctx)
// Retrieve summary property for all machines
// Reference: http://pubs.vmware.com/vsphere-60/topic/com.vmware.wssdk.apiref.doc/vim.VirtualMachine.html
var moList []mo.VirtualMachine
err = v.Retrieve(ctx, []string{"VirtualMachine"}, nil, &moList)
if err != nil {
return nil, err
}
vmList := make([]*VirtualMachine, 0)
for idx := range moList {
vmList = append(vmList, &VirtualMachine{
c: vms.VIM(),
sshAuth: vms.sshAuth,
ref: moList[idx].Reference(),
mo: &moList[idx],
})
}
return vmList, nil
}
func (vms *VirtualMachines) Get(ctx context.Context, name string) (*VirtualMachine, error) {
vmList, err := vms.List(ctx)
if err != nil {
return nil, err
}
for idx, vm := range vmList {
if vm.Name() == name {
return vmList[idx], nil
}
}
return nil, errors.New("vm does not exist")
}
func (vms *VirtualMachines) Create(ctx context.Context, name string, memSize uint, diskSize uint, initScript []byte) (*VirtualMachine, error) {
// we need some into about this ESX server from someplace
// DestinationPath: /vmfs/volumes/datastore1
// SourcePath
container := "datastore1"
path := fmt.Sprintf("%s/%s.vmx", name, name)
initScriptEncoded := ""
if len(initScript) != 0 {
initScriptEncoded = base64.StdEncoding.EncodeToString(initScript)
}
tmpl, err := template.New("ubuntu-lunar.cloudinit.tmpl").ParseFiles("configs/ubuntu-lunar.cloudinit.tmpl")
if err != nil {
panic(err)
}
config := struct {
Name string
Hostname string
MemSizeMB uint
CloudInitBase64 string
InitScriptBase64 string
}{
Name: name,
Hostname: name,
MemSizeMB: memSize,
InitScriptBase64: initScriptEncoded,
}
var b bytes.Buffer
w := bufio.NewWriter(&b)
err = tmpl.Execute(w, config)
if err != nil {
panic(err)
}
err = w.Flush()
if err != nil {
panic(err)
}
cloudInitEncoded := base64.StdEncoding.EncodeToString(b.Bytes())
config.CloudInitBase64 = cloudInitEncoded
fmt.Printf("%s\n", string(b.Bytes()))
// Now encode the vm config
tmpl, err = template.New("ubuntu-lunar.esx.tmpl").ParseFiles("configs/ubuntu-lunar.esx.tmpl")
if err != nil {
panic(err)
}
var upload bytes.Buffer
w = bufio.NewWriter(&upload)
err = tmpl.Execute(w, config)
if err != nil {
panic(err)
}
err = w.Flush()
if err != nil {
panic(err)
}
p := soap.DefaultUpload
err = vms.Mkdir(ctx, container, name)
if err != nil {
panic(err)
}
finder := find.NewFinder(vms.VIM())
ds, err := finder.Datastore(ctx, container)
if err != nil {
return nil, err
}
err = ds.Upload(ctx, &upload, path, &p)
if err != nil {
return nil, err
}
err = vms.cloneImage(ctx, "/vmfs/volumes/nas011/iso/lunar-server-cloudimg-amd64.vmdk", fmt.Sprintf("/vmfs/volumes/%s/%s/%s.vmdk", container, name, name), diskSize)
if err != nil {
return nil, err
}
err = vms.registerVM(ctx, fmt.Sprintf("/vmfs/volumes/%s/%s/%s.vmx", container, name, name))
if err != nil {
return nil, err
}
vm, err := vms.Get(ctx, name)
return vm, err
}
func (vms *VirtualMachines) Destroy(ctx context.Context, name string) error {
vm, err := vms.Get(ctx, name)
if err != nil {
return err
}
err = vm.PowerOff(ctx)
if err != nil {
return err
}
// delete the content
datastore, dir, err := vm.InternalPath()
if err != nil {
return err
}
err = vms.unregisterVM(ctx, vm.Id())
if err != nil {
return err
}
err = vms.wipe(ctx, datastore, dir)
return err
}
func (vms *VirtualMachines) unregisterVM(ctx context.Context, id string) error {
cmd := fmt.Sprintf("vim-cmd vmsvc/unregister %s", id)
_, err := sshutil.CombinedOutput(sshutil.Auth{
User: vms.sshAuth.User,
Password: vms.sshAuth.Password,
Host: vms.sshAuth.Host,
}, cmd)
if err != nil {
fmt.Printf("cmd: %s\n", cmd)
return err
}
return nil
}
func (vms *VirtualMachines) registerVM(ctx context.Context, vmxPath string) error {
cmd := fmt.Sprintf("vim-cmd solo/registervm %s", vmxPath)
_, err := sshutil.CombinedOutput(sshutil.Auth{
User: vms.sshAuth.User,
Password: vms.sshAuth.Password,
Host: vms.sshAuth.Host,
}, cmd)
if err != nil {
fmt.Printf("cmd: %s\n", cmd)
return err
}
return nil
}
func (vms *VirtualMachines) cloneImage(ctx context.Context, src, dest string, size uint) error {
cmd := fmt.Sprintf("vmkfstools --clonevirtualdisk %s --diskformat thin %s", src, dest)
_, err := sshutil.CombinedOutput(sshutil.Auth{
User: vms.sshAuth.User,
Password: vms.sshAuth.Password,
Host: vms.sshAuth.Host,
}, cmd)
if err != nil {
fmt.Printf("cmd: %s\n", cmd)
return err
}
cmd = fmt.Sprintf("vmkfstools -X %s %s", "20G", dest)
_, err = sshutil.CombinedOutput(sshutil.Auth{
User: vms.sshAuth.User,
Password: vms.sshAuth.Password,
Host: vms.sshAuth.Host,
}, cmd)
if err != nil {
fmt.Printf("cmd: %s\n", cmd)
return err
}
return nil
}
func (vms *VirtualMachines) wipe(ctx context.Context, datastore, dir string) error {
if vms.sshAuth != nil {
cmd := fmt.Sprintf("rm -rf /vmfs/volumes/%s/%s", datastore, dir)
_, err := sshutil.CombinedOutput(sshutil.Auth{
User: vms.sshAuth.User,
Password: vms.sshAuth.Password,
Host: vms.sshAuth.Host,
}, cmd)
fmt.Printf("cmd: %s\n", cmd)
return err
} else {
panic("no ssh config")
}
return nil
}
func (vms *VirtualMachines) Mkdir(ctx context.Context, datastore, dir string) error {
// you need a ESX payed license to create directories ... thats some bullshit */
if vms.sshAuth != nil {
cmd := fmt.Sprintf("mkdir -p /vmfs/volumes/%s/%s", datastore, dir)
_, err := sshutil.CombinedOutput(sshutil.Auth{
User: vms.sshAuth.User,
Password: vms.sshAuth.Password,
Host: vms.sshAuth.Host,
}, cmd)
fmt.Printf("cmd: %s\n", cmd)
return err
} else {
panic("no ssh config")
}
return nil
}