diff --git a/commands_test.go b/commands_test.go index 126ce24a28..0438847997 100644 --- a/commands_test.go +++ b/commands_test.go @@ -33,6 +33,10 @@ func (d *FakeDriver) GetState() (state.State, error) { return d.MockState, nil } +func (d *FakeDriver) PreCreateCheck() error { + return nil +} + func (d *FakeDriver) Create() error { return nil } diff --git a/drivers/amazonec2/amazonec2.go b/drivers/amazonec2/amazonec2.go index 2d539df4bf..06b3b8f2c5 100644 --- a/drivers/amazonec2/amazonec2.go +++ b/drivers/amazonec2/amazonec2.go @@ -182,7 +182,28 @@ func (d *Driver) DriverName() string { return driverName } +func (d *Driver) checkPrereqs() error { + // check for existing keypair + key, err := d.getClient().GetKeyPair(d.MachineName) + if err != nil { + return err + } + + if key != nil { + return fmt.Errorf("There is already a keypair with the name %s. Please either remove that keypair or use a different machine name.", d.MachineName) + } + return nil +} + +func (d *Driver) PreCreateCheck() error { + return d.checkPrereqs() +} + func (d *Driver) Create() error { + if err := d.checkPrereqs(); err != nil { + return err + } + log.Infof("Launching instance...") if err := d.createKeyPair(); err != nil { diff --git a/drivers/amazonec2/amz/describe_keypairs.go b/drivers/amazonec2/amz/describe_keypairs.go new file mode 100644 index 0000000000..802c8828e2 --- /dev/null +++ b/drivers/amazonec2/amz/describe_keypairs.go @@ -0,0 +1,6 @@ +package amz + +type DescribeKeyPairsResponse struct { + RequestId string `xml:"requestId"` + KeySet []KeyPair `xml:"keySet>item"` +} diff --git a/drivers/amazonec2/amz/ec2.go b/drivers/amazonec2/amz/ec2.go index e431e1b42c..a79c76ad2f 100644 --- a/drivers/amazonec2/amz/ec2.go +++ b/drivers/amazonec2/amz/ec2.go @@ -438,6 +438,42 @@ func (e *EC2) GetSubnets() ([]Subnet, error) { return subnets, nil } +func (e *EC2) GetKeyPairs() ([]KeyPair, error) { + keyPairs := []KeyPair{} + resp, err := e.performStandardAction("DescribeKeyPairs") + if err != nil { + return keyPairs, err + } + defer resp.Body.Close() + contents, err := ioutil.ReadAll(resp.Body) + if err != nil { + return keyPairs, fmt.Errorf("Error reading AWS response body: %s", err) + } + + unmarshalledResponse := DescribeKeyPairsResponse{} + if err = xml.Unmarshal(contents, &unmarshalledResponse); err != nil { + return keyPairs, fmt.Errorf("Error unmarshalling AWS response XML: %s", err) + } + + keyPairs = unmarshalledResponse.KeySet + + return keyPairs, nil +} + +func (e *EC2) GetKeyPair(name string) (*KeyPair, error) { + keyPairs, err := e.GetKeyPairs() + if err != nil { + return nil, err + } + + for _, key := range keyPairs { + if key.KeyName == name { + return &key, nil + } + } + return nil, nil +} + func (e *EC2) GetInstanceState(instanceId string) (state.State, error) { resp, err := e.performInstanceAction(instanceId, "DescribeInstances", nil) if err != nil { diff --git a/drivers/amazonec2/amz/keypair.go b/drivers/amazonec2/amz/keypair.go index faebe250f2..b14d5977ed 100644 --- a/drivers/amazonec2/amz/keypair.go +++ b/drivers/amazonec2/amz/keypair.go @@ -11,3 +11,8 @@ type ImportKeyPairResponse struct { KeyFingerprint string `xml:"keyFingerprint"` KeyMaterial []byte `xml:"keyMaterial"` } + +type KeyPair struct { + KeyFingerprint string `xml:"keyFingerprint"` + KeyName string `xml:"keyName"` +} diff --git a/drivers/azure/azure.go b/drivers/azure/azure.go index 4cdae637cb..c0871d00bb 100644 --- a/drivers/azure/azure.go +++ b/drivers/azure/azure.go @@ -171,6 +171,10 @@ func (driver *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { return nil } +func (driver *Driver) PreCreateCheck() error { + return nil +} + func (driver *Driver) Create() error { if err := driver.setUserSubscription(); err != nil { return err diff --git a/drivers/digitalocean/digitalocean.go b/drivers/digitalocean/digitalocean.go index 8e86ad03ca..f0640dcdf0 100644 --- a/drivers/digitalocean/digitalocean.go +++ b/drivers/digitalocean/digitalocean.go @@ -95,6 +95,10 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { return nil } +func (d *Driver) PreCreateCheck() error { + return nil +} + func (d *Driver) Create() error { log.Infof("Creating SSH key...") diff --git a/drivers/drivers.go b/drivers/drivers.go index cb507c2638..b9e71f83ec 100644 --- a/drivers/drivers.go +++ b/drivers/drivers.go @@ -32,6 +32,9 @@ type Driver interface { // 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 + // Create a host using the driver's config Create() error diff --git a/drivers/google/google.go b/drivers/google/google.go index 7a8ad5be74..0f2fccd5b4 100644 --- a/drivers/google/google.go +++ b/drivers/google/google.go @@ -110,6 +110,10 @@ func (driver *Driver) initApis() (*ComputeUtil, error) { return newComputeUtil(driver) } +func (d *Driver) PreCreateCheck() error { + return nil +} + // Create creates a GCE VM instance acting as a docker host. func (driver *Driver) Create() error { c, err := newComputeUtil(driver) diff --git a/drivers/none/none.go b/drivers/none/none.go index 037b9900fc..f65d9a1b2c 100644 --- a/drivers/none/none.go +++ b/drivers/none/none.go @@ -69,6 +69,10 @@ 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 } diff --git a/drivers/openstack/openstack.go b/drivers/openstack/openstack.go index cfe9efd937..0f4a13c42d 100644 --- a/drivers/openstack/openstack.go +++ b/drivers/openstack/openstack.go @@ -312,6 +312,10 @@ func (d *Driver) GetState() (state.State, error) { return state.None, nil } +func (d *Driver) PreCreateCheck() error { + return nil +} + func (d *Driver) Create() error { d.KeyPairName = fmt.Sprintf("%s-%s", d.MachineName, utils.GenerateRandomID()) diff --git a/drivers/softlayer/driver.go b/drivers/softlayer/driver.go index bcfee6d31b..b19ea842fe 100644 --- a/drivers/softlayer/driver.go +++ b/drivers/softlayer/driver.go @@ -289,6 +289,10 @@ 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 +} + func (d *Driver) Create() error { waitForStart := func() { log.Infof("Waiting for host to become available") diff --git a/drivers/virtualbox/virtualbox.go b/drivers/virtualbox/virtualbox.go index 7a4cdb8b41..1811f4b86b 100644 --- a/drivers/virtualbox/virtualbox.go +++ b/drivers/virtualbox/virtualbox.go @@ -112,6 +112,10 @@ func cpIso(src, dest string) error { return nil } +func (d *Driver) PreCreateCheck() error { + return nil +} + func (d *Driver) Create() error { var ( err error diff --git a/drivers/vmwarefusion/fusion.go b/drivers/vmwarefusion/fusion.go index 775e0515e4..ef4f2d55fe 100644 --- a/drivers/vmwarefusion/fusion.go +++ b/drivers/vmwarefusion/fusion.go @@ -129,6 +129,10 @@ func (d *Driver) GetState() (state.State, error) { return state.Stopped, nil } +func (d *Driver) PreCreateCheck() error { + return nil +} + func (d *Driver) Create() error { var ( diff --git a/drivers/vmwarevcloudair/vcloudair.go b/drivers/vmwarevcloudair/vcloudair.go index b174fec156..0a7360f631 100644 --- a/drivers/vmwarevcloudair/vcloudair.go +++ b/drivers/vmwarevcloudair/vcloudair.go @@ -260,6 +260,10 @@ func (d *Driver) GetState() (state.State, error) { } +func (d *Driver) PreCreateCheck() error { + return nil +} + func (d *Driver) Create() error { key, err := d.createSSHKey() diff --git a/drivers/vmwarevsphere/vsphere.go b/drivers/vmwarevsphere/vsphere.go index 5b003d8dda..0479ff4a62 100644 --- a/drivers/vmwarevsphere/vsphere.go +++ b/drivers/vmwarevsphere/vsphere.go @@ -215,6 +215,10 @@ func (d *Driver) GetState() (state.State, error) { return state.None, nil } +func (d *Driver) PreCreateCheck() error { + return nil +} + // the current implementation does the following: // 1. check whether the docker directory contains the boot2docker ISO // 2. generate an SSH keypair diff --git a/store.go b/store.go index 61a4025977..b60e56d4ad 100644 --- a/store.go +++ b/store.go @@ -31,7 +31,7 @@ func (s *Store) Create(name string, driverName string, flags drivers.DriverOptio return nil, err } if exists { - return nil, fmt.Errorf("Host %q already exists", name) + return nil, fmt.Errorf("Machine %s already exists", name) } hostPath := filepath.Join(s.Path, name) @@ -46,6 +46,10 @@ func (s *Store) Create(name string, driverName string, flags drivers.DriverOptio } } + if err := host.Driver.PreCreateCheck(); err != nil { + return nil, err + } + if err := os.MkdirAll(hostPath, 0700); err != nil { return nil, err }