Refactor vSphere driver
This commit is contained in:
parent
8d75c273a9
commit
e8d8fd6205
11
artifact.go
11
artifact.go
|
@ -1,15 +1,14 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/object"
|
||||
"context"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
|
||||
)
|
||||
|
||||
const BuilderId = "jetbrains.vsphere"
|
||||
|
||||
type Artifact struct {
|
||||
Name string
|
||||
VM *object.VirtualMachine
|
||||
VM *driver.VirtualMachine
|
||||
}
|
||||
|
||||
func (a *Artifact) BuilderId() string {
|
||||
|
@ -33,11 +32,9 @@ func (a *Artifact) State(name string) interface{} {
|
|||
}
|
||||
|
||||
func (a *Artifact) Destroy() error {
|
||||
ctx := context.TODO()
|
||||
task, err := a.VM.Destroy(ctx)
|
||||
err := a.VM.Destroy()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = task.WaitForResult(ctx, nil)
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/hashicorp/packer/helper/communicator"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
"github.com/hashicorp/packer/communicator/ssh"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
|
||||
)
|
||||
|
||||
type Builder struct {
|
||||
|
@ -93,7 +93,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
|
||||
artifact := &Artifact{
|
||||
Name: b.config.VMName,
|
||||
VM: state.Get("vm").(*object.VirtualMachine),
|
||||
VM: state.Get("vm").(*driver.VirtualMachine),
|
||||
}
|
||||
return artifact, nil
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"github.com/hashicorp/packer/packer"
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
|
||||
)
|
||||
|
||||
|
@ -42,7 +41,7 @@ func checkDefault(t *testing.T, name string, host string) builderT.TestCheckFunc
|
|||
d := testConn(t)
|
||||
vm := getVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := d.VMInfo(vm, "name", "parent", "runtime.host", "resourcePool", "layoutEx.disk")
|
||||
vmInfo, err := vm.Info("name", "parent", "runtime.host", "resourcePool", "layoutEx.disk")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
@ -52,7 +51,7 @@ func checkDefault(t *testing.T, name string, host string) builderT.TestCheckFunc
|
|||
}
|
||||
|
||||
f := d.NewFolder(vmInfo.Parent)
|
||||
folderPath, err := d.GetFolderPath(f)
|
||||
folderPath, err := f.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read folder name: %v", err)
|
||||
}
|
||||
|
@ -61,7 +60,7 @@ func checkDefault(t *testing.T, name string, host string) builderT.TestCheckFunc
|
|||
}
|
||||
|
||||
h := d.NewHost(vmInfo.Runtime.Host)
|
||||
hostInfo, err := d.HostInfo(h, "name")
|
||||
hostInfo, err := h.Info("name")
|
||||
if err != nil {
|
||||
t.Fatal("Cannot read host properties: ", err)
|
||||
}
|
||||
|
@ -71,7 +70,7 @@ func checkDefault(t *testing.T, name string, host string) builderT.TestCheckFunc
|
|||
}
|
||||
|
||||
p := d.NewResourcePool(vmInfo.ResourcePool)
|
||||
poolPath, err := d.GetResourcePoolPath(p)
|
||||
poolPath, err := p.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read resource pool name: %v", err)
|
||||
}
|
||||
|
@ -132,13 +131,13 @@ func checkFolder(t *testing.T, folder string) builderT.TestCheckFunc {
|
|||
d := testConn(t)
|
||||
vm := getVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := d.VMInfo(vm, "parent")
|
||||
vmInfo, err := vm.Info("parent")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
f := d.NewFolder(vmInfo.Parent)
|
||||
path, err := d.GetFolderPath(f)
|
||||
path, err := f.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read folder name: %v", err)
|
||||
}
|
||||
|
@ -170,13 +169,13 @@ func checkResourcePool(t *testing.T, pool string) builderT.TestCheckFunc {
|
|||
d := testConn(t)
|
||||
vm := getVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := d.VMInfo(vm, "resourcePool")
|
||||
vmInfo, err := vm.Info("resourcePool")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
||||
p := d.NewResourcePool(vmInfo.ResourcePool)
|
||||
path, err := d.GetResourcePoolPath(p)
|
||||
path, err := p.Path()
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read resource pool name: %v", err)
|
||||
}
|
||||
|
@ -207,7 +206,7 @@ func checkLinkedClone(t *testing.T) builderT.TestCheckFunc {
|
|||
d := testConn(t)
|
||||
vm := getVM(t, d, artifacts)
|
||||
|
||||
vmInfo, err := d.VMInfo(vm, "layoutEx.disk")
|
||||
vmInfo, err := vm.Info("layoutEx.disk")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
@ -239,7 +238,7 @@ func checkSnapshot(t *testing.T) builderT.TestCheckFunc {
|
|||
d := testConn(t)
|
||||
|
||||
vm := getVM(t, d, artifacts)
|
||||
vmInfo, err := d.VMInfo(vm, "layoutEx.disk")
|
||||
vmInfo, err := vm.Info("layoutEx.disk")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
@ -273,7 +272,7 @@ func checkTemplate(t *testing.T) builderT.TestCheckFunc {
|
|||
d := testConn(t)
|
||||
|
||||
vm := getVM(t, d, artifacts)
|
||||
vmInfo, err := d.VMInfo(vm, "config.template")
|
||||
vmInfo, err := vm.Info("config.template")
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot read VM properties: %v", err)
|
||||
}
|
||||
|
@ -315,7 +314,7 @@ func testConn(t *testing.T) *driver.Driver {
|
|||
return d
|
||||
}
|
||||
|
||||
func getVM(t *testing.T, d *driver.Driver, artifacts []packer.Artifact) *object.VirtualMachine {
|
||||
func getVM(t *testing.T, d *driver.Driver, artifacts []packer.Artifact) *driver.VirtualMachine {
|
||||
artifactRaw := artifacts[0]
|
||||
artifact, _ := artifactRaw.(*Artifact)
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"github.com/vmware/govmomi/object"
|
||||
)
|
||||
|
||||
type Datastore struct {
|
||||
ds *object.Datastore
|
||||
driver *Driver
|
||||
}
|
||||
|
||||
func (d *Driver) FindDatastore(name string) (*Datastore, error) {
|
||||
ds, err := d.finder.Datastore(d.ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Datastore{
|
||||
ds: ds,
|
||||
driver: d,
|
||||
}, nil
|
||||
}
|
193
driver/driver.go
193
driver/driver.go
|
@ -7,9 +7,6 @@ import (
|
|||
"net/url"
|
||||
"fmt"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"errors"
|
||||
"time"
|
||||
"github.com/vmware/govmomi/session"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
|
@ -31,25 +28,6 @@ type ConnectConfig struct {
|
|||
Datacenter string
|
||||
}
|
||||
|
||||
type CloneConfig struct {
|
||||
Template string
|
||||
VMName string
|
||||
Folder string
|
||||
Host string
|
||||
ResourcePool string
|
||||
Datastore string
|
||||
LinkedClone bool
|
||||
}
|
||||
|
||||
type HardwareConfig struct {
|
||||
CPUs int32
|
||||
CPUReservation int64
|
||||
CPULimit int64
|
||||
RAM int64
|
||||
RAMReservation int64
|
||||
RAMReserveAll bool
|
||||
}
|
||||
|
||||
func NewDriver(config *ConnectConfig) (*Driver, error) {
|
||||
ctx := context.TODO()
|
||||
|
||||
|
@ -92,174 +70,3 @@ func NewDriver(config *ConnectConfig) (*Driver, error) {
|
|||
}
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
func (d *Driver) CloneVM(config *CloneConfig) (*object.VirtualMachine, error) {
|
||||
template, err := d.finder.VirtualMachine(d.ctx, config.Template)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
folder, err := d.finder.FolderOrDefault(d.ctx, fmt.Sprintf("/%v/vm/%v", d.datacenter.Name(), config.Folder))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var relocateSpec types.VirtualMachineRelocateSpec
|
||||
|
||||
pool, err := d.finder.ResourcePoolOrDefault(d.ctx, fmt.Sprintf("/%v/host/%v/Resources/%v", d.datacenter.Name(), config.Host, config.ResourcePool))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
poolRef := pool.Reference()
|
||||
relocateSpec.Pool = &poolRef
|
||||
|
||||
if config.Datastore != "" {
|
||||
datastore, err := d.finder.Datastore(d.ctx, config.Datastore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
datastoreRef := datastore.Reference()
|
||||
relocateSpec.Datastore = &datastoreRef
|
||||
}
|
||||
|
||||
var cloneSpec types.VirtualMachineCloneSpec
|
||||
cloneSpec.Location = relocateSpec
|
||||
cloneSpec.PowerOn = false
|
||||
|
||||
if config.LinkedClone == true {
|
||||
cloneSpec.Location.DiskMoveType = "createNewChildDiskBacking"
|
||||
|
||||
var tpl mo.VirtualMachine
|
||||
err = template.Properties(d.ctx, template.Reference(), []string{"snapshot"}, &tpl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tpl.Snapshot == nil {
|
||||
err = errors.New("`linked_clone=true`, but template has no snapshots")
|
||||
return nil, err
|
||||
}
|
||||
cloneSpec.Snapshot = tpl.Snapshot.CurrentSnapshot
|
||||
}
|
||||
|
||||
task, err := template.Clone(d.ctx, folder, config.VMName, cloneSpec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info, err := task.WaitForResult(d.ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vm := object.NewVirtualMachine(d.client.Client, info.Result.(types.ManagedObjectReference))
|
||||
return vm, nil
|
||||
}
|
||||
|
||||
func (d *Driver) DestroyVM(vm *object.VirtualMachine) error {
|
||||
task, err := vm.Destroy(d.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = task.WaitForResult(d.ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Driver) ConfigureVM(vm *object.VirtualMachine, config *HardwareConfig) error {
|
||||
var confSpec types.VirtualMachineConfigSpec
|
||||
confSpec.NumCPUs = config.CPUs
|
||||
confSpec.MemoryMB = config.RAM
|
||||
|
||||
var cpuSpec types.ResourceAllocationInfo
|
||||
cpuSpec.Reservation = config.CPUReservation
|
||||
cpuSpec.Limit = config.CPULimit
|
||||
confSpec.CpuAllocation = &cpuSpec
|
||||
|
||||
var ramSpec types.ResourceAllocationInfo
|
||||
ramSpec.Reservation = config.RAMReservation
|
||||
confSpec.MemoryAllocation = &ramSpec
|
||||
|
||||
confSpec.MemoryReservationLockedToMax = &config.RAMReserveAll
|
||||
|
||||
task, err := vm.Reconfigure(d.ctx, confSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = task.WaitForResult(d.ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Driver) PowerOn(vm *object.VirtualMachine) error {
|
||||
task, err := vm.PowerOn(d.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = task.WaitForResult(d.ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Driver) WaitForIP(vm *object.VirtualMachine) (string, error) {
|
||||
ip, err := vm.WaitForIP(d.ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
func (d *Driver) PowerOff(vm *object.VirtualMachine) error {
|
||||
state, err := vm.PowerState(d.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if state == types.VirtualMachinePowerStatePoweredOff {
|
||||
return nil
|
||||
}
|
||||
|
||||
task, err := vm.PowerOff(d.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = task.WaitForResult(d.ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Driver) StartShutdown(vm *object.VirtualMachine) error {
|
||||
err := vm.ShutdownGuest(d.ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Driver) WaitForShutdown(vm *object.VirtualMachine, timeout time.Duration) error {
|
||||
shutdownTimer := time.After(timeout)
|
||||
for {
|
||||
powerState, err := vm.PowerState(d.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if powerState == "poweredOff" {
|
||||
break
|
||||
}
|
||||
|
||||
select {
|
||||
case <-shutdownTimer:
|
||||
err := errors.New("Timeout while waiting for machine to shut down.")
|
||||
return err
|
||||
default:
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Driver) CreateSnapshot(vm *object.VirtualMachine) error {
|
||||
task, err := vm.CreateSnapshot(d.ctx, "Created by Packer", "", false, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = task.WaitForResult(d.ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Driver) ConvertToTemplate(vm *object.VirtualMachine) error {
|
||||
err := vm.MarkAsTemplate(d.ctx)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -7,42 +7,61 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
func (d *Driver) NewFolder(ref *types.ManagedObjectReference) *object.Folder {
|
||||
return object.NewFolder(d.client.Client, *ref)
|
||||
type Folder struct {
|
||||
driver *Driver
|
||||
folder *object.Folder
|
||||
}
|
||||
|
||||
func (d *Driver) FolderInfo(folder *object.Folder, params ...string) (*mo.Folder, error) {
|
||||
func (d *Driver) NewFolder(ref *types.ManagedObjectReference) *Folder {
|
||||
return &Folder{
|
||||
folder: object.NewFolder(d.client.Client, *ref),
|
||||
driver: d,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Driver) FindFolder(name string) (*Folder, error) {
|
||||
f, err := d.finder.Folder(d.ctx, fmt.Sprintf("/%v/vm/%v", d.datacenter.Name(), name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Folder{
|
||||
folder: f,
|
||||
driver: d,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *Folder) Info(params ...string) (*mo.Folder, error) {
|
||||
var p []string
|
||||
if len(params) == 0 {
|
||||
p = []string{"*"}
|
||||
} else {
|
||||
p = params
|
||||
}
|
||||
var folderInfo mo.Folder
|
||||
err := folder.Properties(d.ctx, folder.Reference(), p, &folderInfo)
|
||||
var info mo.Folder
|
||||
err := f.folder.Properties(f.driver.ctx, f.folder.Reference(), p, &info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &folderInfo, nil
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func (d *Driver) GetFolderPath(folder *object.Folder) (string, error) {
|
||||
f, err := d.FolderInfo(folder, "name", "parent")
|
||||
func (f *Folder) Path() (string, error) {
|
||||
info, err := f.Info("name", "parent")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if f.Parent.Type == "Datacenter" {
|
||||
if info.Parent.Type == "Datacenter" {
|
||||
return "", nil
|
||||
} else {
|
||||
parent := d.NewFolder(f.Parent)
|
||||
parentPath, err := d.GetFolderPath(parent)
|
||||
parent := f.driver.NewFolder(info.Parent)
|
||||
path, err := parent.Path()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if parentPath == "" {
|
||||
return f.Name, nil
|
||||
if path == "" {
|
||||
return info.Name, nil
|
||||
} else {
|
||||
return fmt.Sprintf("%v/%v", parentPath, f.Name), nil
|
||||
return fmt.Sprintf("%v/%v", path, info.Name), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,25 +2,33 @@ package driver
|
|||
|
||||
import (
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
)
|
||||
|
||||
func (d *Driver) NewHost(ref *types.ManagedObjectReference) *object.HostSystem {
|
||||
return object.NewHostSystem(d.client.Client, *ref)
|
||||
type Host struct {
|
||||
driver *Driver
|
||||
host *object.HostSystem
|
||||
}
|
||||
|
||||
func (d *Driver) HostInfo(host *object.HostSystem, params ...string) (*mo.HostSystem, error){
|
||||
func (d *Driver) NewHost(ref *types.ManagedObjectReference) *Host {
|
||||
return &Host{
|
||||
host: object.NewHostSystem(d.client.Client, *ref),
|
||||
driver: d,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Host) Info(params ...string) (*mo.HostSystem, error){
|
||||
var p []string
|
||||
if len(params) == 0 {
|
||||
p = []string{"*"}
|
||||
} else {
|
||||
p = params
|
||||
}
|
||||
var hostInfo mo.HostSystem
|
||||
err := host.Properties(d.ctx, host.Reference(), p, &hostInfo)
|
||||
var info mo.HostSystem
|
||||
err := h.host.Properties(h.driver.ctx, h.host.Reference(), p, &info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &hostInfo, nil
|
||||
return &info, nil
|
||||
}
|
||||
|
|
|
@ -2,47 +2,66 @@ package driver
|
|||
|
||||
import (
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (d *Driver) NewResourcePool(ref *types.ManagedObjectReference) *object.ResourcePool {
|
||||
return object.NewResourcePool(d.client.Client, *ref)
|
||||
type ResourcePool struct {
|
||||
pool *object.ResourcePool
|
||||
driver *Driver
|
||||
}
|
||||
|
||||
func (d *Driver) ResourcePoolInfo(host *object.ResourcePool, params ...string) (*mo.ResourcePool, error){
|
||||
var p []string
|
||||
if len(params) == 0 {
|
||||
p = []string{"*"}
|
||||
} else {
|
||||
p = params
|
||||
func (d *Driver) NewResourcePool(ref *types.ManagedObjectReference) *ResourcePool {
|
||||
return &ResourcePool{
|
||||
pool: object.NewResourcePool(d.client.Client, *ref),
|
||||
driver: d,
|
||||
}
|
||||
var poolInfo mo.ResourcePool
|
||||
err := host.Properties(d.ctx, host.Reference(), p, &poolInfo)
|
||||
}
|
||||
|
||||
func (d *Driver) FindResourcePool(host string, name string) (*ResourcePool, error) {
|
||||
p, err := d.finder.ResourcePool(d.ctx, fmt.Sprintf("/%v/host/%v/Resources/%v", d.datacenter.Name(), host, name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &poolInfo, nil
|
||||
return &ResourcePool{
|
||||
pool: p,
|
||||
driver: d,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Driver) GetResourcePoolPath(pool *object.ResourcePool) (string, error) {
|
||||
f, err := d.ResourcePoolInfo(pool, "name", "parent")
|
||||
func (p *ResourcePool) Info(params ...string) (*mo.ResourcePool, error) {
|
||||
var params2 []string
|
||||
if len(params) == 0 {
|
||||
params2 = []string{"*"}
|
||||
} else {
|
||||
params2 = params
|
||||
}
|
||||
var info mo.ResourcePool
|
||||
err := p.pool.Properties(p.driver.ctx, p.pool.Reference(), params2, &info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func (p *ResourcePool) Path() (string, error) {
|
||||
poolInfo, err := p.Info("name", "parent")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if f.Parent.Type == "ComputeResource" {
|
||||
if poolInfo.Parent.Type == "ComputeResource" {
|
||||
return "", nil
|
||||
} else {
|
||||
parent := d.NewResourcePool(f.Parent)
|
||||
parentPath, err := d.GetResourcePoolPath(parent)
|
||||
parent := p.driver.NewResourcePool(poolInfo.Parent)
|
||||
parentPath, err := parent.Path()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if parentPath == "" {
|
||||
return f.Name, nil
|
||||
return poolInfo.Name, nil
|
||||
} else {
|
||||
return fmt.Sprintf("%v/%v", parentPath, f.Name), nil
|
||||
return fmt.Sprintf("%v/%v", parentPath, poolInfo.Name), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
218
driver/vm.go
218
driver/vm.go
|
@ -3,23 +3,229 @@ package driver
|
|||
import (
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (d *Driver) FindVM(name string) (*object.VirtualMachine, error) {
|
||||
return d.finder.VirtualMachine(d.ctx, name)
|
||||
type VirtualMachine struct {
|
||||
vm *object.VirtualMachine
|
||||
driver *Driver
|
||||
}
|
||||
|
||||
func (d *Driver) VMInfo(vm *object.VirtualMachine, params ...string) (*mo.VirtualMachine, error){
|
||||
type CloneConfig struct {
|
||||
Name string
|
||||
Folder string
|
||||
Host string
|
||||
ResourcePool string
|
||||
Datastore string
|
||||
LinkedClone bool
|
||||
}
|
||||
|
||||
type HardwareConfig struct {
|
||||
CPUs int32
|
||||
CPUReservation int64
|
||||
CPULimit int64
|
||||
RAM int64
|
||||
RAMReservation int64
|
||||
RAMReserveAll bool
|
||||
}
|
||||
|
||||
func (d *Driver) NewVM(ref *types.ManagedObjectReference) *VirtualMachine {
|
||||
return &VirtualMachine{
|
||||
vm: object.NewVirtualMachine(d.client.Client, *ref),
|
||||
driver: d,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Driver) FindVM(name string) (*VirtualMachine, error) {
|
||||
vm, err := d.finder.VirtualMachine(d.ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &VirtualMachine{
|
||||
vm: vm,
|
||||
driver: d,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) Info(params ...string) (*mo.VirtualMachine, error) {
|
||||
var p []string
|
||||
if len(params) == 0 {
|
||||
p = []string{"*"}
|
||||
} else {
|
||||
p = params
|
||||
}
|
||||
var vmInfo mo.VirtualMachine
|
||||
err := vm.Properties(d.ctx, vm.Reference(), p, &vmInfo)
|
||||
var info mo.VirtualMachine
|
||||
err := vm.vm.Properties(vm.driver.ctx, vm.vm.Reference(), p, &info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &vmInfo, nil
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func (template *VirtualMachine) Clone(config *CloneConfig) (*VirtualMachine, error) {
|
||||
folder, err := template.driver.FindFolder(config.Folder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var relocateSpec types.VirtualMachineRelocateSpec
|
||||
|
||||
pool, err := template.driver.FindResourcePool(config.Host, config.ResourcePool)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
poolRef := pool.pool.Reference()
|
||||
relocateSpec.Pool = &poolRef
|
||||
|
||||
if config.Datastore != "" {
|
||||
datastore, err := template.driver.FindDatastore(config.Datastore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
datastoreRef := datastore.ds.Reference()
|
||||
relocateSpec.Datastore = &datastoreRef
|
||||
}
|
||||
|
||||
var cloneSpec types.VirtualMachineCloneSpec
|
||||
cloneSpec.Location = relocateSpec
|
||||
cloneSpec.PowerOn = false
|
||||
|
||||
if config.LinkedClone == true {
|
||||
cloneSpec.Location.DiskMoveType = "createNewChildDiskBacking"
|
||||
|
||||
tpl, err := template.Info("snapshot")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tpl.Snapshot == nil {
|
||||
err = errors.New("`linked_clone=true`, but template has no snapshots")
|
||||
return nil, err
|
||||
}
|
||||
cloneSpec.Snapshot = tpl.Snapshot.CurrentSnapshot
|
||||
}
|
||||
|
||||
task, err := template.vm.Clone(template.driver.ctx, folder.folder, config.Name, cloneSpec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info, err := task.WaitForResult(template.driver.ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ref := info.Result.(types.ManagedObjectReference)
|
||||
vm := template.driver.NewVM(&ref)
|
||||
return vm, nil
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) Destroy() error {
|
||||
task, err := vm.vm.Destroy(vm.driver.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = task.WaitForResult(vm.driver.ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) Configure(config *HardwareConfig) error {
|
||||
var confSpec types.VirtualMachineConfigSpec
|
||||
confSpec.NumCPUs = config.CPUs
|
||||
confSpec.MemoryMB = config.RAM
|
||||
|
||||
var cpuSpec types.ResourceAllocationInfo
|
||||
cpuSpec.Reservation = config.CPUReservation
|
||||
cpuSpec.Limit = config.CPULimit
|
||||
confSpec.CpuAllocation = &cpuSpec
|
||||
|
||||
var ramSpec types.ResourceAllocationInfo
|
||||
ramSpec.Reservation = config.RAMReservation
|
||||
confSpec.MemoryAllocation = &ramSpec
|
||||
|
||||
confSpec.MemoryReservationLockedToMax = &config.RAMReserveAll
|
||||
|
||||
task, err := vm.vm.Reconfigure(vm.driver.ctx, confSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = task.WaitForResult(vm.driver.ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) PowerOn() error {
|
||||
task, err := vm.vm.PowerOn(vm.driver.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = task.WaitForResult(vm.driver.ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) WaitForIP() (string, error) {
|
||||
ip, err := vm.vm.WaitForIP(vm.driver.ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) PowerOff() error {
|
||||
state, err := vm.vm.PowerState(vm.driver.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if state == types.VirtualMachinePowerStatePoweredOff {
|
||||
return nil
|
||||
}
|
||||
|
||||
task, err := vm.vm.PowerOff(vm.driver.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = task.WaitForResult(vm.driver.ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) StartShutdown() error {
|
||||
err := vm.vm.ShutdownGuest(vm.driver.ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) WaitForShutdown(timeout time.Duration) error {
|
||||
shutdownTimer := time.After(timeout)
|
||||
for {
|
||||
powerState, err := vm.vm.PowerState(vm.driver.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if powerState == "poweredOff" {
|
||||
break
|
||||
}
|
||||
|
||||
select {
|
||||
case <-shutdownTimer:
|
||||
err := errors.New("Timeout while waiting for machine to shut down.")
|
||||
return err
|
||||
default:
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) CreateSnapshot(name string) error {
|
||||
task, err := vm.vm.CreateSnapshot(vm.driver.ctx, name, "", false, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = task.WaitForResult(vm.driver.ctx, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) ConvertToTemplate() error {
|
||||
err := vm.vm.MarkAsTemplate(vm.driver.ctx)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package main
|
|||
|
||||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"fmt"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
|
||||
|
@ -44,9 +43,14 @@ func (s *StepCloneVM) Run(state multistep.StateBag) multistep.StepAction {
|
|||
|
||||
ui.Say("Cloning VM...")
|
||||
|
||||
vm, err := d.CloneVM(&driver.CloneConfig{
|
||||
Template: s.config.Template,
|
||||
VMName: s.config.VMName,
|
||||
template, err := d.FindVM(s.config.Template)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
vm, err := template.Clone(&driver.CloneConfig{
|
||||
Name: s.config.VMName,
|
||||
Folder: s.config.Folder,
|
||||
Host: s.config.Host,
|
||||
ResourcePool: s.config.ResourcePool,
|
||||
|
@ -69,15 +73,13 @@ func (s *StepCloneVM) Cleanup(state multistep.StateBag) {
|
|||
return
|
||||
}
|
||||
|
||||
if vm, ok := state.GetOk("vm"); ok {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
d := state.Get("driver").(*driver.Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vm := state.Get("vm").(*driver.VirtualMachine)
|
||||
|
||||
ui.Say("Destroying VM...")
|
||||
ui.Say("Destroying VM...")
|
||||
|
||||
err := d.DestroyVM(vm.(*object.VirtualMachine))
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
err := vm.Destroy()
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package main
|
|||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"fmt"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
|
||||
)
|
||||
|
@ -33,13 +32,12 @@ type StepConfigureHardware struct {
|
|||
|
||||
func (s *StepConfigureHardware) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
d := state.Get("driver").(*driver.Driver)
|
||||
vm := state.Get("vm").(*object.VirtualMachine)
|
||||
vm := state.Get("vm").(*driver.VirtualMachine)
|
||||
|
||||
if *s.config != (HardwareConfig{}) {
|
||||
ui.Say("Customizing hardware parameters...")
|
||||
|
||||
err := d.ConfigureVM(vm, &driver.HardwareConfig{
|
||||
err := vm.Configure(&driver.HardwareConfig{
|
||||
CPUs: s.config.CPUs,
|
||||
CPUReservation: s.config.CPUReservation,
|
||||
CPULimit: s.config.CPULimit,
|
||||
|
|
15
step_run.go
15
step_run.go
|
@ -3,7 +3,6 @@ package main
|
|||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"fmt"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
|
||||
)
|
||||
|
@ -13,18 +12,18 @@ type StepRun struct {
|
|||
|
||||
func (s *StepRun) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
d := state.Get("driver").(*driver.Driver)
|
||||
vm := state.Get("vm").(*object.VirtualMachine)
|
||||
vm := state.Get("vm").(*driver.VirtualMachine)
|
||||
|
||||
ui.Say("Power on VM...")
|
||||
err := d.PowerOn(vm)
|
||||
|
||||
err := vm.PowerOn()
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Say("Waiting for IP...")
|
||||
ip, err := d.WaitForIP(vm)
|
||||
ip, err := vm.WaitForIP()
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
|
@ -43,11 +42,11 @@ func (s *StepRun) Cleanup(state multistep.StateBag) {
|
|||
}
|
||||
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
d := state.Get("driver").(*driver.Driver)
|
||||
vm := state.Get("vm").(*object.VirtualMachine)
|
||||
vm := state.Get("vm").(*driver.VirtualMachine)
|
||||
|
||||
ui.Say("Power off VM...")
|
||||
err := d.PowerOff(vm)
|
||||
|
||||
err := vm.PowerOff()
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package main
|
|||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
@ -41,8 +40,7 @@ type StepShutdown struct {
|
|||
func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
comm := state.Get("communicator").(packer.Communicator)
|
||||
d := state.Get("driver").(*driver.Driver)
|
||||
vm := state.Get("vm").(*object.VirtualMachine)
|
||||
vm := state.Get("vm").(*driver.VirtualMachine)
|
||||
|
||||
if s.config.Command != "" {
|
||||
ui.Say("Executing shutdown command...")
|
||||
|
@ -62,7 +60,7 @@ func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
|||
} else {
|
||||
ui.Say("Shut down VM...")
|
||||
|
||||
err := d.StartShutdown(vm)
|
||||
err := vm.StartShutdown()
|
||||
if err != nil {
|
||||
state.Put("error", fmt.Errorf("Cannot shut down VM: %v", err))
|
||||
return multistep.ActionHalt
|
||||
|
@ -70,7 +68,7 @@ func (s *StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
|||
}
|
||||
|
||||
log.Printf("Waiting max %s for shutdown to complete", s.config.Timeout)
|
||||
err := d.WaitForShutdown(vm, s.config.Timeout)
|
||||
err := vm.WaitForShutdown(s.config.Timeout)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
|
|
|
@ -3,7 +3,6 @@ package main
|
|||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
|
||||
)
|
||||
|
||||
|
@ -13,13 +12,12 @@ type StepCreateSnapshot struct{
|
|||
|
||||
func (s *StepCreateSnapshot) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
d := state.Get("driver").(*driver.Driver)
|
||||
vm := state.Get("vm").(*object.VirtualMachine)
|
||||
vm := state.Get("vm").(*driver.VirtualMachine)
|
||||
|
||||
if s.createSnapshot {
|
||||
ui.Say("Creating snapshot...")
|
||||
|
||||
err := d.CreateSnapshot(vm)
|
||||
err := vm.CreateSnapshot("Created by Packer")
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
|
|
|
@ -3,7 +3,6 @@ package main
|
|||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
|
||||
)
|
||||
|
||||
|
@ -13,12 +12,11 @@ type StepConvertToTemplate struct{
|
|||
|
||||
func (s *StepConvertToTemplate) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
d := state.Get("driver").(*driver.Driver)
|
||||
vm := state.Get("vm").(*object.VirtualMachine)
|
||||
vm := state.Get("vm").(*driver.VirtualMachine)
|
||||
|
||||
if s.ConvertToTemplate {
|
||||
ui.Say("Convert VM into template...")
|
||||
err := d.ConvertToTemplate(vm)
|
||||
err := vm.ConvertToTemplate()
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
|
|
Loading…
Reference in New Issue