func (cmd *clone) cloneVM(ctx context.Context) (*object.Task, error) { // search for the first network card of the source devices, err := cmd.VirtualMachine.Device(ctx) if err != nil { return nil, err } var card *types.VirtualEthernetCard for _, device := range devices { if c, ok := device.(types.BaseVirtualEthernetCard); ok { card = c.GetVirtualEthernetCard() break } } if card == nil { return nil, fmt.Errorf("No network device found.") } // get the new backing information dev, err := cmd.NetworkFlag.Device() if err != nil { return nil, err } //set backing info card.Backing = dev.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard().Backing // prepare virtual device config spec for network card configSpecs := []types.BaseVirtualDeviceConfigSpec{ &types.VirtualDeviceConfigSpec{ Operation: types.VirtualDeviceConfigSpecOperationEdit, Device: card, }, } folderref := cmd.Folder.Reference() poolref := cmd.ResourcePool.Reference() relocateSpec := types.VirtualMachineRelocateSpec{ DeviceChange: configSpecs, Folder: &folderref, Pool: &poolref, } if cmd.HostSystem != nil { hostref := cmd.HostSystem.Reference() relocateSpec.Host = &hostref } cloneSpec := &types.VirtualMachineCloneSpec{ Location: relocateSpec, PowerOn: false, Template: cmd.template, } // clone to storage pod datastoreref := types.ManagedObjectReference{} if cmd.StoragePod != nil && cmd.Datastore == nil { storagePod := cmd.StoragePod.Reference() // Build pod selection spec from config spec podSelectionSpec := types.StorageDrsPodSelectionSpec{ StoragePod: &storagePod, } // Get the virtual machine reference vmref := cmd.VirtualMachine.Reference() // Build the placement spec storagePlacementSpec := types.StoragePlacementSpec{ Folder: &folderref, Vm: &vmref, CloneName: cmd.name, CloneSpec: cloneSpec, PodSelectionSpec: podSelectionSpec, Type: string(types.StoragePlacementSpecPlacementTypeClone), } // Get the storage placement result storageResourceManager := object.NewStorageResourceManager(cmd.Client) result, err := storageResourceManager.RecommendDatastores(ctx, storagePlacementSpec) if err != nil { return nil, err } // Get the recommendations recommendations := result.Recommendations if len(recommendations) == 0 { return nil, fmt.Errorf("no recommendations") } // Get the first recommendation datastoreref = recommendations[0].Action[0].(*types.StoragePlacementAction).Destination } else if cmd.StoragePod == nil && cmd.Datastore != nil { datastoreref = cmd.Datastore.Reference() } else { return nil, fmt.Errorf("Please provide either a datastore or a storagepod") } // Set the destination datastore cloneSpec.Location.Datastore = &datastoreref // Check if vmx already exists if !cmd.force { vmxPath := fmt.Sprintf("%s/%s.vmx", cmd.name, cmd.name) datastore := object.NewDatastore(cmd.Client, datastoreref) _, err := datastore.Stat(ctx, vmxPath) if err == nil { dsPath := cmd.Datastore.Path(vmxPath) return nil, fmt.Errorf("File %s already exists", dsPath) } } // check if customization specification requested if len(cmd.customization) > 0 { // get the customization spec manager customizationSpecManager := object.NewCustomizationSpecManager(cmd.Client) // check if customization specification exists exists, err := customizationSpecManager.DoesCustomizationSpecExist(ctx, cmd.customization) if err != nil { return nil, err } if exists == false { return nil, fmt.Errorf("Customization specification %s does not exists.", cmd.customization) } // get the customization specification customSpecItem, err := customizationSpecManager.GetCustomizationSpec(ctx, cmd.customization) if err != nil { return nil, err } customSpec := customSpecItem.Spec // set the customization cloneSpec.Customization = &customSpec } // clone virtualmachine return cmd.VirtualMachine.Clone(ctx, cmd.Folder, cmd.name, *cloneSpec) }
// // Create creates the VM by // 1. Generating SSH keys // 2. Logs in to vSphere and gathers dc, datastore, network, resource pool and // other information // 3. Clones the VM template // 4. Powers on the VM // 5. Uploads the SSH key bundle // // Parameters: // None // Returns: // (error): various errors from vSphere // func (d *Driver) Create() error { var relocateSpec types.VirtualMachineRelocateSpec log.Infof("Generating SSH Keypair...") if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { return err } // Create context ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Query the inventory c, err := d.vsphereLogin(ctx) if err != nil { return err } defer c.Logout(ctx) // Create a new finder f := find.NewFinder(c.Client, true) dc, err := f.DatacenterOrDefault(ctx, d.Datacenter) if err != nil { return err } folders, err := dc.Folders(ctx) if err != nil { return err } folder := folders.VmFolder f.SetDatacenter(dc) dss, err := f.DatastoreOrDefault(ctx, d.Datastore) if err != nil { return err } rp, err := f.ResourcePoolOrDefault(ctx, d.Pool) if err != nil { // Pick default Resource Pool for Host System hs, err := f.HostSystemOrDefault(ctx, d.HostSystem) if err != nil { log.Warnf("Unable to find host system ", err) } if hs != nil { rp, err = hs.ResourcePool(ctx) if err != nil { return err } if hs != nil { hostref := hs.Reference() relocateSpec.Host = &hostref } } else { return err } } dcName, err := d.getDatacenterName(dc) if err != nil { return err } image, err := d.getVMTemplate(d.VMTemplate, dcName, c.Client) if err != nil { return err } var imageMoRef mo.VirtualMachine err = image.Properties(ctx, image.Reference(), []string{"parent", "config.template", "resourcePool", "snapshot", "guest.toolsVersionStatus2", "config.guestFullName"}, &imageMoRef) if err != nil { return fmt.Errorf("Error reading base VM properties: %s", err) } // Create a CloneSpec to clone the VM datastoreref := dss.Reference() folderref := folder.Reference() poolref := rp.Reference() relocateSpec.Datastore = &datastoreref relocateSpec.Folder = &folderref relocateSpec.Pool = &poolref spec := types.VirtualMachineConfigSpec{ Name: d.MachineName, GuestId: "otherLinux64Guest", Files: &types.VirtualMachineFileInfo{VmPathName: fmt.Sprintf("[%s]", dss.Name())}, NumCPUs: d.CPU, MemoryMB: int64(d.Memory), } cloneSpec := types.VirtualMachineCloneSpec{ Config: &spec, } if imageMoRef.Snapshot != nil { relocateSpec.DiskMoveType = "createNewChildDiskBacking" cloneSpec.Snapshot = imageMoRef.Snapshot.CurrentSnapshot } else { return fmt.Errorf("No snapshots for template, cannot use for cloning") } if d.Network != "" { // search for the first network card of the source devices, err := image.Device(ctx) if err != nil { return fmt.Errorf("Error reading base VM devices: %s", err) } var card *types.VirtualEthernetCard for _, device := range devices { if c, ok := device.(types.BaseVirtualEthernetCard); ok { card = c.GetVirtualEthernetCard() break } } if card == nil { return fmt.Errorf("No network device found for the template.") } // get the new backing information net, err := f.NetworkOrDefault(ctx, d.Network) if err != nil { return fmt.Errorf("Network not found: %s", err) } backing, err := net.EthernetCardBackingInfo(ctx) if err != nil { return fmt.Errorf("Network backing not found: %s", err) } netdev, err := object.EthernetCardTypes().CreateEthernetCard("vmxnet3", backing) if err != nil { return fmt.Errorf("Failed to create ethernet card: %s", err) } //set backing info card.Backing = netdev.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard().Backing // prepare virtual device config spec for network card configSpecs := []types.BaseVirtualDeviceConfigSpec{ &types.VirtualDeviceConfigSpec{ Operation: types.VirtualDeviceConfigSpecOperationEdit, Device: card, }, } relocateSpec.DeviceChange = configSpecs } cloneSpec.Location = relocateSpec task, err := image.Clone(ctx, folder, d.MachineName, cloneSpec) if err != nil { return fmt.Errorf("Error cloning vm: %s", err) } info, err := task.WaitForResult(ctx, nil) if err != nil { return fmt.Errorf("Error cloning vm: %s", err) } vmMoRef := info.Result.(types.ManagedObjectReference) vm := object.NewVirtualMachine(c.Client, vmMoRef) // Power On the VM if err := d.Start(); err != nil { return err } // Upload the bundle return d.uploadBundle(vm.Reference(), ctx, c.Client) }