1/* 2Copyright (c) 2015-2017 VMware, Inc. All Rights Reserved. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package vm 18 19import ( 20 "context" 21 "flag" 22 "fmt" 23 "strings" 24 25 "github.com/vmware/govmomi/govc/cli" 26 "github.com/vmware/govmomi/govc/flags" 27 "github.com/vmware/govmomi/vim25/types" 28) 29 30type extraConfig []types.BaseOptionValue 31 32func (e *extraConfig) String() string { 33 return fmt.Sprintf("%v", *e) 34} 35 36func (e *extraConfig) Set(v string) error { 37 r := strings.SplitN(v, "=", 2) 38 if len(r) < 2 { 39 return fmt.Errorf("failed to parse extraConfig: %s", v) 40 } 41 *e = append(*e, &types.OptionValue{Key: r[0], Value: r[1]}) 42 return nil 43} 44 45type change struct { 46 *flags.VirtualMachineFlag 47 *flags.ResourceAllocationFlag 48 49 types.VirtualMachineConfigSpec 50 extraConfig extraConfig 51} 52 53func init() { 54 cli.Register("vm.change", &change{}) 55} 56 57// setAllocation sets *info=nil if none of the fields have been set. 58// We need non-nil fields for use with flag.FlagSet, but we want the 59// VirtualMachineConfigSpec fields to be nil if none of the related flags were given. 60func setAllocation(info **types.ResourceAllocationInfo) { 61 r := *info 62 63 if r.Shares.Level == "" { 64 r.Shares = nil 65 } else { 66 return 67 } 68 69 if r.Limit != nil { 70 return 71 } 72 73 if r.Reservation != nil { 74 return 75 } 76 77 *info = nil 78} 79 80func (cmd *change) Register(ctx context.Context, f *flag.FlagSet) { 81 cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx) 82 cmd.VirtualMachineFlag.Register(ctx, f) 83 84 cmd.CpuAllocation = &types.ResourceAllocationInfo{Shares: new(types.SharesInfo)} 85 cmd.MemoryAllocation = &types.ResourceAllocationInfo{Shares: new(types.SharesInfo)} 86 cmd.ResourceAllocationFlag = flags.NewResourceAllocationFlag(cmd.CpuAllocation, cmd.MemoryAllocation) 87 cmd.ResourceAllocationFlag.ExpandableReservation = false 88 cmd.ResourceAllocationFlag.Register(ctx, f) 89 90 f.Int64Var(&cmd.MemoryMB, "m", 0, "Size in MB of memory") 91 f.Var(flags.NewInt32(&cmd.NumCPUs), "c", "Number of CPUs") 92 f.StringVar(&cmd.GuestId, "g", "", "Guest OS") 93 f.StringVar(&cmd.Name, "name", "", "Display name") 94 f.Var(&cmd.extraConfig, "e", "ExtraConfig. <key>=<value>") 95 96 f.Var(flags.NewOptionalBool(&cmd.NestedHVEnabled), "nested-hv-enabled", "Enable nested hardware-assisted virtualization") 97 cmd.Tools = &types.ToolsConfigInfo{} 98 f.Var(flags.NewOptionalBool(&cmd.Tools.SyncTimeWithHost), "sync-time-with-host", "Enable SyncTimeWithHost") 99} 100 101func (cmd *change) Description() string { 102 return `Change VM configuration. 103 104To add ExtraConfig variables that can read within the guest, use the 'guestinfo.' prefix. 105 106Examples: 107 govc vm.change -vm $vm -mem.reservation 2048 108 govc vm.change -vm $vm -e smc.present=TRUE -e ich7m.present=TRUE 109 govc vm.change -vm $vm -e guestinfo.vmname $vm 110 # Read the variable set above inside the guest: 111 vmware-rpctool "info-get guestinfo.vmname"` 112} 113 114func (cmd *change) Process(ctx context.Context) error { 115 if err := cmd.VirtualMachineFlag.Process(ctx); err != nil { 116 return err 117 } 118 return nil 119} 120 121func (cmd *change) Run(ctx context.Context, f *flag.FlagSet) error { 122 vm, err := cmd.VirtualMachine() 123 if err != nil { 124 return err 125 } 126 127 if vm == nil { 128 return flag.ErrHelp 129 } 130 131 if len(cmd.extraConfig) > 0 { 132 cmd.VirtualMachineConfigSpec.ExtraConfig = cmd.extraConfig 133 } 134 135 setAllocation(&cmd.CpuAllocation) 136 setAllocation(&cmd.MemoryAllocation) 137 138 task, err := vm.Reconfigure(ctx, cmd.VirtualMachineConfigSpec) 139 if err != nil { 140 return err 141 } 142 143 return task.Wait(ctx) 144} 145