func (d *Driver) Start() error { log.Infof("Starting %s...", d.MachineName) vmrun("start", d.vmxPath(), "nogui") // Do not execute the rest of boot2docker specific configuration, exit here if d.ConfigDriveURL != "" { log.Debugf("Leaving start sequence early, configdrive found") return nil } log.Debugf("Mounting Shared Folders...") var shareName, shareDir string // TODO configurable at some point switch runtime.GOOS { case "darwin": shareName = "Users" shareDir = "/Users" // TODO "linux" and "windows" } if shareDir != "" { if _, err := os.Stat(shareDir); err != nil && !os.IsNotExist(err) { return err } else if !os.IsNotExist(err) { // create mountpoint and mount shared folder command := "[ ! -d " + shareDir + " ]&& sudo mkdir " + shareDir + "; [ -f /usr/local/bin/vmhgfs-fuse ]&& sudo /usr/local/bin/vmhgfs-fuse -o allow_other .host:/" + shareName + " " + shareDir + " || sudo mount -t vmhgfs .host:/" + shareName + " " + shareDir vmrun("-gu", B2DUser, "-gp", B2DPass, "runScriptInGuest", d.vmxPath(), "/bin/sh", command) } } return nil }
func (d *Driver) Create() error { client, err := d.getClient() if err != nil { return err } log.Infof("Creating SSH key...") err = d.createSSHkey() if err != nil { return err } userdata, err := d.getCloudInit() if err != nil { return err } encoded := base64.StdEncoding.EncodeToString(userdata) d.UserData = &encoded log.Infof("Creating Brightbox Server...") log.Debugf("with the following Userdata") log.Debugf("%s", string(userdata)) log.Debugf("Brightbox API Call: Create Server using image %s", d.Image) server, err := client.CreateServer(&d.ServerOptions) if err != nil { return err } d.MachineID = server.Id return nil }
func (d *Driver) Start() error { log.Debugf("Starting VM %s", d.MachineName) d.validateVMRef() err := d.VM.Create() if err != nil { log.Warnf("Failed to start: %s", err) return err } // They wont start immediately time.Sleep(5 * time.Second) for i := 0; i < 90; i++ { time.Sleep(time.Second) ip, _ := d.GetIP() if ip != "" { // Add a second to let things settle time.Sleep(time.Second) return nil } log.Debugf("Waiting for the VM to come up... %d", i) } log.Warnf("Unable to determine VM's IP address, did it fail to boot?") return err }
//GetServerBySerialNumber use the serial number to find the server func (c *ICSPClient) GetServerBySerialNumber(serial string) (Server, error) { var ( servers ServerList server Server ) servers, err := c.GetServers() if err != nil { return server, err } log.Debugf("GetServerBySerialNumber: server count: %d, serialnumber: %s", servers.Count, serial) // grab the target var srv Server for _, server := range servers.Members { log.Debugf("server: %v, serial : %v", server.HostName, server.SerialNumber) if strings.EqualFold(server.SerialNumber, serial) { log.Debugf("found server host: %v", server.HostName) srv = server srv, err = srv.ReloadFull(c) if err != nil { return srv, err } break } } return srv, nil }
// GetServerByIP use the server ip to get the server func (c *ICSPClient) GetServerByIP(ip string) (Server, error) { var ( servers ServerList server Server ) servers, err := c.GetServers() if err != nil { return server, err } log.Debugf("GetServerByIP: server count: %d", servers.Count) // grab the target var srv Server for _, randServer := range servers.Members { server, err := c.GetServerByID(randServer.MID) if err != nil { return server, err } if strings.EqualFold(server.ILO.IPAddress, ip) { log.Debugf("server ip: %v", &server.ILO.IPAddress) srv = server srv, err = srv.ReloadFull(c) if err != nil { return srv, err } break } } return srv, nil }
func (d *Driver) mountSharedFolder(shareDir, shareName string) error { // create mountpoint and mount shared folder addr, err := d.GetSSHHostname() if err != nil { return err } port, err := d.GetSSHPort() if err != nil { return err } auth := &ssh.Auth{ Keys: []string{d.GetSSHKeyPath()}, } client, err := ssh.NewClient(d.GetSSHUsername(), addr, port, auth) if err != nil { return err } command := "[ ! -d " + shareDir + " ]&& sudo mkdir " + shareDir + "; [ -f /usr/bin/vmhgfs-fuse ]&& sudo /usr/bin/vmhgfs-fuse -o allow_other .host:/" + shareName + " " + shareDir + " || sudo mount -t vmhgfs .host:/" + shareName + " " + shareDir log.Debugf("About to run SSH command:\n%s", command) output, err := client.Output(command) log.Debugf("SSH cmd err, output: %v: %s", err, output) return err }
// Test SessionLogout func TestSessionLogout(t *testing.T) { var ( //d *OVTest c *ICSPClient //testSerial string ) if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" { _, c = getTestDriverA() if c == nil { t.Fatalf("Failed to execute getTestDriver() ") } //data, err := c.SessionLogin() // this is needed so we can "copy" the session id to the ov client err := c.RefreshLogin() //log.Debugf(" login key -> %s, session data -> %+v", c.APIKey, data) log.Debugf(" login key -> %s", c.APIKey) assert.NoError(t, err, "SessionLogin threw error -> %s", err) //assert.NotEmpty(t, data.ID, fmt.Sprintf("SessionLogin is empty! something went wrong, err -> %s, data -> %+v\n", err, data)) //assert.Equal(t, "none", c.APIKey) err = c.SessionLogout() log.Debugf(" login key after logout -> %s", c.APIKey) assert.NoError(t, err, "SessionLogout threw error -> %s", err) // test if we can perform an op after logout //_, err = c.GetProfileBySN(testSerial) //assert.Error(t, err, "SessionLogin threw error -> %s", err) } else { /*_, c = getTestDriverU() data, err := c.SessionLogin() assert.Error(t,err, fmt.Sprintf("ALL ok, no error, caught as expected: %s,%+v\n",err, data)) assert.Equal(t, "none", c.APIKey) */ } }
func (d *Driver) waitForIP() error { var ip string var err error log.Infof("Waiting for VM to come online...") for i := 1; i <= 60; i++ { ip, err = d.getIPfromDHCPLease() if err != nil { log.Debugf("Not there yet %d/%d, error: %s", i, 60, err) time.Sleep(2 * time.Second) continue } if ip != "" { log.Debugf("Got an ip: %s", ip) d.IPAddress = ip break } } if ip == "" { return fmt.Errorf("Machine didn't return an IP after 120 seconds, aborting") } // Wait for SSH over NAT to be available before returning to user if err := drivers.WaitForSSH(d); err != nil { return err } return nil }
func (d *Driver) extractKernelImages() error { log.Debugf("Mounting %s", isoFilename) err := hdiutil("attach", d.ResolveStorePath(isoFilename), "-mountpoint", d.ResolveStorePath("b2d-image")) if err != nil { return err } volumeRootDir := d.ResolveStorePath(isoMountPath) vmlinuz64 := volumeRootDir + "/boot/vmlinuz64" initrd := volumeRootDir + "/boot/initrd.img" log.Debugf("Extracting vmlinuz64 into %s", d.ResolveStorePath(".")) if err := mcnutils.CopyFile(vmlinuz64, d.ResolveStorePath("vmlinuz64")); err != nil { return err } log.Debugf("Extracting initrd.img into %s", d.ResolveStorePath(".")) if err := mcnutils.CopyFile(initrd, d.ResolveStorePath("initrd.img")); err != nil { return err } log.Debugf("Unmounting %s", isoFilename) if err := hdiutil("detach", volumeRootDir); err != nil { return err } return nil }
func (provisioner *CoreOSProvisioner) Provision(swarmOptions swarm.Options, authOptions auth.Options, engineOptions engine.Options) error { provisioner.SwarmOptions = swarmOptions provisioner.AuthOptions = authOptions provisioner.EngineOptions = engineOptions if err := provisioner.SetHostname(provisioner.Driver.GetMachineName()); err != nil { return err } if err := makeDockerOptionsDir(provisioner); err != nil { return err } log.Debugf("Preparing certificates") provisioner.AuthOptions = setRemoteAuthOptions(provisioner) log.Debugf("Setting up certificates") if err := ConfigureAuth(provisioner); err != nil { return err } log.Debug("Configuring swarm") if err := configureSwarm(provisioner, swarmOptions, provisioner.AuthOptions); err != nil { return err } return nil }
func (d *Driver) GetIP() (string, error) { // DHCP is used to get the IP, so virtualbox hosts don't have IPs unless // they are running s, err := d.GetState() if err != nil { return "", err } if s != state.Running { return "", drivers.ErrHostIsNotRunning } macAddress, err := d.getHostOnlyMACAddress() if err != nil { return "", err } log.Debugf("Host-only MAC: %s\n", macAddress) output, err := drivers.RunSSHCommandFromDriver(d, "ip addr show") if err != nil { return "", err } log.Debugf("SSH returned: %s\nEND SSH\n", output) ipAddress, err := d.parseIPForMACFromIPAddr(output, macAddress) if err != nil { return "", err } return ipAddress, nil }
func (c *OVClient) UpdateEnclosureGroup(enclosureGroup EnclosureGroup) error { log.Infof("Initializing update of enclosure group for %s.", enclosureGroup.Name) var ( uri = enclosureGroup.URI.String() t *Task ) // refresh login c.RefreshLogin() c.SetAuthHeaderOptions(c.GetAuthHeaderMap()) t = t.NewProfileTask(c) t.ResetTask() log.Debugf("REST : %s \n %+v\n", uri, enclosureGroup) log.Debugf("task -> %+v", t) data, err := c.RestAPICall(rest.PUT, uri, enclosureGroup) if err != nil { t.TaskIsDone = true log.Errorf("Error submitting update enclosure group request: %s", err) return err } log.Debugf("Response update EnclosureGroup %s", data) if err := json.Unmarshal([]byte(data), &t); err != nil { t.TaskIsDone = true log.Errorf("Error with task un-marshal: %s", err) return err } return nil }
// ReadTLSConfig reads the tls config for a machine. func (xcg *X509CertGenerator) ReadTLSConfig(addr string, authOptions *auth.Options) (*tls.Config, error) { caCertPath := authOptions.CaCertPath serverCertPath := authOptions.ServerCertPath serverKeyPath := authOptions.ServerKeyPath log.Debugf("Reading CA certificate from %s", caCertPath) caCert, err := ioutil.ReadFile(caCertPath) if err != nil { return nil, err } log.Debugf("Reading server certificate from %s", serverCertPath) serverCert, err := ioutil.ReadFile(serverCertPath) if err != nil { return nil, err } log.Debugf("Reading server key from %s", serverKeyPath) serverKey, err := ioutil.ReadFile(serverKeyPath) if err != nil { return nil, err } return xcg.getTLSConfig(caCert, serverCert, serverKey, false) }
// GetCurrentTaskStatus - Get the current status func (t *Task) GetCurrentTaskStatus() error { log.Debugf("Working on getting current task status") var ( uri = t.URI ) if uri != "" { log.Debugf(uri.String()) data, err := t.Client.RestAPICall(rest.GET, uri.String(), nil) if err != nil { return err } log.Debugf("data: %s", data) if err := json.Unmarshal([]byte(data), &t); err != nil { return err } } else { log.Debugf("Unable to get current task, no URI found") } if len(t.TaskErrors) > 0 { var errmsg string errmsg = "" for _, te := range t.TaskErrors { errmsg += te.Message + " \n" + strings.Join(te.RecommendedActions, " ") } return errors.New(errmsg) } return nil }
func (v *VBoxCmdManager) vbmOutErr(args ...string) (string, string, error) { cmd := exec.Command(vboxManageCmd, args...) log.Debugf("COMMAND: %v %v", vboxManageCmd, strings.Join(args, " ")) var stdout bytes.Buffer var stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() stderrStr := stderr.String() if len(args) > 0 { log.Debugf("STDOUT:\n{\n%v}", stdout.String()) log.Debugf("STDERR:\n{\n%v}", stderrStr) } if err != nil { if ee, ok := err.(*exec.Error); ok && ee.Err == exec.ErrNotFound { err = ErrVBMNotFound } } if err == nil || strings.HasPrefix(err.Error(), "exit status ") { // VBoxManage will sometimes not set the return code, but has a fatal error // such as VBoxManage.exe: error: VT-x is not available. (VERR_VMX_NO_VMX) if strings.Contains(stderrStr, "error:") { err = fmt.Errorf("%v %v failed:\n%v", vboxManageCmd, strings.Join(args, " "), stderrStr) } } return stdout.String(), stderrStr, err }
func (d *Driver) getMACAdress() (string, error) { args := append(d.xhyveArgs(), "-M") stdout := bytes.Buffer{} cmd := exec.Command(os.Args[0], args...) // TODO: Should be possible without exec log.Debugf("Running command: %s %s", os.Args[0], args) cmd.Stdout = &stdout if err := cmd.Run(); err != nil { if exitErr, ok := err.(*exec.ExitError); ok { log.Debugf("Stderr: %s", exitErr.Stderr) } return "", err } mac := bytes.TrimPrefix(stdout.Bytes(), []byte("MAC: ")) mac = bytes.TrimSpace(mac) hw, err := net.ParseMAC(string(mac)) if err != nil { return "", err } return hw.String(), nil }
func (d *Driver) GetIP() (string, error) { s, err := d.GetState() if err != nil { return "", err } if s != state.Running { return "", drivers.ErrHostIsNotRunning } c, err := NewClient("http://localhost:" + strconv.Itoa(d.APIPort)) if err != nil { return "", err } var ip string for i := 1; i <= 60; i++ { vmip, err := c.GetVMIPAddress(d.MachineName) if err != nil && vmip.Code != 200 { log.Debugf("Not there yet %d/%d, error code: %d, message %s", i, 60, vmip.Code, err) time.Sleep(2 * time.Second) continue } ip = vmip.Message log.Debugf("Got an ip: %s", ip) break } if ip == "" { return "", fmt.Errorf("machine didn't return an IP after 120 seconds, aborting") } return ip, nil }
func (d *Driver) waitForSetupTransactions() { log.Infof("Waiting for host setup transactions to complete") // sometimes we'll hit a case where there's no active transaction, but if // we check again in a few seconds, it moves to the next transaction. We // don't want to get false-positives, so we check a few times in a row to make sure! noActiveCount, maxNoActiveCount := 0, 3 for { t, err := d.GetActiveTransaction() if err != nil { noActiveCount = 0 log.Debugf("Failed to GetActiveTransaction - %+v", err) continue } if t == "" { if noActiveCount == maxNoActiveCount { break } noActiveCount++ } else { noActiveCount = 0 log.Debugf("Still waiting - active transaction is %s...", t) } time.Sleep(2 * time.Second) } }
func (lbe *LocalBinaryExecutor) Start() (*bufio.Scanner, *bufio.Scanner, error) { log.Debugf("Launching plugin server for driver %s", lbe.DriverName) binaryPath, err := exec.LookPath(fmt.Sprintf("docker-machine-driver-%s", lbe.DriverName)) if err != nil { return nil, nil, fmt.Errorf("Driver %q not found. Do you have the plugin binary accessible in your PATH?", lbe.DriverName) } log.Debugf("Found binary path at %s", binaryPath) cmd := exec.Command(binaryPath) lbe.pluginStdout, err = cmd.StdoutPipe() if err != nil { return nil, nil, fmt.Errorf("Error getting cmd stdout pipe: %s", err) } lbe.pluginStderr, err = cmd.StderrPipe() if err != nil { return nil, nil, fmt.Errorf("Error getting cmd stderr pipe: %s", err) } outScanner := bufio.NewScanner(lbe.pluginStdout) errScanner := bufio.NewScanner(lbe.pluginStderr) os.Setenv(PluginEnvKey, PluginEnvVal) if err := cmd.Start(); err != nil { return nil, nil, fmt.Errorf("Error starting plugin binary: %s", err) } return outScanner, errScanner, nil }
// TestGetIloIPAddress verify get ip address for hardware func TestGetIloIPAddress(t *testing.T) { var ( d *OVTest c *ov.OVClient testData utils.Nstring expectsData string ) if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" { d, c = getTestDriverA("dev") testData = utils.Nstring(d.Tc.GetTestData(d.Env, "ServerHardwareURI").(string)) expectsData = d.Tc.GetExpectsData(d.Env, "IloIPAddress").(string) if c == nil { t.Fatalf("Failed to execute getTestDriver() ") } s, err := c.GetServerHardware(testData) assert.NoError(t, err, "GetServerHardware threw error -> %s", err) ip := s.GetIloIPAddress() log.Debugf("server -> %+v", s) log.Debugf("ip -> %+v", ip) assert.Equal(t, expectsData, ip) } }
// Set idle timeout func TestSetIdleTimeout(t *testing.T) { var ( c *ICSPClient // d *ICSPTest testtime int64 ) if os.Getenv("ONEVIEW_TEST_ACCEPTANCE") == "true" { testtime = 25000 _, c = getTestDriverA() if c == nil { t.Fatalf("Failed to execute getTestDriver() ") } err := c.RefreshLogin() log.Debugf(" login key -> %s", c.APIKey) assert.NoError(t, err, "RefreshLogin threw error -> %s", err) err = c.SetIdleTimeout(testtime) assert.NoError(t, err, "SetIdleTimeout threw error -> %s", err) timeout, err := c.GetIdleTimeout() assert.NoError(t, err, "GetIdleTimeout threw error -> %s", err) assert.Equal(t, testtime, timeout, "Should get timeout equal, %s", timeout) log.Debugf(" idle timeout -> %d", timeout) } }
func (sshCmder RedHatSSHCommander) SSHCommand(args string) (string, error) { client, err := drivers.GetSSHClientFromDriver(sshCmder.Driver) if err != nil { return "", err } log.Debugf("About to run SSH command:\n%s", args) // redhat needs "-t" for tty allocation on ssh therefore we check for the // external client and add as needed. // Note: CentOS 7.0 needs multiple "-tt" to force tty allocation when ssh has // no local tty. var output string switch c := client.(type) { case *ssh.ExternalClient: c.BaseArgs = append(c.BaseArgs, "-tt") output, err = c.Output(args) case *ssh.NativeClient: output, err = c.OutputWithPty(args) } log.Debugf("SSH cmd err, output: %v: %s", err, output) if err != nil { return "", fmt.Errorf(`Something went wrong running an SSH command! command : %s err : %v output : %s `, args, err, output) } return output, nil }
// execute command over SSH with user / password authentication func executeSSHCommand(command string, d *Driver) error { log.Debugf("Execute executeSSHCommand: %s", command) config := &cryptossh.ClientConfig{ User: d.SSHUser, Auth: []cryptossh.AuthMethod{ cryptossh.Password(d.SSHPassword), }, } client, err := cryptossh.Dial("tcp", fmt.Sprintf("%s:%d", d.IPAddress, d.SSHPort), config) if err != nil { log.Debugf("Failed to dial:", err) return err } session, err := client.NewSession() if err != nil { log.Debugf("Failed to create session: " + err.Error()) return err } defer session.Close() var b bytes.Buffer session.Stdout = &b if err := session.Run(command); err != nil { log.Debugf("Failed to run: " + err.Error()) return err } log.Debugf("Stdout from executeSSHCommand: %s", b.String()) return nil }
func (c *I3SClient) UpdateGoldenImage(goldenImage GoldenImage) error { log.Infof("Initializing update of golden image for %s.", goldenImage.Name) var ( uri = goldenImage.URI.String() t *Task ) c.SetAuthHeaderOptions(c.GetAuthHeaderMap()) t = t.NewTask(c) t.ResetTask() log.Debugf("REST : %s \n %+v\n", uri, goldenImage) log.Debugf("task -> %+v", t) data, err := c.RestAPICall(rest.PUT, uri, goldenImage) if err != nil { t.TaskIsDone = true log.Errorf("Error submitting update golden image request: %s", err) return err } log.Debugf("Response update Golden Image %s", data) if err := json.Unmarshal([]byte(data), &t); err != nil { t.TaskIsDone = true log.Errorf("Error with task un-marshal: %s", err) return err } err = t.Wait() if err != nil { return err } return nil }
// GetServerByName use the server name to get the server type func (c *ICSPClient) GetServerByName(name string) (Server, error) { var ( servers ServerList server Server ) servers, err := c.GetServers() if err != nil { return server, err } log.Debugf("GetServerByName: server count: %d", servers.Count) // grab the target var srv Server for _, server := range servers.Members { if strings.EqualFold(server.Name, name) { log.Debugf("server name: %v", server.Name) srv = server srv, err = srv.ReloadFull(c) if err != nil { return srv, err } break } } return srv, nil }
func (d *Driver) addDockerEndpoints(vmConfig *vmClient.Role) error { configSets := vmConfig.ConfigurationSets.ConfigurationSet if len(configSets) == 0 { return errors.New("no configuration set") } for i := 0; i < len(configSets); i++ { if configSets[i].ConfigurationSetType != "NetworkConfiguration" { continue } ep := vmClient.InputEndpoint{ Name: "docker", Protocol: "tcp", Port: d.DockerPort, LocalPort: d.DockerPort, } if d.SwarmMaster { swarmEp := vmClient.InputEndpoint{ Name: "docker swarm", Protocol: "tcp", Port: d.DockerSwarmMasterPort, LocalPort: d.DockerSwarmMasterPort, } configSets[i].InputEndpoints.InputEndpoint = append(configSets[i].InputEndpoints.InputEndpoint, swarmEp) log.Debugf("added Docker swarm master endpoint (port %d) to configuration", d.DockerSwarmMasterPort) } configSets[i].InputEndpoints.InputEndpoint = append(configSets[i].InputEndpoints.InputEndpoint, ep) log.Debugf("added Docker endpoint (port %d) to configuration", d.DockerPort) } return nil }
// SaveServer save Server, submit new profile template func (c *ICSPClient) SaveServer(s Server) (o Server, err error) { log.Infof("Saving server attributes for %s.", s.Name) var ( uri = s.URI ) // refresh login c.RefreshLogin() c.SetAuthHeaderOptions(c.GetAuthHeaderMap()) log.Debugf("name -> %s, description -> %s", s.Name, s.Description) log.Debugf("CustomAttributes -> %+v", s.CustomAttributes) sc := s.Clone() log.Debugf("options -> %+v", c.Option) log.Debugf("REST : %s \n %+v\n", uri, sc) data, err := c.RestAPICall(rest.PUT, uri.String(), sc) if err != nil { log.Errorf("Error submitting new server request: %s", err) return o, err } if err := json.Unmarshal([]byte(data), &o); err != nil { return o, err } return o, err }
func (d *Driver) getBlade() (err error) { log.Debug("In getBlade()") d.Profile, err = d.ClientOV.GetProfileByName(d.MachineName) if err != nil { return err } log.Debugf("***> check if we got a profile") if d.Profile.URI.IsNil() { err = fmt.Errorf("Attempting to get machine profile information, unable to find machine in oneview: %s", d.MachineName) return err } // power on the server // get the server hardware associated with that test profile log.Debugf("***> GetServerHardware") d.Hardware, err = d.ClientOV.GetServerHardware(d.Profile.ServerHardwareURI) if d.Hardware.URI.IsNil() { err = fmt.Errorf("Attempting to get machine blade information, unable to find machine: %s", d.MachineName) return err } // get an icsp server if d.Hardware.VirtualSerialNumber.IsNil() { // get the server profile with SerialNumber d.Server, err = d.ClientICSP.GetServerBySerialNumber(d.Hardware.SerialNumber.String()) } else { // get the server profile with the VirtualSerialNumber d.Server, err = d.ClientICSP.GetServerBySerialNumber(d.Hardware.VirtualSerialNumber.String()) } if err != nil { return err } return err }
func (d *Driver) Stop() error { log.Debugf("Stopping VM %s", d.MachineName) d.validateVMRef() s, err := d.GetState() if err != nil { return err } if s != state.Stopped { err := d.VM.DestroyFlags(libvirt.VIR_DOMAIN_DESTROY_GRACEFUL) if err != nil { log.Warnf("Failed to gracefully shutdown VM") return err } for i := 0; i < 90; i++ { time.Sleep(time.Second) s, _ := d.GetState() log.Debugf("VM state: %s", s) if s == state.Stopped { return nil } } return errors.New("VM Failed to gracefully shutdown, try the kill command") } return nil }
func (d *Driver) checkImage() error { client, err := d.getClient() if err != nil { return err } var image *brightbox.Image if d.Image == "" { log.Info("No image specified. Looking for default image") log.Debugf("Brightbox API Call: List of Images") images, err := client.Images() if err != nil { return err } image, err = GetDefaultImage(images) if err != nil { return err } d.Image = image.Id } else { log.Debugf("Brightbox API Call: Image Details for %s", d.Image) image, err = client.Image(d.Image) if err != nil { return err } } if image.Arch != "x86_64" { return fmt.Errorf("Docker requires a 64 bit image. Image %s not suitable", d.Image) } if d.SSHUser == "" { log.Debug("Setting SSH Username from image details") d.SSHUser = image.Username } log.Debugf("Image %s selected. SSH user is %s", d.Image, d.SSHUser) return nil }