builder/vmware: Support reading guest IP from DHCP
This commit is contained in:
parent
323647e3a6
commit
aee611db4f
|
@ -1,5 +1,14 @@
|
||||||
package vmware
|
package vmware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// Interface to help find the IP address of a running virtual machine.
|
// Interface to help find the IP address of a running virtual machine.
|
||||||
type GuestIPFinder interface {
|
type GuestIPFinder interface {
|
||||||
GuestIP() (string, error)
|
GuestIP() (string, error)
|
||||||
|
@ -9,12 +18,55 @@ type GuestIPFinder interface {
|
||||||
// lease information from the VMware network devices.
|
// lease information from the VMware network devices.
|
||||||
type DHCPLeaseGuestLookup struct {
|
type DHCPLeaseGuestLookup struct {
|
||||||
// Device that the guest is connected to.
|
// Device that the guest is connected to.
|
||||||
Device string
|
Device string
|
||||||
|
|
||||||
// MAC address of the guest.
|
// MAC address of the guest.
|
||||||
MACAddress string
|
MACAddress string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *DHCPLeaseGuestLookup) GuestIP() (string, error) {
|
func (f *DHCPLeaseGuestLookup) GuestIP() (string, error) {
|
||||||
return "", nil
|
fh, err := os.Open(fmt.Sprintf("/var/db/vmware/vmnet-dhcpd-%s.leases", f.Device))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
dhcpBytes, err := ioutil.ReadAll(fh)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastIp string
|
||||||
|
var lastLeaseEnd time.Time
|
||||||
|
|
||||||
|
var curIp string
|
||||||
|
var curLeaseEnd time.Time
|
||||||
|
|
||||||
|
ipLineRe := regexp.MustCompile(`^lease (.+?) {$`)
|
||||||
|
endTimeLineRe := regexp.MustCompile(`^\s*ends \d (.+?);$`)
|
||||||
|
macLineRe := regexp.MustCompile(`^\s*hardware ethernet (.+?);$`)
|
||||||
|
|
||||||
|
for _, line := range strings.Split(string(dhcpBytes), "\n") {
|
||||||
|
matches := ipLineRe.FindStringSubmatch(line)
|
||||||
|
if matches != nil {
|
||||||
|
lastIp = matches[1]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
matches = endTimeLineRe.FindStringSubmatch(line)
|
||||||
|
if matches != nil {
|
||||||
|
lastLeaseEnd, _ = time.Parse("2006/01/02 15:04:05", matches[1])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the mac address matches and this lease ends farther in the
|
||||||
|
// future than the last match we might have, then choose it.
|
||||||
|
matches = macLineRe.FindStringSubmatch(line)
|
||||||
|
if matches != nil && matches[1] == f.MACAddress && curLeaseEnd.Before(lastLeaseEnd) {
|
||||||
|
curIp = lastIp
|
||||||
|
curLeaseEnd = lastLeaseEnd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return curIp, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
package vmware
|
package vmware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"github.com/mitchellh/multistep"
|
"github.com/mitchellh/multistep"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This step waits for SSH to become available and establishes an SSH
|
// This step waits for SSH to become available and establishes an SSH
|
||||||
|
@ -11,21 +16,63 @@ import (
|
||||||
// Uses:
|
// Uses:
|
||||||
// config *config
|
// config *config
|
||||||
// ui packer.Ui
|
// ui packer.Ui
|
||||||
|
// vmx_path string
|
||||||
//
|
//
|
||||||
// Produces:
|
// Produces:
|
||||||
// <nothing>
|
// <nothing>
|
||||||
type stepWaitForSSH struct{}
|
type stepWaitForSSH struct{}
|
||||||
|
|
||||||
func (stepWaitForSSH) Run(state map[string]interface{}) multistep.StepAction {
|
func (s *stepWaitForSSH) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state["ui"].(packer.Ui)
|
||||||
|
vmxPath := state["vmx_path"].(string)
|
||||||
|
|
||||||
ui.Say("Waiting for SSH to become available...")
|
ui.Say("Waiting for SSH to become available...")
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
|
log.Println("Lookup up IP information...")
|
||||||
// First we wait for the IP to become available...
|
// First we wait for the IP to become available...
|
||||||
|
ipLookup, err := s.dhcpLeaseLookup(vmxPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Can't lookup via DHCP lease: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ip, err := ipLookup.GuestIP()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("IP lookup failed: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Detected IP: %s", ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (stepWaitForSSH) Cleanup(map[string]interface{}) {}
|
func (s *stepWaitForSSH) Cleanup(map[string]interface{}) {}
|
||||||
|
|
||||||
|
// Reads the network information for lookup via DHCP.
|
||||||
|
func (s *stepWaitForSSH) dhcpLeaseLookup(vmxPath string) (GuestIPFinder, error) {
|
||||||
|
f, err := os.Open(vmxPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
vmxBytes, err := ioutil.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
vmxData := ParseVMX(string(vmxBytes))
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
macAddress := ""
|
||||||
|
if macAddress, ok = vmxData["ethernet0.address"]; !ok || macAddress == "" {
|
||||||
|
if macAddress, ok = vmxData["ethernet0.generatedAddress"]; !ok || macAddress == "" {
|
||||||
|
return nil, errors.New("couldn't find MAC address in VMX")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DHCPLeaseGuestLookup{"vmnet8", macAddress}, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue