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