Beispiel #1
0
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)
}
Beispiel #2
0
//
// 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)
}