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