github.com/vmware/govmomi@v0.51.0/cli/vm/instantclone.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package vm 6 7 import ( 8 "context" 9 "flag" 10 "fmt" 11 12 "github.com/vmware/govmomi/cli" 13 "github.com/vmware/govmomi/cli/flags" 14 "github.com/vmware/govmomi/object" 15 "github.com/vmware/govmomi/vim25" 16 "github.com/vmware/govmomi/vim25/types" 17 ) 18 19 type instantclone struct { 20 *flags.ClientFlag 21 *flags.DatacenterFlag 22 *flags.DatastoreFlag 23 *flags.ResourcePoolFlag 24 *flags.NetworkFlag 25 *flags.FolderFlag 26 *flags.VirtualMachineFlag 27 28 name string 29 extraConfig extraConfig 30 31 Client *vim25.Client 32 Datacenter *object.Datacenter 33 Datastore *object.Datastore 34 ResourcePool *object.ResourcePool 35 Folder *object.Folder 36 VirtualMachine *object.VirtualMachine 37 } 38 39 func init() { 40 cli.Register("vm.instantclone", &instantclone{}) 41 } 42 43 func (cmd *instantclone) Register(ctx context.Context, f *flag.FlagSet) { 44 cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) 45 cmd.ClientFlag.Register(ctx, f) 46 47 cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx) 48 cmd.DatacenterFlag.Register(ctx, f) 49 50 cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx) 51 cmd.DatastoreFlag.Register(ctx, f) 52 53 cmd.ResourcePoolFlag, ctx = flags.NewResourcePoolFlag(ctx) 54 cmd.ResourcePoolFlag.Register(ctx, f) 55 56 cmd.NetworkFlag, ctx = flags.NewNetworkFlag(ctx) 57 cmd.NetworkFlag.Register(ctx, f) 58 59 cmd.FolderFlag, ctx = flags.NewFolderFlag(ctx) 60 cmd.FolderFlag.Register(ctx, f) 61 62 cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx) 63 cmd.VirtualMachineFlag.Register(ctx, f) 64 65 f.Var(&cmd.extraConfig, "e", "ExtraConfig. <key>=<value>") 66 } 67 68 func (cmd *instantclone) Usage() string { 69 return "NAME" 70 } 71 72 func (cmd *instantclone) Description() string { 73 return `Instant Clone VM to NAME. 74 75 Examples: 76 govc vm.instantclone -vm source-vm new-vm 77 # Configure ExtraConfig variables on a guest VM: 78 govc vm.instantclone -vm source-vm -e guestinfo.ipaddress=192.168.0.1 -e guestinfo.netmask=255.255.255.0 new-vm 79 # Read the variable set above inside the guest: 80 vmware-rpctool "info-get guestinfo.ipaddress" 81 vmware-rpctool "info-get guestinfo.netmask"` 82 } 83 84 func (cmd *instantclone) Process(ctx context.Context) error { 85 if err := cmd.ClientFlag.Process(ctx); err != nil { 86 return err 87 } 88 if err := cmd.DatacenterFlag.Process(ctx); err != nil { 89 return err 90 } 91 if err := cmd.DatastoreFlag.Process(ctx); err != nil { 92 return err 93 } 94 if err := cmd.ResourcePoolFlag.Process(ctx); err != nil { 95 return err 96 } 97 if err := cmd.NetworkFlag.Process(ctx); err != nil { 98 return err 99 } 100 if err := cmd.FolderFlag.Process(ctx); err != nil { 101 return err 102 } 103 if err := cmd.VirtualMachineFlag.Process(ctx); err != nil { 104 return err 105 } 106 107 return nil 108 } 109 110 func (cmd *instantclone) Run(ctx context.Context, f *flag.FlagSet) error { 111 var err error 112 113 if len(f.Args()) != 1 { 114 return flag.ErrHelp 115 } 116 117 cmd.name = f.Arg(0) 118 if cmd.name == "" { 119 return flag.ErrHelp 120 } 121 122 cmd.Client, err = cmd.ClientFlag.Client() 123 if err != nil { 124 return err 125 } 126 127 cmd.Datacenter, err = cmd.DatacenterFlag.Datacenter() 128 if err != nil { 129 return err 130 } 131 132 cmd.Datastore, err = cmd.DatastoreFlag.Datastore() 133 if err != nil { 134 return err 135 } 136 137 cmd.Folder, err = cmd.FolderFlag.Folder() 138 if err != nil { 139 return err 140 } 141 142 cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool() 143 if err != nil { 144 return err 145 } 146 147 cmd.VirtualMachine, err = cmd.VirtualMachineFlag.VirtualMachine() 148 if err != nil { 149 return err 150 } 151 152 if cmd.VirtualMachine == nil { 153 return flag.ErrHelp 154 } 155 156 _, err = cmd.instantcloneVM(ctx) 157 if err != nil { 158 return err 159 } 160 161 return nil 162 } 163 164 func (cmd *instantclone) instantcloneVM(ctx context.Context) (*object.VirtualMachine, error) { 165 relocateSpec := types.VirtualMachineRelocateSpec{} 166 167 if cmd.NetworkFlag.IsSet() { 168 devices, err := cmd.VirtualMachine.Device(ctx) 169 if err != nil { 170 return nil, err 171 } 172 173 // prepare virtual device config spec for network card 174 configSpecs := []types.BaseVirtualDeviceConfigSpec{} 175 176 op := types.VirtualDeviceConfigSpecOperationAdd 177 card, derr := cmd.NetworkFlag.Device() 178 if derr != nil { 179 return nil, derr 180 } 181 // search for the first network card of the source 182 for _, device := range devices { 183 if _, ok := device.(types.BaseVirtualEthernetCard); ok { 184 op = types.VirtualDeviceConfigSpecOperationEdit 185 // set new backing info 186 cmd.NetworkFlag.Change(device, card) 187 card = device 188 break 189 } 190 } 191 192 configSpecs = append(configSpecs, &types.VirtualDeviceConfigSpec{ 193 Operation: op, 194 Device: card, 195 }) 196 197 relocateSpec.DeviceChange = configSpecs 198 } 199 200 if cmd.FolderFlag.IsSet() { 201 folderref := cmd.Folder.Reference() 202 relocateSpec.Folder = &folderref 203 } 204 205 if cmd.ResourcePoolFlag.IsSet() { 206 poolref := cmd.ResourcePool.Reference() 207 relocateSpec.Pool = &poolref 208 } 209 210 if cmd.DatastoreFlag.IsSet() { 211 datastoreref := cmd.Datastore.Reference() 212 relocateSpec.Datastore = &datastoreref 213 } 214 215 instantcloneSpec := &types.VirtualMachineInstantCloneSpec{ 216 Name: cmd.name, 217 Location: relocateSpec, 218 } 219 220 if len(cmd.extraConfig) > 0 { 221 instantcloneSpec.Config = cmd.extraConfig 222 } 223 224 task, err := cmd.VirtualMachine.InstantClone(ctx, *instantcloneSpec) 225 if err != nil { 226 return nil, err 227 } 228 229 logger := cmd.ProgressLogger(fmt.Sprintf("Instant Cloning %s to %s...", cmd.VirtualMachine.InventoryPath, cmd.name)) 230 defer logger.Wait() 231 232 info, err := task.WaitForResult(ctx, logger) 233 if err != nil { 234 return nil, err 235 } 236 237 return object.NewVirtualMachine(cmd.Client, info.Result.(types.ManagedObjectReference)), nil 238 }