CreateOptsExt struct and ToServerCreateMap method; add key pair acceptance test
diff --git a/acceptance/openstack/compute/v2/bootfromvolume_test.go b/acceptance/openstack/compute/v2/bootfromvolume_test.go
index 715af26..1fb44e8 100644
--- a/acceptance/openstack/compute/v2/bootfromvolume_test.go
+++ b/acceptance/openstack/compute/v2/bootfromvolume_test.go
@@ -45,6 +45,6 @@
}).Extract()
th.AssertNoErr(t, err)
t.Logf("Created server: %+v\n", server)
- //defer deleteServer(t, client, server)
+ defer servers.Delete(client, server.ID)
t.Logf("Deleting server [%s]...", name)
}
diff --git a/acceptance/openstack/compute/v2/keypairs_test.go b/acceptance/openstack/compute/v2/keypairs_test.go
new file mode 100644
index 0000000..44ce29f
--- /dev/null
+++ b/acceptance/openstack/compute/v2/keypairs_test.go
@@ -0,0 +1,65 @@
+// +build acceptance
+
+package v2
+
+import (
+ "crypto/rand"
+ "crypto/rsa"
+ "testing"
+
+ "github.com/rackspace/gophercloud/acceptance/tools"
+ "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
+ "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
+ th "github.com/rackspace/gophercloud/testhelper"
+
+ "code.google.com/p/go.crypto/ssh"
+)
+
+func TestCreateServerWithKeyPair(t *testing.T) {
+ client, err := newClient()
+ th.AssertNoErr(t, err)
+
+ if testing.Short() {
+ t.Skip("Skipping test that requires server creation in short mode.")
+ }
+
+ privateKey, err := rsa.GenerateKey(rand.Reader, 2014)
+ publicKey := privateKey.PublicKey
+ pub, err := ssh.NewPublicKey(&publicKey)
+ th.AssertNoErr(t, err)
+ pubBytes := ssh.MarshalAuthorizedKey(pub)
+ pk := string(pubBytes)
+
+ kp, err := keypairs.Create(client, keypairs.CreateOpts{
+ Name: "gophercloud_test_key_pair",
+ PublicKey: pk,
+ }).Extract()
+ th.AssertNoErr(t, err)
+ t.Logf("Created key pair: %s\n", kp)
+
+ choices, err := ComputeChoicesFromEnv()
+ th.AssertNoErr(t, err)
+
+ name := tools.RandomString("Gophercloud-", 8)
+ t.Logf("Creating server [%s] with key pair.", name)
+
+ serverCreateOpts := servers.CreateOpts{
+ Name: name,
+ FlavorRef: choices.FlavorID,
+ ImageRef: choices.ImageID,
+ }
+
+ server, err := servers.Create(client, keypairs.CreateOptsExt{
+ serverCreateOpts,
+ "gophercloud_test_key_pair",
+ }).Extract()
+ th.AssertNoErr(t, err)
+ defer servers.Delete(client, server.ID)
+ t.Logf("Created server: %+v\n", server)
+
+ t.Logf("Deleting key pair [%s]...", kp.Name)
+ err = keypairs.Delete(client, "gophercloud_test_key_pair").ExtractErr()
+ th.AssertNoErr(t, err)
+
+ t.Logf("Deleting server [%s]...", name)
+}
diff --git a/openstack/compute/v2/extensions/keypairs/requests.go b/openstack/compute/v2/extensions/keypairs/requests.go
index 7d1a2ac..7b372a3 100644
--- a/openstack/compute/v2/extensions/keypairs/requests.go
+++ b/openstack/compute/v2/extensions/keypairs/requests.go
@@ -5,9 +5,34 @@
"github.com/racker/perigee"
"github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
"github.com/rackspace/gophercloud/pagination"
)
+// CreateOptsExt adds a KeyPair option to the base CreateOpts.
+type CreateOptsExt struct {
+ servers.CreateOptsBuilder
+ KeyName string `json:"key_name,omitempty"`
+}
+
+// ToServerCreateMap adds the key_name and, optionally, key_data options to
+// the base server creation options.
+func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
+ base, err := opts.CreateOptsBuilder.ToServerCreateMap()
+ if err != nil {
+ return nil, err
+ }
+
+ if opts.KeyName == "" {
+ return base, nil
+ }
+
+ serverMap := base["server"].(map[string]interface{})
+ serverMap["key_name"] = opts.KeyName
+
+ return base, nil
+}
+
// List returns a Pager that allows you to iterate over a collection of KeyPairs.
func List(client *gophercloud.ServiceClient) pagination.Pager {
return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
@@ -21,7 +46,7 @@
ToKeyPairCreateMap() (map[string]interface{}, error)
}
-// CreateOpts species keypair creation or import parameters.
+// CreateOpts specifies keypair creation or import parameters.
type CreateOpts struct {
// Name [required] is a friendly name to refer to this KeyPair in other services.
Name string