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
+}