Skip to content

Commit

Permalink
Added basic WinRM communicator support
Browse files Browse the repository at this point in the history
- Only VMWare ISO Builder currently supported
  • Loading branch information
sneal committed May 17, 2014
1 parent 1b659d2 commit 112ed70
Show file tree
Hide file tree
Showing 21 changed files with 1,028 additions and 101 deletions.
28 changes: 8 additions & 20 deletions builder/vmware/common/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type Driver interface {

// SSHAddress returns the SSH address for the VM that is being
// managed by this driver.
SSHAddress(multistep.StateBag) (string, error)
IPAddress(multistep.StateBag) (string, error)

// Start starts a VM specified by the path to the VMX given.
Start(string, bool) error
Expand Down Expand Up @@ -68,39 +68,27 @@ func NewDriver(dconfig *DriverConfig, config *SSHConfig) (Driver, error) {
drivers = []Driver{
&Fusion6Driver{
Fusion5Driver: Fusion5Driver{
AppPath: dconfig.FusionAppPath,
SSHConfig: config,
AppPath: dconfig.FusionAppPath,
},
},
&Fusion5Driver{
AppPath: dconfig.FusionAppPath,
SSHConfig: config,
AppPath: dconfig.FusionAppPath,
},
}
case "linux":
drivers = []Driver{
&Workstation10Driver{
Workstation9Driver: Workstation9Driver{
SSHConfig: config,
},
},
&Workstation9Driver{
SSHConfig: config,
},
&Player5LinuxDriver{
SSHConfig: config,
Workstation9Driver: Workstation9Driver{},
},
&Workstation9Driver{},
&Player5LinuxDriver{},
}
case "windows":
drivers = []Driver{
&Workstation10Driver{
Workstation9Driver: Workstation9Driver{
SSHConfig: config,
},
},
&Workstation9Driver{
SSHConfig: config,
Workstation9Driver: Workstation9Driver{},
},
&Workstation9Driver{},
}
default:
return nil, fmt.Errorf("can't find driver for OS: %s", runtime.GOOS)
Expand Down
7 changes: 2 additions & 5 deletions builder/vmware/common/driver_fusion5.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ import (
type Fusion5Driver struct {
// This is the path to the "VMware Fusion.app"
AppPath string

// SSHConfig are the SSH settings for the Fusion VM
SSHConfig *SSHConfig
}

func (d *Fusion5Driver) Clone(dst, src string) error {
Expand Down Expand Up @@ -69,8 +66,8 @@ func (d *Fusion5Driver) IsRunning(vmxPath string) (bool, error) {
return false, nil
}

func (d *Fusion5Driver) SSHAddress(state multistep.StateBag) (string, error) {
return SSHAddressFunc(d.SSHConfig)(state)
func (d *Fusion5Driver) IPAddress(state multistep.StateBag) (string, error) {
return IPAddressFunc()(state)
}

func (d *Fusion5Driver) Start(vmxPath string, headless bool) error {
Expand Down
16 changes: 8 additions & 8 deletions builder/vmware/common/driver_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ type DriverMock struct {
IsRunningResult bool
IsRunningErr error

SSHAddressCalled bool
SSHAddressState multistep.StateBag
SSHAddressResult string
SSHAddressErr error
IPAddressCalled bool
IPAddressState multistep.StateBag
IPAddressResult string
IPAddressErr error

StartCalled bool
StartPath string
Expand Down Expand Up @@ -92,10 +92,10 @@ func (d *DriverMock) IsRunning(path string) (bool, error) {
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) IPAddress(state multistep.StateBag) (string, error) {
d.IPAddressCalled = true
d.IPAddressState = state
return d.IPAddressResult, d.IPAddressErr
}

func (d *DriverMock) Start(path string, headless bool) error {
Expand Down
7 changes: 2 additions & 5 deletions builder/vmware/common/driver_player5.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ type Player5LinuxDriver struct {
VdiskManagerPath string
QemuImgPath string
VmrunPath string

// SSHConfig are the SSH settings for the Fusion VM
SSHConfig *SSHConfig
}

func (d *Player5LinuxDriver) Clone(dst, src string) error {
Expand Down Expand Up @@ -96,8 +93,8 @@ func (d *Player5LinuxDriver) IsRunning(vmxPath string) (bool, error) {
return false, nil
}

func (d *Player5LinuxDriver) SSHAddress(state multistep.StateBag) (string, error) {
return SSHAddressFunc(d.SSHConfig)(state)
func (d *Player5LinuxDriver) IPAddress(state multistep.StateBag) (string, error) {
return IPAddressFunc()(state)
}

func (d *Player5LinuxDriver) Start(vmxPath string, headless bool) error {
Expand Down
7 changes: 2 additions & 5 deletions builder/vmware/common/driver_workstation9.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ type Workstation9Driver struct {
AppPath string
VdiskManagerPath string
VmrunPath string

// SSHConfig are the SSH settings for the Fusion VM
SSHConfig *SSHConfig
}

func (d *Workstation9Driver) Clone(dst, src string) error {
Expand Down Expand Up @@ -70,8 +67,8 @@ func (d *Workstation9Driver) IsRunning(vmxPath string) (bool, error) {
return false, nil
}

func (d *Workstation9Driver) SSHAddress(state multistep.StateBag) (string, error) {
return SSHAddressFunc(d.SSHConfig)(state)
func (d *Workstation9Driver) IPAddress(state multistep.StateBag) (string, error) {
return IPAddressFunc()(state)
}

func (d *Workstation9Driver) Start(vmxPath string, headless bool) error {
Expand Down
56 changes: 56 additions & 0 deletions builder/vmware/common/guest_ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package common

import (
"errors"
"fmt"
"github.com/mitchellh/multistep"
"io/ioutil"
"log"
"os"
Expand All @@ -28,6 +30,60 @@ type DHCPLeaseGuestLookup struct {
MACAddress string
}

func IPAddressFunc() func(multistep.StateBag) (string, error) {
return func(state multistep.StateBag) (string, error) {
return LookupGuestIPAddress(state)
}
}

// Finds the Guest IP address from VMWare
func LookupGuestIPAddress(state multistep.StateBag) (string, error) {
driver := state.Get("driver").(Driver)
vmxPath := state.Get("vmx_path").(string)

log.Println("Lookup up IP information...")
f, err := os.Open(vmxPath)
if err != nil {
return "", err
}
defer f.Close()

vmxBytes, err := ioutil.ReadAll(f)
if err != nil {
return "", 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 "", errors.New("couldn't find MAC address in VMX")
}
}

ipLookup := &DHCPLeaseGuestLookup{
Driver: driver,
Device: "vmnet8",
MACAddress: macAddress,
}

ipAddress, err := ipLookup.GuestIP()
if err != nil {
log.Printf("IP lookup failed: %s", err)
return "", fmt.Errorf("IP lookup failed: %s", err)
}

if ipAddress == "" {
log.Println("IP is blank, no IP yet.")
return "", errors.New("IP is blank")
}

log.Printf("Detected IP: %s", ipAddress)
return ipAddress, nil
}

func (f *DHCPLeaseGuestLookup) GuestIP() (string, error) {
dhcpLeasesPath := f.Driver.DhcpLeasesPath(f.Device)
log.Printf("DHCP leases path: %s", dhcpLeasesPath)
Expand Down
17 changes: 15 additions & 2 deletions builder/vmware/common/run_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ package common

import (
"fmt"
"strings"
"time"

"github.com/mitchellh/packer/packer"
)

type RunConfig struct {
Headless bool `mapstructure:"headless"`
RawBootWait string `mapstructure:"boot_wait"`
CommunicatorType string `mapstructure:"communicator_type"`
Headless bool `mapstructure:"headless"`
RawBootWait string `mapstructure:"boot_wait"`

BootWait time.Duration ``
}
Expand All @@ -19,6 +21,12 @@ func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error {
c.RawBootWait = "10s"
}

if c.CommunicatorType == "" {
c.CommunicatorType = "ssh"
} else {
c.CommunicatorType = strings.ToLower(c.CommunicatorType)
}

templates := map[string]*string{
"boot_wait": &c.RawBootWait,
}
Expand All @@ -40,5 +48,10 @@ func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error {
}
}

if c.CommunicatorType != "winrm" && c.CommunicatorType != "ssh" {
errs = append(
errs, fmt.Errorf("Invalid communicator type: %s, expected ssh or winrm", c.CommunicatorType))
}

return errs
}
41 changes: 40 additions & 1 deletion builder/vmware/common/run_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"testing"
)

func TestRunConfigPrepare(t *testing.T) {
func TestRunConfigPrepare_BootWait(t *testing.T) {
var c *RunConfig

// Test a default boot_wait
Expand Down Expand Up @@ -34,3 +34,42 @@ func TestRunConfigPrepare(t *testing.T) {
t.Fatalf("bad: %#v", errs)
}
}

func TestRunConfigPrepare_CommunicatorType(t *testing.T) {
var c *RunConfig

// Test a default communicator_type
c = new(RunConfig)
c.CommunicatorType = ""
errs := c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("bad: %#v", errs)
}
if c.CommunicatorType != "ssh" {
t.Fatalf("bad default communicator type: %s", c.CommunicatorType)
}

// Test with a bad communicator type
c = new(RunConfig)
c.CommunicatorType = "foo"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) == 0 {
t.Fatal("should error")
}

// Test with ssh
c = new(RunConfig)
c.CommunicatorType = "ssh"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("bad: %#v", errs)
}

// Test with winrm
c = new(RunConfig)
c.CommunicatorType = "winrm"
errs = c.Prepare(testConfigTemplate(t))
if len(errs) > 0 {
t.Fatalf("bad: %#v", errs)
}
}
44 changes: 2 additions & 42 deletions builder/vmware/common/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,25 @@ package common

import (
gossh "code.google.com/p/go.crypto/ssh"
"errors"
"fmt"
"io/ioutil"
"log"
"os"

"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/communicator/ssh"
)

func SSHAddressFunc(config *SSHConfig) func(multistep.StateBag) (string, error) {
func SSHAddressFunc(config *SSHConfig, driver Driver) func(multistep.StateBag) (string, error) {
return func(state multistep.StateBag) (string, error) {
driver := state.Get("driver").(Driver)
vmxPath := state.Get("vmx_path").(string)

if config.SSHHost != "" {
return fmt.Sprintf("%s:%d", config.SSHHost, config.SSHPort), nil
}

log.Println("Lookup up IP information...")
f, err := os.Open(vmxPath)
if err != nil {
return "", err
}
defer f.Close()

vmxBytes, err := ioutil.ReadAll(f)
ipAddress, err := driver.IPAddress(state)
if err != nil {
return "", 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 "", errors.New("couldn't find MAC address in VMX")
}
}

ipLookup := &DHCPLeaseGuestLookup{
Driver: driver,
Device: "vmnet8",
MACAddress: macAddress,
}

ipAddress, err := ipLookup.GuestIP()
if err != nil {
log.Printf("IP lookup failed: %s", err)
return "", fmt.Errorf("IP lookup failed: %s", err)
}

if ipAddress == "" {
log.Println("IP is blank, no IP yet.")
return "", errors.New("IP is blank")
}

log.Printf("Detected IP: %s", ipAddress)
return fmt.Sprintf("%s:%d", ipAddress, config.SSHPort), nil
}
}
Expand Down
Loading

0 comments on commit 112ed70

Please sign in to comment.