// Create has the following implementation: // 1. check whether the docker directory contains the boot2docker ISO // 2. generate an SSH keypair and bundle it in a tar. // 3. create a virtual machine with the boot2docker ISO mounted; // 4. reconfigure the virtual machine network and disk size; func (d *Driver) Create() error { b2dutils := mcnutils.NewB2dUtils(d.StorePath) if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil { return err } 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() 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 } f.SetDatacenter(dc) dss, err := f.DatastoreOrDefault(ctx, d.Datastore) if err != nil { return err } net, err := f.NetworkOrDefault(ctx, d.Network) if err != nil { return err } hs, err := f.HostSystemOrDefault(ctx, d.HostSystem) if err != nil { return err } var rp *object.ResourcePool if d.Pool != "" { // Find specified Resource Pool rp, err = f.ResourcePool(ctx, d.Pool) if err != nil { return err } } else { // Pick default Resource Pool for Host System rp, err = hs.ResourcePool(ctx) if err != nil { return err } } spec := types.VirtualMachineConfigSpec{ Name: d.MachineName, GuestId: "otherLinux64Guest", Files: &types.VirtualMachineFileInfo{VmPathName: fmt.Sprintf("[%s]", dss.Name())}, NumCPUs: int32(d.CPU), MemoryMB: int64(d.Memory), } scsi, err := object.SCSIControllerTypes().CreateSCSIController("pvscsi") if err != nil { return err } spec.DeviceChange = append(spec.DeviceChange, &types.VirtualDeviceConfigSpec{ Operation: types.VirtualDeviceConfigSpecOperationAdd, Device: scsi, }) log.Infof("Creating VM...") folders, err := dc.Folders(ctx) task, err := folders.VmFolder.CreateVM(ctx, spec, rp, hs) if err != nil { return err } info, err := task.WaitForResult(ctx, nil) if err != nil { return err } log.Infof("Uploading Boot2docker ISO ...") dsurl, err := dss.URL(ctx, dc, fmt.Sprintf("%s/%s", d.MachineName, isoFilename)) if err != nil { return err } p := soap.DefaultUpload if err = c.Client.UploadFile(d.ISO, dsurl, &p); err != nil { return err } // Retrieve the new VM vm := object.NewVirtualMachine(c.Client, info.Result.(types.ManagedObjectReference)) devices, err := vm.Device(ctx) if err != nil { return err } var add []types.BaseVirtualDevice controller, err := devices.FindDiskController("scsi") if err != nil { return err } disk := devices.CreateDisk(controller, dss.Reference(), dss.Path(fmt.Sprintf("%s/%s.vmdk", d.MachineName, d.MachineName))) // Convert MB to KB disk.CapacityInKB = int64(d.DiskSize) * 1024 add = append(add, disk) ide, err := devices.FindIDEController("") if err != nil { return err } cdrom, err := devices.CreateCdrom(ide) if err != nil { return err } add = append(add, devices.InsertIso(cdrom, dss.Path(fmt.Sprintf("%s/%s", d.MachineName, isoFilename)))) backing, err := net.EthernetCardBackingInfo(ctx) if err != nil { return err } netdev, err := object.EthernetCardTypes().CreateEthernetCard("vmxnet3", backing) if err != nil { return err } log.Infof("Reconfiguring VM...") add = append(add, netdev) if vm.AddDevice(ctx, add...); err != nil { return err } if err := d.Start(); err != nil { return err } log.Infof("Provisioning certs and ssh keys...") // Generate a tar keys bundle if err := d.generateKeyBundle(); err != nil { return err } opman := guest.NewOperationsManager(c.Client, vm.Reference()) fileman, err := opman.FileManager(ctx) if err != nil { return err } src := d.ResolveStorePath("userdata.tar") s, err := os.Stat(src) if err != nil { return err } auth := AuthFlag{} flag := FileAttrFlag{} auth.auth.Username = B2DUser auth.auth.Password = B2DPass flag.SetPerms(0, 0, 660) url, err := fileman.InitiateFileTransferToGuest(ctx, auth.Auth(), "/home/docker/userdata.tar", flag.Attr(), s.Size(), true) if err != nil { return err } u, err := c.Client.ParseURL(url) if err != nil { return err } if err = c.Client.UploadFile(src, u, nil); err != nil { return err } procman, err := opman.ProcessManager(ctx) if err != nil { return err } var env []string guestspec := types.GuestProgramSpec{ ProgramPath: "/usr/bin/sudo", Arguments: "/bin/mv /home/docker/userdata.tar /var/lib/boot2docker/userdata.tar && /usr/bin/sudo tar xf /var/lib/boot2docker/userdata.tar -C /home/docker/ > /var/log/userdata.log 2>&1 && /usr/bin/sudo chown -R docker:staff /home/docker", WorkingDirectory: "", EnvVariables: env, } _, err = procman.StartProgram(ctx, auth.Auth(), &guestspec) if err != nil { return err } return nil }
// // 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) }