From b5426eba35fe23aedac518b35d38be04f7c94abb Mon Sep 17 00:00:00 2001 From: Nikolas Grottendieck Date: Sun, 26 Sep 2021 13:40:09 +0200 Subject: [PATCH] govc: Add feature to read file contents for ExtraConfig Closes: #2488 --- govc/USAGE.md | 3 +++ govc/test/vm.bats | 26 ++++++++++++++++++++++++++ govc/vm/change.go | 38 +++++++++++++++++++++++++++++++++----- 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/govc/USAGE.md b/govc/USAGE.md index 272778bb2..b59a2c06f 100644 --- a/govc/USAGE.md +++ b/govc/USAGE.md @@ -4962,6 +4962,8 @@ Examples: # Enable both cpu and memory hotplug on a guest: govc vm.change -vm $vm -cpu-hot-add-enabled -memory-hot-add-enabled govc vm.change -vm $vm -e guestinfo.vmname $vm + # Read the contents of a file and use them as ExtraConfig value + govc vm.change -vm $vm -f guestinfo.data="$(realpath .)/vmdata.config" # Read the variable set above inside the guest: vmware-rpctool "info-get guestinfo.vmname" govc vm.change -vm $vm -latency high @@ -4976,6 +4978,7 @@ Options: -cpu.reservation= CPU reservation in MHz -cpu.shares= CPU shares level or number -e=[] ExtraConfig. = + -f=[] ExtraConfig. = -g= Guest OS -latency= Latency sensitivity (low|normal|high) -m=0 Size in MB of memory diff --git a/govc/test/vm.bats b/govc/test/vm.bats index a6d79c60d..f5f8dbe31 100755 --- a/govc/test/vm.bats +++ b/govc/test/vm.bats @@ -142,6 +142,7 @@ load test_helper assert_line "Memory: 1024MB" assert_line "CPU: 2 vCPU(s)" + # test extraConfig run govc vm.change -e "guestinfo.a=1" -e "guestinfo.b=2" -vm $id assert_success @@ -150,6 +151,18 @@ load test_helper assert_line "guestinfo.a: 1" assert_line "guestinfo.b: 2" + # test extraConfigFile + run govc vm.change -f "guestinfo.c=this_is_not_an_existing.file" -vm $id + assert_failure + + echo -n "3" > "$BATS_TMPDIR/extraConfigFile.conf" + run govc vm.change -f "guestinfo.d=$BATS_TMPDIR/extraConfigFile.conf" -vm $id + assert_success + + run govc vm.info -e $id + assert_success + assert_line "guestinfo.d: 3" + run govc vm.change -sync-time-with-host=false -vm $id assert_success @@ -419,6 +432,19 @@ load test_helper assert_success refute_line "guestinfo.a: 2" + # test extraConfigFile + run govc vm.change -f "guestinfo.b=this_is_not_an_existing.file" -vm $id + assert_failure + echo -n "3" > "$BATS_TMPDIR/extraConfigFile.conf" + run govc vm.change -f "guestinfo.b=$BATS_TMPDIR/extraConfigFile.conf" -vm $id + assert_success + run govc vm.info -e $id + assert_success + assert_line "guestinfo.b: 3" + run govc vm.change -f "guestinfo.b=" -vm $id + assert_success + refute_line "guestinfo.b: 3" + # test optional bool Config run govc vm.change -nested-hv-enabled=true -vm "$id" assert_success diff --git a/govc/vm/change.go b/govc/vm/change.go index a08df1735..f986a51b4 100644 --- a/govc/vm/change.go +++ b/govc/vm/change.go @@ -20,6 +20,7 @@ import ( "context" "flag" "fmt" + "io/ioutil" "reflect" "strings" @@ -43,13 +44,39 @@ func (e *extraConfig) Set(v string) error { return nil } +type extraConfigFile []types.BaseOptionValue + +func (e *extraConfigFile) String() string { + return fmt.Sprintf("%v", *e) +} + +func (e *extraConfigFile) Set(v string) error { + r := strings.SplitN(v, "=", 2) + if len(r) < 2 { + return fmt.Errorf("failed to parse extraConfigFile: %s", v) + } + + var fileContents = "" + if len(r[1]) > 0 { + contents, err := ioutil.ReadFile(r[1]) + if err != nil { + return fmt.Errorf("failed to parse extraConfigFile '%s': %w", v, err) + } + fileContents = string(contents) + } + + *e = append(*e, &types.OptionValue{Key: r[0], Value: fileContents}) + return nil +} + type change struct { *flags.VirtualMachineFlag *flags.ResourceAllocationFlag types.VirtualMachineConfigSpec - extraConfig extraConfig - Latency string + extraConfig extraConfig + extraConfigFile extraConfigFile + Latency string } func init() { @@ -119,6 +146,7 @@ func (cmd *change) Register(ctx context.Context, f *flag.FlagSet) { f.StringVar(&cmd.Annotation, "annotation", "", "VM description") f.StringVar(&cmd.Uuid, "uuid", "", "BIOS UUID") f.Var(&cmd.extraConfig, "e", "ExtraConfig. =") + f.Var(&cmd.extraConfigFile, "f", "ExtraConfig. =") f.Var(flags.NewOptionalBool(&cmd.NestedHVEnabled), "nested-hv-enabled", "Enable nested hardware-assisted virtualization") cmd.Tools = &types.ToolsConfigInfo{} @@ -140,6 +168,8 @@ Examples: # Enable both cpu and memory hotplug on a guest: govc vm.change -vm $vm -cpu-hot-add-enabled -memory-hot-add-enabled govc vm.change -vm $vm -e guestinfo.vmname $vm + # Read the contents of a file and use them as ExtraConfig value + govc vm.change -vm $vm -f guestinfo.data="$(realpath .)/vmdata.config" # Read the variable set above inside the guest: vmware-rpctool "info-get guestinfo.vmname" govc vm.change -vm $vm -latency high @@ -164,9 +194,7 @@ func (cmd *change) Run(ctx context.Context, f *flag.FlagSet) error { return flag.ErrHelp } - if len(cmd.extraConfig) > 0 { - cmd.VirtualMachineConfigSpec.ExtraConfig = cmd.extraConfig - } + cmd.VirtualMachineConfigSpec.ExtraConfig = append(cmd.extraConfig, cmd.extraConfigFile...) setAllocation(&cmd.CpuAllocation) setAllocation(&cmd.MemoryAllocation)