Add server action: change admin password
diff --git a/acceptance/openstack/compute_test.go b/acceptance/openstack/compute_test.go
index 4c487c7..f8c80f5 100644
--- a/acceptance/openstack/compute_test.go
+++ b/acceptance/openstack/compute_test.go
@@ -184,3 +184,30 @@
 		return
 	}
 }
+
+func TestServerAction(t *testing.T) {
+	ts, err := setupForCRUD()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = createServer(ts)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	defer func(){
+		servers.Delete(ts.client, ts.createdServer.Id)
+	}()
+
+	err = waitForStatus(ts, "ACTIVE")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = changeAdminPassword(ts)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
diff --git a/acceptance/openstack/tools_test.go b/acceptance/openstack/tools_test.go
index c9a004f..0743221 100644
--- a/acceptance/openstack/tools_test.go
+++ b/acceptance/openstack/tools_test.go
@@ -169,13 +169,13 @@
 		}
 
 		if ts.gottenServer.Status == s {
-			fmt.Printf("Server created after %d seconds (approximately)\n", 300-timeout)
+			fmt.Printf("Server reached state %s after %d seconds (approximately)\n", s, 300-timeout)
 			break
 		}
 	}
 
 	if err == errTimeout {
-		fmt.Printf("I'm not waiting around.\n")
+		fmt.Printf("Time out -- I'm not waiting around.\n")
 		err = nil
 	}
 
@@ -229,6 +229,27 @@
 	return err
 }
 
+func changeAdminPassword(ts *testState) error {
+	fmt.Println("Current password: "+ts.createdServer.AdminPass)
+	randomPassword := randomString("", 16)
+	for randomPassword == ts.createdServer.AdminPass {
+		randomPassword = randomString("", 16)
+	}
+	fmt.Println("    New password: "+randomPassword)
+	
+	err := servers.ChangeAdminPassword(ts.client, ts.createdServer.Id, randomPassword)
+	if err != nil {
+		return err
+	}
+	
+	err = waitForStatus(ts, "PASSWORD")
+	if err != nil {
+		return err
+	}
+	
+	return waitForStatus(ts, "ACTIVE")
+}
+
 // randomString generates a string of given length, but random content.
 // All content will be within the ASCII graphic character set.
 // (Implementation from Even Shaw's contribution on
diff --git a/openstack/compute/servers/client.go b/openstack/compute/servers/client.go
index 3d51dd8..3ce6965 100644
--- a/openstack/compute/servers/client.go
+++ b/openstack/compute/servers/client.go
@@ -42,6 +42,10 @@
 	return c.getDeleteUrl(id)
 }
 
+func (c *Client) getActionUrl(id string) string {
+	return fmt.Sprintf("%s/servers/%s/action", c.endpoint, id)
+}
+
 func (c *Client) getListHeaders() (map[string]string, error) {
 	t, err := c.getAuthToken()
 	if err != nil {
@@ -69,6 +73,10 @@
 	return c.getListHeaders()
 }
 
+func (c *Client) getActionHeaders() (map[string]string, error) {
+	return c.getListHeaders()
+}
+
 func (c *Client) getAuthToken() (string, error) {
 	var err error
 
diff --git a/openstack/compute/servers/requests.go b/openstack/compute/servers/requests.go
index 28abd1c..772699b 100644
--- a/openstack/compute/servers/requests.go
+++ b/openstack/compute/servers/requests.go
@@ -96,3 +96,21 @@
 	})
 	return sr, err
 }
+
+// ChangeAdminPassword alters the administrator or root password for a specified
+// server.
+func ChangeAdminPassword(c *Client, id, newPassword string) error {
+	h, err := c.getActionHeaders()
+	if err != nil {
+		return err
+	}
+
+	err = perigee.Post(c.getActionUrl(id), perigee.Options{
+		ReqBody: struct{C map[string]string `json:"changePassword"`}{
+			map[string]string{"adminPass": newPassword},
+		},
+		MoreHeaders: h,
+		OkCodes: []int{202},
+	})
+	return err
+}
diff --git a/openstack/compute/servers/servers.go b/openstack/compute/servers/servers.go
index e3bdbe3..28d66d0 100644
--- a/openstack/compute/servers/servers.go
+++ b/openstack/compute/servers/servers.go
@@ -36,6 +36,9 @@
 // Metadata includes a list of all user-specified key-value pairs attached to the server.
 //
 // Links includes HTTP references to the itself, useful for passing along to other APIs that might want a server reference.
+//
+// AdminPass will generally be empty ("").  However, it will contain the administrative password chosen when provisioning a new server without a set AdminPass setting in the first place.
+// Note that this is the ONLY time this field will be valid.
 type Server struct {
 	Id         string
 	TenantId   string `mapstructure:tenant_id`
@@ -53,6 +56,7 @@
 	Addresses  map[string]interface{}
 	Metadata   map[string]interface{}
 	Links      []interface{}
+	AdminPass  string `mapstructure:adminPass`
 }
 
 // GetServers interprets the result of a List() call, producing a slice of Server entities.