Commit d424ed1e authored by Rickard von Essen's avatar Rickard von Essen

builder/parallels: Use most recent DHCP lease when determening IP.

Fixes #1746. Problem establishing SSH connection with Fedora 21 and
Parallels
parent ef9cceca
......@@ -55,6 +55,7 @@ func NewDriver() (Driver, error) {
var drivers map[string]Driver
var prlctlPath string
var supportedVersions []string
dhcp_lease_file := "/Library/Preferences/Parallels/parallels_dhcp_leases"
if runtime.GOOS != "darwin" {
return nil, fmt.Errorf(
......@@ -74,11 +75,13 @@ func NewDriver() (Driver, error) {
drivers = map[string]Driver{
"10": &Parallels10Driver{
Parallels9Driver: Parallels9Driver{
PrlctlPath: prlctlPath,
PrlctlPath: prlctlPath,
dhcp_lease_file: dhcp_lease_file,
},
},
"9": &Parallels9Driver{
PrlctlPath: prlctlPath,
PrlctlPath: prlctlPath,
dhcp_lease_file: dhcp_lease_file,
},
}
......
......@@ -9,6 +9,7 @@ import (
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
......@@ -18,6 +19,8 @@ import (
type Parallels9Driver struct {
// This is the path to the "prlctl" application.
PrlctlPath string
// The path to the parallels_dhcp_leases file
dhcp_lease_file string
}
func (d *Parallels9Driver) Import(name, srcPath, dstDir string, reassignMac bool) error {
......@@ -276,31 +279,43 @@ func (d *Parallels9Driver) Mac(vmName string) (string, error) {
}
// Finds the IP address of a VM connected that uses DHCP by its MAC address
//
// Parses the file /Library/Preferences/Parallels/parallels_dhcp_leases
// file contain a list of DHCP leases given by Parallels Desktop
// Example line:
// 10.211.55.181="1418921112,1800,001c42f593fb,ff42f593fb000100011c25b9ff001c42f593fb"
// IP Address ="Lease expiry, Lease time, MAC, MAC or DUID"
func (d *Parallels9Driver) IpAddress(mac string) (string, error) {
var stdout bytes.Buffer
dhcp_lease_file := "/Library/Preferences/Parallels/parallels_dhcp_leases"
if len(mac) != 12 {
return "", fmt.Errorf("Not a valid MAC address: %s. It should be exactly 12 digits.", mac)
}
cmd := exec.Command("grep", "-i", mac, dhcp_lease_file)
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
leases, err := ioutil.ReadFile(d.dhcp_lease_file)
if err != nil {
return "", err
}
stdoutString := strings.TrimSpace(stdout.String())
re := regexp.MustCompile("(.*)=.*")
ipMatch := re.FindAllStringSubmatch(stdoutString, 1)
re := regexp.MustCompile("(.*)=\"(.*),(.*)," + strings.ToLower(mac) + ",.*\"")
mostRecentIp := ""
mostRecentLease := uint64(0)
for _, l := range re.FindAllStringSubmatch(string(leases), -1) {
ip := l[1]
expiry, _ := strconv.ParseUint(l[2], 10, 64)
leaseTime, _ := strconv.ParseUint(l[3], 10, 32)
log.Printf("Found lease: %s for MAC: %s, expiring at %d, leased for %d s.\n", ip, mac, expiry, leaseTime)
if mostRecentLease <= expiry-leaseTime {
mostRecentIp = ip
mostRecentLease = expiry - leaseTime
}
}
if len(ipMatch) != 1 {
return "", fmt.Errorf("IP lease not found for MAC address %s in: %s\n", mac, dhcp_lease_file)
if len(mostRecentIp) == 0 {
return "", fmt.Errorf("IP lease not found for MAC address %s in: %s\n", mac, d.dhcp_lease_file)
}
ip := ipMatch[0][1]
log.Printf("Found IP lease: %s for MAC address %s\n", ip, mac)
return ip, nil
log.Printf("Found IP lease: %s for MAC address %s\n", mostRecentIp, mac)
return mostRecentIp, nil
}
func (d *Parallels9Driver) ToolsIsoPath(k string) (string, error) {
......
package common
import (
"io/ioutil"
"os"
"testing"
)
func TestParallels9Driver_impl(t *testing.T) {
var _ Driver = new(Parallels9Driver)
}
func TestIpAddress(t *testing.T) {
tf, err := ioutil.TempFile("", "packer")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.Remove(tf.Name())
d := Parallels9Driver{
dhcp_lease_file: tf.Name(),
}
// No lease should be found in an empty file
ip, err := d.IpAddress("123456789012")
if err == nil {
t.Fatalf("Found IP: \"%v\". No IP should be found!\n", ip)
}
// The most recent lease, 10.211.55.126 should be found
c := []byte(`
[vnic0]
10.211.55.125="1418288000,1800,001c4235240c,ff4235240c000100011c1c10e7001c4235240c"
10.211.55.126="1418288969,1800,001c4235240c,ff4235240c000100011c1c11ad001c4235240c"
10.211.55.254="1411712008,1800,001c42a51419,01001c42a51419"
`)
ioutil.WriteFile(tf.Name(), c, 0666)
ip, err = d.IpAddress("001C4235240c")
if err != nil {
t.Fatalf("Error: %v\n", err)
}
if ip != "10.211.55.126" {
t.Fatalf("Should have found 10.211.55.126, not %s!\n", ip)
}
// The most recent lease, 10.211.55.124 should be found
c = []byte(`[vnic0]
10.211.55.124="1418288969,1800,001c4235240c,ff4235240c000100011c1c11ad001c4235240c"
10.211.55.125="1418288000,1800,001c4235240c,ff4235240c000100011c1c10e7001c4235240c"
10.211.55.254="1411712008,1800,001c42a51419,01001c42a51419"
`)
ioutil.WriteFile(tf.Name(), c, 0666)
ip, err = d.IpAddress("001c4235240c")
if err != nil {
t.Fatalf("Error: %v\n", err)
}
if ip != "10.211.55.124" {
t.Fatalf("Should have found 10.211.55.124, not %s!\n", ip)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment