builder/vmware/common: Mock driver and test for DHCP Lease IP lookup
This commit is contained in:
parent
458bfd186f
commit
e5f674a8c2
|
@ -0,0 +1,113 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/multistep"
|
||||
)
|
||||
|
||||
type DriverMock struct {
|
||||
CompactDiskCalled bool
|
||||
CompactDiskPath string
|
||||
CompactDiskErr error
|
||||
|
||||
CreateDiskCalled bool
|
||||
CreateDiskOutput string
|
||||
CreateDiskSize string
|
||||
CreateDiskTypeId string
|
||||
CreateDiskErr error
|
||||
|
||||
IsRunningCalled bool
|
||||
IsRunningPath string
|
||||
IsRunningResult bool
|
||||
IsRunningErr error
|
||||
|
||||
SSHAddressCalled bool
|
||||
SSHAddressState multistep.StateBag
|
||||
SSHAddressResult string
|
||||
SSHAddressErr error
|
||||
|
||||
StartCalled bool
|
||||
StartPath string
|
||||
StartHeadless bool
|
||||
StartErr error
|
||||
|
||||
StopCalled bool
|
||||
StopPath string
|
||||
StopErr error
|
||||
|
||||
SuppressMessagesCalled bool
|
||||
SuppressMessagesPath string
|
||||
SuppressMessagesErr error
|
||||
|
||||
ToolsIsoPathCalled bool
|
||||
ToolsIsoPathFlavor string
|
||||
ToolsIsoPathResult string
|
||||
|
||||
DhcpLeasesPathCalled bool
|
||||
DhcpLeasesPathDevice string
|
||||
DhcpLeasesPathResult string
|
||||
|
||||
VerifyCalled bool
|
||||
VerifyErr error
|
||||
}
|
||||
|
||||
func (d *DriverMock) CompactDisk(path string) error {
|
||||
d.CompactDiskCalled = true
|
||||
d.CompactDiskPath = path
|
||||
return d.CompactDiskErr
|
||||
}
|
||||
|
||||
func (d *DriverMock) CreateDisk(output string, size string, typeId string) error {
|
||||
d.CreateDiskCalled = true
|
||||
d.CreateDiskOutput = output
|
||||
d.CreateDiskSize = size
|
||||
d.CreateDiskTypeId = typeId
|
||||
return d.CreateDiskErr
|
||||
}
|
||||
|
||||
func (d *DriverMock) IsRunning(path string) (bool, error) {
|
||||
d.IsRunningCalled = true
|
||||
d.IsRunningPath = path
|
||||
return d.IsRunningResult, d.IsRunningErr
|
||||
}
|
||||
|
||||
func (d *DriverMock) SSHAddress(state multistep.StateBag) (string, error) {
|
||||
d.SSHAddressCalled = true
|
||||
d.SSHAddressState = state
|
||||
return d.SSHAddressResult, d.SSHAddressErr
|
||||
}
|
||||
|
||||
func (d *DriverMock) Start(path string, headless bool) error {
|
||||
d.StartCalled = true
|
||||
d.StartPath = path
|
||||
d.StartHeadless = headless
|
||||
return d.StartErr
|
||||
}
|
||||
|
||||
func (d *DriverMock) Stop(path string) error {
|
||||
d.StopCalled = true
|
||||
d.StopPath = path
|
||||
return d.StopErr
|
||||
}
|
||||
|
||||
func (d *DriverMock) SuppressMessages(path string) error {
|
||||
d.SuppressMessagesCalled = true
|
||||
d.SuppressMessagesPath = path
|
||||
return d.SuppressMessagesErr
|
||||
}
|
||||
|
||||
func (d *DriverMock) ToolsIsoPath(flavor string) string {
|
||||
d.ToolsIsoPathCalled = true
|
||||
d.ToolsIsoPathFlavor = flavor
|
||||
return d.ToolsIsoPathResult
|
||||
}
|
||||
|
||||
func (d *DriverMock) DhcpLeasesPath(device string) string {
|
||||
d.DhcpLeasesPathCalled = true
|
||||
d.DhcpLeasesPathDevice = device
|
||||
return d.DhcpLeasesPathResult
|
||||
}
|
||||
|
||||
func (d *DriverMock) Verify() error {
|
||||
d.VerifyCalled = true
|
||||
return d.VerifyErr
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDriverMock_impl(t *testing.T) {
|
||||
var _ Driver = new(DriverMock)
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDHCPLeaseGuestLookup_impl(t *testing.T) {
|
||||
var _ GuestIPFinder = new(DHCPLeaseGuestLookup)
|
||||
}
|
||||
|
||||
func TestDHCPLeaseGuestLookup(t *testing.T) {
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if _, err := tf.Write([]byte(testLeaseContents)); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
tf.Close()
|
||||
defer os.Remove(tf.Name())
|
||||
|
||||
driver := new(DriverMock)
|
||||
driver.DhcpLeasesPathResult = tf.Name()
|
||||
|
||||
finder := &DHCPLeaseGuestLookup{
|
||||
Driver: driver,
|
||||
Device: "vmnet8",
|
||||
MACAddress: "00:0c:29:59:91:02",
|
||||
}
|
||||
|
||||
ip, err := finder.GuestIP()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if !driver.DhcpLeasesPathCalled {
|
||||
t.Fatal("should ask for DHCP leases path")
|
||||
}
|
||||
if driver.DhcpLeasesPathDevice != "vmnet8" {
|
||||
t.Fatal("should be vmnet8")
|
||||
}
|
||||
|
||||
if ip != "192.168.126.130" {
|
||||
t.Fatalf("bad: %#v", ip)
|
||||
}
|
||||
}
|
||||
|
||||
const testLeaseContents = `
|
||||
# All times in this file are in UTC (GMT), not your local timezone. This is
|
||||
# not a bug, so please don't ask about it. There is no portable way to
|
||||
# store leases in the local timezone, so please don't request this as a
|
||||
# feature. If this is inconvenient or confusing to you, we sincerely
|
||||
# apologize. Seriously, though - don't ask.
|
||||
# The format of this file is documented in the dhcpd.leases(5) manual page.
|
||||
|
||||
lease 192.168.126.129 {
|
||||
starts 0 2013/09/15 23:58:51;
|
||||
ends 1 2013/09/16 00:28:51;
|
||||
hardware ethernet 00:0c:29:59:91:02;
|
||||
client-hostname "precise64";
|
||||
}
|
||||
lease 192.168.126.130 {
|
||||
starts 2 2013/09/17 21:39:07;
|
||||
ends 2 2013/09/17 22:09:07;
|
||||
hardware ethernet 00:0c:29:59:91:02;
|
||||
client-hostname "precise64";
|
||||
}
|
||||
lease 192.168.126.128 {
|
||||
starts 0 2013/09/15 20:09:59;
|
||||
ends 0 2013/09/15 20:21:58;
|
||||
hardware ethernet 00:0c:29:59:91:02;
|
||||
client-hostname "precise64";
|
||||
}
|
||||
lease 192.168.126.127 {
|
||||
starts 0 2013/09/15 20:09:59;
|
||||
ends 0 2013/09/15 20:21:58;
|
||||
hardware ethernet 01:0c:29:59:91:02;
|
||||
client-hostname "precise64";
|
||||
|
||||
`
|
|
@ -1,91 +0,0 @@
|
|||
package iso
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
vmwcommon "github.com/mitchellh/packer/builder/vmware/common"
|
||||
)
|
||||
|
||||
// Interface to help find the IP address of a running virtual machine.
|
||||
type GuestIPFinder interface {
|
||||
GuestIP() (string, error)
|
||||
}
|
||||
|
||||
// DHCPLeaseGuestLookup looks up the IP address of a guest using DHCP
|
||||
// lease information from the VMware network devices.
|
||||
type DHCPLeaseGuestLookup struct {
|
||||
// Driver that is being used (to find leases path)
|
||||
Driver vmwcommon.Driver
|
||||
|
||||
// Device that the guest is connected to.
|
||||
Device string
|
||||
|
||||
// MAC address of the guest.
|
||||
MACAddress string
|
||||
}
|
||||
|
||||
func (f *DHCPLeaseGuestLookup) GuestIP() (string, error) {
|
||||
dhcpLeasesPath := f.Driver.DhcpLeasesPath(f.Device)
|
||||
log.Printf("DHCP leases path: %s", dhcpLeasesPath)
|
||||
if dhcpLeasesPath == "" {
|
||||
return "", errors.New("no DHCP leases path found.")
|
||||
}
|
||||
|
||||
fh, err := os.Open(dhcpLeasesPath)
|
||||
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") {
|
||||
// Need to trim off CR character when running in windows
|
||||
line = strings.TrimRight(line, "\r")
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
if curIp == "" {
|
||||
return "", errors.New("IP not found for MAC in DHCP leases")
|
||||
}
|
||||
|
||||
return curIp, nil
|
||||
}
|
Loading…
Reference in New Issue