1package generic 2 3import ( 4 "errors" 5 "fmt" 6 "net" 7 "os" 8 "path" 9 "strconv" 10 "time" 11 12 "github.com/docker/machine/libmachine/drivers" 13 "github.com/docker/machine/libmachine/engine" 14 "github.com/docker/machine/libmachine/log" 15 "github.com/docker/machine/libmachine/mcnflag" 16 "github.com/docker/machine/libmachine/mcnutils" 17 "github.com/docker/machine/libmachine/state" 18) 19 20type Driver struct { 21 *drivers.BaseDriver 22 EnginePort int 23 SSHKey string 24} 25 26const ( 27 defaultTimeout = 1 * time.Second 28) 29 30// GetCreateFlags registers the flags this driver adds to 31// "docker hosts create" 32func (d *Driver) GetCreateFlags() []mcnflag.Flag { 33 return []mcnflag.Flag{ 34 mcnflag.IntFlag{ 35 Name: "generic-engine-port", 36 Usage: "Docker engine port", 37 Value: engine.DefaultPort, 38 EnvVar: "GENERIC_ENGINE_PORT", 39 }, 40 mcnflag.StringFlag{ 41 Name: "generic-ip-address", 42 Usage: "IP Address of machine", 43 EnvVar: "GENERIC_IP_ADDRESS", 44 }, 45 mcnflag.StringFlag{ 46 Name: "generic-ssh-user", 47 Usage: "SSH user", 48 Value: drivers.DefaultSSHUser, 49 EnvVar: "GENERIC_SSH_USER", 50 }, 51 mcnflag.StringFlag{ 52 Name: "generic-ssh-key", 53 Usage: "SSH private key path (if not provided, default SSH key will be used)", 54 Value: "", 55 EnvVar: "GENERIC_SSH_KEY", 56 }, 57 mcnflag.IntFlag{ 58 Name: "generic-ssh-port", 59 Usage: "SSH port", 60 Value: drivers.DefaultSSHPort, 61 EnvVar: "GENERIC_SSH_PORT", 62 }, 63 } 64} 65 66// NewDriver creates and returns a new instance of the driver 67func NewDriver(hostName, storePath string) drivers.Driver { 68 return &Driver{ 69 EnginePort: engine.DefaultPort, 70 BaseDriver: &drivers.BaseDriver{ 71 MachineName: hostName, 72 StorePath: storePath, 73 }, 74 } 75} 76 77// DriverName returns the name of the driver 78func (d *Driver) DriverName() string { 79 return "generic" 80} 81 82func (d *Driver) GetSSHHostname() (string, error) { 83 return d.GetIP() 84} 85 86func (d *Driver) GetSSHUsername() string { 87 return d.SSHUser 88} 89 90func (d *Driver) GetSSHKeyPath() string { 91 return d.SSHKeyPath 92} 93 94func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { 95 d.EnginePort = flags.Int("generic-engine-port") 96 d.IPAddress = flags.String("generic-ip-address") 97 d.SSHUser = flags.String("generic-ssh-user") 98 d.SSHKey = flags.String("generic-ssh-key") 99 d.SSHPort = flags.Int("generic-ssh-port") 100 101 if d.IPAddress == "" { 102 return errors.New("generic driver requires the --generic-ip-address option") 103 } 104 105 return nil 106} 107 108func (d *Driver) PreCreateCheck() error { 109 if d.SSHKey != "" { 110 if _, err := os.Stat(d.SSHKey); os.IsNotExist(err) { 111 return fmt.Errorf("SSH key does not exist: %q", d.SSHKey) 112 } 113 114 // TODO: validate the key is a valid key 115 } 116 117 return nil 118} 119 120func (d *Driver) Create() error { 121 if d.SSHKey == "" { 122 log.Info("No SSH key specified. Assuming an existing key at the default location.") 123 } else { 124 log.Info("Importing SSH key...") 125 126 d.SSHKeyPath = d.ResolveStorePath(path.Base(d.SSHKey)) 127 if err := copySSHKey(d.SSHKey, d.SSHKeyPath); err != nil { 128 return err 129 } 130 131 if err := copySSHKey(d.SSHKey+".pub", d.SSHKeyPath+".pub"); err != nil { 132 log.Infof("Couldn't copy SSH public key : %s", err) 133 } 134 } 135 136 log.Debugf("IP: %s", d.IPAddress) 137 138 return nil 139} 140 141func (d *Driver) GetURL() (string, error) { 142 if err := drivers.MustBeRunning(d); err != nil { 143 return "", err 144 } 145 146 ip, err := d.GetIP() 147 if err != nil { 148 return "", err 149 } 150 151 return fmt.Sprintf("tcp://%s", net.JoinHostPort(ip, strconv.Itoa(d.EnginePort))), nil 152} 153 154func (d *Driver) GetState() (state.State, error) { 155 address := net.JoinHostPort(d.IPAddress, strconv.Itoa(d.SSHPort)) 156 157 _, err := net.DialTimeout("tcp", address, defaultTimeout) 158 if err != nil { 159 return state.Stopped, nil 160 } 161 162 return state.Running, nil 163} 164 165func (d *Driver) Start() error { 166 return errors.New("generic driver does not support start") 167} 168 169func (d *Driver) Stop() error { 170 return errors.New("generic driver does not support stop") 171} 172 173func (d *Driver) Restart() error { 174 _, err := drivers.RunSSHCommandFromDriver(d, "sudo shutdown -r now") 175 return err 176} 177 178func (d *Driver) Kill() error { 179 return errors.New("generic driver does not support kill") 180} 181 182func (d *Driver) Remove() error { 183 return nil 184} 185 186func copySSHKey(src, dst string) error { 187 if err := mcnutils.CopyFile(src, dst); err != nil { 188 return fmt.Errorf("unable to copy ssh key: %s", err) 189 } 190 191 if err := os.Chmod(dst, 0600); err != nil { 192 return fmt.Errorf("unable to set permissions on the ssh key: %s", err) 193 } 194 195 return nil 196} 197