github.com/vmware/govmomi@v0.43.0/govc/vm/instantclone.go (about)

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