github.com/vmware/govmomi@v0.37.1/govc/vm/change.go (about) 1 /* 2 Copyright (c) 2015-2017 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 "os" 24 "reflect" 25 "strings" 26 27 "github.com/vmware/govmomi/govc/cli" 28 "github.com/vmware/govmomi/govc/flags" 29 "github.com/vmware/govmomi/vim25/types" 30 ) 31 32 type extraConfig []types.BaseOptionValue 33 34 func (e *extraConfig) String() string { 35 return fmt.Sprintf("%v", *e) 36 } 37 38 func (e *extraConfig) Set(v string) error { 39 r := strings.SplitN(v, "=", 2) 40 if len(r) < 2 { 41 return fmt.Errorf("failed to parse extraConfig: %s", v) 42 } 43 *e = append(*e, &types.OptionValue{Key: r[0], Value: r[1]}) 44 return nil 45 } 46 47 type extraConfigFile []types.BaseOptionValue 48 49 func (e *extraConfigFile) String() string { 50 return fmt.Sprintf("%v", *e) 51 } 52 53 func (e *extraConfigFile) Set(v string) error { 54 r := strings.SplitN(v, "=", 2) 55 if len(r) < 2 { 56 return fmt.Errorf("failed to parse extraConfigFile: %s", v) 57 } 58 59 var fileContents = "" 60 if len(r[1]) > 0 { 61 contents, err := os.ReadFile(r[1]) 62 if err != nil { 63 return fmt.Errorf("failed to parse extraConfigFile '%s': %w", v, err) 64 } 65 fileContents = string(contents) 66 } 67 68 *e = append(*e, &types.OptionValue{Key: r[0], Value: fileContents}) 69 return nil 70 } 71 72 type change struct { 73 *flags.VirtualMachineFlag 74 *flags.ResourceAllocationFlag 75 76 types.VirtualMachineConfigSpec 77 extraConfig extraConfig 78 extraConfigFile extraConfigFile 79 Latency string 80 hwUpgradePolicy string 81 } 82 83 func init() { 84 cli.Register("vm.change", &change{}) 85 } 86 87 var latencyLevels = []string{ 88 string(types.LatencySensitivitySensitivityLevelLow), 89 string(types.LatencySensitivitySensitivityLevelNormal), 90 string(types.LatencySensitivitySensitivityLevelHigh), 91 } 92 93 // setLatency validates latency level if set 94 func (cmd *change) setLatency() error { 95 if cmd.Latency == "" { 96 return nil 97 } 98 for _, l := range latencyLevels { 99 if l == cmd.Latency { 100 cmd.LatencySensitivity = &types.LatencySensitivity{ 101 Level: types.LatencySensitivitySensitivityLevel(cmd.Latency), 102 } 103 return nil 104 } 105 } 106 return fmt.Errorf("latency must be one of: %s", strings.Join(latencyLevels, "|")) 107 } 108 109 var hwUpgradePolicies = []string{ 110 string(types.ScheduledHardwareUpgradeInfoHardwareUpgradePolicyOnSoftPowerOff), 111 string(types.ScheduledHardwareUpgradeInfoHardwareUpgradePolicyNever), 112 string(types.ScheduledHardwareUpgradeInfoHardwareUpgradePolicyAlways), 113 } 114 115 // setHwUpgradePolicy validates hwUpgradePolicy if set 116 func (cmd *change) setHwUpgradePolicy() error { 117 if cmd.hwUpgradePolicy == "" { 118 return nil 119 } 120 for _, l := range hwUpgradePolicies { 121 if l == cmd.hwUpgradePolicy { 122 cmd.ScheduledHardwareUpgradeInfo = &types.ScheduledHardwareUpgradeInfo{ 123 UpgradePolicy: string(types.ScheduledHardwareUpgradeInfoHardwareUpgradePolicy(cmd.hwUpgradePolicy)), 124 } 125 return nil 126 } 127 } 128 return fmt.Errorf("Hardware upgrade policy must be one of: %s", strings.Join(hwUpgradePolicies, "|")) 129 } 130 131 // setAllocation sets *info=nil if none of the fields have been set. 132 // We need non-nil fields for use with flag.FlagSet, but we want the 133 // VirtualMachineConfigSpec fields to be nil if none of the related flags were given. 134 func setAllocation(info **types.ResourceAllocationInfo) { 135 r := *info 136 137 if r.Shares.Level == "" { 138 r.Shares = nil 139 } else { 140 return 141 } 142 143 if r.Limit != nil { 144 return 145 } 146 147 if r.Reservation != nil { 148 return 149 } 150 151 *info = nil 152 } 153 154 func (cmd *change) Register(ctx context.Context, f *flag.FlagSet) { 155 cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx) 156 cmd.VirtualMachineFlag.Register(ctx, f) 157 158 cmd.CpuAllocation = &types.ResourceAllocationInfo{Shares: new(types.SharesInfo)} 159 cmd.MemoryAllocation = &types.ResourceAllocationInfo{Shares: new(types.SharesInfo)} 160 cmd.ResourceAllocationFlag = flags.NewResourceAllocationFlag(cmd.CpuAllocation, cmd.MemoryAllocation) 161 cmd.ResourceAllocationFlag.ExpandableReservation = false 162 cmd.ResourceAllocationFlag.Register(ctx, f) 163 164 f.Int64Var(&cmd.MemoryMB, "m", 0, "Size in MB of memory") 165 f.Var(flags.NewInt32(&cmd.NumCPUs), "c", "Number of CPUs") 166 f.StringVar(&cmd.GuestId, "g", "", "Guest OS") 167 f.StringVar(&cmd.Name, "name", "", "Display name") 168 f.StringVar(&cmd.Latency, "latency", "", fmt.Sprintf("Latency sensitivity (%s)", strings.Join(latencyLevels, "|"))) 169 f.StringVar(&cmd.Annotation, "annotation", "", "VM description") 170 f.StringVar(&cmd.Uuid, "uuid", "", "BIOS UUID") 171 f.Var(&cmd.extraConfig, "e", "ExtraConfig. <key>=<value>") 172 f.Var(&cmd.extraConfigFile, "f", "ExtraConfig. <key>=<absolute path to file>") 173 174 f.Var(flags.NewOptionalBool(&cmd.NestedHVEnabled), "nested-hv-enabled", "Enable nested hardware-assisted virtualization") 175 cmd.Tools = &types.ToolsConfigInfo{} 176 f.Var(flags.NewOptionalBool(&cmd.Tools.SyncTimeWithHost), "sync-time-with-host", "Enable SyncTimeWithHost") 177 f.Var(flags.NewOptionalBool(&cmd.VPMCEnabled), "vpmc-enabled", "Enable CPU performance counters") 178 f.Var(flags.NewOptionalBool(&cmd.MemoryHotAddEnabled), "memory-hot-add-enabled", "Enable memory hot add") 179 f.Var(flags.NewOptionalBool(&cmd.MemoryReservationLockedToMax), "memory-pin", "Reserve all guest memory") 180 f.Var(flags.NewOptionalBool(&cmd.CpuHotAddEnabled), "cpu-hot-add-enabled", "Enable CPU hot add") 181 cmd.Flags = &types.VirtualMachineFlagInfo{} 182 f.Var(flags.NewOptionalBool(&cmd.Flags.VvtdEnabled), "iommu-enabled", "Enable IOMMU") 183 184 f.StringVar(&cmd.hwUpgradePolicy, "scheduled-hw-upgrade-policy", "", fmt.Sprintf("Schedule hardware upgrade policy (%s)", strings.Join(hwUpgradePolicies, "|"))) 185 } 186 187 func (cmd *change) Description() string { 188 return `Change VM configuration. 189 190 To add ExtraConfig variables that can read within the guest, use the 'guestinfo.' prefix. 191 192 Examples: 193 govc vm.change -vm $vm -mem.reservation 2048 194 govc vm.change -vm $vm -e smc.present=TRUE -e ich7m.present=TRUE 195 # Enable both cpu and memory hotplug on a guest: 196 govc vm.change -vm $vm -cpu-hot-add-enabled -memory-hot-add-enabled 197 govc vm.change -vm $vm -e guestinfo.vmname $vm 198 # Read the contents of a file and use them as ExtraConfig value 199 govc vm.change -vm $vm -f guestinfo.data="$(realpath .)/vmdata.config" 200 # Read the variable set above inside the guest: 201 vmware-rpctool "info-get guestinfo.vmname" 202 govc vm.change -vm $vm -latency high 203 govc vm.change -vm $vm -latency normal 204 govc vm.change -vm $vm -uuid 4139c345-7186-4924-a842-36b69a24159b 205 govc vm.change -vm $vm -scheduled-hw-upgrade-policy always` 206 } 207 208 func (cmd *change) Process(ctx context.Context) error { 209 if err := cmd.VirtualMachineFlag.Process(ctx); err != nil { 210 return err 211 } 212 return nil 213 } 214 215 func (cmd *change) Run(ctx context.Context, f *flag.FlagSet) error { 216 vm, err := cmd.VirtualMachine() 217 if err != nil { 218 return err 219 } 220 221 if vm == nil { 222 return flag.ErrHelp 223 } 224 225 cmd.VirtualMachineConfigSpec.ExtraConfig = append(cmd.extraConfig, cmd.extraConfigFile...) 226 227 setAllocation(&cmd.CpuAllocation) 228 setAllocation(&cmd.MemoryAllocation) 229 if reflect.DeepEqual(cmd.Tools, new(types.ToolsConfigInfo)) { 230 cmd.Tools = nil // no flags set, avoid sending <tools/> in the request 231 } 232 233 if reflect.DeepEqual(cmd.Flags, new(types.VirtualMachineFlagInfo)) { 234 cmd.Flags = nil // no flags set, avoid sending <flags/> in the request 235 } 236 237 if err = cmd.setLatency(); err != nil { 238 return err 239 } 240 241 if err = cmd.setHwUpgradePolicy(); err != nil { 242 return err 243 } 244 245 task, err := vm.Reconfigure(ctx, cmd.VirtualMachineConfigSpec) 246 if err != nil { 247 return err 248 } 249 250 return task.Wait(ctx) 251 }