Rackspace Auto Scale: Add webhooks Get()
diff --git a/rackspace/autoscale/v1/webhooks/fixtures.go b/rackspace/autoscale/v1/webhooks/fixtures.go
index f243289..46ba6b8 100644
--- a/rackspace/autoscale/v1/webhooks/fixtures.go
+++ b/rackspace/autoscale/v1/webhooks/fixtures.go
@@ -71,6 +71,27 @@
 ]
 `
 
+// WebhookGetBody contains the canned body of a webhooks.Get response.
+const WebhookGetBody = `
+{
+  "webhook": {
+    "id": "2bd1822c-58c5-49fd-8b3d-ed44781a58d1",
+    "name": "first hook",
+    "links": [
+      {
+        "href": "https://dfw.autoscale.api.rackspacecloud.com/v1.0/123456/groups/60b15dad-5ea1-43fa-9a12-a1d737b4da07/policies/2b48d247-0282-4b9d-8775-5c4b67e8e649/webhooks/2bd1822c-58c5-49fd-8b3d-ed44781a58d1/",
+        "rel": "self"
+      },
+      {
+        "href": "https://dfw.autoscale.api.rackspacecloud.com/v1.0/execute/1/714c1c17c5e6ea5ef1e710d5ccc62e492575bab5216184d4c27dc0164db1bc06/",
+        "rel": "capability"
+      }
+    ],
+    "metadata": {}
+  }
+}
+`
+
 var (
 	// FirstWebhook is a Webhook corresponding to the first result in WebhookListBody.
 	FirstWebhook = Webhook{
@@ -141,3 +162,21 @@
 		fmt.Fprintf(w, WebhookCreateBody)
 	})
 }
+
+// HandleWebhookGetSuccessfully sets up the test server to respond to a webhooks Get request.
+func HandleWebhookGetSuccessfully(t *testing.T) {
+	groupID := "10eb3219-1b12-4b34-b1e4-e10ee4f24c65"
+	policyID := "2b48d247-0282-4b9d-8775-5c4b67e8e649"
+	webhookID := "2bd1822c-58c5-49fd-8b3d-ed44781a58d1"
+
+	path := fmt.Sprintf("/groups/%s/policies/%s/webhooks/%s", groupID, policyID, webhookID)
+
+	th.Mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+
+		w.Header().Add("Content-Type", "application/json")
+
+		fmt.Fprintf(w, WebhookGetBody)
+	})
+}
diff --git a/rackspace/autoscale/v1/webhooks/requests.go b/rackspace/autoscale/v1/webhooks/requests.go
index 5bcc3da..38aa4a7 100644
--- a/rackspace/autoscale/v1/webhooks/requests.go
+++ b/rackspace/autoscale/v1/webhooks/requests.go
@@ -84,3 +84,12 @@
 	pr := pagination.PageResultFromParsed(resp, res.Body)
 	return CreateResult{pagination.SinglePageBase(pr)}
 }
+
+// Get requests the details of a single webhook with the given ID.
+func Get(client *gophercloud.ServiceClient, groupID, policyID, webhookID string) GetResult {
+	var result GetResult
+
+	_, result.Err = client.Get(getURL(client, groupID, policyID, webhookID), &result.Body, nil)
+
+	return result
+}
diff --git a/rackspace/autoscale/v1/webhooks/requests_test.go b/rackspace/autoscale/v1/webhooks/requests_test.go
index 8c17aa2..5a46a63 100644
--- a/rackspace/autoscale/v1/webhooks/requests_test.go
+++ b/rackspace/autoscale/v1/webhooks/requests_test.go
@@ -11,6 +11,8 @@
 const (
 	groupID  = "10eb3219-1b12-4b34-b1e4-e10ee4f24c65"
 	policyID = "2b48d247-0282-4b9d-8775-5c4b67e8e649"
+	firstID  = "2bd1822c-58c5-49fd-8b3d-ed44781a58d1" // FirstWebhook
+	secondID = "76711c36-dfbe-4f5e-bea6-cded99690515" // SecondWebhook
 )
 
 func TestList(t *testing.T) {
@@ -71,3 +73,16 @@
 	th.CheckDeepEquals(t, FirstWebhook, webhooks[0])
 	th.CheckDeepEquals(t, SecondWebhook, webhooks[1])
 }
+
+func TestGet(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+	HandleWebhookGetSuccessfully(t)
+
+	client := client.ServiceClient()
+
+	webhook, err := Get(client, groupID, policyID, firstID).Extract()
+
+	th.AssertNoErr(t, err)
+	th.CheckDeepEquals(t, FirstWebhook, *webhook)
+}
diff --git a/rackspace/autoscale/v1/webhooks/results.go b/rackspace/autoscale/v1/webhooks/results.go
index 410f5cb..0fa550e 100644
--- a/rackspace/autoscale/v1/webhooks/results.go
+++ b/rackspace/autoscale/v1/webhooks/results.go
@@ -11,6 +11,21 @@
 	gophercloud.Result
 }
 
+// Extract interprets any webhookResult as a Webhook, if possible.
+func (r webhookResult) Extract() (*Webhook, error) {
+	if r.Err != nil {
+		return nil, r.Err
+	}
+
+	var response struct {
+		Webhook Webhook `mapstructure:"webhook"`
+	}
+
+	err := mapstructure.Decode(r.Body, &response)
+
+	return &response.Webhook, err
+}
+
 // CreateResult represents the result of a create operation. Multiple webhooks
 // can be created in a single call, so the result should be treated as a typical
 // pagination Page.  ExtractWebhooks() can be used to extract a slice of
@@ -19,6 +34,11 @@
 	pagination.SinglePageBase
 }
 
+// GetResult temporarily contains the response from a Get call.
+type GetResult struct {
+	webhookResult
+}
+
 // ExtractWebhooks extracts a slice of Webhooks from a CreateResult.
 func (res CreateResult) ExtractWebhooks() ([]Webhook, error) {
 	if res.Err != nil {
diff --git a/rackspace/autoscale/v1/webhooks/urls.go b/rackspace/autoscale/v1/webhooks/urls.go
index 90825a0..d5b7dcb 100644
--- a/rackspace/autoscale/v1/webhooks/urls.go
+++ b/rackspace/autoscale/v1/webhooks/urls.go
@@ -9,3 +9,7 @@
 func createURL(c *gophercloud.ServiceClient, groupID, policyID string) string {
 	return c.ServiceURL("groups", groupID, "policies", policyID, "webhooks")
 }
+
+func getURL(c *gophercloud.ServiceClient, groupID, policyID, webhookID string) string {
+	return c.ServiceURL("groups", groupID, "policies", policyID, "webhooks", webhookID)
+}