func (cmd *clone) Run(ctx context.Context, f *flag.FlagSet) error { var err error if len(f.Args()) != 1 { return flag.ErrHelp } cmd.name = f.Arg(0) if cmd.name == "" { return flag.ErrHelp } cmd.Client, err = cmd.ClientFlag.Client() if err != nil { return err } cmd.Datacenter, err = cmd.DatacenterFlag.Datacenter() if err != nil { return err } if cmd.StoragePodFlag.Isset() { cmd.StoragePod, err = cmd.StoragePodFlag.StoragePod() if err != nil { return err } } else { cmd.Datastore, err = cmd.DatastoreFlag.Datastore() if err != nil { return err } } cmd.HostSystem, err = cmd.HostSystemFlag.HostSystemIfSpecified() if err != nil { return err } if cmd.HostSystem != nil { if cmd.ResourcePool, err = cmd.HostSystem.ResourcePool(context.TODO()); err != nil { return err } } else { // -host is optional if cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool(); err != nil { return err } } if cmd.Folder, err = cmd.FolderFlag.Folder(); err != nil { return err } if cmd.VirtualMachine, err = cmd.VirtualMachineFlag.VirtualMachine(); err != nil { return err } task, err := cmd.cloneVM(context.TODO()) if err != nil { return err } info, err := task.WaitForResult(context.TODO(), nil) if err != nil { return err } vm := object.NewVirtualMachine(cmd.Client, info.Result.(types.ManagedObjectReference)) if cmd.cpus > 0 || cmd.memory > 0 { vmConfigSpec := types.VirtualMachineConfigSpec{} if cmd.cpus > 0 { vmConfigSpec.NumCPUs = int32(cmd.cpus) } if cmd.memory > 0 { vmConfigSpec.MemoryMB = int64(cmd.memory) } task, err := vm.Reconfigure(context.TODO(), vmConfigSpec) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } } if cmd.on { task, err := vm.PowerOn(context.TODO()) if err != nil { return err } _, err = task.WaitForResult(context.TODO(), nil) if err != nil { return err } if cmd.waitForIP { _, err = vm.WaitForIP(ctx) if err != nil { return err } } } return nil }
func resourceVirtualMachineCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*vim25.Client) dc_name := d.Get("datacenter").(string) if dc_name == "" { finder := find.NewFinder(client, false) dc, err := finder.DefaultDatacenter(context.TODO()) if err != nil { return fmt.Errorf("Error reading default datacenter: %s", err) } var dc_mo mo.Datacenter err = dc.Properties(context.TODO(), dc.Reference(), []string{"name"}, &dc_mo) if err != nil { return fmt.Errorf("Error reading datacenter name: %s", err) } dc_name = dc_mo.Name d.Set("datacenter", dc_name) } image_name := d.Get("image").(string) image_ref, err := object.NewSearchIndex(client).FindByInventoryPath(context.TODO(), fmt.Sprintf("%s/vm/%s", dc_name, image_name)) if err != nil { return fmt.Errorf("Error reading vm: %s", err) } if image_ref == nil { return fmt.Errorf("Cannot find image %s", image_name) } image := image_ref.(*object.VirtualMachine) var image_mo mo.VirtualMachine err = image.Properties(context.TODO(), image.Reference(), []string{"parent", "config.template", "resourcePool", "snapshot", "guest.toolsVersionStatus2", "config.guestFullName"}, &image_mo) if err != nil { return fmt.Errorf("Error reading base VM properties: %s", err) } var folder_ref object.Reference var folder *object.Folder if d.Get("folder").(string) != "" { folder_ref, err = object.NewSearchIndex(client).FindByInventoryPath(context.TODO(), fmt.Sprintf("%v/vm/%v", dc_name, d.Get("folder").(string))) if err != nil { return fmt.Errorf("Error reading folder: %s", err) } if folder_ref == nil { return fmt.Errorf("Cannot find folder %s", d.Get("folder").(string)) } folder = folder_ref.(*object.Folder) } else { folder = object.NewFolder(client, *image_mo.Parent) } host_name := d.Get("host").(string) if host_name == "" { if image_mo.Config.Template == true { return fmt.Errorf("Image is a template, 'host' is a required") } else { var pool_mo mo.ResourcePool err = property.DefaultCollector(client).RetrieveOne(context.TODO(), *image_mo.ResourcePool, []string{"owner"}, &pool_mo) if err != nil { return fmt.Errorf("Error reading resource pool of base VM: %s", err) } if strings.Contains(pool_mo.Owner.Value, "domain-s") { var host_mo mo.ComputeResource err = property.DefaultCollector(client).RetrieveOne(context.TODO(), pool_mo.Owner, []string{"name"}, &host_mo) if err != nil { return fmt.Errorf("Error reading host of base VM: %s", err) } host_name = host_mo.Name } else if strings.Contains(pool_mo.Owner.Value, "domain-c") { var cluster_mo mo.ClusterComputeResource err = property.DefaultCollector(client).RetrieveOne(context.TODO(), pool_mo.Owner, []string{"name"}, &cluster_mo) if err != nil { return fmt.Errorf("Error reading cluster of base VM: %s", err) } host_name = cluster_mo.Name } else { return fmt.Errorf("Unknown compute resource format of base VM: %s", pool_mo.Owner.Value) } } } pool_name := d.Get("resource_pool").(string) pool_ref, err := object.NewSearchIndex(client).FindByInventoryPath(context.TODO(), fmt.Sprintf("%v/host/%v/Resources/%v", dc_name, host_name, pool_name)) if err != nil { return fmt.Errorf("Error reading resource pool: %s", err) } if pool_ref == nil { return fmt.Errorf("Cannot find resource pool %s", pool_name) } var relocateSpec types.VirtualMachineRelocateSpec var pool_mor types.ManagedObjectReference pool_mor = pool_ref.Reference() relocateSpec.Pool = &pool_mor if d.Get("linked_clone").(bool) { relocateSpec.DiskMoveType = "createNewChildDiskBacking" } var confSpec types.VirtualMachineConfigSpec if d.Get("cpus") != nil { confSpec.NumCPUs = d.Get("cpus").(int) } if d.Get("memory") != nil { confSpec.MemoryMB = int64(d.Get("memory").(int)) } params := d.Get("configuration_parameters").(map[string]interface{}) var ov []types.BaseOptionValue if len(params) > 0 { for k, v := range params { key := k value := v o := types.OptionValue{ Key: key, Value: &value, } ov = append(ov, &o) } confSpec.ExtraConfig = ov } cloneSpec := types.VirtualMachineCloneSpec{ Location: relocateSpec, Config: &confSpec, PowerOn: d.Get("power_on").(bool), } if d.Get("linked_clone").(bool) { if image_mo.Snapshot == nil { return fmt.Errorf("`linked_clone=true`, but image VM has no snapshots") } cloneSpec.Snapshot = image_mo.Snapshot.CurrentSnapshot } domain := d.Get("domain").(string) ip_address := d.Get("ip_address").(string) if domain != "" { if image_mo.Guest.ToolsVersionStatus2 == "guestToolsNotInstalled" { return fmt.Errorf("VMware tools are not installed in base VM") } if !strings.Contains(image_mo.Config.GuestFullName, "Linux") && !strings.Contains(image_mo.Config.GuestFullName, "CentOS") { return fmt.Errorf("Guest customization is supported only for Linux. Base image OS is: %s", image_mo.Config.GuestFullName) } customizationSpec := types.CustomizationSpec{ GlobalIPSettings: types.CustomizationGlobalIPSettings{}, Identity: &types.CustomizationLinuxPrep{ HostName: &types.CustomizationVirtualMachineName{}, Domain: domain, }, NicSettingMap: []types.CustomizationAdapterMapping{ { Adapter: types.CustomizationIPSettings{}, }, }, } if ip_address != "" { mask := d.Get("subnet_mask").(string) if mask == "" { return fmt.Errorf("'subnet_mask' must be set, if static 'ip_address' is specified") } customizationSpec.NicSettingMap[0].Adapter.Ip = &types.CustomizationFixedIp{ IpAddress: ip_address, } customizationSpec.NicSettingMap[0].Adapter.SubnetMask = d.Get("subnet_mask").(string) gateway := d.Get("gateway").(string) if gateway != "" { customizationSpec.NicSettingMap[0].Adapter.Gateway = []string{gateway} } } else { customizationSpec.NicSettingMap[0].Adapter.Ip = &types.CustomizationDhcpIpGenerator{} } cloneSpec.Customization = &customizationSpec } else if ip_address != "" { return fmt.Errorf("'domain' must be set, if static 'ip_address' is specified") } task, err := image.Clone(context.TODO(), folder, d.Get("name").(string), cloneSpec) if err != nil { return fmt.Errorf("Error clonning vm: %s", err) } info, err := task.WaitForResult(context.TODO(), nil) if err != nil { return fmt.Errorf("Error clonning vm: %s", err) } vm_mor := info.Result.(types.ManagedObjectReference) d.SetId(vm_mor.Value) vm := object.NewVirtualMachine(client, vm_mor) // workaround for https://github.com/vmware/govmomi/issues/218 if ip_address == "" && d.Get("power_on").(bool) { ip, err := vm.WaitForIP(context.TODO()) if err != nil { log.Printf("[ERROR] Cannot read ip address: %s", err) } else { d.Set("ip_address", ip) d.SetConnInfo(map[string]string{ "type": "ssh", "host": ip, }) } } return nil }
func resourceVSphereVirtualMachineUpdate(d *schema.ResourceData, meta interface{}) error { // flag if changes have to be applied hasChanges := false // flag if changes have to be done when powered off rebootRequired := false // make config spec configSpec := types.VirtualMachineConfigSpec{} if d.HasChange("vcpu") { configSpec.NumCPUs = d.Get("vcpu").(int) hasChanges = true rebootRequired = true } if d.HasChange("memory") { configSpec.MemoryMB = int64(d.Get("memory").(int)) hasChanges = true rebootRequired = true } // do nothing if there are no changes if !hasChanges { return nil } client := meta.(*govmomi.Client) dc, err := getDatacenter(client, d.Get("datacenter").(string)) if err != nil { return err } finder := find.NewFinder(client.Client, true) finder = finder.SetDatacenter(dc) vm, err := finder.VirtualMachine(context.TODO(), vmPath(d.Get("folder").(string), d.Get("name").(string))) if err != nil { return err } log.Printf("[DEBUG] virtual machine config spec: %v", configSpec) if rebootRequired { log.Printf("[INFO] Shutting down virtual machine: %s", d.Id()) task, err := vm.PowerOff(context.TODO()) if err != nil { return err } err = task.Wait(context.TODO()) if err != nil { return err } } log.Printf("[INFO] Reconfiguring virtual machine: %s", d.Id()) task, err := vm.Reconfigure(context.TODO(), configSpec) if err != nil { log.Printf("[ERROR] %s", err) } err = task.Wait(context.TODO()) if err != nil { log.Printf("[ERROR] %s", err) } if rebootRequired { task, err = vm.PowerOn(context.TODO()) if err != nil { return err } err = task.Wait(context.TODO()) if err != nil { log.Printf("[ERROR] %s", err) } } ip, err := vm.WaitForIP(context.TODO()) if err != nil { return err } log.Printf("[DEBUG] ip address: %v", ip) return resourceVSphereVirtualMachineRead(d, meta) }
func resourceVSphereVirtualMachineUpdate(d *schema.ResourceData, meta interface{}) error { // flag if changes have to be applied hasChanges := false // flag if changes have to be done when powered off rebootRequired := false // make config spec configSpec := types.VirtualMachineConfigSpec{} if d.HasChange("vcpu") { configSpec.NumCPUs = int32(d.Get("vcpu").(int)) hasChanges = true rebootRequired = true } if d.HasChange("memory") { configSpec.MemoryMB = int64(d.Get("memory").(int)) hasChanges = true rebootRequired = true } client := meta.(*govmomi.Client) dc, err := getDatacenter(client, d.Get("datacenter").(string)) if err != nil { return err } finder := find.NewFinder(client.Client, true) finder = finder.SetDatacenter(dc) vm, err := finder.VirtualMachine(context.TODO(), vmPath(d.Get("folder").(string), d.Get("name").(string))) if err != nil { return err } if d.HasChange("disk") { hasChanges = true oldDisks, newDisks := d.GetChange("disk") oldDiskSet := oldDisks.(*schema.Set) newDiskSet := newDisks.(*schema.Set) addedDisks := newDiskSet.Difference(oldDiskSet) removedDisks := oldDiskSet.Difference(newDiskSet) // Removed disks for _, diskRaw := range removedDisks.List() { if disk, ok := diskRaw.(map[string]interface{}); ok { devices, err := vm.Device(context.TODO()) if err != nil { return fmt.Errorf("[ERROR] Update Remove Disk - Could not get virtual device list: %v", err) } virtualDisk := devices.FindByKey(int32(disk["key"].(int))) keep := false if v, ok := d.GetOk("keep_on_remove"); ok { keep = v.(bool) } err = vm.RemoveDevice(context.TODO(), keep, virtualDisk) if err != nil { return fmt.Errorf("[ERROR] Update Remove Disk - Error removing disk: %v", err) } } } // Added disks for _, diskRaw := range addedDisks.List() { if disk, ok := diskRaw.(map[string]interface{}); ok { var datastore *object.Datastore if disk["datastore"] == "" { datastore, err = finder.DefaultDatastore(context.TODO()) if err != nil { return fmt.Errorf("[ERROR] Update Remove Disk - Error finding datastore: %v", err) } } else { datastore, err = finder.Datastore(context.TODO(), disk["datastore"].(string)) if err != nil { log.Printf("[ERROR] Couldn't find datastore %v. %s", disk["datastore"].(string), err) return err } } var size int64 if disk["size"] == 0 { size = 0 } else { size = int64(disk["size"].(int)) } iops := int64(disk["iops"].(int)) controller_type := disk["controller"].(string) var mo mo.VirtualMachine vm.Properties(context.TODO(), vm.Reference(), []string{"summary", "config"}, &mo) var diskPath string switch { case disk["vmdk"] != "": diskPath = disk["vmdk"].(string) case disk["name"] != "": snapshotFullDir := mo.Config.Files.SnapshotDirectory split := strings.Split(snapshotFullDir, " ") if len(split) != 2 { return fmt.Errorf("[ERROR] createVirtualMachine - failed to split snapshot directory: %v", snapshotFullDir) } vmWorkingPath := split[1] diskPath = vmWorkingPath + disk["name"].(string) default: return fmt.Errorf("[ERROR] resourceVSphereVirtualMachineUpdate - Neither vmdk path nor vmdk name was given") } log.Printf("[INFO] Attaching disk: %v", diskPath) err = addHardDisk(vm, size, iops, "thin", datastore, diskPath, controller_type) if err != nil { log.Printf("[ERROR] Add Hard Disk Failed: %v", err) return err } } if err != nil { return err } } } // do nothing if there are no changes if !hasChanges { return nil } log.Printf("[DEBUG] virtual machine config spec: %v", configSpec) if rebootRequired { log.Printf("[INFO] Shutting down virtual machine: %s", d.Id()) task, err := vm.PowerOff(context.TODO()) if err != nil { return err } err = task.Wait(context.TODO()) if err != nil { return err } } log.Printf("[INFO] Reconfiguring virtual machine: %s", d.Id()) task, err := vm.Reconfigure(context.TODO(), configSpec) if err != nil { log.Printf("[ERROR] %s", err) } err = task.Wait(context.TODO()) if err != nil { log.Printf("[ERROR] %s", err) } if rebootRequired { task, err = vm.PowerOn(context.TODO()) if err != nil { return err } err = task.Wait(context.TODO()) if err != nil { log.Printf("[ERROR] %s", err) } } ip, err := vm.WaitForIP(context.TODO()) if err != nil { return err } log.Printf("[DEBUG] ip address: %v", ip) return resourceVSphereVirtualMachineRead(d, meta) }