diff --git a/builder/vmware/common/driver.go b/builder/vmware/common/driver.go index 745b48d69..3e38442a2 100644 --- a/builder/vmware/common/driver.go +++ b/builder/vmware/common/driver.go @@ -64,6 +64,7 @@ type Driver interface { /// These methods are generally implemented by the VmwareDriver /// structure within this file. A driver implementation can /// reimplement these, though, if it wants. + GetVmwareDriver() VmwareDriver // Get the guest hw address for the vm GuestAddress(multistep.StateBag) (string, error) diff --git a/builder/vmware/common/driver_fusion5.go b/builder/vmware/common/driver_fusion5.go index 4bc5ae301..e8c49155c 100644 --- a/builder/vmware/common/driver_fusion5.go +++ b/builder/vmware/common/driver_fusion5.go @@ -173,3 +173,7 @@ const fusionSuppressPlist = ` ` + +func (d *Fusion5Driver) GetVmwareDriver() VmwareDriver { + return d.VmwareDriver +} diff --git a/builder/vmware/common/driver_fusion6.go b/builder/vmware/common/driver_fusion6.go index af42c7ef9..2f0563eb5 100644 --- a/builder/vmware/common/driver_fusion6.go +++ b/builder/vmware/common/driver_fusion6.go @@ -68,3 +68,7 @@ func (d *Fusion6Driver) Verify() error { return compareVersions(matches[1], VMWARE_FUSION_VERSION, "Fusion Professional") } + +func (d *Fusion6Driver) GetVmwareDriver() VmwareDriver { + return d.Fusion5Driver.VmwareDriver +} diff --git a/builder/vmware/common/driver_player5.go b/builder/vmware/common/driver_player5.go index 240b44a11..04fb4e897 100644 --- a/builder/vmware/common/driver_player5.go +++ b/builder/vmware/common/driver_player5.go @@ -209,3 +209,7 @@ func (d *Player5Driver) ToolsIsoPath(flavor string) string { func (d *Player5Driver) ToolsInstall() error { return nil } + +func (d *Player5Driver) GetVmwareDriver() VmwareDriver { + return d.VmwareDriver +} diff --git a/builder/vmware/common/driver_player6.go b/builder/vmware/common/driver_player6.go index d1cc7be88..1ccb84b85 100644 --- a/builder/vmware/common/driver_player6.go +++ b/builder/vmware/common/driver_player6.go @@ -35,3 +35,7 @@ func (d *Player6Driver) Verify() error { return playerVerifyVersion(VMWARE_PLAYER_VERSION) } + +func (d *Player6Driver) GetVmwareDriver() VmwareDriver { + return d.Player5Driver.VmwareDriver +} diff --git a/builder/vmware/common/driver_workstation10.go b/builder/vmware/common/driver_workstation10.go index 7e6ac8b8f..471fce37d 100644 --- a/builder/vmware/common/driver_workstation10.go +++ b/builder/vmware/common/driver_workstation10.go @@ -33,3 +33,7 @@ func (d *Workstation10Driver) Verify() error { return workstationVerifyVersion(VMWARE_WS_VERSION) } + +func (d *Workstation10Driver) GetVmwareDriver() VmwareDriver { + return d.Workstation9Driver.VmwareDriver +} diff --git a/builder/vmware/common/driver_workstation9.go b/builder/vmware/common/driver_workstation9.go index 8a6eb5556..af2d7df35 100644 --- a/builder/vmware/common/driver_workstation9.go +++ b/builder/vmware/common/driver_workstation9.go @@ -170,3 +170,7 @@ func (d *Workstation9Driver) ToolsIsoPath(flavor string) string { func (d *Workstation9Driver) ToolsInstall() error { return nil } + +func (d *Workstation9Driver) GetVmwareDriver() VmwareDriver { + return d.VmwareDriver +} diff --git a/builder/vmware/iso/driver_esx5.go b/builder/vmware/iso/driver_esx5.go index 6df8271f6..d2f00ea81 100644 --- a/builder/vmware/iso/driver_esx5.go +++ b/builder/vmware/iso/driver_esx5.go @@ -26,7 +26,7 @@ import ( // ESX5 driver talks to an ESXi5 hypervisor remotely over SSH to build // virtual machines. This driver can only manage one machine at a time. type ESX5Driver struct { - vmwcommon.VmwareDriver + base vmwcommon.VmwareDriver Host string Port uint @@ -173,6 +173,101 @@ func (d *ESX5Driver) HostIP(multistep.StateBag) (string, error) { return host, err } +func (d *ESX5Driver) GuestIP(multistep.StateBag) (string, error) { + // GuestIP is defined by the user as d.Host..but let's validate it just to be sure + conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", d.Host, d.Port)) + defer conn.Close() + if err != nil { + return "", err + } + + host, _, err := net.SplitHostPort(conn.RemoteAddr().String()) + return host, err +} + +func (d *ESX5Driver) HostAddress(multistep.StateBag) (string, error) { + // make a connection + conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", d.Host, d.Port)) + defer conn.Close() + if err != nil { + return "", err + } + + // get the local address (the host) + host, _, err := net.SplitHostPort(conn.LocalAddr().String()) + if err != nil { + return "", fmt.Errorf("Unable to determine host address for ESXi: %v", err) + } + + // iterate through all the interfaces.. + interfaces, err := net.Interfaces() + if err != nil { + return "", fmt.Errorf("Unable to enumerate host interfaces : %v", err) + } + + for _, intf := range interfaces { + addrs, err := intf.Addrs() + if err != nil { + continue + } + + // ..checking to see if any if it's addrs match the host address + for _, addr := range addrs { + if addr.String() == host { // FIXME: Is this the proper way to compare two HardwareAddrs? + return intf.HardwareAddr.String(), nil + } + } + } + + // ..unfortunately nothing was found + return "", fmt.Errorf("Unable to locate interface matching host address in ESXi: %v", host) +} + +func (d *ESX5Driver) GuestAddress(multistep.StateBag) (string, error) { + // list all the interfaces on the esx host + r, err := d.esxcli("network", "ip", "interface", "list") + if err != nil { + return "", fmt.Errorf("Could not retrieve network interfaces for ESXi: %v", err) + } + + // rip out the interface name and the MAC address from the csv output + addrs := make(map[string]string) + for record, err := r.read(); record != nil && err == nil; record, err = r.read() { + if strings.ToUpper(record["Enabled"]) != "TRUE" { + continue + } + addrs[record["Name"]] = record["MAC Address"] + } + + // list all the addresses on the esx host + r, err = d.esxcli("network", "ip", "interface", "ipv4", "get") + if err != nil { + return "", fmt.Errorf("Could not retrieve network addresses for ESXi: %v", err) + } + + // figure out the interface name that matches the specified d.Host address + var intf string + intf = "" + for record, err := r.read(); record != nil && err == nil; record, err = r.read() { + if record["IPv4 Address"] == d.Host && record["Name"] != "" { + intf = record["Name"] + break + } + } + if intf == "" { + return "", fmt.Errorf("Unable to find matching address for ESXi guest") + } + + // find the MAC address according to the interface name + result, ok := addrs[intf] + if !ok { + return "", fmt.Errorf("Unable to find address for ESXi guest interface") + } + + // ..and we're good + return result, nil +} + func (d *ESX5Driver) VNCAddress(_ string, portMin, portMax uint) (string, uint, error) { var vncPort uint @@ -530,6 +625,10 @@ func (d *ESX5Driver) esxcli(args ...string) (*esxcliReader, error) { return &esxcliReader{r, header}, nil } +func (d *ESX5Driver) GetVmwareDriver() vmwcommon.VmwareDriver { + return d.base +} + type esxcliReader struct { cr *csv.Reader header []string diff --git a/builder/vmware/iso/step_create_vmx.go b/builder/vmware/iso/step_create_vmx.go index 207d38caa..bf6bb3d6c 100644 --- a/builder/vmware/iso/step_create_vmx.go +++ b/builder/vmware/iso/step_create_vmx.go @@ -370,7 +370,7 @@ func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multist /// Check the network type that the user specified network := config.Network - driver := state.Get("driver").(vmwcommon.VmwareDriver) + driver := state.Get("driver").(vmwcommon.Driver).GetVmwareDriver() // read netmap config pathNetmap := driver.NetmapConfPath()