From cb782c223a5952eb838edd73037a53ed0cf37905 Mon Sep 17 00:00:00 2001 From: Michael Kuzmin Date: Fri, 16 Mar 2018 00:53:25 +0300 Subject: [PATCH] Cluster support (#61) --- clone/step_clone.go | 16 ++++------------ common/vm_config.go | 25 +++++++++++++++++++++++++ driver/host.go | 3 +-- driver/resource_pool.go | 11 +++++++++-- driver/resource_pool_acc_test.go | 2 +- driver/vm.go | 18 ++++++++++++------ iso/step_create.go | 16 +++------------- 7 files changed, 55 insertions(+), 36 deletions(-) create mode 100644 common/vm_config.go diff --git a/clone/step_clone.go b/clone/step_clone.go index ca166ba36..8f216a1fa 100644 --- a/clone/step_clone.go +++ b/clone/step_clone.go @@ -5,30 +5,21 @@ import ( "github.com/hashicorp/packer/packer" "fmt" "github.com/jetbrains-infra/packer-builder-vsphere/driver" + "github.com/jetbrains-infra/packer-builder-vsphere/common" ) type CloneConfig struct { Template string `mapstructure:"template"` - VMName string `mapstructure:"vm_name"` - Folder string `mapstructure:"folder"` - Host string `mapstructure:"host"` - ResourcePool string `mapstructure:"resource_pool"` - Datastore string `mapstructure:"datastore"` + common.VMConfig `mapstructure:",squash"` LinkedClone bool `mapstructure:"linked_clone"` } func (c *CloneConfig) Prepare() []error { - var errs []error + errs := c.VMConfig.Prepare() if c.Template == "" { errs = append(errs, fmt.Errorf("Template name is required")) } - if c.VMName == "" { - errs = append(errs, fmt.Errorf("Target VM name is required")) - } - if c.Host == "" { - errs = append(errs, fmt.Errorf("vSphere host is required")) - } return errs } @@ -52,6 +43,7 @@ func (s *StepCloneVM) Run(state multistep.StateBag) multistep.StepAction { vm, err := template.Clone(&driver.CloneConfig{ Name: s.config.VMName, Folder: s.config.Folder, + Cluster: s.config.Cluster, Host: s.config.Host, ResourcePool: s.config.ResourcePool, Datastore: s.config.Datastore, diff --git a/common/vm_config.go b/common/vm_config.go new file mode 100644 index 000000000..fb6a8996d --- /dev/null +++ b/common/vm_config.go @@ -0,0 +1,25 @@ +package common + +import "fmt" + +type VMConfig struct { + VMName string `mapstructure:"vm_name"` + Folder string `mapstructure:"folder"` + Cluster string `mapstructure:"cluster"` + Host string `mapstructure:"host"` + ResourcePool string `mapstructure:"resource_pool"` + Datastore string `mapstructure:"datastore"` +} + +func (c *VMConfig) Prepare() []error { + var errs []error + + if c.VMName == "" { + errs = append(errs, fmt.Errorf("Target VM name is required")) + } + if c.Cluster == "" && c.Host == "" { + errs = append(errs, fmt.Errorf("vSphere host or cluster is required")) + } + + return errs +} diff --git a/driver/host.go b/driver/host.go index 351a48789..234c72349 100644 --- a/driver/host.go +++ b/driver/host.go @@ -4,7 +4,6 @@ import ( "github.com/vmware/govmomi/object" "github.com/vmware/govmomi/vim25/types" "github.com/vmware/govmomi/vim25/mo" - "fmt" ) type Host struct { @@ -20,7 +19,7 @@ func (d *Driver) NewHost(ref *types.ManagedObjectReference) *Host { } func (d *Driver) FindHost(name string) (*Host, error) { - h, err := d.finder.HostSystem(d.ctx, fmt.Sprintf("/%v/host/%v", d.datacenter.Name(), name)) + h, err := d.finder.HostSystem(d.ctx, name) if err != nil { return nil, err } diff --git a/driver/resource_pool.go b/driver/resource_pool.go index 48553f661..7f869dbce 100644 --- a/driver/resource_pool.go +++ b/driver/resource_pool.go @@ -19,8 +19,15 @@ func (d *Driver) NewResourcePool(ref *types.ManagedObjectReference) *ResourcePoo } } -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)) +func (d *Driver) FindResourcePool(cluster string, host string, name string) (*ResourcePool, error) { + var res string + if cluster != "" { + res = cluster + } else { + res = host + } + + p, err := d.finder.ResourcePool(d.ctx, fmt.Sprintf("%v/Resources/%v", res, name)) if err != nil { return nil, err } diff --git a/driver/resource_pool_acc_test.go b/driver/resource_pool_acc_test.go index 5b43bacf1..af4cba868 100644 --- a/driver/resource_pool_acc_test.go +++ b/driver/resource_pool_acc_test.go @@ -6,7 +6,7 @@ func TestResourcePoolAcc(t *testing.T) { initDriverAcceptanceTest(t) d := newTestDriver(t) - p, err := d.FindResourcePool("esxi-1.vsphere65.test", "pool1/pool2") + p, err := d.FindResourcePool("","esxi-1.vsphere65.test", "pool1/pool2") if err != nil { t.Fatalf("Cannot find the default resource pool '%v': %v", "pool1/pool2", err) } diff --git a/driver/vm.go b/driver/vm.go index 9668c1a2b..6f60bab67 100644 --- a/driver/vm.go +++ b/driver/vm.go @@ -18,6 +18,7 @@ type VirtualMachine struct { type CloneConfig struct { Name string Folder string + Cluster string Host string ResourcePool string Datastore string @@ -44,6 +45,7 @@ type CreateConfig struct { Annotation string Name string Folder string + Cluster string Host string ResourcePool string Datastore string @@ -79,14 +81,18 @@ func (d *Driver) CreateVM(config *CreateConfig) (*VirtualMachine, error) { return nil, err } - resourcePool, err := d.FindResourcePool(config.Host, config.ResourcePool) + resourcePool, err := d.FindResourcePool(config.Cluster, config.Host, config.ResourcePool) if err != nil { return nil, err } - host, err := d.FindHost(config.Host) - if err != nil { - return nil, err + var host *object.HostSystem + if config.Host != "" { + h, err := d.FindHost(config.Host) + if err != nil { + return nil, err + } + host = h.host } datastore, err := d.FindDatastore(config.Datastore) @@ -126,7 +132,7 @@ func (d *Driver) CreateVM(config *CreateConfig) (*VirtualMachine, error) { VmPathName: fmt.Sprintf("[%s]", datastore.Name()), } - task, err := folder.folder.CreateVM(d.ctx, createSpec, resourcePool.pool, host.host) + task, err := folder.folder.CreateVM(d.ctx, createSpec, resourcePool.pool, host) if err != nil { return nil, err } @@ -172,7 +178,7 @@ func (template *VirtualMachine) Clone(config *CloneConfig) (*VirtualMachine, err var relocateSpec types.VirtualMachineRelocateSpec - pool, err := template.driver.FindResourcePool(config.Host, config.ResourcePool) + pool, err := template.driver.FindResourcePool(config.Cluster, config.Host, config.ResourcePool) if err != nil { return nil, err } diff --git a/iso/step_create.go b/iso/step_create.go index 1bbd3b6f1..849779d77 100644 --- a/iso/step_create.go +++ b/iso/step_create.go @@ -9,16 +9,12 @@ import ( ) type CreateConfig struct { + common.VMConfig `mapstructure:",squash"` common.HardwareConfig `mapstructure:",squash"` DiskThinProvisioned bool `mapstructure:"disk_thin_provisioned"` DiskControllerType string `mapstructure:"disk_controller_type"` - VMName string `mapstructure:"vm_name"` - Folder string `mapstructure:"folder"` - Host string `mapstructure:"host"` - ResourcePool string `mapstructure:"resource_pool"` - Datastore string `mapstructure:"datastore"` GuestOSType string `mapstructure:"guest_os_type"` Network string `mapstructure:"network"` NetworkCard string `mapstructure:"network_card"` @@ -32,16 +28,9 @@ func (c *CreateConfig) Prepare() []error { tmp := *c // do recursive calls + errs = append(errs, tmp.VMConfig.Prepare()...) errs = append(errs, tmp.HardwareConfig.Prepare()...) - // check for errors - if tmp.VMName == "" { - errs = append(errs, fmt.Errorf("Target VM name is required")) - } - if tmp.Host == "" { - errs = append(errs, fmt.Errorf("vSphere host is required")) - } - if len(errs) > 0 { return errs } @@ -74,6 +63,7 @@ func (s *StepCreateVM) Run(state multistep.StateBag) multistep.StepAction { DiskControllerType: s.Config.DiskControllerType, Name: s.Config.VMName, Folder: s.Config.Folder, + Cluster: s.Config.Cluster, Host: s.Config.Host, ResourcePool: s.Config.ResourcePool, Datastore: s.Config.Datastore,