openstack abandon stack op and unit test
diff --git a/openstack/orchestration/v1/stacks/fixtures.go b/openstack/orchestration/v1/stacks/fixtures.go
index 31814cc..72e327d 100644
--- a/openstack/orchestration/v1/stacks/fixtures.go
+++ b/openstack/orchestration/v1/stacks/fixtures.go
@@ -227,7 +227,7 @@
}
// HandleDeleteSuccessfully creates an HTTP handler at `/stacks/postman_stack/16ef0584-4458-41eb-87c8-0dc8d5f66c87`
-// on the test handler mux that responds with an `Delete` response.
+// on the test handler mux that responds with a `Delete` response.
func HandleDeleteSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/stacks/gophercloud-test-stack-2/db6977b2-27aa-4775-9ae7-6213212d4ada", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "DELETE")
@@ -265,7 +265,7 @@
}
// HandlePreviewSuccessfully creates an HTTP handler at `/stacks/preview`
-// on the test handler mux that responds with an `Preview` response.
+// on the test handler mux that responds with a `Preview` response.
func HandlePreviewSuccessfully(t *testing.T, output string) {
th.Mux.HandleFunc("/stacks/preview", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "POST")
@@ -277,3 +277,99 @@
fmt.Fprintf(w, output)
})
}
+
+// AbandonExpected represents the expected object from an Abandon request.
+var AbandonExpected = &AbandonedStack{
+ Status: "COMPLETE",
+ Name: "postman_stack",
+ Template: `
+ {
+ "heat_template_version": "2013-05-23",
+ "description": "Simple template to test heat commands",
+ "parameters": {
+ "flavor": {
+ "default": "m1.tiny",
+ "type": "string"
+ }
+ },
+ "resources": {
+ "hello_world": {
+ "type": "OS::Nova::Server",
+ "properties": {
+ "key_name": "heat_key",
+ "flavor": {
+ "get_param": "flavor"
+ },
+ "image": "ad091b52-742f-469e-8f3c-fd81cadf0743",
+ "user_data": "#!/bin/bash -xv\necho \"hello world\" > /root/hello-world.txt\n"
+ }
+ }
+ }
+ }`,
+ Action: "CREATE",
+ ID: "16ef0584-4458-41eb-87c8-0dc8d5f66c87",
+ Resources: map[string]interface{}{
+ "hello_world": map[string]interface{}{
+ "status": "COMPLETE",
+ "name": "hello_world",
+ "resource_id": "8a310d36-46fc-436f-8be4-37a696b8ac63",
+ "action": "CREATE",
+ "type": "OS::Nova::Server",
+ },
+ },
+}
+
+// AbandonOutput represents the response body from an Abandon request.
+const AbandonOutput = `
+{
+ "status": "COMPLETE",
+ "name": "postman_stack",
+ "template": {
+ "heat_template_version": "2013-05-23",
+ "description": "Simple template to test heat commands",
+ "parameters": {
+ "flavor": {
+ "default": "m1.tiny",
+ "type": "string"
+ }
+ },
+ "resources": {
+ "hello_world": {
+ "type": "OS::Nova::Server",
+ "properties": {
+ "key_name": "heat_key",
+ "flavor": {
+ "get_param": "flavor"
+ },
+ "image": "ad091b52-742f-469e-8f3c-fd81cadf0743",
+ "user_data": "#!/bin/bash -xv\necho \"hello world\" > /root/hello-world.txt\n"
+ }
+ }
+ }
+ },
+ "action": "CREATE",
+ "id": "16ef0584-4458-41eb-87c8-0dc8d5f66c87",
+ "resources": {
+ "hello_world": {
+ "status": "COMPLETE",
+ "name": "hello_world",
+ "resource_id": "8a310d36-46fc-436f-8be4-37a696b8ac63",
+ "action": "CREATE",
+ "type": "OS::Nova::Server",
+ }
+ }
+}`
+
+// HandleAbandonSuccessfully creates an HTTP handler at `/stacks/postman_stack/16ef0584-4458-41eb-87c8-0dc8d5f66c87/abandon`
+// on the test handler mux that responds with an `Abandon` response.
+func HandleAbandonSuccessfully(t *testing.T) {
+ th.Mux.HandleFunc("/stacks/postman_stack/16ef0584-4458-41eb-87c8-0dc8d5f66c87/abandon", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "DELETE")
+ th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+ th.TestHeader(t, r, "Accept", "application/json")
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ fmt.Fprintf(w, AbandonOutput)
+ })
+}
diff --git a/openstack/orchestration/v1/stacks/requests.go b/openstack/orchestration/v1/stacks/requests.go
index 81b4ea0..49f9749 100644
--- a/openstack/orchestration/v1/stacks/requests.go
+++ b/openstack/orchestration/v1/stacks/requests.go
@@ -8,13 +8,16 @@
"github.com/rackspace/gophercloud/pagination"
)
+// Rollback is used to specify whether or not a stack can be rolled back.
type Rollback *bool
var (
- disable = true
+ disable = true
+ // Disable is used to specify that a stack cannot be rolled back.
Disable Rollback = &disable
enable = false
- Enable Rollback = &enable
+ // Enable is used to specify that a stack can be rolled back.
+ Enable Rollback = &enable
)
// CreateOptsBuilder is the interface options structs have to satisfy in order
@@ -517,7 +520,7 @@
var res AbandonResult
// Send request to API
- _, res.Err = perigee.Request("POST", abandonURL(c, stackName, stackID), perigee.Options{
+ _, res.Err = perigee.Request("DELETE", abandonURL(c, stackName, stackID), perigee.Options{
MoreHeaders: c.AuthenticatedHeaders(),
Results: &res.Body,
OkCodes: []int{200},
diff --git a/openstack/orchestration/v1/stacks/requests_test.go b/openstack/orchestration/v1/stacks/requests_test.go
index 1e32ca2..8217529 100644
--- a/openstack/orchestration/v1/stacks/requests_test.go
+++ b/openstack/orchestration/v1/stacks/requests_test.go
@@ -215,3 +215,15 @@
expected := PreviewExpected
th.AssertDeepEquals(t, expected, actual)
}
+
+func TestAbandonStack(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ HandleAbandonSuccessfully(t)
+
+ actual, err := Abandon(fake.ServiceClient(), "postman_stack", "16ef0584-4458-41eb-87c8-0dc8d5f66c87").Extract()
+ th.AssertNoErr(t, err)
+
+ expected := AbandonExpected
+ th.AssertDeepEquals(t, expected, actual)
+}
diff --git a/openstack/orchestration/v1/stacks/results.go b/openstack/orchestration/v1/stacks/results.go
index b648fb2..84d6f9e 100644
--- a/openstack/orchestration/v1/stacks/results.go
+++ b/openstack/orchestration/v1/stacks/results.go
@@ -253,9 +253,33 @@
return res.Stack, err
}
+// AbandonedStack represents the result of an Abandon operation.
type AbandonedStack struct {
+ Status string `mapstructure:"status"`
+ Name string `mapstructure:"name"`
+ Template string `mapstructure:"template"`
+ Action string `mapstructure:"action"`
+ ID string `mapstructure:"id"`
+ Resources map[string]interface{} `mapstructure:"resources"`
}
+// AbandonResult represents the result of an Abandon operation.
type AbandonResult struct {
gophercloud.Result
}
+
+// Extract returns a pointer to an AbandonedStack object and is called after an
+// Abandon operation.
+func (r AbandonResult) Extract() (*AbandonedStack, error) {
+ if r.Err != nil {
+ return nil, r.Err
+ }
+
+ var res AbandonedStack
+
+ if err := mapstructure.Decode(r.Body, &res); err != nil {
+ return nil, err
+ }
+
+ return &res, nil
+}