Rackspace Auto Scale: Add webhooks Create()
diff --git a/rackspace/autoscale/v1/webhooks/fixtures.go b/rackspace/autoscale/v1/webhooks/fixtures.go
index 18f6b63..f243289 100644
--- a/rackspace/autoscale/v1/webhooks/fixtures.go
+++ b/rackspace/autoscale/v1/webhooks/fixtures.go
@@ -53,6 +53,24 @@
}
`
+// WebhookCreateBody contains the canned body of a webhooks.Create response.
+const WebhookCreateBody = WebhookListBody
+
+// WebhookCreateRequest contains the canned body of a webhooks.Create request.
+const WebhookCreateRequest = `
+[
+ {
+ "name": "first hook"
+ },
+ {
+ "name": "second hook",
+ "metadata": {
+ "notes": "a note about this webhook"
+ }
+ }
+]
+`
+
var (
// FirstWebhook is a Webhook corresponding to the first result in WebhookListBody.
FirstWebhook = Webhook{
@@ -104,3 +122,22 @@
fmt.Fprintf(w, WebhookListBody)
})
}
+
+// HandleWebhookCreateSuccessfully sets up the test server to respond to a webhooks Create request.
+func HandleWebhookCreateSuccessfully(t *testing.T) {
+ path := "/groups/10eb3219-1b12-4b34-b1e4-e10ee4f24c65/policies/2b48d247-0282-4b9d-8775-5c4b67e8e649/webhooks"
+
+ th.Mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.TestHeader(t, r, "Content-Type", "application/json")
+ th.TestHeader(t, r, "Accept", "application/json")
+
+ th.TestJSONRequest(t, r, WebhookCreateRequest)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated)
+
+ fmt.Fprintf(w, WebhookCreateBody)
+ })
+}
diff --git a/rackspace/autoscale/v1/webhooks/requests.go b/rackspace/autoscale/v1/webhooks/requests.go
index 1d56cef..5bcc3da 100644
--- a/rackspace/autoscale/v1/webhooks/requests.go
+++ b/rackspace/autoscale/v1/webhooks/requests.go
@@ -1,6 +1,8 @@
package webhooks
import (
+ "errors"
+
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
)
@@ -15,3 +17,70 @@
return pagination.NewPager(client, url, createPageFn)
}
+
+// CreateOptsBuilder is the interface responsible for generating the JSON
+// for a Create operation.
+type CreateOptsBuilder interface {
+ ToWebhookCreateMap() ([]map[string]interface{}, error)
+}
+
+// CreateOpts is a slice of CreateOpt structs, that allow the user to create
+// multiple webhooks in a single operation.
+type CreateOpts []CreateOpt
+
+// CreateOpt represents the options to create a webhook.
+type CreateOpt struct {
+ // Name [required] is a name for the webhook.
+ Name string
+
+ // Metadata [optional] is user-provided key-value metadata.
+ // Maximum length for keys and values is 256 characters.
+ Metadata map[string]string
+}
+
+// ToWebhookCreateMap converts a slice of CreateOpt structs into a map for use
+// in the request body of a Create operation.
+func (opts CreateOpts) ToWebhookCreateMap() ([]map[string]interface{}, error) {
+ var webhooks []map[string]interface{}
+
+ for _, o := range opts {
+ if o.Name == "" {
+ return nil, errors.New("Cannot create a Webhook without a name.")
+ }
+
+ hook := make(map[string]interface{})
+
+ hook["name"] = o.Name
+
+ if o.Metadata != nil {
+ hook["metadata"] = o.Metadata
+ }
+
+ webhooks = append(webhooks, hook)
+ }
+
+ return webhooks, nil
+}
+
+// Create requests a new webhook be created and associated with the given group
+// and scaling policy.
+func Create(client *gophercloud.ServiceClient, groupID, policyID string, opts CreateOptsBuilder) CreateResult {
+ var res CreateResult
+
+ reqBody, err := opts.ToWebhookCreateMap()
+
+ if err != nil {
+ res.Err = err
+ return res
+ }
+
+ resp, err := client.Post(createURL(client, groupID, policyID), reqBody, &res.Body, nil)
+
+ if err != nil {
+ res.Err = err
+ return res
+ }
+
+ pr := pagination.PageResultFromParsed(resp, res.Body)
+ return CreateResult{pagination.SinglePageBase(pr)}
+}
diff --git a/rackspace/autoscale/v1/webhooks/requests_test.go b/rackspace/autoscale/v1/webhooks/requests_test.go
index c0c1258..8c17aa2 100644
--- a/rackspace/autoscale/v1/webhooks/requests_test.go
+++ b/rackspace/autoscale/v1/webhooks/requests_test.go
@@ -8,14 +8,16 @@
"github.com/rackspace/gophercloud/testhelper/client"
)
+const (
+ groupID = "10eb3219-1b12-4b34-b1e4-e10ee4f24c65"
+ policyID = "2b48d247-0282-4b9d-8775-5c4b67e8e649"
+)
+
func TestList(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleWebhookListSuccessfully(t)
- groupID := "10eb3219-1b12-4b34-b1e4-e10ee4f24c65"
- policyID := "2b48d247-0282-4b9d-8775-5c4b67e8e649"
-
pages := 0
pager := List(client.ServiceClient(), groupID, policyID)
@@ -44,3 +46,28 @@
t.Errorf("Expected 1 page, saw %d", pages)
}
}
+
+func TestCreate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ HandleWebhookCreateSuccessfully(t)
+
+ client := client.ServiceClient()
+ opts := CreateOpts{
+ {
+ Name: "first hook",
+ },
+ {
+ Name: "second hook",
+ Metadata: map[string]string{
+ "notes": "a note about this webhook",
+ },
+ },
+ }
+
+ webhooks, err := Create(client, groupID, policyID, opts).ExtractWebhooks()
+
+ th.AssertNoErr(t, err)
+ th.CheckDeepEquals(t, FirstWebhook, webhooks[0])
+ th.CheckDeepEquals(t, SecondWebhook, webhooks[1])
+}
diff --git a/rackspace/autoscale/v1/webhooks/results.go b/rackspace/autoscale/v1/webhooks/results.go
index a15e20e..410f5cb 100644
--- a/rackspace/autoscale/v1/webhooks/results.go
+++ b/rackspace/autoscale/v1/webhooks/results.go
@@ -11,6 +11,23 @@
gophercloud.Result
}
+// 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
+// Webhooks from a single page.
+type CreateResult struct {
+ pagination.SinglePageBase
+}
+
+// ExtractWebhooks extracts a slice of Webhooks from a CreateResult.
+func (res CreateResult) ExtractWebhooks() ([]Webhook, error) {
+ if res.Err != nil {
+ return nil, res.Err
+ }
+
+ return commonExtractWebhooks(res.Body)
+}
+
// Webhook represents a webhook associted with a scaling policy.
type Webhook struct {
// UUID for the webhook.
@@ -46,13 +63,15 @@
// ExtractWebhooks interprets the results of a single page from a List() call,
// producing a slice of Webhooks.
func ExtractWebhooks(page pagination.Page) ([]Webhook, error) {
- casted := page.(WebhookPage).Body
+ return commonExtractWebhooks(page.(WebhookPage).Body)
+}
+func commonExtractWebhooks(body interface{}) ([]Webhook, error) {
var response struct {
Webhooks []Webhook `mapstructure:"webhooks"`
}
- err := mapstructure.Decode(casted, &response)
+ err := mapstructure.Decode(body, &response)
if err != nil {
return nil, err
diff --git a/rackspace/autoscale/v1/webhooks/urls.go b/rackspace/autoscale/v1/webhooks/urls.go
index 802db89..90825a0 100644
--- a/rackspace/autoscale/v1/webhooks/urls.go
+++ b/rackspace/autoscale/v1/webhooks/urls.go
@@ -5,3 +5,7 @@
func listURL(c *gophercloud.ServiceClient, groupID, policyID string) string {
return c.ServiceURL("groups", groupID, "policies", policyID, "webhooks")
}
+
+func createURL(c *gophercloud.ServiceClient, groupID, policyID string) string {
+ return c.ServiceURL("groups", groupID, "policies", policyID, "webhooks")
+}