Merge pull request #351 from jrperritt/add-update-server-method-for-rackspace

Add Update operation for Rackspace servers
diff --git a/acceptance/rackspace/compute/v2/servers_test.go b/acceptance/rackspace/compute/v2/servers_test.go
index 81c8599..a8b5937 100644
--- a/acceptance/rackspace/compute/v2/servers_test.go
+++ b/acceptance/rackspace/compute/v2/servers_test.go
@@ -100,6 +100,18 @@
 	logServer(t, details, -1)
 }
 
+func updateServer(t *testing.T, client *gophercloud.ServiceClient, server *os.Server) {
+	t.Logf("> servers.Get")
+
+	opts := os.UpdateOpts{
+		Name: "updated-server",
+	}
+	updatedServer, err := servers.Update(client, server.ID, opts).Extract()
+	th.AssertNoErr(t, err)
+	th.AssertEquals(t, "updated-server", updatedServer.Name)
+	logServer(t, updatedServer, -1)
+}
+
 func listServers(t *testing.T, client *gophercloud.ServiceClient) {
 	t.Logf("> servers.List")
 
@@ -197,6 +209,7 @@
 	defer deleteServer(t, client, server)
 
 	getServer(t, client, server)
+	updateServer(t, client, server)
 	listServers(t, client)
 	changeAdminPassword(t, client, server)
 	rebootServer(t, client, server)
diff --git a/rackspace/compute/v2/servers/delegate.go b/rackspace/compute/v2/servers/delegate.go
index 4c7b249..173868e 100644
--- a/rackspace/compute/v2/servers/delegate.go
+++ b/rackspace/compute/v2/servers/delegate.go
@@ -16,6 +16,11 @@
 	return os.Create(client, opts)
 }
 
+// Update requests an existing server to be updated with the supplied options.
+func Update(client *gophercloud.ServiceClient, id string, opts os.UpdateOptsBuilder) os.UpdateResult {
+	return os.Update(client, id, opts)
+}
+
 // Delete requests that a server previously provisioned be removed from your account.
 func Delete(client *gophercloud.ServiceClient, id string) os.DeleteResult {
 	return os.Delete(client, id)
diff --git a/rackspace/compute/v2/servers/delegate_test.go b/rackspace/compute/v2/servers/delegate_test.go
index 7f41404..c3d9cc0 100644
--- a/rackspace/compute/v2/servers/delegate_test.go
+++ b/rackspace/compute/v2/servers/delegate_test.go
@@ -77,6 +77,28 @@
 	th.CheckDeepEquals(t, &GophercloudServer, actual)
 }
 
+func TestUpdateServer(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	th.Mux.HandleFunc("/servers/8c65cb68-0681-4c30-bc88-6b83a8a26aee", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "PUT")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+		th.TestJSONRequest(t, r, `{ "server": { "name": "test-server-updated" } }`)
+
+		w.Header().Add("Content-Type", "application/json")
+
+		fmt.Fprintf(w, UpdateOutput)
+	})
+
+	opts := os.UpdateOpts{
+		Name: "test-server-updated",
+	}
+	actual, err := Update(client.ServiceClient(), "8c65cb68-0681-4c30-bc88-6b83a8a26aee", opts).Extract()
+	th.AssertNoErr(t, err)
+	th.CheckDeepEquals(t, &GophercloudUpdatedServer, actual)
+}
+
 func TestChangeAdminPassword(t *testing.T) {
 	th.SetupHTTP()
 	defer th.TeardownHTTP()
diff --git a/rackspace/compute/v2/servers/fixtures.go b/rackspace/compute/v2/servers/fixtures.go
index b22a289..75cccd0 100644
--- a/rackspace/compute/v2/servers/fixtures.go
+++ b/rackspace/compute/v2/servers/fixtures.go
@@ -215,6 +215,77 @@
 }
 `
 
+// UpdateOutput is the recorded output of a Rackspace servers.Update request.
+const UpdateOutput = `
+{
+	"server": {
+		"OS-DCF:diskConfig": "AUTO",
+		"OS-EXT-STS:power_state": 1,
+		"OS-EXT-STS:task_state": null,
+		"OS-EXT-STS:vm_state": "active",
+		"accessIPv4": "1.2.4.8",
+		"accessIPv6": "2001:4800:6666:105:2a0f:c056:f594:7777",
+		"addresses": {
+			"private": [
+			{
+				"addr": "10.20.40.80",
+				"version": 4
+			}
+			],
+			"public": [
+			{
+				"addr": "1.2.4.8",
+				"version": 4
+				},
+				{
+					"addr": "2001:4800:6666:105:2a0f:c056:f594:7777",
+					"version": 6
+				}
+			]
+		},
+		"created": "2014-10-21T14:42:16Z",
+		"flavor": {
+			"id": "performance1-1",
+			"links": [
+			{
+				"href": "https://dfw.servers.api.rackspacecloud.com/111111/flavors/performance1-1",
+				"rel": "bookmark"
+			}
+			]
+		},
+		"hostId": "430d2ae02de0a7af77012c94778145eccf67e75b1fac0528aa10d4a7",
+		"id": "8c65cb68-0681-4c30-bc88-6b83a8a26aee",
+		"image": {
+			"id": "e19a734c-c7e6-443a-830c-242209c4d65d",
+			"links": [
+			{
+				"href": "https://dfw.servers.api.rackspacecloud.com/111111/images/e19a734c-c7e6-443a-830c-242209c4d65d",
+				"rel": "bookmark"
+			}
+			]
+		},
+		"key_name": null,
+		"links": [
+		{
+			"href": "https://dfw.servers.api.rackspacecloud.com/v2/111111/servers/8c65cb68-0681-4c30-bc88-6b83a8a26aee",
+			"rel": "self"
+		},
+		{
+			"href": "https://dfw.servers.api.rackspacecloud.com/111111/servers/8c65cb68-0681-4c30-bc88-6b83a8a26aee",
+			"rel": "bookmark"
+		}
+		],
+		"metadata": {},
+		"name": "test-server-updated",
+		"progress": 100,
+		"status": "ACTIVE",
+		"tenant_id": "111111",
+		"updated": "2014-10-21T14:42:57Z",
+		"user_id": "14ae7bb21d81423694655f4dd30f2930"
+	}
+}
+`
+
 // CreateOutput contains a sample of Rackspace's response to a Create call.
 const CreateOutput = `
 {
@@ -428,6 +499,70 @@
 	AdminPass: "",
 }
 
+// GophercloudUpdatedServer is the expected result from parsing UpdateOutput.
+var GophercloudUpdatedServer = os.Server{
+	ID:         "8c65cb68-0681-4c30-bc88-6b83a8a26aee",
+	Name:       "test-server-updated",
+	TenantID:   "111111",
+	UserID:     "14ae7bb21d81423694655f4dd30f2930",
+	HostID:     "430d2ae02de0a7af77012c94778145eccf67e75b1fac0528aa10d4a7",
+	Updated:    "2014-10-21T14:42:57Z",
+	Created:    "2014-10-21T14:42:16Z",
+	AccessIPv4: "1.2.4.8",
+	AccessIPv6: "2001:4800:6666:105:2a0f:c056:f594:7777",
+	Progress:   100,
+	Status:     "ACTIVE",
+	Image: map[string]interface{}{
+		"id": "e19a734c-c7e6-443a-830c-242209c4d65d",
+		"links": []interface{}{
+			map[string]interface{}{
+				"href": "https://dfw.servers.api.rackspacecloud.com/111111/images/e19a734c-c7e6-443a-830c-242209c4d65d",
+				"rel":  "bookmark",
+			},
+		},
+	},
+	Flavor: map[string]interface{}{
+		"id": "performance1-1",
+		"links": []interface{}{
+			map[string]interface{}{
+				"href": "https://dfw.servers.api.rackspacecloud.com/111111/flavors/performance1-1",
+				"rel":  "bookmark",
+			},
+		},
+	},
+	Addresses: map[string]interface{}{
+		"private": []interface{}{
+			map[string]interface{}{
+				"addr":    "10.20.40.80",
+				"version": float64(4.0),
+			},
+		},
+		"public": []interface{}{
+			map[string]interface{}{
+				"addr":    "2001:4800:6666:105:2a0f:c056:f594:7777",
+				"version": float64(6.0),
+			},
+			map[string]interface{}{
+				"addr":    "1.2.4.8",
+				"version": float64(4.0),
+			},
+		},
+	},
+	Metadata: map[string]interface{}{},
+	Links: []interface{}{
+		map[string]interface{}{
+			"href": "https://dfw.servers.api.rackspacecloud.com/v2/111111/servers/8c65cb68-0681-4c30-bc88-6b83a8a26aee",
+			"rel":  "self",
+		},
+		map[string]interface{}{
+			"href": "https://dfw.servers.api.rackspacecloud.com/111111/servers/8c65cb68-0681-4c30-bc88-6b83a8a26aee",
+			"rel":  "bookmark",
+		},
+	},
+	KeyName:   "",
+	AdminPass: "",
+}
+
 // CreatedServer is the partial Server struct that can be parsed from CreateOutput.
 var CreatedServer = os.Server{
 	ID:        "bb63327b-6a2f-34bc-b0ef-4b6d97ea637e",