Add server action: reboot server
diff --git a/acceptance/openstack/compute_test.go b/acceptance/openstack/compute_test.go
index f8c80f5..1cc154a 100644
--- a/acceptance/openstack/compute_test.go
+++ b/acceptance/openstack/compute_test.go
@@ -209,5 +209,15 @@
 	if err != nil {
 		t.Fatal(err)
 	}
+
+	err = servers.Reboot(ts.client, ts.createdServer.Id, "aldhjflaskhjf")
+	if err == nil {
+		t.Fatal("Expected the SDK to provide an ArgumentError here")
+	}
+
+	err = rebootServer(ts)
+	if err != nil {
+		t.Fatal(err)
+	}
 }
 
diff --git a/acceptance/openstack/tools_test.go b/acceptance/openstack/tools_test.go
index 0743221..c447d4a 100644
--- a/acceptance/openstack/tools_test.go
+++ b/acceptance/openstack/tools_test.go
@@ -250,6 +250,21 @@
 	return waitForStatus(ts, "ACTIVE")
 }
 
+func rebootServer(ts *testState) error {
+	fmt.Println("Attempting reboot of server "+ts.createdServer.Id)
+	err := servers.Reboot(ts.client, ts.createdServer.Id, servers.OSReboot)
+	if err != nil {
+		return err
+	}
+	
+	err = waitForStatus(ts, "REBOOT")
+	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/requests.go b/openstack/compute/servers/requests.go
index 772699b..207c6de 100644
--- a/openstack/compute/servers/requests.go
+++ b/openstack/compute/servers/requests.go
@@ -2,6 +2,7 @@
 
 import (
 	"github.com/racker/perigee"
+	"fmt"
 )
 
 // ListResult abstracts the raw results of making a List() request against the
@@ -10,6 +11,12 @@
 // provided through separate, type-safe accessors or methods.
 type ListResult map[string]interface{}
 
+// ServerResult abstracts a single server description,
+// as returned by the OpenStack provider.
+// As OpenStack extensions may freely alter the response bodies of the
+// structures returned to the client,
+// you may only safely access the data provided through
+// separate, type-safe accessors or methods.
 type ServerResult map[string]interface{}
 
 // List makes a request against the API to list servers accessible to you.
@@ -114,3 +121,74 @@
 	})
 	return err
 }
+
+// ArgumentError errors occur when an argument supplied to a package function
+// fails to fall within acceptable values.  For example, the Reboot() function
+// expects the "how" parameter to be one of HardReboot or SoftReboot.  These
+// constants are (currently) strings, leading someone to wonder if they can pass
+// other string values instead, perhaps in an effort to break the API of their
+// provider.  Reboot() returns this error in this situation.
+//
+// Function identifies which function was called/which function is generating
+// the error.
+// Argument identifies which formal argument was responsible for producing the
+// error.
+// Value provides the value as it was passed into the function.
+type ArgumentError struct {
+	Function, Argument string
+	Value interface{}
+}
+
+// Error yields a useful diagnostic for debugging purposes.
+func (e *ArgumentError) Error() string {
+	return fmt.Sprintf("Bad argument in call to %s, formal parameter %s, value %#v", e.Function, e.Argument, e.Value)
+}
+
+func (e *ArgumentError) String() string {
+	return e.Error()
+}
+
+// These constants determine how a server should be rebooted.
+// See the Reboot() function for further details.
+const (
+	SoftReboot = "SOFT"
+	HardReboot = "HARD"
+	OSReboot = SoftReboot
+	PowerCycle = HardReboot
+)
+
+// Reboot requests that a given server reboot.
+// Two methods exist for rebooting a server:
+//
+// HardReboot (aka PowerCycle) -- restarts the server instance by physically
+// cutting power to the machine, or if a VM, terminating it at the hypervisor
+// level.  It's done.  Caput.  Full stop.  Then, after a brief while, power is
+// restored or the VM instance restarted.
+//
+// SoftReboot (aka OSReboot).  This approach simply tells the OS to restart
+// under its own procedures.  E.g., in Linux, asking it to enter runlevel 6,
+// or executing "sudo shutdown -r now", or by wasking Windows to restart the
+// machine.
+func Reboot(c *Client, id, how string) error {
+	if (how != SoftReboot) && (how != HardReboot) {
+		return &ArgumentError{
+			Function: "Reboot",
+			Argument: "how",
+			Value: how,
+		}
+	}
+	
+	h, err := c.getActionHeaders()
+	if err != nil {
+		return err
+	}
+
+	err = perigee.Post(c.getActionUrl(id), perigee.Options{
+		ReqBody: struct{C map[string]string `json:"reboot"`}{
+			map[string]string{"type": how},
+		},
+		MoreHeaders: h,
+		OkCodes: []int{202},
+	})
+	return err
+}