diff --git a/commands.go b/commands.go index 17d2f62250..bbdead7a16 100644 --- a/commands.go +++ b/commands.go @@ -554,9 +554,9 @@ func cmdSsh(c *cli.Context) { } if len(c.Args()) <= 1 { - sshCmd, err = host.Driver.GetSSHCommand() + sshCmd, err = host.GetSSHCommand() } else { - sshCmd, err = host.Driver.GetSSHCommand(c.Args()[1:]...) + sshCmd, err = host.GetSSHCommand(c.Args()[1:]...) } if err != nil { log.Fatal(err) @@ -578,7 +578,7 @@ func machineCommand(actionName string, machine *Host, errorChan chan<- error) { "stop": machine.Driver.Stop, "restart": machine.Driver.Restart, "kill": machine.Driver.Kill, - "upgrade": machine.Driver.Upgrade, + "upgrade": machine.Upgrade, } log.Debugf("command=%s machine=%s", actionName, machine.Name) diff --git a/commands_test.go b/commands_test.go index ce875bec1e..96a9af0441 100644 --- a/commands_test.go +++ b/commands_test.go @@ -12,6 +12,7 @@ import ( "github.com/codegangsta/cli" drivers "github.com/docker/machine/drivers" + "github.com/docker/machine/provider" "github.com/docker/machine/state" ) @@ -23,6 +24,14 @@ func (d *FakeDriver) DriverName() string { return "fakedriver" } +func (d *FakeDriver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *FakeDriver) DeauthorizePort(ports []*drivers.Port) error { + return nil +} + func (d *FakeDriver) SetConfigFromFlags(flags drivers.DriverOptions) error { return nil } @@ -31,10 +40,34 @@ func (d *FakeDriver) GetURL() (string, error) { return "", nil } +func (d *FakeDriver) GetMachineName() string { + return "" +} + +func (d *FakeDriver) GetProviderType() provider.ProviderType { + return provider.None +} + func (d *FakeDriver) GetIP() (string, error) { return "", nil } +func (d *FakeDriver) GetSSHHostname() (string, error) { + return "", nil +} + +func (d *FakeDriver) GetSSHKeyPath() string { + return "" +} + +func (d *FakeDriver) GetSSHPort() (int, error) { + return 0, nil +} + +func (d *FakeDriver) GetSSHUsername() string { + return "" +} + func (d *FakeDriver) GetState() (state.State, error) { return d.MockState, nil } diff --git a/drivers/amazonec2/amazonec2.go b/drivers/amazonec2/amazonec2.go index 5a9586f6af..88f89915bb 100644 --- a/drivers/amazonec2/amazonec2.go +++ b/drivers/amazonec2/amazonec2.go @@ -7,8 +7,7 @@ import ( "io" "io/ioutil" "net/url" - "os/exec" - "path" + "path/filepath" "strconv" "strings" @@ -16,6 +15,7 @@ import ( "github.com/codegangsta/cli" "github.com/docker/machine/drivers" "github.com/docker/machine/drivers/amazonec2/amz" + "github.com/docker/machine/provider" "github.com/docker/machine/ssh" "github.com/docker/machine/state" "github.com/docker/machine/utils" @@ -27,7 +27,6 @@ const ( defaultInstanceType = "t2.micro" defaultRootSize = 16 ipRange = "0.0.0.0/0" - dockerConfigDir = "/etc/docker" machineSecurityGroupName = "docker-machine" ) @@ -44,6 +43,8 @@ type Driver struct { Region string AMI string SSHKeyID int + SSHUser string + SSHPort int KeyName string InstanceId string InstanceType string @@ -161,7 +162,25 @@ func GetCreateFlags() []cli.Flag { func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) { id := generateId() - return &Driver{Id: id, MachineName: machineName, storePath: storePath, CaCertPath: caCert, PrivateKeyPath: privateKey}, nil + return &Driver{ + Id: id, + MachineName: machineName, + storePath: storePath, + CaCertPath: caCert, + PrivateKeyPath: privateKey, + }, nil +} + +func (d *Driver) GetProviderType() provider.ProviderType { + return provider.Remote +} + +func (d *Driver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) DeauthorizePort(ports []*drivers.Port) error { + return nil } func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { @@ -191,6 +210,8 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.SwarmMaster = flags.Bool("swarm-master") d.SwarmHost = flags.String("swarm-host") d.SwarmDiscovery = flags.String("swarm-discovery") + d.SSHUser = "ubuntu" + d.SSHPort = 22 if d.AccessKey == "" { return fmt.Errorf("amazonec2 driver requires the --amazonec2-access-key option") @@ -222,6 +243,10 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { return nil } +func (d *Driver) GetMachineName() string { + return d.MachineName +} + func (d *Driver) DriverName() string { return driverName } @@ -346,8 +371,6 @@ func (d *Driver) Create() error { return err } - log.Info("Configuring Machine...") - log.Debug("Settings tags for instance") tags := map[string]string{ "Name": d.MachineName, @@ -357,21 +380,6 @@ func (d *Driver) Create() error { return err } - log.Debugf("Setting hostname: %s", d.MachineName) - cmd, err := d.GetSSHCommand(fmt.Sprintf( - "echo \"127.0.0.1 %s\" | sudo tee -a /etc/hosts && sudo hostname %s && echo \"%s\" | sudo tee /etc/hostname", - d.MachineName, - d.MachineName, - d.MachineName, - )) - - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - return nil } @@ -413,6 +421,27 @@ func (d *Driver) GetState() (state.State, error) { return state.None, nil } +func (d *Driver) GetSSHHostname() (string, error) { + // TODO: use @nathanleclaire retry func here (ehazlett) + return d.GetIP() +} + +func (d *Driver) GetSSHPort() (int, error) { + if d.SSHPort == 0 { + d.SSHPort = 22 + } + + return d.SSHPort, nil +} + +func (d *Driver) GetSSHUsername() string { + if d.SSHUser == "" { + d.SSHUser = "ubuntu" + } + + return d.SSHUser +} + func (d *Driver) Start() error { if err := d.getClient().StartInstance(d.InstanceId); err != nil { return err @@ -460,69 +489,13 @@ func (d *Driver) Kill() error { return nil } -func (d *Driver) StartDocker() error { - log.Debug("Starting Docker...") - - cmd, err := d.GetSSHCommand("sudo service docker start") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) StopDocker() error { - log.Debug("Stopping Docker...") - - cmd, err := d.GetSSHCommand("sudo service docker stop") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) GetDockerConfigDir() string { - return dockerConfigDir -} - -func (d *Driver) Upgrade() error { - log.Debugf("Upgrading Docker") - - cmd, err := d.GetSSHCommand("sudo apt-get update && sudo apt-get install --upgrade lxc-docker") - if err != nil { - return err - - } - if err := cmd.Run(); err != nil { - return err - - } - - return cmd.Run() -} - -func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) { - return ssh.GetSSHCommand(d.IPAddress, 22, "ubuntu", d.sshKeyPath(), args...), nil -} - func (d *Driver) getClient() *amz.EC2 { auth := amz.GetAuth(d.AccessKey, d.SecretKey, d.SessionToken) return amz.NewEC2(auth, d.Region) } -func (d *Driver) sshKeyPath() string { - return path.Join(d.storePath, "id_rsa") -} - -func (d *Driver) publicSSHKeyPath() string { - return d.sshKeyPath() + ".pub" +func (d *Driver) GetSSHKeyPath() string { + return filepath.Join(d.storePath, "id_rsa") } func (d *Driver) getInstance() (*amz.EC2Instance, error) { @@ -555,11 +528,11 @@ func (d *Driver) waitForInstance() error { func (d *Driver) createKeyPair() error { - if err := ssh.GenerateSSHKey(d.sshKeyPath()); err != nil { + if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { return err } - publicKey, err := ioutil.ReadFile(d.publicSSHKeyPath()) + publicKey, err := ioutil.ReadFile(d.GetSSHKeyPath() + ".pub") if err != nil { return err } diff --git a/drivers/azure/azure.go b/drivers/azure/azure.go index 614e702948..6e10b051b7 100644 --- a/drivers/azure/azure.go +++ b/drivers/azure/azure.go @@ -17,6 +17,7 @@ import ( "github.com/codegangsta/cli" "github.com/docker/docker/utils" "github.com/docker/machine/drivers" + "github.com/docker/machine/provider" "github.com/docker/machine/ssh" "github.com/docker/machine/state" ) @@ -32,9 +33,9 @@ type Driver struct { PublishSettingsFilePath string Location string Size string - UserName string UserPassword string Image string + SSHUser string SSHPort int DockerPort int CaCertPath string @@ -52,7 +53,7 @@ func init() { }) } -// GetCreateFlags registers the flags this driver adds to +// GetCreateFlags registers the flags this d adds to // "docker hosts create" func GetCreateFlags() []cli.Flag { return []cli.Flag{ @@ -112,16 +113,56 @@ func GetCreateFlags() []cli.Flag { } func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) { - driver := &Driver{MachineName: machineName, storePath: storePath, CaCertPath: caCert, PrivateKeyPath: privateKey} - return driver, nil + d := &Driver{MachineName: machineName, storePath: storePath, CaCertPath: caCert, PrivateKeyPath: privateKey} + return d, nil } -func (driver *Driver) DriverName() string { +func (d *Driver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) DeauthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) GetMachineName() string { + return d.MachineName +} + +func (d *Driver) GetSSHHostname() (string, error) { + return d.GetIP() +} + +func (d *Driver) GetSSHKeyPath() string { + return filepath.Join(d.storePath, "id_rsa") +} + +func (d *Driver) GetSSHPort() (int, error) { + if d.SSHPort == 0 { + d.SSHPort = 22 + } + + return d.SSHPort, nil +} + +func (d *Driver) GetSSHUsername() string { + if d.SSHUser == "" { + d.SSHUser = "ubuntu" + } + + return d.SSHUser +} + +func (d *Driver) GetProviderType() provider.ProviderType { + return provider.Remote +} + +func (d *Driver) DriverName() string { return "azure" } -func (driver *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { - driver.SubscriptionID = flags.String("azure-subscription-id") +func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { + d.SubscriptionID = flags.String("azure-subscription-id") cert := flags.String("azure-subscription-cert") publishSettings := flags.String("azure-publish-settings-file") @@ -132,51 +173,51 @@ func (driver *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { if _, err := os.Stat(cert); os.IsNotExist(err) { return err } - driver.SubscriptionCert = cert + d.SubscriptionCert = cert } if publishSettings != "" { if _, err := os.Stat(publishSettings); os.IsNotExist(err) { return err } - driver.PublishSettingsFilePath = publishSettings + d.PublishSettingsFilePath = publishSettings } - if (driver.SubscriptionID == "" || driver.SubscriptionCert == "") && driver.PublishSettingsFilePath == "" { + if (d.SubscriptionID == "" || d.SubscriptionCert == "") && d.PublishSettingsFilePath == "" { return errors.New("Please specify azure subscription params using options: --azure-subscription-id and --azure-subscription-cert or --azure-publish-settings-file") } if image == "" { - driver.Image = "b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-14_04_1-LTS-amd64-server-20140927-en-us-30GB" + d.Image = "b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-14_04_1-LTS-amd64-server-20140927-en-us-30GB" } else { - driver.Image = image + d.Image = image } - driver.Location = flags.String("azure-location") - driver.Size = flags.String("azure-size") + d.Location = flags.String("azure-location") + d.Size = flags.String("azure-size") if strings.ToLower(username) == "docker" { return errors.New("'docker' is not valid user name for docker host. Please specify another user name") } - driver.UserName = username - driver.UserPassword = flags.String("azure-password") - driver.DockerPort = flags.Int("azure-docker-port") - driver.SSHPort = flags.Int("azure-ssh-port") - driver.SwarmMaster = flags.Bool("swarm-master") - driver.SwarmHost = flags.String("swarm-host") - driver.SwarmDiscovery = flags.String("swarm-discovery") + d.SSHUser = username + d.UserPassword = flags.String("azure-password") + d.DockerPort = flags.Int("azure-docker-port") + d.SSHPort = flags.Int("azure-ssh-port") + d.SwarmMaster = flags.Bool("swarm-master") + d.SwarmHost = flags.String("swarm-host") + d.SwarmDiscovery = flags.String("swarm-discovery") return nil } -func (driver *Driver) PreCreateCheck() error { - if err := driver.setUserSubscription(); err != nil { +func (d *Driver) PreCreateCheck() error { + if err := d.setUserSubscription(); err != nil { return err } // check azure DNS to make sure name is available - available, response, err := vmClient.CheckHostedServiceNameAvailability(driver.MachineName) + available, response, err := vmClient.CheckHostedServiceNameAvailability(d.MachineName) if err != nil { return err } @@ -188,77 +229,58 @@ func (driver *Driver) PreCreateCheck() error { return nil } -func (driver *Driver) Create() error { - if err := driver.setUserSubscription(); err != nil { +func (d *Driver) Create() error { + if err := d.setUserSubscription(); err != nil { return err } log.Info("Creating Azure machine...") - vmConfig, err := vmClient.CreateAzureVMConfiguration(driver.MachineName, driver.Size, driver.Image, driver.Location) + vmConfig, err := vmClient.CreateAzureVMConfiguration(d.MachineName, d.Size, d.Image, d.Location) if err != nil { return err } log.Debug("Generating certificate for Azure...") - if err := driver.generateCertForAzure(); err != nil { + if err := d.generateCertForAzure(); err != nil { return err } log.Debug("Adding Linux provisioning...") - vmConfig, err = vmClient.AddAzureLinuxProvisioningConfig(vmConfig, driver.UserName, driver.UserPassword, driver.azureCertPath(), driver.SSHPort) + vmConfig, err = vmClient.AddAzureLinuxProvisioningConfig(vmConfig, d.GetSSHUsername(), d.UserPassword, d.azureCertPath(), d.SSHPort) if err != nil { return err } log.Debug("Authorizing ports...") - if err := driver.addDockerEndpoint(vmConfig); err != nil { + if err := d.addDockerEndpoint(vmConfig); err != nil { return err } log.Debug("Creating VM...") - if err := vmClient.CreateAzureVM(vmConfig, driver.MachineName, driver.Location); err != nil { + if err := vmClient.CreateAzureVM(vmConfig, d.MachineName, d.Location); err != nil { return err } log.Info("Waiting for SSH...") - log.Debugf("Host: %s SSH Port: %d", driver.getHostname(), driver.SSHPort) - return ssh.WaitForTCP(fmt.Sprintf("%s:%d", driver.getHostname(), driver.SSHPort)) + log.Debugf("Host: %s SSH Port: %d", d.getHostname(), d.SSHPort) + return ssh.WaitForTCP(fmt.Sprintf("%s:%d", d.getHostname(), d.SSHPort)) } -func (driver *Driver) runSSHCommand(command string, retries int) error { - cmd, err := driver.GetSSHCommand(command) - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - if err.Error() == "exit status 255" { - if retries == 0 { - return err - } - return driver.runSSHCommand(command, retries-1) - } - - return err - } - - return nil -} - -func (driver *Driver) GetURL() (string, error) { - url := fmt.Sprintf("tcp://%s:%v", driver.getHostname(), driver.DockerPort) +func (d *Driver) GetURL() (string, error) { + url := fmt.Sprintf("tcp://%s:%v", d.getHostname(), d.DockerPort) return url, nil } -func (driver *Driver) GetIP() (string, error) { - return driver.getHostname(), nil +func (d *Driver) GetIP() (string, error) { + return d.getHostname(), nil } -func (driver *Driver) GetState() (state.State, error) { - if err := driver.setUserSubscription(); err != nil { +func (d *Driver) GetState() (state.State, error) { + if err := d.setUserSubscription(); err != nil { return state.Error, err } - dockerVM, err := vmClient.GetVMDeployment(driver.MachineName, driver.MachineName) + dockerVM, err := vmClient.GetVMDeployment(d.MachineName, d.MachineName) if err != nil { if strings.Contains(err.Error(), "Code: ResourceNotFound") { return state.Error, errors.New("Azure host was not found. Please check your Azure subscription.") @@ -280,146 +302,98 @@ func (driver *Driver) GetState() (state.State, error) { return state.None, nil } -func (driver *Driver) Start() error { - if err := driver.setUserSubscription(); err != nil { +func (d *Driver) Start() error { + if err := d.setUserSubscription(); err != nil { return err } - if vmState, err := driver.GetState(); err != nil { + if vmState, err := d.GetState(); err != nil { return err } else if vmState == state.Running || vmState == state.Starting { log.Infof("Host is already running or starting") return nil } - log.Debugf("starting %s", driver.MachineName) + log.Debugf("starting %s", d.MachineName) - if err := vmClient.StartRole(driver.MachineName, driver.MachineName, driver.MachineName); err != nil { + if err := vmClient.StartRole(d.MachineName, d.MachineName, d.MachineName); err != nil { return err } - if err := driver.waitForSSH(); err != nil { + if err := d.waitForSSH(); err != nil { return err } - return driver.waitForDocker() + return d.waitForDocker() } -func (driver *Driver) Stop() error { - if err := driver.setUserSubscription(); err != nil { +func (d *Driver) Stop() error { + if err := d.setUserSubscription(); err != nil { return err } - if vmState, err := driver.GetState(); err != nil { + if vmState, err := d.GetState(); err != nil { return err } else if vmState == state.Stopped { log.Infof("Host is already stopped") return nil } - log.Debugf("stopping %s", driver.MachineName) + log.Debugf("stopping %s", d.MachineName) - return vmClient.ShutdownRole(driver.MachineName, driver.MachineName, driver.MachineName) + return vmClient.ShutdownRole(d.MachineName, d.MachineName, d.MachineName) } -func (driver *Driver) Remove() error { - if err := driver.setUserSubscription(); err != nil { +func (d *Driver) Remove() error { + if err := d.setUserSubscription(); err != nil { return err } - if available, _, err := vmClient.CheckHostedServiceNameAvailability(driver.MachineName); err != nil { + if available, _, err := vmClient.CheckHostedServiceNameAvailability(d.MachineName); err != nil { return err } else if available { return nil } - log.Debugf("removing %s", driver.MachineName) + log.Debugf("removing %s", d.MachineName) - return vmClient.DeleteHostedService(driver.MachineName) + return vmClient.DeleteHostedService(d.MachineName) } -func (driver *Driver) Restart() error { - err := driver.setUserSubscription() +func (d *Driver) Restart() error { + err := d.setUserSubscription() if err != nil { return err } - if vmState, err := driver.GetState(); err != nil { + if vmState, err := d.GetState(); err != nil { return err } else if vmState == state.Stopped { return errors.New("Host is already stopped, use start command to run it") } - log.Debugf("restarting %s", driver.MachineName) + log.Debugf("restarting %s", d.MachineName) - if err := vmClient.RestartRole(driver.MachineName, driver.MachineName, driver.MachineName); err != nil { + if err := vmClient.RestartRole(d.MachineName, d.MachineName, d.MachineName); err != nil { return err } - if err := driver.waitForSSH(); err != nil { + if err := d.waitForSSH(); err != nil { return err } - return driver.waitForDocker() + return d.waitForDocker() } -func (driver *Driver) Kill() error { - if err := driver.setUserSubscription(); err != nil { +func (d *Driver) Kill() error { + if err := d.setUserSubscription(); err != nil { return err } - if vmState, err := driver.GetState(); err != nil { + if vmState, err := d.GetState(); err != nil { return err } else if vmState == state.Stopped { log.Infof("Host is already stopped") return nil } - log.Debugf("killing %s", driver.MachineName) + log.Debugf("killing %s", d.MachineName) - return vmClient.ShutdownRole(driver.MachineName, driver.MachineName, driver.MachineName) -} - -func (d *Driver) StartDocker() error { - log.Debug("Starting Docker...") - - cmd, err := d.GetSSHCommand("sudo service docker start") - if err != nil { - return err - } - return cmd.Run() -} - -func (d *Driver) StopDocker() error { - log.Debug("Stopping Docker...") - - cmd, err := d.GetSSHCommand("sudo service docker stop") - if err != nil { - return err - } - return cmd.Run() -} - -func (d *Driver) GetDockerConfigDir() string { - return dockerConfigDir -} - -func (driver *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) { - if err := driver.setUserSubscription(); err != nil { - return nil, err - } - - if vmState, err := driver.GetState(); err != nil { - return nil, err - } else if vmState == state.Stopped { - return nil, errors.New("Azure host is stopped. Please start it before using ssh command.") - } - - return ssh.GetSSHCommand(driver.getHostname(), driver.SSHPort, driver.UserName, driver.sshKeyPath(), args...), nil -} - -func (driver *Driver) Upgrade() error { - log.Debugf("Upgrading Docker") - - cmd, err := driver.GetSSHCommand("sudo apt-get update && sudo apt-get install --upgrade lxc-docker") - if err != nil { - return err - } - return cmd.Run() + return vmClient.ShutdownRole(d.MachineName, d.MachineName, d.MachineName) } func generateVMName() string { @@ -427,14 +401,14 @@ func generateVMName() string { return fmt.Sprintf("docker-host-%s", randomID) } -func (driver *Driver) setUserSubscription() error { - if driver.PublishSettingsFilePath != "" { - return azure.ImportPublishSettingsFile(driver.PublishSettingsFilePath) +func (d *Driver) setUserSubscription() error { + if d.PublishSettingsFilePath != "" { + return azure.ImportPublishSettingsFile(d.PublishSettingsFilePath) } - return azure.ImportPublishSettings(driver.SubscriptionID, driver.SubscriptionCert) + return azure.ImportPublishSettings(d.SubscriptionID, d.SubscriptionCert) } -func (driver *Driver) addDockerEndpoint(vmConfig *vmClient.Role) error { +func (d *Driver) addDockerEndpoint(vmConfig *vmClient.Role) error { configSets := vmConfig.ConfigurationSets.ConfigurationSet if len(configSets) == 0 { return errors.New("no configuration set") @@ -446,23 +420,23 @@ func (driver *Driver) addDockerEndpoint(vmConfig *vmClient.Role) error { ep := vmClient.InputEndpoint{ Name: "docker", Protocol: "tcp", - Port: driver.DockerPort, - LocalPort: driver.DockerPort} + Port: d.DockerPort, + LocalPort: d.DockerPort} configSets[i].InputEndpoints.InputEndpoint = append(configSets[i].InputEndpoints.InputEndpoint, ep) - log.Debugf("added Docker endpoint (port %d) to configuration", driver.DockerPort) + log.Debugf("added Docker endpoint (port %d) to configuration", d.DockerPort) } return nil } -func (driver *Driver) waitForSSH() error { +func (d *Driver) waitForSSH() error { log.Infof("Waiting for SSH...") - return ssh.WaitForTCP(fmt.Sprintf("%s:%v", driver.getHostname(), driver.SSHPort)) + return ssh.WaitForTCP(fmt.Sprintf("%s:%v", d.getHostname(), d.SSHPort)) } -func (driver *Driver) waitForDocker() error { +func (d *Driver) waitForDocker() error { log.Infof("Waiting for docker daemon on host to be available...") maxRepeats := 48 - url := fmt.Sprintf("%s:%v", driver.getHostname(), driver.DockerPort) + url := fmt.Sprintf("%s:%v", d.getHostname(), d.DockerPort) success := waitForDockerEndpoint(url, maxRepeats) if !success { return errors.New("Can not run docker daemon on remote machine. Please try again.") @@ -488,23 +462,23 @@ func waitForDockerEndpoint(url string, maxRepeats int) bool { return true } -func (driver *Driver) generateCertForAzure() error { - if err := ssh.GenerateSSHKey(driver.sshKeyPath()); err != nil { +func (d *Driver) generateCertForAzure() error { + if err := ssh.GenerateSSHKey(d.sshKeyPath()); err != nil { return err } - cmd := exec.Command("openssl", "req", "-x509", "-key", driver.sshKeyPath(), "-nodes", "-days", "365", "-newkey", "rsa:2048", "-out", driver.azureCertPath(), "-subj", "/C=AU/ST=Some-State/O=InternetWidgitsPtyLtd/CN=\\*") + cmd := exec.Command("openssl", "req", "-x509", "-key", d.sshKeyPath(), "-nodes", "-days", "365", "-newkey", "rsa:2048", "-out", d.azureCertPath(), "-subj", "/C=AU/ST=Some-State/O=InternetWidgitsPtyLtd/CN=\\*") return cmd.Run() } -func (driver *Driver) sshKeyPath() string { - return filepath.Join(driver.storePath, "id_rsa") +func (d *Driver) sshKeyPath() string { + return filepath.Join(d.storePath, "id_rsa") } -func (driver *Driver) azureCertPath() string { - return filepath.Join(driver.storePath, "azure_cert.pem") +func (d *Driver) azureCertPath() string { + return filepath.Join(d.storePath, "azure_cert.pem") } -func (driver *Driver) getHostname() string { - return driver.MachineName + ".cloudapp.net" +func (d *Driver) getHostname() string { + return d.MachineName + ".cloudapp.net" } diff --git a/drivers/digitalocean/digitalocean.go b/drivers/digitalocean/digitalocean.go index 7c8f9ef7d7..50cc3dc3b6 100644 --- a/drivers/digitalocean/digitalocean.go +++ b/drivers/digitalocean/digitalocean.go @@ -12,6 +12,7 @@ import ( "github.com/codegangsta/cli" "github.com/digitalocean/godo" "github.com/docker/machine/drivers" + "github.com/docker/machine/provider" "github.com/docker/machine/ssh" "github.com/docker/machine/state" ) @@ -29,6 +30,8 @@ type Driver struct { IPAddress string Region string SSHKeyID int + SSHUser string + SSHPort int Size string IPv6 bool Backups bool @@ -98,6 +101,46 @@ func NewDriver(machineName string, storePath string, caCert string, privateKey s return &Driver{MachineName: machineName, storePath: storePath, CaCertPath: caCert, PrivateKeyPath: privateKey}, nil } +func (d *Driver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) DeauthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) GetMachineName() string { + return d.MachineName +} + +func (d *Driver) GetSSHHostname() (string, error) { + return d.GetIP() +} + +func (d *Driver) GetSSHKeyPath() string { + return filepath.Join(d.storePath, "id_rsa") +} + +func (d *Driver) GetSSHPort() (int, error) { + if d.SSHPort == 0 { + d.SSHPort = 22 + } + + return d.SSHPort, nil +} + +func (d *Driver) GetSSHUsername() string { + if d.SSHUser == "" { + d.SSHUser = "root" + } + + return d.SSHUser +} + +func (d *Driver) GetProviderType() provider.ProviderType { + return provider.Remote +} + func (d *Driver) DriverName() string { return "digitalocean" } @@ -113,6 +156,8 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.SwarmMaster = flags.Bool("swarm-master") d.SwarmHost = flags.String("swarm-host") d.SwarmDiscovery = flags.String("swarm-discovery") + d.SSHUser = "root" + d.SSHPort = 22 if d.AccessToken == "" { return fmt.Errorf("digitalocean driver requires the --digitalocean-access-token option") diff --git a/drivers/drivers.go b/drivers/drivers.go index 2562327464..46ad7eacdb 100644 --- a/drivers/drivers.go +++ b/drivers/drivers.go @@ -7,69 +7,83 @@ import ( "sort" "github.com/codegangsta/cli" + "github.com/docker/machine/provider" + "github.com/docker/machine/ssh" "github.com/docker/machine/state" ) +type Port struct { + Protocol string + Port int +} + // Driver defines how a host is created and controlled. Different types of // driver represent different ways hosts can be created (e.g. different // hypervisors, different cloud providers) type Driver interface { + // AuthorizePort authorizes a port for machine access + AuthorizePort(ports []*Port) error + + // Create a host using the driver's config + Create() error + + // DeauthorizePort removes a port for machine access + DeauthorizePort(ports []*Port) error + // DriverName returns the name of the driver as it is registered DriverName() string - // SetConfigFromFlags configures the driver with the object that was returned - // by RegisterCreateFlags - SetConfigFromFlags(flags DriverOptions) error - - // GetURL returns a Docker compatible host URL for connecting to this host - // e.g. tcp://1.2.3.4:2376 - GetURL() (string, error) - // GetIP returns an IP or hostname that this host is available at // e.g. 1.2.3.4 or docker-host-d60b70a14d3a.cloudapp.net GetIP() (string, error) + // GetMachineName returns the name of the machine + GetMachineName() string + + // GetSSHHostname returns hostname for use with ssh + GetSSHHostname() (string, error) + + // GetSSHKeyPath returns key path for use with ssh + GetSSHKeyPath() string + + // GetSSHPort returns port for use with ssh + GetSSHPort() (int, error) + + // GetSSHUsername returns username for use with ssh + GetSSHUsername() string + + // GetURL returns a Docker compatible host URL for connecting to this host + // e.g. tcp://1.2.3.4:2376 + GetURL() (string, error) + // GetState returns the state that the host is in (running, stopped, etc) GetState() (state.State, error) - // PreCreate allows for pre-create operations to make sure a driver is ready for creation - PreCreateCheck() error + // GetProviderType returns whether the instance is local/remote + GetProviderType() provider.ProviderType - // Create a host using the driver's config - Create() error + // Kill stops a host forcefully + Kill() error + + // PreCreateCheck allows for pre-create operations to make sure a driver is ready for creation + PreCreateCheck() error // Remove a host Remove() error + // Restart a host. This may just call Stop(); Start() if the provider does not + // have any special restart behaviour. + Restart() error + + // SetConfigFromFlags configures the driver with the object that was returned + // by RegisterCreateFlags + SetConfigFromFlags(flags DriverOptions) error + // Start a host Start() error // Stop a host gracefully Stop() error - - // Restart a host. This may just call Stop(); Start() if the provider does not - // have any special restart behaviour. - Restart() error - - // Kill stops a host forcefully - Kill() error - - // StartDocker starts a Docker daemon on the machine - StartDocker() error - - // StopDocker stops a Docker daemon on the machine - StopDocker() error - - // Upgrade the version of Docker on the host to the latest version - Upgrade() error - - // GetDockerConfigDir returns the config directory for storing daemon configs - GetDockerConfigDir() string - - // GetSSHCommand returns a command for SSH pointing at the correct user, host - // and keys for the host with args appended. If no args are passed, it will - // initiate an interactive SSH session as if SSH were passed no args. - GetSSHCommand(args ...string) (*exec.Cmd, error) } // RegisteredDriver is used to register a driver with the Register function. @@ -144,3 +158,20 @@ type DriverOptions interface { Int(key string) int Bool(key string) bool } + +func GetSSHCommandFromDriver(d Driver, args ...string) (*exec.Cmd, error) { + host, err := d.GetSSHHostname() + if err != nil { + return nil, err + } + + port, err := d.GetSSHPort() + if err != nil { + return nil, err + } + + user := d.GetSSHUsername() + keyPath := d.GetSSHKeyPath() + + return ssh.GetSSHCommand(host, port, user, keyPath, args...), nil +} diff --git a/drivers/google/compute_util.go b/drivers/google/compute_util.go index a5a4a7fe23..45ee1c00cb 100644 --- a/drivers/google/compute_util.go +++ b/drivers/google/compute_util.go @@ -28,8 +28,7 @@ type ComputeUtil struct { } const ( - apiURL = "https://www.googleapis.com/compute/v1/projects/" - //imageName = "https://www.googleapis.com/compute/v1/projects/google-containers/global/images/container-vm-v20150129" + apiURL = "https://www.googleapis.com/compute/v1/projects/" imageName = "https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/ubuntu-1404-trusty-v20150128" firewallRule = "docker-machines" port = "2376" @@ -48,7 +47,7 @@ func newComputeUtil(driver *Driver) (*ComputeUtil, error) { authTokenPath: driver.AuthTokenPath, zone: driver.Zone, instanceName: driver.MachineName, - userName: driver.UserName, + userName: driver.SSHUser, project: driver.Project, service: service, zoneURL: apiURL + driver.Project + "/zones/" + driver.Zone, @@ -203,7 +202,7 @@ func (c *ComputeUtil) createInstance(d *Driver) error { c.waitForSSH(ip) // Update the SSH Key - sshKey, err := ioutil.ReadFile(d.publicSSHKeyPath) + sshKey, err := ioutil.ReadFile(d.GetSSHKeyPath() + ".pub") if err != nil { return err } @@ -226,39 +225,6 @@ func (c *ComputeUtil) createInstance(d *Driver) error { return err } - log.Info("Configuring Machine...") - - log.Debugf("Setting hostname: %s", d.MachineName) - cmd, err := d.GetSSHCommand(fmt.Sprintf( - "echo \"127.0.0.1 %s\" | sudo tee -a /etc/hosts && sudo hostname %s && echo \"%s\" | sudo tee /etc/hostname", - d.MachineName, - d.MachineName, - d.MachineName, - )) - - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (c *ComputeUtil) updateDocker(d *Driver) error { - log.Debugf("Upgrading Docker") - - cmd, err := d.GetSSHCommand("sudo apt-get update && sudo apt-get install --upgrade lxc-docker") - if err != nil { - return err - - } - if err := cmd.Run(); err != nil { - return err - - } - return nil } diff --git a/drivers/google/google.go b/drivers/google/google.go index 8a7ed10727..832276d14f 100644 --- a/drivers/google/google.go +++ b/drivers/google/google.go @@ -2,16 +2,14 @@ package google import ( "fmt" - - "github.com/docker/machine/state" - - "os/exec" - "path" + "path/filepath" log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" "github.com/docker/machine/drivers" + "github.com/docker/machine/provider" "github.com/docker/machine/ssh" + "github.com/docker/machine/state" ) const ( @@ -20,29 +18,27 @@ const ( // Driver is a struct compatible with the docker.hosts.drivers.Driver interface. type Driver struct { - MachineName string - Zone string - MachineType string - Scopes string - DiskSize int - AuthTokenPath string - storePath string - UserName string - Project string - CaCertPath string - PrivateKeyPath string - sshKeyPath string - publicSSHKeyPath string - SwarmMaster bool - SwarmHost string - SwarmDiscovery string + MachineName string + SSHUser string + SSHPort int + Zone string + MachineType string + Scopes string + DiskSize int + AuthTokenPath string + storePath string + Project string + CaCertPath string + PrivateKeyPath string + SwarmMaster bool + SwarmHost string + SwarmDiscovery string } // CreateFlags are the command line flags used to create a driver. type CreateFlags struct { Zone *string MachineType *string - UserName *string Project *string Scopes *string DiskSize *int @@ -105,40 +101,79 @@ func GetCreateFlags() []cli.Flag { // NewDriver creates a Driver with the specified storePath. func NewDriver(machineName string, storePath string, caCert string, privateKey string) (drivers.Driver, error) { return &Driver{ - MachineName: machineName, - storePath: storePath, - CaCertPath: caCert, - PrivateKeyPath: privateKey, - sshKeyPath: path.Join(storePath, "id_rsa"), - publicSSHKeyPath: path.Join(storePath, "id_rsa.pub"), + MachineName: machineName, + storePath: storePath, + CaCertPath: caCert, + PrivateKeyPath: privateKey, }, nil } +func (d *Driver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) DeauthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) GetMachineName() string { + return d.MachineName +} + +func (d *Driver) GetSSHHostname() (string, error) { + return d.GetIP() +} + +func (d *Driver) GetSSHKeyPath() string { + return filepath.Join(d.storePath, "id_rsa") +} + +func (d *Driver) GetSSHPort() (int, error) { + if d.SSHPort == 0 { + d.SSHPort = 22 + } + + return d.SSHPort, nil +} + +func (d *Driver) GetSSHUsername() string { + if d.SSHUser == "" { + d.SSHUser = "docker-user" + } + + return d.SSHUser +} + +func (d *Driver) GetProviderType() provider.ProviderType { + return provider.Remote +} + // DriverName returns the name of the driver. -func (driver *Driver) DriverName() string { +func (d *Driver) DriverName() string { return "google" } // SetConfigFromFlags initializes the driver based on the command line flags. -func (driver *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { - driver.Zone = flags.String("google-zone") - driver.MachineType = flags.String("google-machine-type") - driver.DiskSize = flags.Int("google-disk-size") - driver.UserName = flags.String("google-username") - driver.AuthTokenPath = flags.String("google-auth-token") - driver.Project = flags.String("google-project") - driver.Scopes = flags.String("google-scopes") - driver.SwarmMaster = flags.Bool("swarm-master") - driver.SwarmHost = flags.String("swarm-host") - driver.SwarmDiscovery = flags.String("swarm-discovery") - if driver.Project == "" { +func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { + d.Zone = flags.String("google-zone") + d.MachineType = flags.String("google-machine-type") + d.DiskSize = flags.Int("google-disk-size") + d.AuthTokenPath = flags.String("google-auth-token") + d.Project = flags.String("google-project") + d.Scopes = flags.String("google-scopes") + d.SwarmMaster = flags.Bool("swarm-master") + d.SwarmHost = flags.String("swarm-host") + d.SwarmDiscovery = flags.String("swarm-discovery") + if d.Project == "" { return fmt.Errorf("Please specify the Google Cloud Project name using the option --google-project.") } + d.SSHUser = flags.String("google-username") + d.SSHPort = 22 return nil } -func (driver *Driver) initApis() (*ComputeUtil, error) { - return newComputeUtil(driver) +func (d *Driver) initApis() (*ComputeUtil, error) { + return newComputeUtil(d) } func (d *Driver) PreCreateCheck() error { @@ -146,8 +181,8 @@ func (d *Driver) PreCreateCheck() error { } // Create creates a GCE VM instance acting as a docker host. -func (driver *Driver) Create() error { - c, err := newComputeUtil(driver) +func (d *Driver) Create() error { + c, err := newComputeUtil(d) if err != nil { return err } @@ -155,20 +190,20 @@ func (driver *Driver) Create() error { // Check if the instance already exists. There will be an error if the instance // doesn't exist, so just check instance for nil. if instance, _ := c.instance(); instance != nil { - return fmt.Errorf("Instance %v already exists.", driver.MachineName) + return fmt.Errorf("Instance %v already exists.", d.MachineName) } log.Infof("Generating SSH Key") - if err := ssh.GenerateSSHKey(driver.sshKeyPath); err != nil { + if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { return err } - return c.createInstance(driver) + return c.createInstance(d) } // GetURL returns the URL of the remote docker daemon. -func (driver *Driver) GetURL() (string, error) { - ip, err := driver.GetIP() +func (d *Driver) GetURL() (string, error) { + ip, err := d.GetIP() if err != nil { return "", err } @@ -177,8 +212,8 @@ func (driver *Driver) GetURL() (string, error) { } // GetIP returns the IP address of the GCE instance. -func (driver *Driver) GetIP() (string, error) { - c, err := newComputeUtil(driver) +func (d *Driver) GetIP() (string, error) { + c, err := newComputeUtil(d) if err != nil { return "", err } @@ -186,8 +221,8 @@ func (driver *Driver) GetIP() (string, error) { } // GetState returns a docker.hosts.state.State value representing the current state of the host. -func (driver *Driver) GetState() (state.State, error) { - c, err := newComputeUtil(driver) +func (d *Driver) GetState() (state.State, error) { + c, err := newComputeUtil(d) if err != nil { return state.None, err } @@ -215,17 +250,17 @@ func (driver *Driver) GetState() (state.State, error) { } // Start creates a GCE instance and attaches it to the existing disk. -func (driver *Driver) Start() error { - c, err := newComputeUtil(driver) +func (d *Driver) Start() error { + c, err := newComputeUtil(d) if err != nil { return err } - return c.createInstance(driver) + return c.createInstance(d) } // Stop deletes the GCE instance, but keeps the disk. -func (driver *Driver) Stop() error { - c, err := newComputeUtil(driver) +func (d *Driver) Stop() error { + c, err := newComputeUtil(d) if err != nil { return err } @@ -233,12 +268,12 @@ func (driver *Driver) Stop() error { } // Remove deletes the GCE instance and the disk. -func (driver *Driver) Remove() error { - c, err := newComputeUtil(driver) +func (d *Driver) Remove() error { + c, err := newComputeUtil(d) if err != nil { return err } - s, err := driver.GetState() + s, err := d.GetState() if err != nil { return err } @@ -251,8 +286,8 @@ func (driver *Driver) Remove() error { } // Restart deletes and recreates the GCE instance, keeping the disk. -func (driver *Driver) Restart() error { - c, err := newComputeUtil(driver) +func (d *Driver) Restart() error { + c, err := newComputeUtil(d) if err != nil { return err } @@ -260,60 +295,10 @@ func (driver *Driver) Restart() error { return err } - return c.createInstance(driver) + return c.createInstance(d) } // Kill deletes the GCE instance, but keeps the disk. -func (driver *Driver) Kill() error { - return driver.Stop() -} - -func (d *Driver) StartDocker() error { - log.Debug("Starting Docker...") - - cmd, err := d.GetSSHCommand("sudo service docker start") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) StopDocker() error { - log.Debug("Stopping Docker...") - - cmd, err := d.GetSSHCommand("sudo service docker stop") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) GetDockerConfigDir() string { - return dockerConfigDir -} - -// GetSSHCommand returns a command that will run over SSH on the GCE instance. -func (driver *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) { - ip, err := driver.GetIP() - if err != nil { - return nil, err - } - return ssh.GetSSHCommand(ip, 22, driver.UserName, driver.sshKeyPath, args...), nil -} - -// Upgrade upgrades the docker daemon on the host to the latest version. -func (driver *Driver) Upgrade() error { - c, err := newComputeUtil(driver) - if err != nil { - return err - } - return c.updateDocker(driver) +func (d *Driver) Kill() error { + return d.Stop() } diff --git a/drivers/hyperv/hyperv_windows.go b/drivers/hyperv/hyperv_windows.go index 858436531f..26bdd95c57 100644 --- a/drivers/hyperv/hyperv_windows.go +++ b/drivers/hyperv/hyperv_windows.go @@ -6,13 +6,13 @@ import ( "fmt" "io/ioutil" "os" - "os/exec" "path/filepath" "time" log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" "github.com/docker/machine/drivers" + "github.com/docker/machine/provider" "github.com/docker/machine/ssh" "github.com/docker/machine/state" "github.com/docker/machine/utils" @@ -23,6 +23,8 @@ const ( ) type Driver struct { + SSHUser string + SSHPort int storePath string boot2DockerURL string boot2DockerLoc string @@ -83,6 +85,8 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.SwarmMaster = flags.Bool("swarm-master") d.SwarmHost = flags.String("swarm-host") d.SwarmDiscovery = flags.String("swarm-discovery") + d.SSHUser = "docker" + d.SSHPort = 22 return nil } @@ -90,6 +94,46 @@ func NewDriver(machineName string, storePath string, caCert string, privateKey s return &Driver{MachineName: machineName, storePath: storePath, CaCertPath: caCert, PrivateKeyPath: privateKey}, nil } +func (d *Driver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) DeauthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) GetMachineName() string { + return d.MachineName +} + +func (d *Driver) GetSSHHostname() (string, error) { + return d.GetIP() +} + +func (d *Driver) GetSSHKeyPath() string { + return filepath.Join(d.storePath, "id_rsa") +} + +func (d *Driver) GetSSHPort() (int, error) { + if d.SSHPort == 0 { + d.SSHPort = 22 + } + + return d.SSHPort, nil +} + +func (d *Driver) GetSSHUsername() string { + if d.SSHUser == "" { + d.SSHUser = "docker" + } + + return d.SSHUser +} + +func (d *Driver) GetProviderType() provider.ProviderType { + return provider.Local +} + func (d *Driver) DriverName() string { return "hyper-v" } @@ -195,7 +239,7 @@ func (d *Driver) Create() error { log.Infof("Creating SSH key...") - if err := ssh.GenerateSSHKey(d.sshKeyPath()); err != nil { + if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { return err } @@ -253,21 +297,6 @@ func (d *Driver) Create() error { return err } - log.Infof("Setting hostname...") - cmd, err := d.GetSSHCommand(fmt.Sprintf( - "sudo hostname %s && echo \"%s\" | sudo tee /var/lib/boot2docker/etc/hostname", - d.MachineName, - d.MachineName, - )) - if err != nil { - return err - - } - if err := cmd.Run(); err != nil { - return err - - } - return nil } @@ -412,77 +441,8 @@ func (d *Driver) GetIP() (string, error) { return resp[0], nil } -func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) { - ip, err := d.GetIP() - if err != nil { - return nil, err - } - return ssh.GetSSHCommand(ip, 22, "docker", d.sshKeyPath(), args...), nil -} - -func (d *Driver) Upgrade() error { - log.Infof("Stopping machine...") - if err := d.Stop(); err != nil { - return err - } - - b2dutils := utils.NewB2dUtils("", "") - isoURL, err := b2dutils.GetLatestBoot2DockerReleaseURL() - if err != nil { - return err - } - - log.Infof("Downloading boot2docker...") - if err := b2dutils.DownloadISO(d.storePath, "boot2docker.iso", isoURL); err != nil { - return err - } - - log.Infof("Starting machine...") - if err := d.Start(); err != nil { - return err - } - - return nil -} - -func (d *Driver) StartDocker() error { - log.Debug("Starting Docker...") - - cmd, err := d.GetSSHCommand("sudo /etc/init.d/docker start") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) StopDocker() error { - log.Debug("Stopping Docker...") - - cmd, err := d.GetSSHCommand("if [ -e /var/run/docker.pid ]; then sudo /etc/init.d/docker stop ; fi") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) GetDockerConfigDir() string { - return dockerConfigDir -} - -func (d *Driver) sshKeyPath() string { - return filepath.Join(d.storePath, "id_rsa") -} - func (d *Driver) publicSSHKeyPath() string { - return d.sshKeyPath() + ".pub" + return d.GetSSHKeyPath() + ".pub" } func (d *Driver) generateDiskImage() error { diff --git a/drivers/none/none.go b/drivers/none/none.go index f65d9a1b2c..1b8a275fb3 100644 --- a/drivers/none/none.go +++ b/drivers/none/none.go @@ -2,11 +2,11 @@ package none import ( "fmt" - "os/exec" "github.com/codegangsta/cli" "github.com/docker/docker/api" "github.com/docker/machine/drivers" + "github.com/docker/machine/provider" "github.com/docker/machine/state" ) @@ -38,10 +38,74 @@ func NewDriver(machineName string, storePath string, caCert string, privateKey s return &Driver{}, nil } +func (d *Driver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) Create() error { + return nil +} + +func (d *Driver) DeauthorizePort(ports []*drivers.Port) error { + return nil +} + func (d *Driver) DriverName() string { return "none" } +func (d *Driver) GetIP() (string, error) { + return "", nil +} + +func (d *Driver) GetMachineName() string { + return "" +} + +func (d *Driver) GetSSHHostname() (string, error) { + return "", nil +} + +func (d *Driver) GetSSHKeyPath() string { + return "" +} + +func (d *Driver) GetSSHPort() (int, error) { + return 0, nil +} + +func (d *Driver) GetSSHUsername() string { + return "" +} + +func (d *Driver) GetURL() (string, error) { + return d.URL, nil +} + +func (d *Driver) GetState() (state.State, error) { + return state.None, nil +} + +func (d *Driver) GetProviderType() provider.ProviderType { + return provider.None +} + +func (d *Driver) Kill() error { + return fmt.Errorf("hosts without a driver cannot be killed") +} + +func (d *Driver) PreCreateCheck() error { + return nil +} + +func (d *Driver) Remove() error { + return nil +} + +func (d *Driver) Restart() error { + return fmt.Errorf("hosts without a driver cannot be restarted") +} + func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { url := flags.String("url") @@ -57,26 +121,6 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { return nil } -func (d *Driver) GetURL() (string, error) { - return d.URL, nil -} - -func (d *Driver) GetIP() (string, error) { - return "", nil -} - -func (d *Driver) GetState() (state.State, error) { - return state.None, nil -} - -func (d *Driver) PreCreateCheck() error { - return nil -} - -func (d *Driver) Create() error { - return nil -} - func (d *Driver) Start() error { return fmt.Errorf("hosts without a driver cannot be started") } @@ -84,35 +128,3 @@ func (d *Driver) Start() error { func (d *Driver) Stop() error { return fmt.Errorf("hosts without a driver cannot be stopped") } - -func (d *Driver) Remove() error { - return nil -} - -func (d *Driver) Restart() error { - return fmt.Errorf("hosts without a driver cannot be restarted") -} - -func (d *Driver) Kill() error { - return fmt.Errorf("hosts without a driver cannot be killed") -} - -func (d *Driver) StartDocker() error { - return fmt.Errorf("hosts without a driver cannot start docker") -} - -func (d *Driver) StopDocker() error { - return fmt.Errorf("hosts without a driver cannot stop docker") -} - -func (d *Driver) GetDockerConfigDir() string { - return "" -} - -func (d *Driver) Upgrade() error { - return fmt.Errorf("hosts without a driver cannot be upgraded") -} - -func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) { - return nil, fmt.Errorf("hosts without a driver do not support SSH") -} diff --git a/drivers/openstack/openstack.go b/drivers/openstack/openstack.go index cacff28f45..261b4b47ca 100644 --- a/drivers/openstack/openstack.go +++ b/drivers/openstack/openstack.go @@ -3,8 +3,7 @@ package openstack import ( "fmt" "io/ioutil" - "os/exec" - "path" + "path/filepath" "strings" "time" @@ -12,6 +11,7 @@ import ( "github.com/codegangsta/cli" "github.com/docker/docker/utils" "github.com/docker/machine/drivers" + "github.com/docker/machine/provider" "github.com/docker/machine/ssh" "github.com/docker/machine/state" ) @@ -203,6 +203,46 @@ func NewDerivedDriver(machineName string, storePath string, client Client, caCer }, nil } +func (d *Driver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) DeauthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) GetMachineName() string { + return d.MachineName +} + +func (d *Driver) GetSSHHostname() (string, error) { + return d.GetIP() +} + +func (d *Driver) GetSSHKeyPath() string { + return filepath.Join(d.storePath, "id_rsa") +} + +func (d *Driver) GetSSHPort() (int, error) { + if d.SSHPort == 0 { + d.SSHPort = 22 + } + + return d.SSHPort, nil +} + +func (d *Driver) GetSSHUsername() string { + if d.SSHUser == "" { + d.SSHUser = "root" + } + + return d.SSHUser +} + +func (d *Driver) GetProviderType() provider.ProviderType { + return provider.Remote +} + func (d *Driver) DriverName() string { return "openstack" } @@ -402,69 +442,6 @@ func (d *Driver) Kill() error { return d.Stop() } -func (d *Driver) Upgrade() error { - log.Debugf("Upgrading Docker") - - cmd, err := d.GetSSHCommand("sudo apt-get update && sudo apt-get install --upgrade lxc-docker") - if err != nil { - return err - - } - if err := cmd.Run(); err != nil { - return err - - } - - return cmd.Run() -} - -func (d *Driver) StartDocker() error { - log.Debug("Starting Docker...") - - cmd, err := d.GetSSHCommand("sudo service docker start") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) StopDocker() error { - log.Debug("Stopping Docker...") - - cmd, err := d.GetSSHCommand("sudo service docker stop") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) GetDockerConfigDir() string { - return dockerConfigDir -} - -func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) { - ip, err := d.GetIP() - if err != nil { - return nil, err - } - - if len(args) != 0 && d.SSHUser != "root" { - cmd := strings.Replace(strings.Join(args, " "), "'", "\\'", -1) - args = []string{"sudo", "sh", "-c", fmt.Sprintf("'%s'", cmd)} - } - - log.WithField("MachineId", d.MachineId).Debug("Command: %s", args) - return ssh.GetSSHCommand(ip, d.SSHPort, d.SSHUser, d.sshKeyPath(), args...), nil -} - const ( errorMandatoryEnvOrOption string = "%s must be specified either using the environment variable %s or the CLI option %s" errorMandatoryOption string = "%s must be specified using the CLI option %s" @@ -624,7 +601,7 @@ func (d *Driver) initNetwork() error { func (d *Driver) createSSHKey() error { log.WithField("Name", d.KeyPairName).Debug("Creating Key Pair...") - if err := ssh.GenerateSSHKey(d.sshKeyPath()); err != nil { + if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { return err } publicKey, err := ioutil.ReadFile(d.publicSSHKeyPath()) @@ -746,10 +723,6 @@ func (d *Driver) waitForInstanceToStart() error { return d.waitForSSHServer() } -func (d *Driver) sshKeyPath() string { - return path.Join(d.storePath, "id_rsa") -} - func (d *Driver) publicSSHKeyPath() string { - return d.sshKeyPath() + ".pub" + return d.GetSSHKeyPath() + ".pub" } diff --git a/drivers/softlayer/driver.go b/drivers/softlayer/driver.go index a60dd2f923..155ce74890 100644 --- a/drivers/softlayer/driver.go +++ b/drivers/softlayer/driver.go @@ -4,14 +4,14 @@ import ( "fmt" "io/ioutil" "os" - "os/exec" - "path" + "path/filepath" "regexp" "time" log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" "github.com/docker/machine/drivers" + "github.com/docker/machine/provider" "github.com/docker/machine/ssh" "github.com/docker/machine/state" ) @@ -27,6 +27,8 @@ type Driver struct { deviceConfig *deviceConfig Id int Client *Client + SSHUser string + SSHPort int MachineName string CaCertPath string PrivateKeyPath string @@ -59,6 +61,46 @@ func NewDriver(machineName string, storePath string, caCert string, privateKey s return &Driver{MachineName: machineName, storePath: storePath, CaCertPath: caCert, PrivateKeyPath: privateKey}, nil } +func (d *Driver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) DeauthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) GetMachineName() string { + return d.MachineName +} + +func (d *Driver) GetSSHHostname() (string, error) { + return d.GetIP() +} + +func (d *Driver) GetSSHKeyPath() string { + return filepath.Join(d.storePath, "id_rsa") +} + +func (d *Driver) GetSSHPort() (int, error) { + if d.SSHPort == 0 { + d.SSHPort = 22 + } + + return d.SSHPort, nil +} + +func (d *Driver) GetSSHUsername() string { + if d.SSHUser == "" { + d.SSHUser = "root" + } + + return d.SSHUser +} + +func (d *Driver) GetProviderType() provider.ProviderType { + return provider.Remote +} + func GetCreateFlags() []cli.Flag { // Set hourly billing to true by default since codegangsta cli doesn't take default bool values if os.Getenv("SOFTLAYER_HOURLY_BILLING") == "" { @@ -188,6 +230,8 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.SwarmMaster = flags.Bool("swarm-master") d.SwarmHost = flags.String("swarm-host") d.SwarmDiscovery = flags.String("swarm-discovery") + d.SSHUser = "root" + d.SSHPort = 22 if err := validateClientConfig(d.Client); err != nil { return err @@ -216,38 +260,6 @@ func (d *Driver) DriverName() string { return "softlayer" } -func (d *Driver) StartDocker() error { - log.Debug("Starting Docker...") - - cmd, err := d.GetSSHCommand("sudo service docker start") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) StopDocker() error { - log.Debug("Stopping Docker...") - - cmd, err := d.GetSSHCommand("sudo service docker stop") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) GetDockerConfigDir() string { - return dockerConfigDir -} - func (d *Driver) GetURL() (string, error) { ip, err := d.GetIP() if err != nil { @@ -283,10 +295,6 @@ func (d *Driver) GetState() (state.State, error) { return vmState, nil } -func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) { - return ssh.GetSSHCommand(d.IPAddress, 22, "root", d.sshKeyPath(), args...), nil -} - func (d *Driver) PreCreateCheck() error { return nil } @@ -351,7 +359,7 @@ func (d *Driver) Create() error { waitForStart() ssh.WaitForTCP(d.IPAddress + ":22") - cmd, err := d.GetSSHCommand("sudo apt-get update && DEBIAN_FRONTEND=noninteractive sudo apt-get install -yq curl") + cmd, err := drivers.GetSSHCommandFromDriver(d, "sudo apt-get update && DEBIAN_FRONTEND=noninteractive sudo apt-get install -yq curl") if err != nil { return err @@ -382,7 +390,7 @@ func (d *Driver) buildHostSpec() *HostSpec { } func (d *Driver) createSSHKey() (*SshKey, error) { - if err := ssh.GenerateSSHKey(d.sshKeyPath()); err != nil { + if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { return nil, err } @@ -400,11 +408,7 @@ func (d *Driver) createSSHKey() (*SshKey, error) { } func (d *Driver) publicSSHKeyPath() string { - return d.sshKeyPath() + ".pub" -} - -func (d *Driver) sshKeyPath() string { - return path.Join(d.storePath, "id_rsa") + return d.GetSSHKeyPath() + ".pub" } func (d *Driver) Kill() error { @@ -430,19 +434,3 @@ func (d *Driver) Start() error { func (d *Driver) Stop() error { return d.getClient().VirtualGuest().PowerOff(d.Id) } - -func (d *Driver) Upgrade() error { - log.Debugf("Upgrading Docker") - - cmd, err := d.GetSSHCommand("sudo apt-get update && DEBIAN_FRONTEND=noninteractive sudo apt-get install -yq --upgrade lxc-docker") - if err != nil { - return err - - } - if err := cmd.Run(); err != nil { - return err - - } - - return cmd.Run() -} diff --git a/drivers/utils.go b/drivers/utils.go deleted file mode 100644 index 2e6204848b..0000000000 --- a/drivers/utils.go +++ /dev/null @@ -1,42 +0,0 @@ -package drivers - -import ( - "fmt" - "os" - "path" - "path/filepath" - - "github.com/docker/machine/utils" -) - -func PublicKeyPath() string { - return filepath.Join(utils.GetDockerDir(), "public-key.json") -} - -func AddPublicKeyToAuthorizedHosts(d Driver, authorizedKeysPath string) error { - f, err := os.Open(PublicKeyPath()) - if err != nil { - return err - } - defer f.Close() - - // Use path.Join here, want to create unix path even when running on Windows. - cmdString := fmt.Sprintf("mkdir -p %q && cat > %q", authorizedKeysPath, - path.Join(authorizedKeysPath, "docker-host.json")) - cmd, err := d.GetSSHCommand(cmdString) - if err != nil { - return err - } - cmd.Stdin = f - return cmd.Run() -} - -func PublicKeyExists() (bool, error) { - _, err := os.Stat(PublicKeyPath()) - if err == nil { - return true, nil - } else if os.IsNotExist(err) { - return false, nil - } - return false, err -} diff --git a/drivers/virtualbox/virtualbox.go b/drivers/virtualbox/virtualbox.go index ed65ee4369..8e7005d72d 100644 --- a/drivers/virtualbox/virtualbox.go +++ b/drivers/virtualbox/virtualbox.go @@ -19,6 +19,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" "github.com/docker/machine/drivers" + "github.com/docker/machine/provider" "github.com/docker/machine/ssh" "github.com/docker/machine/state" "github.com/docker/machine/utils" @@ -31,6 +32,7 @@ const ( type Driver struct { MachineName string + SSHUser string SSHPort int Memory int DiskSize int @@ -83,6 +85,42 @@ func NewDriver(machineName string, storePath string, caCert string, privateKey s return &Driver{MachineName: machineName, storePath: storePath, CaCertPath: caCert, PrivateKeyPath: privateKey}, nil } +func (d *Driver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) DeauthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) GetMachineName() string { + return d.MachineName +} + +func (d *Driver) GetSSHHostname() (string, error) { + return "localhost", nil +} + +func (d *Driver) GetSSHKeyPath() string { + return filepath.Join(d.storePath, "id_rsa") +} + +func (d *Driver) GetSSHPort() (int, error) { + return d.SSHPort, nil +} + +func (d *Driver) GetSSHUsername() string { + if d.SSHUser == "" { + d.SSHUser = "docker" + } + + return d.SSHUser +} + +func (d *Driver) GetProviderType() provider.ProviderType { + return provider.Local +} + func (d *Driver) DriverName() string { return "virtualbox" } @@ -105,6 +143,7 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.SwarmMaster = flags.Bool("swarm-master") d.SwarmHost = flags.String("swarm-host") d.SwarmDiscovery = flags.String("swarm-discovery") + d.SSHUser = "docker" return nil } @@ -172,7 +211,7 @@ func (d *Driver) Create() error { log.Infof("Creating SSH key...") - if err := ssh.GenerateSSHKey(d.sshKeyPath()); err != nil { + if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { return err } @@ -321,20 +360,6 @@ func (d *Driver) Create() error { return err } - cmd, err := d.GetSSHCommand(fmt.Sprintf( - "sudo hostname %s && echo \"%s\" | sudo tee /var/lib/boot2docker/etc/hostname", - d.MachineName, - d.MachineName, - )) - if err != nil { - return err - - } - if err := cmd.Run(); err != nil { - return err - - } - return nil } @@ -415,31 +440,6 @@ func (d *Driver) Kill() error { return vbm("controlvm", d.MachineName, "poweroff") } -func (d *Driver) Upgrade() error { - log.Infof("Stopping machine...") - if err := d.Stop(); err != nil { - return err - } - - b2dutils := utils.NewB2dUtils("", "") - isoURL, err := b2dutils.GetLatestBoot2DockerReleaseURL() - if err != nil { - return err - } - - log.Infof("Downloading boot2docker...") - if err := b2dutils.DownloadISO(d.storePath, "boot2docker.iso", isoURL); err != nil { - return err - } - - log.Infof("Starting machine...") - if err := d.Start(); err != nil { - return err - } - - return nil -} - func (d *Driver) GetState() (state.State, error) { stdout, stderr, err := vbmOutErr("showvminfo", d.MachineName, "--machinereadable") @@ -483,8 +483,7 @@ func (d *Driver) GetIP() (string, error) { if s != state.Running { return "", drivers.ErrHostIsNotRunning } - - cmd, err := d.GetSSHCommand("ip addr show dev eth1") + cmd, err := drivers.GetSSHCommandFromDriver(d, "ip addr show dev eth1") if err != nil { return "", err } @@ -510,48 +509,8 @@ func (d *Driver) GetIP() (string, error) { return "", fmt.Errorf("No IP address found %s", out) } -func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) { - return ssh.GetSSHCommand("localhost", d.SSHPort, "docker", d.sshKeyPath(), args...), nil -} - -func (d *Driver) StartDocker() error { - log.Debug("Starting Docker...") - - cmd, err := d.GetSSHCommand("sudo /etc/init.d/docker start") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) StopDocker() error { - log.Debug("Stopping Docker...") - - cmd, err := d.GetSSHCommand("if [ -e /var/run/docker.pid ]; then sudo /etc/init.d/docker stop ; fi") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) GetDockerConfigDir() string { - return dockerConfigDir -} - -func (d *Driver) sshKeyPath() string { - return filepath.Join(d.storePath, "id_rsa") -} - func (d *Driver) publicSSHKeyPath() string { - return d.sshKeyPath() + ".pub" + return d.GetSSHKeyPath() + ".pub" } func (d *Driver) diskPath() string { diff --git a/drivers/vmwarefusion/fusion_darwin.go b/drivers/vmwarefusion/fusion_darwin.go index 82bff84d36..d52d9b8bdc 100644 --- a/drivers/vmwarefusion/fusion_darwin.go +++ b/drivers/vmwarefusion/fusion_darwin.go @@ -11,7 +11,6 @@ import ( "io/ioutil" "net/http" "os" - "os/exec" "path" "path/filepath" "regexp" @@ -23,6 +22,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" "github.com/docker/machine/drivers" + "github.com/docker/machine/provider" "github.com/docker/machine/ssh" "github.com/docker/machine/state" "github.com/docker/machine/utils" @@ -50,6 +50,8 @@ type Driver struct { SwarmHost string SwarmDiscovery string CPUS int + SSHUser string + SSHPort int storePath string } @@ -95,6 +97,46 @@ func NewDriver(machineName string, storePath string, caCert string, privateKey s return &Driver{MachineName: machineName, storePath: storePath, CaCertPath: caCert, PrivateKeyPath: privateKey}, nil } +func (d *Driver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) DeauthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) GetMachineName() string { + return d.MachineName +} + +func (d *Driver) GetSSHHostname() (string, error) { + return d.GetIP() +} + +func (d *Driver) GetSSHKeyPath() string { + return filepath.Join(d.storePath, "id_rsa") +} + +func (d *Driver) GetSSHPort() (int, error) { + if d.SSHPort == 0 { + d.SSHPort = 22 + } + + return d.SSHPort, nil +} + +func (d *Driver) GetSSHUsername() string { + if d.SSHUser == "" { + d.SSHUser = "docker" + } + + return d.SSHUser +} + +func (d *Driver) GetProviderType() provider.ProviderType { + return provider.Local +} + func (d *Driver) DriverName() string { return "vmwarefusion" } @@ -108,6 +150,8 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.SwarmHost = flags.String("swarm-host") d.SwarmDiscovery = flags.String("swarm-discovery") d.CPUS = runtime.NumCPU() + d.SSHUser = "docker" + d.SSHPort = 22 // We support a maximum of 16 cpu to be consistent with Virtual Hardware 10 // specs. @@ -209,7 +253,7 @@ func (d *Driver) Create() error { } log.Infof("Creating SSH key...") - if err := ssh.GenerateSSHKey(d.sshKeyPath()); err != nil { + if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { return err } @@ -284,20 +328,6 @@ func (d *Driver) Create() error { // Expand tar file. vmrun("-gu", B2D_USER, "-gp", B2D_PASS, "runScriptInGuest", d.vmxPath(), "/bin/sh", "sudo /bin/mv /home/docker/userdata.tar /var/lib/boot2docker/userdata.tar && sudo tar xf /var/lib/boot2docker/userdata.tar -C /home/docker/ > /var/log/userdata.log 2>&1 && sudo chown -R docker:staff /home/docker") - log.Debugf("Setting hostname: %s", d.MachineName) - cmd, err := d.GetSSHCommand(fmt.Sprintf( - "echo \"127.0.0.1 %s\" | sudo tee -a /etc/hosts && sudo hostname %s && echo \"%s\" | sudo tee /etc/hostname", - d.MachineName, - d.MachineName, - d.MachineName, - )) - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - return nil } @@ -338,51 +368,10 @@ func (d *Driver) Kill() error { return nil } -func (d *Driver) StartDocker() error { - log.Debug("Starting Docker...") - - cmd, err := d.GetSSHCommand("sudo /etc/init.d/docker start") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) StopDocker() error { - log.Debug("Stopping Docker...") - - // Check if pidfile exists, then if process exists, depending on that stop docker or remove pidfile - cmd, err := d.GetSSHCommand("if [ -e /var/run/docker.pid ]; then if [ -f /proc/$(cat /var/run/docker.pid)/status ]; then sudo /etc/init.d/docker stop; else rm -f /var/run/docker.pid; fi fi") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) GetDockerConfigDir() string { - return dockerConfigDir -} - func (d *Driver) Upgrade() error { return fmt.Errorf("VMware Fusion does not currently support the upgrade operation.") } -func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) { - ip, err := d.GetIP() - if err != nil { - return nil, err - } - return ssh.GetSSHCommand(ip, 22, "docker", d.sshKeyPath(), args...), nil -} - func (d *Driver) vmxPath() string { return path.Join(d.storePath, fmt.Sprintf("%s.vmx", d.MachineName)) } @@ -500,12 +489,8 @@ func (d *Driver) getIPfromDHCPLease() (string, error) { } -func (d *Driver) sshKeyPath() string { - return path.Join(d.storePath, "id_rsa") -} - func (d *Driver) publicSSHKeyPath() string { - return d.sshKeyPath() + ".pub" + return d.GetSSHKeyPath() + ".pub" } // Make a boot2docker userdata.tar key bundle diff --git a/drivers/vmwarevcloudair/vcloudair.go b/drivers/vmwarevcloudair/vcloudair.go index b613b5318c..2560cc0510 100644 --- a/drivers/vmwarevcloudair/vcloudair.go +++ b/drivers/vmwarevcloudair/vcloudair.go @@ -7,8 +7,7 @@ package vmwarevcloudair import ( "fmt" "io/ioutil" - "os/exec" - "path" + "path/filepath" "strings" "github.com/vmware/govcloudair" @@ -17,6 +16,7 @@ import ( "github.com/codegangsta/cli" "github.com/docker/docker/utils" "github.com/docker/machine/drivers" + "github.com/docker/machine/provider" "github.com/docker/machine/ssh" "github.com/docker/machine/state" ) @@ -36,6 +36,7 @@ type Driver struct { Catalog string CatalogItem string MachineName string + SSHUser string SSHPort int DockerPort int Provision bool @@ -61,6 +62,7 @@ type CreateFlags struct { Catalog *string CatalogItem *string Name *string + SSHUser string SSHPort *int DockerPort *int Provision *bool @@ -166,55 +168,96 @@ func NewDriver(machineName string, storePath string, caCert string, privateKey s return driver, nil } +func (d *Driver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) DeauthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) GetMachineName() string { + return d.MachineName +} + +func (d *Driver) GetSSHHostname() (string, error) { + return d.GetIP() +} + +func (d *Driver) GetSSHKeyPath() string { + return filepath.Join(d.storePath, "id_rsa") +} + +func (d *Driver) GetSSHPort() (int, error) { + if d.SSHPort == 0 { + d.SSHPort = 22 + } + + return d.SSHPort, nil +} + +func (d *Driver) GetSSHUsername() string { + if d.SSHUser == "" { + d.SSHUser = "root" + } + + return d.SSHUser +} + +func (d *Driver) GetProviderType() provider.ProviderType { + return provider.Remote +} + // Driver interface implementation -func (driver *Driver) DriverName() string { +func (d *Driver) DriverName() string { return "vmwarevcloudair" } -func (driver *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { +func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { - driver.UserName = flags.String("vmwarevcloudair-username") - driver.UserPassword = flags.String("vmwarevcloudair-password") - driver.VDCID = flags.String("vmwarevcloudair-vdcid") - driver.PublicIP = flags.String("vmwarevcloudair-publicip") - driver.SwarmMaster = flags.Bool("swarm-master") - driver.SwarmHost = flags.String("swarm-host") - driver.SwarmDiscovery = flags.String("swarm-discovery") + d.UserName = flags.String("vmwarevcloudair-username") + d.UserPassword = flags.String("vmwarevcloudair-password") + d.VDCID = flags.String("vmwarevcloudair-vdcid") + d.PublicIP = flags.String("vmwarevcloudair-publicip") + d.SwarmMaster = flags.Bool("swarm-master") + d.SwarmHost = flags.String("swarm-host") + d.SwarmDiscovery = flags.String("swarm-discovery") // Check for required Params - if driver.UserName == "" || driver.UserPassword == "" || driver.VDCID == "" || driver.PublicIP == "" { + if d.UserName == "" || d.UserPassword == "" || d.VDCID == "" || d.PublicIP == "" { return fmt.Errorf("Please specify vcloudair mandatory params using options: -vmwarevcloudair-username -vmwarevcloudair-password -vmwarevcloudair-vdcid and -vmwarevcloudair-publicip") } // If ComputeID is not set we're using a VPC, hence setting ComputeID = VDCID if flags.String("vmwarevcloudair-computeid") == "" { - driver.ComputeID = flags.String("vmwarevcloudair-vdcid") + d.ComputeID = flags.String("vmwarevcloudair-vdcid") } else { - driver.ComputeID = flags.String("vmwarevcloudair-computeid") + d.ComputeID = flags.String("vmwarevcloudair-computeid") } // If the Org VDC Network is empty, set it to the default routed network. if flags.String("vmwarevcloudair-orgvdcnetwork") == "" { - driver.OrgVDCNet = flags.String("vmwarevcloudair-vdcid") + "-default-routed" + d.OrgVDCNet = flags.String("vmwarevcloudair-vdcid") + "-default-routed" } else { - driver.OrgVDCNet = flags.String("vmwarevcloudair-orgvdcnetwork") + d.OrgVDCNet = flags.String("vmwarevcloudair-orgvdcnetwork") } // If the Edge Gateway is empty, just set it to the default edge gateway. if flags.String("vmwarevcloudair-edgegateway") == "" { - driver.EdgeGateway = flags.String("vmwarevcloudair-vdcid") + d.EdgeGateway = flags.String("vmwarevcloudair-vdcid") } else { - driver.EdgeGateway = flags.String("vmwarevcloudair-edgegateway") + d.EdgeGateway = flags.String("vmwarevcloudair-edgegateway") } - driver.Catalog = flags.String("vmwarevcloudair-catalog") - driver.CatalogItem = flags.String("vmwarevcloudair-catalogitem") + d.Catalog = flags.String("vmwarevcloudair-catalog") + d.CatalogItem = flags.String("vmwarevcloudair-catalogitem") - driver.DockerPort = flags.Int("vmwarevcloudair-docker-port") - driver.SSHPort = flags.Int("vmwarevcloudair-ssh-port") - driver.Provision = flags.Bool("vmwarevcloudair-provision") - driver.CPUCount = flags.Int("vmwarevcloudair-cpu-count") - driver.MemorySize = flags.Int("vmwarevcloudair-memory-size") + d.DockerPort = flags.Int("vmwarevcloudair-docker-port") + d.SSHUser = "root" + d.SSHPort = flags.Int("vmwarevcloudair-ssh-port") + d.Provision = flags.Bool("vmwarevcloudair-provision") + d.CPUCount = flags.Int("vmwarevcloudair-cpu-count") + d.MemorySize = flags.Int("vmwarevcloudair-memory-size") return nil } @@ -395,26 +438,10 @@ func (d *Driver) Create() error { return err } - log.Info("Configuring Machine...") - - log.Debugf("Setting hostname: %s", d.MachineName) - cmd, err := d.GetSSHCommand(fmt.Sprintf( - "echo \"127.0.0.1 %s\" | sudo tee -a /etc/hosts && sudo hostname %s && echo \"%s\" | sudo tee /etc/hostname", - d.MachineName, - d.MachineName, - d.MachineName, - )) - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - connTest := "ping -c 3 www.google.com >/dev/null 2>&1 && ( echo \"Connectivity and DNS tests passed.\" ) || ( echo \"Connectivity and DNS tests failed, trying to add Nameserver to resolv.conf\"; echo \"nameserver 8.8.8.8\" >> /etc/resolv.conf )" log.Debugf("Connectivity and DNS sanity test...") - cmd, err = d.GetSSHCommand(connTest) + cmd, err := drivers.GetSSHCommandFromDriver(d, connTest) if err != nil { return err } @@ -437,7 +464,6 @@ func (d *Driver) Create() error { } func (d *Driver) Remove() error { - p, err := govcloudair.NewClient() if err != nil { return err @@ -660,7 +686,6 @@ func (d *Driver) Restart() error { } func (d *Driver) Kill() error { - p, err := govcloudair.NewClient() if err != nil { return err @@ -703,58 +728,6 @@ func (d *Driver) Kill() error { } -func (d *Driver) StartDocker() error { - log.Debug("Starting Docker...") - - cmd, err := d.GetSSHCommand("sudo service docker start") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) StopDocker() error { - log.Debug("Stopping Docker...") - - cmd, err := d.GetSSHCommand("sudo service docker stop") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) GetDockerConfigDir() string { - return dockerConfigDir -} - -func (d *Driver) Upgrade() error { - log.Debugf("Upgrading Docker") - - cmd, err := d.GetSSHCommand("sudo apt-get update && sudo apt-get install --upgrade lxc-docker") - if err != nil { - return err - - } - if err := cmd.Run(); err != nil { - return err - - } - - return cmd.Run() -} - -func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) { - return ssh.GetSSHCommand(d.PublicIP, d.SSHPort, "root", d.sshKeyPath(), args...), nil -} - // Helpers func generateVMName() string { @@ -763,8 +736,7 @@ func generateVMName() string { } func (d *Driver) createSSHKey() (string, error) { - - if err := ssh.GenerateSSHKey(d.sshKeyPath()); err != nil { + if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { return "", err } @@ -776,10 +748,6 @@ func (d *Driver) createSSHKey() (string, error) { return string(publicKey), nil } -func (d *Driver) sshKeyPath() string { - return path.Join(d.storePath, "id_rsa") -} - func (d *Driver) publicSSHKeyPath() string { - return d.sshKeyPath() + ".pub" + return d.GetSSHKeyPath() + ".pub" } diff --git a/drivers/vmwarevsphere/vsphere.go b/drivers/vmwarevsphere/vsphere.go index 865299d0e7..5fcdb92b4b 100644 --- a/drivers/vmwarevsphere/vsphere.go +++ b/drivers/vmwarevsphere/vsphere.go @@ -11,7 +11,6 @@ import ( "io/ioutil" "net/http" "os" - "os/exec" "path" "path/filepath" "strings" @@ -22,10 +21,10 @@ import ( "github.com/codegangsta/cli" "github.com/docker/machine/drivers" "github.com/docker/machine/drivers/vmwarevsphere/errors" + "github.com/docker/machine/provider" "github.com/docker/machine/ssh" "github.com/docker/machine/state" "github.com/docker/machine/utils" - // cssh "golang.org/x/crypto/ssh" ) const ( @@ -40,6 +39,7 @@ const ( type Driver struct { MachineName string + SSHUser string SSHPort int CPU int Memory int @@ -160,11 +160,52 @@ func NewDriver(machineName string, storePath string, caCert string, privateKey s return &Driver{MachineName: machineName, StorePath: storePath, CaCertPath: caCert, PrivateKeyPath: privateKey}, nil } +func (d *Driver) AuthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) DeauthorizePort(ports []*drivers.Port) error { + return nil +} + +func (d *Driver) GetMachineName() string { + return d.MachineName +} + +func (d *Driver) GetSSHHostname() (string, error) { + return d.GetIP() +} + +func (d *Driver) GetSSHKeyPath() string { + return filepath.Join(d.storePath, "id_rsa") +} + +func (d *Driver) GetSSHPort() (int, error) { + if d.SSHPort == 0 { + d.SSHPort = 22 + } + + return d.SSHPort, nil +} + +func (d *Driver) GetSSHUsername() string { + if d.SSHUser == "" { + d.SSHUser = "docker" + } + + return d.SSHUser +} + +func (d *Driver) GetProviderType() provider.ProviderType { + return provider.Local +} + func (d *Driver) DriverName() string { return "vmwarevsphere" } func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { + d.SSHUser = "docker" d.SSHPort = 22 d.CPU = flags.Int("vmwarevsphere-cpu-count") d.Memory = flags.Int("vmwarevsphere-memory-size") @@ -243,7 +284,6 @@ func (d *Driver) Create() error { var ( isoURL string - err error ) b2dutils := utils.NewB2dUtils("", "") @@ -305,7 +345,7 @@ func (d *Driver) Create() error { } log.Infof("Generating SSH Keypair...") - if err := ssh.GenerateSSHKey(d.sshKeyPath()); err != nil { + if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil { return err } @@ -357,20 +397,6 @@ func (d *Driver) Create() error { return err } - log.Debugf("Setting hostname: %s", d.MachineName) - cmd, err := d.GetSSHCommand(fmt.Sprintf( - "echo \"127.0.0.1 %s\" | sudo tee -a /etc/hosts && sudo hostname %s && echo \"%s\" | sudo tee /etc/hostname", - d.MachineName, - d.MachineName, - d.MachineName, - )) - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - return nil } @@ -469,56 +495,12 @@ func (d *Driver) Kill() error { return nil } -func (d *Driver) StartDocker() error { - log.Debug("Starting Docker...") - - cmd, err := d.GetSSHCommand("sudo /etc/init.d/docker start") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) StopDocker() error { - log.Debug("Stopping Docker...") - - cmd, err := d.GetSSHCommand("sudo /etc/init.d/docker stop") - if err != nil { - return err - } - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -func (d *Driver) GetDockerConfigDir() string { - return dockerConfigDir -} - func (d *Driver) Upgrade() error { return fmt.Errorf("upgrade is not supported for vsphere driver at this moment") } -func (d *Driver) GetSSHCommand(args ...string) (*exec.Cmd, error) { - ip, err := d.GetIP() - if err != nil { - return nil, err - } - return ssh.GetSSHCommand(ip, d.SSHPort, "docker", d.sshKeyPath(), args...), nil -} - -func (d *Driver) sshKeyPath() string { - return path.Join(d.storePath, "id_rsa") -} - func (d *Driver) publicSSHKeyPath() string { - return d.sshKeyPath() + ".pub" + return d.GetSSHKeyPath() + ".pub" } func (d *Driver) checkVsphereConfig() error { diff --git a/host.go b/host.go index 43e5d08806..d579599e7f 100644 --- a/host.go +++ b/host.go @@ -9,6 +9,7 @@ import ( "net" "net/url" "os" + "os/exec" "path" "path/filepath" "regexp" @@ -18,13 +19,16 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/machine/drivers" + "github.com/docker/machine/provider" + "github.com/docker/machine/ssh" "github.com/docker/machine/utils" ) var ( - validHostNameChars = `[a-zA-Z0-9\-\.]` - validHostNamePattern = regexp.MustCompile(`^` + validHostNameChars + `+$`) - ErrInvalidHostname = errors.New("Invalid hostname specified") + validHostNameChars = `[a-zA-Z0-9\-\.]` + validHostNamePattern = regexp.MustCompile(`^` + validHostNameChars + `+$`) + ErrInvalidHostname = errors.New("Invalid hostname specified") + ErrUnknownHypervisorType = errors.New("Unknown hypervisor type") ) const ( @@ -106,6 +110,20 @@ func ValidateHostName(name string) (string, error) { return name, nil } +func (h *Host) GetDockerConfigDir() (string, error) { + // TODO: this will be refactored in https://github.com/docker/machine/issues/699 + switch h.Driver.GetProviderType() { + case provider.Local: + return "/var/lib/boot2docker", nil + case provider.Remote: + return "/etc/default", nil + case provider.None: + return "", nil + default: + return "", ErrUnknownHypervisorType + } +} + func (h *Host) ConfigureSwarm(discovery string, master bool, host string, addr string) error { d := h.Driver @@ -122,7 +140,11 @@ func (h *Host) ConfigureSwarm(discovery string, master bool, host string, addr s addr = fmt.Sprintf("%s:2376", ip) } - basePath := d.GetDockerConfigDir() + basePath, err := h.GetDockerConfigDir() + if err != nil { + return err + } + tlsCaCert := path.Join(basePath, "ca.pem") tlsCert := path.Join(basePath, "server.pem") tlsKey := path.Join(basePath, "server-key.pem") @@ -142,7 +164,7 @@ func (h *Host) ConfigureSwarm(discovery string, master bool, host string, addr s return err } - cmd, err := d.GetSSHCommand(fmt.Sprintf("sudo docker pull %s", swarmDockerImage)) + cmd, err := h.GetSSHCommand(fmt.Sprintf("sudo docker pull %s", swarmDockerImage)) if err != nil { return err } @@ -150,12 +172,17 @@ func (h *Host) ConfigureSwarm(discovery string, master bool, host string, addr s return err } + dockerDir, err := h.GetDockerConfigDir() + if err != nil { + return err + } + // if master start master agent if master { log.Debug("launching swarm master") log.Debugf("master args: %s", masterArgs) - cmd, err = d.GetSSHCommand(fmt.Sprintf("sudo docker run -d -p %s:%s --restart=always --name swarm-agent-master -v %s:%s %s manage %s", - port, port, d.GetDockerConfigDir(), d.GetDockerConfigDir(), swarmDockerImage, masterArgs)) + cmd, err = h.GetSSHCommand(fmt.Sprintf("sudo docker run -d -p %s:%s --restart=always --name swarm-agent-master -v %s:%s %s manage %s", + port, port, dockerDir, dockerDir, swarmDockerImage, masterArgs)) if err != nil { return err } @@ -167,8 +194,63 @@ func (h *Host) ConfigureSwarm(discovery string, master bool, host string, addr s // start node agent log.Debug("launching swarm node") log.Debugf("node args: %s", nodeArgs) - cmd, err = d.GetSSHCommand(fmt.Sprintf("sudo docker run -d --restart=always --name swarm-agent -v %s:%s %s join %s", - d.GetDockerConfigDir(), d.GetDockerConfigDir(), swarmDockerImage, nodeArgs)) + cmd, err = h.GetSSHCommand(fmt.Sprintf("sudo docker run -d --restart=always --name swarm-agent -v %s:%s %s join %s", + dockerDir, dockerDir, swarmDockerImage, nodeArgs)) + if err != nil { + return err + } + if err := cmd.Run(); err != nil { + return err + } + + return nil +} + +func (h *Host) StartDocker() error { + log.Debug("Starting Docker...") + + var ( + cmd *exec.Cmd + err error + ) + + switch h.Driver.GetProviderType() { + case provider.Local: + cmd, err = h.GetSSHCommand("sudo /etc/init.d/docker start") + case provider.Remote: + cmd, err = h.GetSSHCommand("sudo service docker start") + default: + return ErrUnknownHypervisorType + } + + if err != nil { + return err + } + + if err := cmd.Run(); err != nil { + return err + } + + return nil +} + +func (h *Host) StopDocker() error { + log.Debug("Stopping Docker...") + + var ( + cmd *exec.Cmd + err error + ) + + switch h.Driver.GetProviderType() { + case provider.Local: + cmd, err = h.GetSSHCommand("if [ -e /var/run/docker.pid ]; then sudo /etc/init.d/docker stop ; fi") + case provider.Remote: + cmd, err = h.GetSSHCommand("sudo service docker stop") + default: + return ErrUnknownHypervisorType + } + if err != nil { return err } @@ -242,11 +324,16 @@ func (h *Host) ConfigureAuth() error { return fmt.Errorf("error generating server cert: %s", err) } - if err := d.StopDocker(); err != nil { + if err := h.StopDocker(); err != nil { return err } - cmd, err := d.GetSSHCommand(fmt.Sprintf("sudo mkdir -p %s", d.GetDockerConfigDir())) + dockerDir, err := h.GetDockerConfigDir() + if err != nil { + return err + } + + cmd, err := h.GetSSHCommand(fmt.Sprintf("sudo mkdir -p %s", dockerDir)) if err != nil { return err } @@ -262,21 +349,21 @@ func (h *Host) ConfigureAuth() error { // due to windows clients, we cannot use filepath.Join as the paths // will be mucked on the linux hosts - machineCaCertPath := path.Join(d.GetDockerConfigDir(), "ca.pem") + machineCaCertPath := path.Join(dockerDir, "ca.pem") serverCert, err := ioutil.ReadFile(serverCertPath) if err != nil { return err } - machineServerCertPath := path.Join(d.GetDockerConfigDir(), "server.pem") + machineServerCertPath := path.Join(dockerDir, "server.pem") serverKey, err := ioutil.ReadFile(serverKeyPath) if err != nil { return err } - machineServerKeyPath := path.Join(d.GetDockerConfigDir(), "server-key.pem") + machineServerKeyPath := path.Join(dockerDir, "server-key.pem") - cmd, err = d.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee -a %s", string(caCert), machineCaCertPath)) + cmd, err = h.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee -a %s", string(caCert), machineCaCertPath)) if err != nil { return err } @@ -284,7 +371,7 @@ func (h *Host) ConfigureAuth() error { return err } - cmd, err = d.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee -a %s", string(serverKey), machineServerKeyPath)) + cmd, err = h.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee -a %s", string(serverKey), machineServerKeyPath)) if err != nil { return err } @@ -292,7 +379,7 @@ func (h *Host) ConfigureAuth() error { return err } - cmd, err = d.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee -a %s", string(serverCert), machineServerCertPath)) + cmd, err = h.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee -a %s", string(serverCert), machineServerCertPath)) if err != nil { return err } @@ -318,9 +405,12 @@ func (h *Host) ConfigureAuth() error { dockerPort = dPort } - cfg := h.generateDockerConfig(dockerPort, machineCaCertPath, machineServerKeyPath, machineServerCertPath) + cfg, err := h.generateDockerConfig(dockerPort, machineCaCertPath, machineServerKeyPath, machineServerCertPath) + if err != nil { + return err + } - cmd, err = d.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee -a %s", cfg.EngineConfig, cfg.EngineConfigPath)) + cmd, err = h.GetSSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee -a %s", cfg.EngineConfig, cfg.EngineConfigPath)) if err != nil { return err } @@ -328,14 +418,14 @@ func (h *Host) ConfigureAuth() error { return err } - if err := d.StartDocker(); err != nil { + if err := h.StartDocker(); err != nil { return err } return nil } -func (h *Host) generateDockerConfig(dockerPort int, caCertPath string, serverKeyPath string, serverCertPath string) *DockerConfig { +func (h *Host) generateDockerConfig(dockerPort int, caCertPath string, serverKeyPath string, serverCertPath string) (*DockerConfig, error) { d := h.Driver var ( daemonOpts string @@ -353,10 +443,15 @@ func (h *Host) generateDockerConfig(dockerPort int, caCertPath string, serverKey strings.Join(swarmLabels, " "), ) + dockerDir, err := h.GetDockerConfigDir() + if err != nil { + return nil, err + } + switch d.DriverName() { case "virtualbox", "vmwarefusion", "vmwarevsphere", "hyper-v": daemonOpts = fmt.Sprintf("-H tcp://0.0.0.0:%d", dockerPort) - daemonOptsCfg = path.Join(d.GetDockerConfigDir(), "profile") + daemonOptsCfg = path.Join(dockerDir, "profile") opts := fmt.Sprintf("%s %s", defaultDaemonOpts, daemonOpts) daemonCfg = fmt.Sprintf(`EXTRA_ARGS='%s' CACERT=%s @@ -373,7 +468,7 @@ DOCKER_TLS=no`, opts, caCertPath, serverKeyPath, serverCertPath) return &DockerConfig{ EngineConfig: daemonCfg, EngineConfigPath: daemonOptsCfg, - } + }, nil } func (h *Host) Create(name string) error { @@ -387,13 +482,18 @@ func (h *Host) Create(name string) error { return err } - // install docker - if err := h.Provision(); err != nil { + // save to store + if err := h.SaveConfig(); err != nil { return err } - // save to store - if err := h.SaveConfig(); err != nil { + // set hostname + if err := h.SetHostname(); err != nil { + return err + } + + // install docker + if err := h.Provision(); err != nil { return err } @@ -409,7 +509,7 @@ func (h *Host) Provision() error { // install docker - until cloudinit we use ubuntu everywhere so we // just install it using the docker repos - cmd, err := h.Driver.GetSSHCommand("if [ ! -e /usr/bin/docker ]; then curl -sSL https://get.docker.com | sh -; fi") + cmd, err := h.GetSSHCommand("if [ ! -e /usr/bin/docker ]; then curl -sSL https://get.docker.com | sh -; fi") if err != nil { return err } @@ -427,6 +527,67 @@ func (h *Host) Provision() error { return nil } +func (h *Host) GetSSHCommand(args ...string) (*exec.Cmd, error) { + addr, err := h.Driver.GetSSHHostname() + if err != nil { + return nil, err + } + + user := h.Driver.GetSSHUsername() + + port, err := h.Driver.GetSSHPort() + if err != nil { + return nil, err + } + + keyPath := h.Driver.GetSSHKeyPath() + + cmd := ssh.GetSSHCommand(addr, port, user, keyPath, args...) + return cmd, nil +} + +func (h *Host) SetHostname() error { + var ( + cmd *exec.Cmd + err error + ) + + log.Debugf("setting hostname for provider type %s: %s", + h.Driver.GetProviderType(), + h.Name, + ) + + switch h.Driver.GetProviderType() { + case provider.None: + return nil + case provider.Local: + cmd, err = h.GetSSHCommand(fmt.Sprintf( + "sudo hostname %s && echo \"%s\" | sudo tee /var/lib/boot2docker/etc/hostname", + h.Name, + h.Name, + )) + case provider.Remote: + cmd, err = h.GetSSHCommand(fmt.Sprintf( + "echo \"127.0.0.1 %s\" | sudo tee -a /etc/hosts && sudo hostname %s && echo \"%s\" | sudo tee /etc/hostname", + h.Name, + h.Name, + h.Name, + )) + default: + return ErrUnknownHypervisorType + } + + if err != nil { + return err + } + + if err := cmd.Run(); err != nil { + return err + } + + return nil +} + func (h *Host) Start() error { return h.Driver.Start() } @@ -436,7 +597,8 @@ func (h *Host) Stop() error { } func (h *Host) Upgrade() error { - return h.Driver.Upgrade() + // TODO: refactor to provisioner + return fmt.Errorf("centralized upgrade coming in the provisioner") } func (h *Host) Remove(force bool) error { diff --git a/host_test.go b/host_test.go index a84564bcd2..faf4317447 100644 --- a/host_test.go +++ b/host_test.go @@ -129,7 +129,10 @@ func TestGenerateDockerConfigNonLocal(t *testing.T) { serverCertPath := "/test/server-cert" engineConfigPath := "/etc/default/docker" - dockerCfg := host.generateDockerConfig(dockerPort, caCertPath, serverKeyPath, serverCertPath) + dockerCfg, err := host.generateDockerConfig(dockerPort, caCertPath, serverKeyPath, serverCertPath) + if err != nil { + t.Fatal(err) + } if dockerCfg.EngineConfigPath != engineConfigPath { t.Fatalf("expected engine path %s; received %s", engineConfigPath, dockerCfg.EngineConfigPath) @@ -170,8 +173,11 @@ func TestMachinePort(t *testing.T) { if err != nil { t.Fatal(err) } - cfg := host.generateDockerConfig(dockerPort, "", "", "") + cfg, err := host.generateDockerConfig(dockerPort, "", "", "") + if err != nil { + t.Fatal(err) + } re := regexp.MustCompile("--host=tcp://.*:(.+)") m := re.FindStringSubmatch(cfg.EngineConfig) if len(m) == 0 { @@ -210,7 +216,11 @@ func TestMachineCustomPort(t *testing.T) { if err != nil { t.Fatal(err) } - cfg := host.generateDockerConfig(dockerPort, "", "", "") + + cfg, err := host.generateDockerConfig(dockerPort, "", "", "") + if err != nil { + t.Fatal(err) + } re := regexp.MustCompile("--host=tcp://.*:(.+)") m := re.FindStringSubmatch(cfg.EngineConfig) diff --git a/provider/provider.go b/provider/provider.go new file mode 100644 index 0000000000..713c62cad1 --- /dev/null +++ b/provider/provider.go @@ -0,0 +1,25 @@ +package provider + +// ProviderType represents the type of a provider for a machine +type ProviderType int + +const ( + None ProviderType = iota + Local + Remote +) + +var providerTypes = []string{ + "", + "Local", + "Remote", +} + +// Given a type, returns its string representation +func (t ProviderType) String() string { + if int(t) >= 0 && int(t) < len(providerTypes) { + return providerTypes[t] + } else { + return "" + } +} diff --git a/provider/provider_test.go b/provider/provider_test.go new file mode 100644 index 0000000000..60a5ebcf84 --- /dev/null +++ b/provider/provider_test.go @@ -0,0 +1,17 @@ +package provider + +import ( + "testing" +) + +func TestProviderType(t *testing.T) { + if None.String() != "" { + t.Fatal("None provider type should be empty string") + } + if Local.String() != "Local" { + t.Fatal("Local provider type should be 'Local'") + } + if Remote.String() != "Remote" { + t.Fatal("Remote provider type should be 'Remote'") + } +} diff --git a/ssh/ssh.go b/ssh/ssh.go index 080dd1236b..2f96fac736 100644 --- a/ssh/ssh.go +++ b/ssh/ssh.go @@ -11,7 +11,6 @@ import ( ) func GetSSHCommand(host string, port int, user string, sshKey string, args ...string) *exec.Cmd { - defaultSSHArgs := []string{ "-o", "IdentitiesOnly=yes", "-o", "StrictHostKeyChecking=no", diff --git a/test/integration/driver-digitalocean.bats b/test/integration/driver-digitalocean.bats index 86b582301f..511e15d7dd 100644 --- a/test/integration/driver-digitalocean.bats +++ b/test/integration/driver-digitalocean.bats @@ -95,6 +95,7 @@ export MACHINE_STORAGE_PATH=/tmp/machine-bats-test-$DRIVER } @test "$DRIVER: remove" { + run sleep 20 run machine rm -f $NAME [ "$status" -eq 0 ] } diff --git a/test/integration/driver-virtualbox.bats b/test/integration/driver-virtualbox.bats index e7ba6b3e21..124b600a8d 100644 --- a/test/integration/driver-virtualbox.bats +++ b/test/integration/driver-virtualbox.bats @@ -31,6 +31,11 @@ function setup() { [ "$status" -eq 0 ] } +@test "$DRIVER: upgrade" { + run machine upgrade $NAME + [ "$status" -eq 0 ] +} + @test "$DRIVER: ls" { run machine ls [ "$status" -eq 0 ]