openstack preview stack op and unit test
diff --git a/openstack/orchestration/v1/stacks/fixtures.go b/openstack/orchestration/v1/stacks/fixtures.go
index 3809583..31814cc 100644
--- a/openstack/orchestration/v1/stacks/fixtures.go
+++ b/openstack/orchestration/v1/stacks/fixtures.go
@@ -238,3 +238,42 @@
w.WriteHeader(http.StatusNoContent)
})
}
+
+// GetExpected represents the expected object from a Get request.
+var PreviewExpected = &PreviewedStack{
+ DisableRollback: true,
+ Description: "Simple template to test heat commands",
+ Parameters: map[string]string{
+ "flavor": "m1.tiny",
+ "OS::stack_name": "postman_stack",
+ "OS::stack_id": "16ef0584-4458-41eb-87c8-0dc8d5f66c87",
+ },
+ StatusReason: "Stack CREATE completed successfully",
+ Name: "postman_stack",
+ CreationTime: time.Date(2015, 2, 3, 20, 7, 39, 0, time.UTC),
+ Links: []gophercloud.Link{
+ gophercloud.Link{
+ Href: "http://166.76.160.117:8004/v1/98606384f58d4ad0b3db7d0d779549ac/stacks/postman_stack/16ef0584-4458-41eb-87c8-0dc8d5f66c87",
+ Rel: "self",
+ },
+ },
+ Capabilities: []interface{}{},
+ NotificationTopics: []interface{}{},
+ Status: "CREATE_COMPLETE",
+ ID: "16ef0584-4458-41eb-87c8-0dc8d5f66c87",
+ TemplateDescription: "Simple template to test heat commands",
+}
+
+// HandlePreviewSuccessfully creates an HTTP handler at `/stacks/preview`
+// on the test handler mux that responds with an `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")
+ 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, output)
+ })
+}
diff --git a/openstack/orchestration/v1/stacks/requests.go b/openstack/orchestration/v1/stacks/requests.go
index 8d27e7b..81b4ea0 100644
--- a/openstack/orchestration/v1/stacks/requests.go
+++ b/openstack/orchestration/v1/stacks/requests.go
@@ -49,7 +49,7 @@
// (OPTIONAL) Enables or disables deletion of all stack resources when a stack
// creation fails. Default is true, meaning all resources are not deleted when
// stack creation fails.
- DisableRollback *bool
+ DisableRollback Rollback
// (OPTIONAL) A stringified JSON environment for the stack.
Environment string
// (OPTIONAL) A map that maps file names to file contents. It can also be used
@@ -155,7 +155,7 @@
// (OPTIONAL) Enables or disables deletion of all stack resources when a stack
// creation fails. Default is true, meaning all resources are not deleted when
// stack creation fails.
- DisableRollback *bool
+ DisableRollback Rollback
// (OPTIONAL) A stringified JSON environment for the stack.
Environment string
// (OPTIONAL) A map that maps file names to file contents. It can also be used
@@ -322,12 +322,30 @@
// UpdateOpts contains the common options struct used in this package's Update
// operation.
type UpdateOpts struct {
- Environment string
- Files map[string]interface{}
- Parameters map[string]string
- Template string
+ // (REQUIRED) The timeout for stack creation in minutes.
+ Timeout int
+ // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
+ // This value is ignored if Template is supplied inline.
TemplateURL string
- Timeout int
+ // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
+ // is a stringified version of the JSON/YAML template. Since the template will likely
+ // be located in a file, one way to set this variable is by using ioutil.ReadFile:
+ // import "io/ioutil"
+ // var opts stacks.CreateOpts
+ // b, err := ioutil.ReadFile("path/to/you/template/file.json")
+ // if err != nil {
+ // // handle error...
+ // }
+ // opts.Template = string(b)
+ Template string
+ // (OPTIONAL) A stringified JSON environment for the stack.
+ Environment string
+ // (OPTIONAL) A map that maps file names to file contents. It can also be used
+ // to pass provider template contents. Example:
+ // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
+ Files map[string]interface{}
+ // (OPTIONAL) User-defined parameters to pass to the template.
+ Parameters map[string]string
}
// ToStackUpdateMap casts a CreateOpts struct to a map.
@@ -402,14 +420,36 @@
// PreviewOpts contains the common options struct used in this package's Preview
// operation.
type PreviewOpts struct {
- DisableRollback *bool
- Environment string
- Files map[string]interface{}
- Name string
- Parameters map[string]string
- Template string
- TemplateURL string
- Timeout int
+ // (REQUIRED) The name of the stack. It must start with an alphabetic character.
+ Name string
+ // (REQUIRED) The timeout for stack creation in minutes.
+ Timeout int
+ // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
+ // This value is ignored if Template is supplied inline.
+ TemplateURL string
+ // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
+ // is a stringified version of the JSON/YAML template. Since the template will likely
+ // be located in a file, one way to set this variable is by using ioutil.ReadFile:
+ // import "io/ioutil"
+ // var opts stacks.CreateOpts
+ // b, err := ioutil.ReadFile("path/to/you/template/file.json")
+ // if err != nil {
+ // // handle error...
+ // }
+ // opts.Template = string(b)
+ Template string
+ // (OPTIONAL) Enables or disables deletion of all stack resources when a stack
+ // creation fails. Default is true, meaning all resources are not deleted when
+ // stack creation fails.
+ DisableRollback Rollback
+ // (OPTIONAL) A stringified JSON environment for the stack.
+ Environment string
+ // (OPTIONAL) A map that maps file names to file contents. It can also be used
+ // to pass provider template contents. Example:
+ // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
+ Files map[string]interface{}
+ // (OPTIONAL) User-defined parameters to pass to the template.
+ Parameters map[string]string
}
// ToStackPreviewMap casts a PreviewOpts struct to a map.
diff --git a/openstack/orchestration/v1/stacks/requests_test.go b/openstack/orchestration/v1/stacks/requests_test.go
index cbaa1e0..1e32ca2 100644
--- a/openstack/orchestration/v1/stacks/requests_test.go
+++ b/openstack/orchestration/v1/stacks/requests_test.go
@@ -171,3 +171,47 @@
err := Delete(fake.ServiceClient(), "gophercloud-test-stack-2", "db6977b2-27aa-4775-9ae7-6213212d4ada").ExtractErr()
th.AssertNoErr(t, err)
}
+
+func TestPreviewStack(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ HandlePreviewSuccessfully(t, GetOutput)
+
+ previewOpts := PreviewOpts{
+ Name: "stackcreated",
+ Timeout: 60,
+ Template: `
+ {
+ "stack_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"
+ }
+ }
+ }
+ }
+ }`,
+ DisableRollback: Disable,
+ }
+ actual, err := Preview(fake.ServiceClient(), previewOpts).Extract()
+ th.AssertNoErr(t, err)
+
+ expected := PreviewExpected
+ th.AssertDeepEquals(t, expected, actual)
+}
diff --git a/openstack/orchestration/v1/stacks/results.go b/openstack/orchestration/v1/stacks/results.go
index d69031c..b648fb2 100644
--- a/openstack/orchestration/v1/stacks/results.go
+++ b/openstack/orchestration/v1/stacks/results.go
@@ -184,28 +184,32 @@
gophercloud.ErrResult
}
+// PreviewedStack represents the result of a Preview operation.
type PreviewedStack struct {
- Capabilities []interface{} `mapstructure:"capabilities"`
- CreationTime time.Time `mapstructure:"-"`
- Description string `mapstructure:"description"`
- DisableRollback bool `mapstructure:"disable_rollback"`
- ID string `mapstructure:"id"`
- Links []gophercloud.Link `mapstructure:"links"`
- Name string `mapstructure:"stack_name"`
- NotificationTopics []interface{} `mapstructure:"notification_topics"`
- Parameters map[string]string `mapstructure:"parameters"`
- Resources []map[string]string `mapstructure:"resources"`
- Status string `mapstructure:"stack_status"`
- StausReason string `mapstructure:"stack_status_reason"`
- TemplateDescription string `mapstructure:"template_description"`
- Timeout int `mapstructure:"timeout_mins"`
- UpdatedTime time.Time `mapstructure:"-"`
+ Capabilities []interface{} `mapstructure:"capabilities"`
+ CreationTime time.Time `mapstructure:"-"`
+ Description string `mapstructure:"description"`
+ DisableRollback bool `mapstructure:"disable_rollback"`
+ ID string `mapstructure:"id"`
+ Links []gophercloud.Link `mapstructure:"links"`
+ Name string `mapstructure:"stack_name"`
+ NotificationTopics []interface{} `mapstructure:"notification_topics"`
+ Parameters map[string]string `mapstructure:"parameters"`
+ Resources []map[string]interface{} `mapstructure:"resources"`
+ Status string `mapstructure:"stack_status"`
+ StatusReason string `mapstructure:"stack_status_reason"`
+ TemplateDescription string `mapstructure:"template_description"`
+ Timeout int `mapstructure:"timeout_mins"`
+ UpdatedTime time.Time `mapstructure:"-"`
}
+// PreviewResult represents the result of a Preview operation.
type PreviewResult struct {
gophercloud.Result
}
+// Extract returns a pointer to a PreviewedStack object and is called after a
+// Preview operation.
func (r PreviewResult) Extract() (*PreviewedStack, error) {
if r.Err != nil {
return nil, r.Err