diff --git a/govc/USAGE.md b/govc/USAGE.md index ed83ae796..b2bcf0d15 100644 --- a/govc/USAGE.md +++ b/govc/USAGE.md @@ -2169,6 +2169,7 @@ Examples: govc vm.clone -vm template-vm new-vm Options: + -annotation= VM description -c=0 Number of CPUs -customization= Customization Specification Name -datastore-cluster= Datastore cluster [GOVC_DATASTORE_CLUSTER] @@ -2193,6 +2194,7 @@ Options: Usage: govc vm.create [OPTIONS] Options: + -annotation= VM description -c=1 Number of CPUs -datastore-cluster= Datastore cluster [GOVC_DATASTORE_CLUSTER] -disk= Disk path (to use existing) OR size (to create new, e.g. 20GB) @@ -2287,18 +2289,23 @@ These values can also be obtained using: govc vm.info -json $vm | jq -r .VirtualMachines[].Guest.Net[].IpConfig.IpAddress[].IpAddress +When given the '-n' flag, filters '-a' behavior to the nic specified by MAC address or device name. + The 'esxcli' flag does not require vmware-tools to be installed, but does require the ESX host to have the /Net/GuestIPHack setting enabled. Examples: govc vm.ip $vm govc vm.ip -a -v4 $vm + govc vm.ip -n 00:0c:29:57:7b:c3 $vm + govc vm.ip -n ethernet-0 $vm govc host.esxcli system settings advanced set -o /Net/GuestIPHack -i 1 govc vm.ip -esxcli $vm Options: -a=false Wait for an IP address on all NICs -esxcli=false Use esxcli instead of guest tools + -n= Wait for IP address on NIC, specified by device name or MAC -v4=false Only report IPv4 addresses ``` diff --git a/govc/test/vm.bats b/govc/test/vm.bats index f2df78234..a5235ad2e 100755 --- a/govc/test/vm.bats +++ b/govc/test/vm.bats @@ -13,6 +13,21 @@ load test_helper run govc vm.ip -a -v4 $id assert_success + + run govc vm.ip -n $(vm_mac $id) $id + assert_success + + run govc vm.ip -n ethernet-0 $id + assert_success + + ip=$(govc vm.ip $id) + + # add a second nic + run govc vm.network.add -vm $id "VM Network" + assert_success + + res=$(govc vm.ip -n ethernet-0 $id) + assert_equal $ip $res } @test "vm.ip -esxcli" { diff --git a/govc/vm/ip.go b/govc/vm/ip.go index e4bc3de15..696d2f708 100644 --- a/govc/vm/ip.go +++ b/govc/vm/ip.go @@ -36,6 +36,7 @@ type ip struct { esx bool all bool v4 bool + nic string } func init() { @@ -51,6 +52,7 @@ func (cmd *ip) Register(ctx context.Context, f *flag.FlagSet) { f.BoolVar(&cmd.esx, "esxcli", false, "Use esxcli instead of guest tools") f.BoolVar(&cmd.all, "a", false, "Wait for an IP address on all NICs") + f.StringVar(&cmd.nic, "n", "", "Wait for IP address on NIC, specified by device name or MAC") f.BoolVar(&cmd.v4, "v4", false, "Only report IPv4 addresses") } @@ -76,12 +78,16 @@ These values can also be obtained using: govc vm.info -json $vm | jq -r .VirtualMachines[].Guest.Net[].IpConfig.IpAddress[].IpAddress +When given the '-n' flag, filters '-a' behavior to the nic specified by MAC address or device name. + The 'esxcli' flag does not require vmware-tools to be installed, but does require the ESX host to have the /Net/GuestIPHack setting enabled. Examples: govc vm.ip $vm govc vm.ip -a -v4 $vm + govc vm.ip -n 00:0c:29:57:7b:c3 $vm + govc vm.ip -n ethernet-0 $vm govc host.esxcli system settings advanced set -o /Net/GuestIPHack -i 1 govc vm.ip -esxcli $vm` } @@ -131,9 +137,14 @@ func (cmd *ip) Run(ctx context.Context, f *flag.FlagSet) error { } } } else { + var hwaddr []string + if cmd.nic != "" { + hwaddr = strings.Split(cmd.nic, ",") + } + get = func(vm *object.VirtualMachine) (string, error) { - if cmd.all { - macs, err := vm.WaitForNetIP(ctx, cmd.v4) + if cmd.all || hwaddr != nil { + macs, err := vm.WaitForNetIP(ctx, cmd.v4, hwaddr...) if err != nil { return "", err } diff --git a/object/virtual_machine.go b/object/virtual_machine.go index 1b0cd06b9..008d3e83b 100644 --- a/object/virtual_machine.go +++ b/object/virtual_machine.go @@ -229,9 +229,12 @@ func (v VirtualMachine) WaitForIP(ctx context.Context) (string, error) { // WaitForNetIP waits for the VM guest.net property to report an IP address for all VM NICs. // Only consider IPv4 addresses if the v4 param is true. +// By default, wait for all NICs to get an IP address, unless 1 or more device is given. +// A device can be specified by the MAC address or the device name, e.g. "ethernet-0". // Returns a map with MAC address as the key and IP address list as the value. -func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][]string, error) { +func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool, device ...string) (map[string][]string, error) { macs := make(map[string][]string) + eths := make(map[string]string) p := property.DefaultCollector(v.c) @@ -242,14 +245,15 @@ func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][ continue } - devices := c.Val.(types.ArrayOfVirtualDevice).VirtualDevice - for _, device := range devices { - if nic, ok := device.(types.BaseVirtualEthernetCard); ok { + devices := VirtualDeviceList(c.Val.(types.ArrayOfVirtualDevice).VirtualDevice) + for _, d := range devices { + if nic, ok := d.(types.BaseVirtualEthernetCard); ok { mac := nic.GetVirtualEthernetCard().MacAddress if mac == "" { return false } macs[mac] = nil + eths[devices.Name(d)] = mac } } } @@ -257,6 +261,17 @@ func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][ return true }) + if len(device) != 0 { + // Only wait for specific NIC(s) + macs = make(map[string][]string) + for _, mac := range device { + if eth, ok := eths[mac]; ok { + mac = eth // device name, e.g. "ethernet-0" + } + macs[mac] = nil + } + } + err = property.Wait(ctx, p, v.Reference(), []string{"guest.net"}, func(pc []types.PropertyChange) bool { for _, c := range pc { if c.Op != types.PropertyChangeOpAssign {