From 1ff52979fe82b89a1004ebbaf299e1b879080ef3 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 31 Jul 2013 14:46:12 -0700 Subject: [PATCH] builder/vmware: redo host IP stuff for Windows --- builder/vmware/host_ip.go | 36 ------ builder/vmware/host_ip_ifconfig.go | 37 ++++++ ...st_ip_test.go => host_ip_ifconfig_test.go} | 0 builder/vmware/host_ip_vmnetnatconf.go | 64 ++++++++++ builder/vmware/host_ip_vmnetnatconf_test.go | 11 ++ builder/vmware/host_ip_windows.go | 118 ------------------ builder/vmware/step_type_boot_command.go | 9 +- 7 files changed, 120 insertions(+), 155 deletions(-) create mode 100644 builder/vmware/host_ip_ifconfig.go rename builder/vmware/{host_ip_test.go => host_ip_ifconfig_test.go} (100%) create mode 100644 builder/vmware/host_ip_vmnetnatconf.go create mode 100644 builder/vmware/host_ip_vmnetnatconf_test.go delete mode 100644 builder/vmware/host_ip_windows.go diff --git a/builder/vmware/host_ip.go b/builder/vmware/host_ip.go index 44163b9c3..3da687f15 100644 --- a/builder/vmware/host_ip.go +++ b/builder/vmware/host_ip.go @@ -2,44 +2,8 @@ package vmware -import ( - "bytes" - "errors" - "os/exec" - "regexp" -) - // Interface to help find the host IP that is available from within // the VMware virtual machines. type HostIPFinder interface { HostIP() (string, error) } - -// IfconfigIPFinder finds the host IP based on the output of `ifconfig`. -type IfconfigIPFinder struct { - Device string -} - -func (f *IfconfigIPFinder) HostIP() (string, error) { - ifconfigPath, err := exec.LookPath("ifconfig") - if err != nil { - return "", err - } - - stdout := new(bytes.Buffer) - - cmd := exec.Command(ifconfigPath, f.Device) - cmd.Stdout = stdout - cmd.Stderr = new(bytes.Buffer) - if err := cmd.Run(); err != nil { - return "", err - } - - re := regexp.MustCompile(`inet\s*(?:addr:)?(.+?)\s`) - matches := re.FindStringSubmatch(stdout.String()) - if matches == nil { - return "", errors.New("IP not found in ifconfig output...") - } - - return matches[1], nil -} diff --git a/builder/vmware/host_ip_ifconfig.go b/builder/vmware/host_ip_ifconfig.go new file mode 100644 index 000000000..08606daf0 --- /dev/null +++ b/builder/vmware/host_ip_ifconfig.go @@ -0,0 +1,37 @@ +package vmware + +import ( + "bytes" + "errors" + "os/exec" + "regexp" +) + +// IfconfigIPFinder finds the host IP based on the output of `ifconfig`. +type IfconfigIPFinder struct { + Device string +} + +func (f *IfconfigIPFinder) HostIP() (string, error) { + ifconfigPath, err := exec.LookPath("ifconfig") + if err != nil { + return "", err + } + + stdout := new(bytes.Buffer) + + cmd := exec.Command(ifconfigPath, f.Device) + cmd.Stdout = stdout + cmd.Stderr = new(bytes.Buffer) + if err := cmd.Run(); err != nil { + return "", err + } + + re := regexp.MustCompile(`inet\s*(?:addr:)?(.+?)\s`) + matches := re.FindStringSubmatch(stdout.String()) + if matches == nil { + return "", errors.New("IP not found in ifconfig output...") + } + + return matches[1], nil +} diff --git a/builder/vmware/host_ip_test.go b/builder/vmware/host_ip_ifconfig_test.go similarity index 100% rename from builder/vmware/host_ip_test.go rename to builder/vmware/host_ip_ifconfig_test.go diff --git a/builder/vmware/host_ip_vmnetnatconf.go b/builder/vmware/host_ip_vmnetnatconf.go new file mode 100644 index 000000000..3fd055e44 --- /dev/null +++ b/builder/vmware/host_ip_vmnetnatconf.go @@ -0,0 +1,64 @@ +package vmware + +import ( + "bufio" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "regexp" + "strings" +) + +// VMnetNatConfIPFinder finds the IP address of the host machine by +// retrieving the IP from the vmnetnat.conf. This isn't a full proof +// technique but so far it has not failed. +type VMnetNatConfIPFinder struct{} + +func (*VMnetNatConfIPFinder) HostIP() (string, error) { + programData := os.Getenv("ProgramData") + if programData == "" { + return "", errors.New("ProgramData directory not found.") + } + + programData = strings.Replace(programData, "\\", "/", -1) + vmnetnat := filepath.Join(programData, "/VMware/vmnetnat.conf") + if _, err := os.Stat(vmnetnat); err != nil { + return "", fmt.Errorf("Error with vmnetnat.conf: %s", err) + } + + f, err := os.Open(vmnetnat) + if err != nil { + return "", err + } + defer f.Close() + + ipRe := regexp.MustCompile(`^\s*ip\s*=\s*(.+?)\s*$`) + + r := bufio.NewReader(f) + for { + line, err := r.ReadString('\n') + if line != "" { + matches := ipRe.FindStringSubmatch(line) + if matches != nil { + ip := matches[1] + dotIndex := strings.LastIndex(ip, ".") + if dotIndex == -1 { + continue + } + + ip = ip[0:dotIndex] + ".1" + return ip, nil + } + } + + if err == io.EOF { + break + } + + return "", err + } + + return "", errors.New("host IP not found in NAT config") +} diff --git a/builder/vmware/host_ip_vmnetnatconf_test.go b/builder/vmware/host_ip_vmnetnatconf_test.go new file mode 100644 index 000000000..a5fc26f27 --- /dev/null +++ b/builder/vmware/host_ip_vmnetnatconf_test.go @@ -0,0 +1,11 @@ +package vmware + +import "testing" + +func TestVMnetNatConfIPFinder_Impl(t *testing.T) { + var raw interface{} + raw = &VMnetNatConfIPFinder{} + if _, ok := raw.(HostIPFinder); !ok { + t.Fatalf("VMnetNatConfIPFinder is not a host IP finder") + } +} diff --git a/builder/vmware/host_ip_windows.go b/builder/vmware/host_ip_windows.go deleted file mode 100644 index a6613016d..000000000 --- a/builder/vmware/host_ip_windows.go +++ /dev/null @@ -1,118 +0,0 @@ -// +build windows -// Contributed by Ross Smith II (smithii.com) - -package vmware - -import ( - "errors" - "io/ioutil" - "log" - "net" - "os" - "regexp" - "strings" -) - -// Interface to help find the host IP that is available from within -// the VMware virtual machines. -type HostIPFinder interface { - HostIP() (string, error) -} - -// IfconfigIPFinder finds the host IP based on the output of `ifconfig`. -type IfconfigIPFinder struct { - Device string -} - -func (f *IfconfigIPFinder) HostIP() (string, error) { - ift, err := net.Interfaces() - if err != nil { - return "", errors.New("No network interfaces found") - } - - vmwareMac, err := getVMWareMAC() - if err != nil { - log.Print(err) - } - - log.Printf("Searching for MAC %s", vmwareMac) - re := regexp.MustCompile("(?i)^" + vmwareMac) - - ip := "" - - for _, ifi := range ift { - mac := ifi.HardwareAddr.String() - log.Printf("Found MAC %s", mac) - - matches := re.FindStringSubmatch(mac) - - if matches == nil { - continue - } - - addrs, err := ifi.Addrs() - if err != nil { - log.Printf("No IP addresses found for MAC %s", mac) - continue - } - - for _, address := range addrs { - ip = address.String() - log.Printf("Found IP address %s for MAC %s", ip, mac) - } - - // continue looping as VMNet8 comes after VMNet1 (at least on my system) - } - - if ip == "" { - return "", errors.New("No MACs found matching " + vmwareMac) - } - - log.Printf("Returning IP address %s", ip) - - return ip, nil -} - -func getVMWareMAC() (string, error) { - // return the first three tuples, if the actual MAC cannot be found - const defaultMacRe = "00:50:56" - - programData := os.Getenv("ProgramData") - programData = strings.Replace(programData, "\\", "/", -1) - vmnetnat := programData + "/VMware/vmnetnat.conf" - if _, err := os.Stat(vmnetnat); os.IsNotExist(err) { - log.Printf("File not found: '%s' (found '%s' in %%ProgramData%%)", vmnetnat, programData) - return defaultMacRe, err - } - - log.Printf("Searching for key hostMAC in '%s'", vmnetnat) - - fh, err := os.Open(vmnetnat) - if err != nil { - return defaultMacRe, err - } - defer fh.Close() - - bytes, err := ioutil.ReadAll(fh) - if err != nil { - return defaultMacRe, err - } - - hostMacRe := regexp.MustCompile(`(?i)^\s*hostMAC\s*=\s*(.+)\s*$`) - - for _, line := range strings.Split(string(bytes), "\n") { - // Need to trim off CR character when running in windows - line = strings.TrimRight(line, "\r") - - matches := hostMacRe.FindStringSubmatch(line) - if matches != nil { - log.Printf("Found MAC '%s' in '%s'", matches[1], vmnetnat) - return matches[1], nil - } - } - - log.Printf("Did not find key hostMAC in '%s', using %s instead", vmnetnat, defaultMacRe) - - return defaultMacRe, nil - -} diff --git a/builder/vmware/step_type_boot_command.go b/builder/vmware/step_type_boot_command.go index a7c0f9d5b..86224e5ff 100644 --- a/builder/vmware/step_type_boot_command.go +++ b/builder/vmware/step_type_boot_command.go @@ -8,6 +8,7 @@ import ( "github.com/mitchellh/packer/packer" "log" "net" + "runtime" "strings" "text/template" "time" @@ -64,7 +65,13 @@ func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAc log.Printf("Connected to VNC desktop: %s", c.DesktopName) // Determine the host IP - ipFinder := &IfconfigIPFinder{"vmnet8"} + var ipFinder HostIPFinder + if runtime.GOOS == "windows" { + ipFinder = new(VMnetNatConfIPFinder) + } else { + ipFinder = &IfconfigIPFinder{Device: "vmnet8"} + } + hostIp, err := ipFinder.HostIP() if err != nil { err := fmt.Errorf("Error detecting host IP: %s", err)