285 lines
6.3 KiB
Go
285 lines
6.3 KiB
Go
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
|
|
}
|