diff --git a/builder/vmware/common/driver.go b/builder/vmware/common/driver.go index ec34e70b5..e65e429b9 100644 --- a/builder/vmware/common/driver.go +++ b/builder/vmware/common/driver.go @@ -83,44 +83,61 @@ type Driver interface { // system, or an error if the driver couldn't be initialized. func NewDriver(dconfig *DriverConfig, config *SSHConfig) (Driver, error) { drivers := []Driver{} - - switch runtime.GOOS { - case "darwin": + log.Printf("**** NewDriver()") + if dconfig.RemoteType != "" { + log.Printf("**** Creating the remote driver.") drivers = []Driver{ - &Fusion6Driver{ - Fusion5Driver: Fusion5Driver{ + &ESX5Driver{ + Host: dconfig.RemoteHost, + Port: dconfig.RemotePort, + Username: dconfig.RemoteUser, + Password: dconfig.RemotePassword, + PrivateKey: dconfig.RemotePrivateKey, + Datastore: dconfig.RemoteDatastore, + CacheDatastore: dconfig.RemoteCacheDatastore, + CacheDirectory: dconfig.RemoteCacheDirectory, + }, + } + + } else { + switch runtime.GOOS { + case "darwin": + drivers = []Driver{ + &Fusion6Driver{ + Fusion5Driver: Fusion5Driver{ + AppPath: dconfig.FusionAppPath, + SSHConfig: config, + }, + }, + &Fusion5Driver{ AppPath: dconfig.FusionAppPath, SSHConfig: config, }, - }, - &Fusion5Driver{ - AppPath: dconfig.FusionAppPath, - SSHConfig: config, - }, - } - case "linux": - fallthrough - case "windows": - drivers = []Driver{ - &Workstation10Driver{ - Workstation9Driver: Workstation9Driver{ + } + case "linux": + fallthrough + case "windows": + drivers = []Driver{ + &Workstation10Driver{ + Workstation9Driver: Workstation9Driver{ + SSHConfig: config, + }, + }, + &Workstation9Driver{ SSHConfig: config, }, - }, - &Workstation9Driver{ - SSHConfig: config, - }, - &Player6Driver{ - Player5Driver: Player5Driver{ + &Player6Driver{ + Player5Driver: Player5Driver{ + SSHConfig: config, + }, + }, + &Player5Driver{ SSHConfig: config, }, - }, - &Player5Driver{ - SSHConfig: config, - }, + } + default: + return nil, fmt.Errorf("can't find driver for OS: %s", runtime.GOOS) } - default: - return nil, fmt.Errorf("can't find driver for OS: %s", runtime.GOOS) } errs := "" diff --git a/builder/vmware/common/driver_config.go b/builder/vmware/common/driver_config.go index 13c9e96ac..a58070502 100644 --- a/builder/vmware/common/driver_config.go +++ b/builder/vmware/common/driver_config.go @@ -7,7 +7,16 @@ import ( ) type DriverConfig struct { - FusionAppPath string `mapstructure:"fusion_app_path"` + FusionAppPath string `mapstructure:"fusion_app_path"` + RemoteType string `mapstructure:"remote_type"` + RemoteDatastore string `mapstructure:"remote_datastore"` + RemoteCacheDatastore string `mapstructure:"remote_cache_datastore"` + RemoteCacheDirectory string `mapstructure:"remote_cache_directory"` + RemoteHost string `mapstructure:"remote_host"` + RemotePort uint `mapstructure:"remote_port"` + RemoteUser string `mapstructure:"remote_username"` + RemotePassword string `mapstructure:"remote_password"` + RemotePrivateKey string `mapstructure:"remote_private_key_file"` } func (c *DriverConfig) Prepare(ctx *interpolate.Context) []error { diff --git a/builder/vmware/iso/driver_esx5.go b/builder/vmware/common/driver_esx5.go similarity index 89% rename from builder/vmware/iso/driver_esx5.go rename to builder/vmware/common/driver_esx5.go index 2f37f60b9..8269dd8f3 100644 --- a/builder/vmware/iso/driver_esx5.go +++ b/builder/vmware/common/driver_esx5.go @@ -1,4 +1,4 @@ -package iso +package common import ( "bufio" @@ -43,7 +43,20 @@ type ESX5Driver struct { } func (d *ESX5Driver) Clone(dst, src string, linked bool) error { - return errors.New("Cloning is not supported with the ESX driver.") + ret, err := d.sh("test -r %s", src) + if err != nil { + return errors.New("Source VMX not found") + } + + ret, err = d.run(nil, "ls") + files := strings.Split(ret, "\n") + if err != nil { + return errors.New("Error running cmd") + } + for _, f := range files { + log.Printf("One file is: %s", f) + } + log.Printf("Return was: %s", ret) } func (d *ESX5Driver) CompactDisk(diskPathLocal string) error { @@ -375,74 +388,71 @@ func (ESX5Driver) UpdateVMX(_, password string, port uint, data map[string]strin } func (d *ESX5Driver) CommHost(state multistep.StateBag) (string, error) { - config := state.Get("config").(*Config) - sshc := config.SSHConfig.Comm - port := sshc.SSHPort - if sshc.Type == "winrm" { - port = sshc.WinRMPort - } - - if address := config.CommConfig.Host(); address != "" { - return address, nil - } - - r, err := d.esxcli("network", "vm", "list") - if err != nil { - return "", err - } - - // The value in the Name field returned by 'esxcli network vm list' - // corresponds directly to the value of displayName set in the VMX file - var displayName string - if v, ok := state.GetOk("display_name"); ok { - displayName = v.(string) - } - record, err := r.find("Name", displayName) - if err != nil { - return "", err - } - wid := record["WorldID"] - if wid == "" { - return "", errors.New("VM WorldID not found") - } - - r, err = d.esxcli("network", "vm", "port", "list", "-w", wid) - if err != nil { - return "", err - } - - // Loop through interfaces - for { - record, err = r.read() - if err == io.EOF { - break - } - if err != nil { - return "", err - } - - if record["IPAddress"] == "0.0.0.0" { - continue - } - // When multiple NICs are connected to the same network, choose - // one that has a route back. This Dial should ensure that. - conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", record["IPAddress"], port), 2*time.Second) - if err != nil { - if e, ok := err.(*net.OpError); ok { - if e.Timeout() { - log.Printf("Timeout connecting to %s", record["IPAddress"]) - continue - } else if strings.Contains(e.Error(), "connection refused") { - log.Printf("Connection refused when connecting to: %s", record["IPAddress"]) - continue - } - } - } else { - defer conn.Close() - address := record["IPAddress"] - return address, nil - } - } + // config := state.Get("config").(*Config) + // sshc := config.SSHConfig.Comm + // port := sshc.SSHPort + // if sshc.Type == "winrm" { + // port = sshc.WinRMPort + // } + // + // if address, ok := state.GetOk("vm_address"); ok { + // return address.(string), nil + // } + // + // if address := config.CommConfig.Host(); address != "" { + // state.Put("vm_address", address) + // return address, nil + // } + // + // r, err := d.esxcli("network", "vm", "list") + // if err != nil { + // return "", err + // } + // + // record, err := r.find("Name", config.VMName) + // if err != nil { + // return "", err + // } + // wid := record["WorldID"] + // if wid == "" { + // return "", errors.New("VM WorldID not found") + // } + // + // r, err = d.esxcli("network", "vm", "port", "list", "-w", wid) + // if err != nil { + // return "", err + // } + // + // // Loop through interfaces + // for { + // record, err = r.read() + // if err == io.EOF { + // break + // } + // if err != nil { + // return "", err + // } + // + // if record["IPAddress"] == "0.0.0.0" { + // continue + // } + // // When multiple NICs are connected to the same network, choose + // // one that has a route back. This Dial should ensure that. + // conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", record["IPAddress"], port), 2*time.Second) + // if err != nil { + // if e, ok := err.(*net.OpError); ok { + // if e.Timeout() { + // log.Printf("Timeout connecting to %s", record["IPAddress"]) + // continue + // } + // } + // } else { + // defer conn.Close() + // address := record["IPAddress"] + // state.Put("vm_address", address) + // return address, nil + // } + // } return "", errors.New("No interface on the VM has an IP address ready") } diff --git a/builder/vmware/common/driver_esx5_test.go b/builder/vmware/common/driver_esx5_test.go new file mode 100644 index 000000000..2fec8ee7f --- /dev/null +++ b/builder/vmware/common/driver_esx5_test.go @@ -0,0 +1,97 @@ +package common + +import ( + "fmt" + "net" + "testing" + + "github.com/mitchellh/multistep" +) + +func TestESX5Driver_implDriver(t *testing.T) { + var _ Driver = new(ESX5Driver) +} + +func TestESX5Driver_UpdateVMX(t *testing.T) { + var driver ESX5Driver + data := make(map[string]string) + driver.UpdateVMX("0.0.0.0", "", 5900, data) + if _, ok := data["remotedisplay.vnc.ip"]; ok { + // Do not add the remotedisplay.vnc.ip on ESXi + t.Fatal("invalid VMX data key: remotedisplay.vnc.ip") + } + if enabled := data["remotedisplay.vnc.enabled"]; enabled != "TRUE" { + t.Errorf("bad VMX data for key remotedisplay.vnc.enabled: %v", enabled) + } + if port := data["remotedisplay.vnc.port"]; port != fmt.Sprint(port) { + t.Errorf("bad VMX data for key remotedisplay.vnc.port: %v", port) + } +} + +func TestESX5Driver_implOutputDir(t *testing.T) { + var _ OutputDir = new(ESX5Driver) +} + +func TestESX5Driver_implVNCAddressFinder(t *testing.T) { + var _ VNCAddressFinder = new(ESX5Driver) +} + +func TestESX5Driver_implRemoteDriver(t *testing.T) { + var _ RemoteDriver = new(ESX5Driver) +} + +func TestESX5Driver_HostIP(t *testing.T) { + expected_host := "127.0.0.1" + + //create mock SSH server + listen, _ := net.Listen("tcp", fmt.Sprintf("%s:0", expected_host)) + port := listen.Addr().(*net.TCPAddr).Port + defer listen.Close() + + driver := ESX5Driver{Host: "localhost", Port: uint(port)} + + if host, _ := driver.HostIP(); host != expected_host { + t.Error(fmt.Sprintf("Expected string, %s but got %s", expected_host, host)) + } +} + +func TestESX5Driver_CommHost(t *testing.T) { + const expected_host = "127.0.0.1" + + config := testConfig() + config["communicator"] = "winrm" + config["winrm_username"] = "username" + config["winrm_password"] = "password" + config["winrm_host"] = expected_host + + var b Builder + warns, err := b.Prepare(config) + if len(warns) > 0 { + t.Fatalf("bad: %#v", warns) + } + if err != nil { + t.Fatalf("should not have error: %s", err) + } + if host := b.config.CommConfig.Host(); host != expected_host { + t.Fatalf("setup failed, bad host name: %s", host) + } + + state := new(multistep.BasicStateBag) + state.Put("config", &b.config) + + var driver ESX5Driver + host, err := driver.CommHost(state) + if err != nil { + t.Fatalf("should not have error: %s", err) + } + if host != expected_host { + t.Errorf("bad host name: %s", host) + } + address, ok := state.GetOk("vm_address") + if !ok { + t.Error("state not updated with vm_address") + } + if address.(string) != expected_host { + t.Errorf("bad vm_address: %s", address.(string)) + } +} diff --git a/builder/vmware/iso/driver.go b/builder/vmware/iso/driver.go index f461c0927..6580c3108 100644 --- a/builder/vmware/iso/driver.go +++ b/builder/vmware/iso/driver.go @@ -16,7 +16,7 @@ func NewDriver(config *Config) (vmwcommon.Driver, error) { } drivers = []vmwcommon.Driver{ - &ESX5Driver{ + &vmwcommon.ESX5Driver{ Host: config.RemoteHost, Port: config.RemotePort, Username: config.RemoteUser,