blob: 2566bb226fe45ac9970ed5f3a4fb33e2c15e0084 [file] [log] [blame]
Jon Perritt35e27e42014-12-05 11:10:46 -07001package stacks
2
3import (
4 "errors"
Pratik Mallya827c03e2015-09-17 00:10:47 -05005 "strings"
Jon Perritt35e27e42014-12-05 11:10:46 -07006
Jon Perritt27249f42016-02-18 10:35:59 -06007 "github.com/gophercloud/gophercloud"
8 "github.com/gophercloud/gophercloud/pagination"
Jon Perritt35e27e42014-12-05 11:10:46 -07009)
10
Jon Perritt9209df42015-02-05 12:55:33 -070011// Rollback is used to specify whether or not a stack can be rolled back.
Jon Perrittb20ba0b2015-02-03 13:13:42 -070012type Rollback *bool
13
14var (
Jon Perritt9209df42015-02-05 12:55:33 -070015 disable = true
16 // Disable is used to specify that a stack cannot be rolled back.
Jon Perrittb20ba0b2015-02-03 13:13:42 -070017 Disable Rollback = &disable
18 enable = false
Jon Perritt9209df42015-02-05 12:55:33 -070019 // Enable is used to specify that a stack can be rolled back.
20 Enable Rollback = &enable
Jon Perrittb20ba0b2015-02-03 13:13:42 -070021)
22
Jon Perritt35e27e42014-12-05 11:10:46 -070023// CreateOptsBuilder is the interface options structs have to satisfy in order
24// to be used in the main Create operation in this package. Since many
25// extensions decorate or modify the common logic, it is useful for them to
26// satisfy a basic interface in order for them to be used.
27type CreateOptsBuilder interface {
28 ToStackCreateMap() (map[string]interface{}, error)
29}
30
31// CreateOpts is the common options struct used in this package's Create
32// operation.
33type CreateOpts struct {
Jon Perritt952f3e12015-02-03 12:13:24 -070034 // (REQUIRED) The name of the stack. It must start with an alphabetic character.
35 Name string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050036 // (REQUIRED) A structure that contains either the template file or url. Call the
37 // associated methods to extract the information relevant to send in a create request.
38 TemplateOpts *Template
39 // (DEPRECATED): Please use TemplateOpts for providing the template. If
40 // TemplateOpts is provided, TemplateURL will be ignored
Jon Perritt952f3e12015-02-03 12:13:24 -070041 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
42 // This value is ignored if Template is supplied inline.
43 TemplateURL string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050044 // (DEPRECATED): Please use TemplateOpts for providing the template. If
45 // TemplateOpts is provided, Template will be ignored
Jon Perritt952f3e12015-02-03 12:13:24 -070046 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
47 // is a stringified version of the JSON/YAML template. Since the template will likely
48 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
49 // import "io/ioutil"
50 // var opts stacks.CreateOpts
51 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
52 // if err != nil {
53 // // handle error...
54 // }
55 // opts.Template = string(b)
56 Template string
57 // (OPTIONAL) Enables or disables deletion of all stack resources when a stack
58 // creation fails. Default is true, meaning all resources are not deleted when
59 // stack creation fails.
Jon Perritt37f97742015-02-04 18:55:05 -070060 DisableRollback Rollback
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050061 // (OPTIONAL) A structure that contains details for the environment of the stack.
62 EnvironmentOpts *Environment
63 // (DEPRECATED): Please use EnvironmentOpts to provide Environment data
Jon Perritt952f3e12015-02-03 12:13:24 -070064 // (OPTIONAL) A stringified JSON environment for the stack.
65 Environment string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050066 // (DEPRECATED): Files is automatically determined
67 // by parsing the template and environment passed as TemplateOpts and
68 // EnvironmentOpts respectively.
Jon Perritt952f3e12015-02-03 12:13:24 -070069 // (OPTIONAL) A map that maps file names to file contents. It can also be used
70 // to pass provider template contents. Example:
71 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
72 Files map[string]interface{}
73 // (OPTIONAL) User-defined parameters to pass to the template.
74 Parameters map[string]string
Jon Perritt91709892015-02-11 17:53:43 -070075 // (OPTIONAL) The timeout for stack creation in minutes.
76 Timeout int
Pratik Mallya827c03e2015-09-17 00:10:47 -050077 // (OPTIONAL) A list of tags to assosciate with the Stack
78 Tags []string
Jon Perritt35e27e42014-12-05 11:10:46 -070079}
80
81// ToStackCreateMap casts a CreateOpts struct to a map.
82func (opts CreateOpts) ToStackCreateMap() (map[string]interface{}, error) {
83 s := make(map[string]interface{})
84
85 if opts.Name == "" {
86 return s, errors.New("Required field 'Name' not provided.")
87 }
88 s["stack_name"] = opts.Name
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050089 Files := make(map[string]string)
90 if opts.TemplateOpts == nil {
91 if opts.Template != "" {
92 s["template"] = opts.Template
93 } else if opts.TemplateURL != "" {
94 s["template_url"] = opts.TemplateURL
95 } else {
96 return s, errors.New("Either Template or TemplateURL must be provided.")
97 }
Jon Perritt35e27e42014-12-05 11:10:46 -070098 } else {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050099 if err := opts.TemplateOpts.Parse(); err != nil {
100 return nil, err
101 }
102
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500103 if err := opts.TemplateOpts.getFileContents(opts.TemplateOpts.Parsed, ignoreIfTemplate, true); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500104 return nil, err
105 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500106 opts.TemplateOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500107 s["template"] = string(opts.TemplateOpts.Bin)
108
109 for k, v := range opts.TemplateOpts.Files {
110 Files[k] = v
111 }
112 }
113 if opts.DisableRollback != nil {
114 s["disable_rollback"] = &opts.DisableRollback
115 }
116
117 if opts.EnvironmentOpts != nil {
118 if err := opts.EnvironmentOpts.Parse(); err != nil {
119 return nil, err
120 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500121 if err := opts.EnvironmentOpts.getRRFileContents(ignoreIfEnvironment); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500122 return nil, err
123 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500124 opts.EnvironmentOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500125 for k, v := range opts.EnvironmentOpts.Files {
126 Files[k] = v
127 }
128 s["environment"] = string(opts.EnvironmentOpts.Bin)
129 } else if opts.Environment != "" {
130 s["environment"] = opts.Environment
131 }
132
133 if opts.Files != nil {
134 s["files"] = opts.Files
135 } else {
136 s["files"] = Files
Jon Perritt35e27e42014-12-05 11:10:46 -0700137 }
138
139 if opts.DisableRollback != nil {
140 s["disable_rollback"] = &opts.DisableRollback
141 }
142
Jon Perritt35e27e42014-12-05 11:10:46 -0700143 if opts.Parameters != nil {
144 s["parameters"] = opts.Parameters
145 }
146
Jon Perritt91709892015-02-11 17:53:43 -0700147 if opts.Timeout != 0 {
148 s["timeout_mins"] = opts.Timeout
Jon Perritt35e27e42014-12-05 11:10:46 -0700149 }
150
Pratik Mallya827c03e2015-09-17 00:10:47 -0500151 if opts.Tags != nil {
152 s["tags"] = strings.Join(opts.Tags, ",")
153 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700154 return s, nil
155}
156
157// Create accepts a CreateOpts struct and creates a new stack using the values
158// provided.
159func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
160 var res CreateResult
161
162 reqBody, err := opts.ToStackCreateMap()
163 if err != nil {
164 res.Err = err
165 return res
166 }
167
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100168 _, res.Err = c.Post(createURL(c), reqBody, &res.Body, nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700169 return res
170}
171
172// AdoptOptsBuilder is the interface options structs have to satisfy in order
173// to be used in the Adopt function in this package. Since many
174// extensions decorate or modify the common logic, it is useful for them to
175// satisfy a basic interface in order for them to be used.
176type AdoptOptsBuilder interface {
177 ToStackAdoptMap() (map[string]interface{}, error)
178}
179
180// AdoptOpts is the common options struct used in this package's Adopt
181// operation.
182type AdoptOpts struct {
Jon Perritt9741dd92015-02-04 12:05:47 -0700183 // (REQUIRED) Existing resources data represented as a string to add to the
184 // new stack. Data returned by Abandon could be provided as AdoptsStackData.
185 AdoptStackData string
186 // (REQUIRED) The name of the stack. It must start with an alphabetic character.
187 Name string
188 // (REQUIRED) The timeout for stack creation in minutes.
189 Timeout int
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500190 // (REQUIRED) A structure that contains either the template file or url. Call the
191 // associated methods to extract the information relevant to send in a create request.
192 TemplateOpts *Template
193 // (DEPRECATED): Please use TemplateOpts for providing the template. If
194 // TemplateOpts is provided, TemplateURL will be ignored
Jon Perritt9741dd92015-02-04 12:05:47 -0700195 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
196 // This value is ignored if Template is supplied inline.
197 TemplateURL string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500198 // (DEPRECATED): Please use TemplateOpts for providing the template. If
199 // TemplateOpts is provided, Template will be ignored
Jon Perritt9741dd92015-02-04 12:05:47 -0700200 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
201 // is a stringified version of the JSON/YAML template. Since the template will likely
202 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
203 // import "io/ioutil"
204 // var opts stacks.CreateOpts
205 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
206 // if err != nil {
207 // // handle error...
208 // }
209 // opts.Template = string(b)
210 Template string
211 // (OPTIONAL) Enables or disables deletion of all stack resources when a stack
212 // creation fails. Default is true, meaning all resources are not deleted when
213 // stack creation fails.
Jon Perritt37f97742015-02-04 18:55:05 -0700214 DisableRollback Rollback
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500215 // (OPTIONAL) A structure that contains details for the environment of the stack.
216 EnvironmentOpts *Environment
217 // (DEPRECATED): Please use EnvironmentOpts to provide Environment data
Jon Perritt9741dd92015-02-04 12:05:47 -0700218 // (OPTIONAL) A stringified JSON environment for the stack.
219 Environment string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500220 // (DEPRECATED): Files is automatically determined
221 // by parsing the template and environment passed as TemplateOpts and
222 // EnvironmentOpts respectively.
Jon Perritt9741dd92015-02-04 12:05:47 -0700223 // (OPTIONAL) A map that maps file names to file contents. It can also be used
224 // to pass provider template contents. Example:
225 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
226 Files map[string]interface{}
227 // (OPTIONAL) User-defined parameters to pass to the template.
228 Parameters map[string]string
Jon Perritt35e27e42014-12-05 11:10:46 -0700229}
230
231// ToStackAdoptMap casts a CreateOpts struct to a map.
232func (opts AdoptOpts) ToStackAdoptMap() (map[string]interface{}, error) {
233 s := make(map[string]interface{})
234
235 if opts.Name == "" {
236 return s, errors.New("Required field 'Name' not provided.")
237 }
238 s["stack_name"] = opts.Name
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500239 Files := make(map[string]string)
Pratik Mallya7e6b7b92015-09-30 19:03:08 -0500240 if opts.AdoptStackData != "" {
241 s["adopt_stack_data"] = opts.AdoptStackData
242 } else if opts.TemplateOpts == nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500243 if opts.Template != "" {
244 s["template"] = opts.Template
245 } else if opts.TemplateURL != "" {
246 s["template_url"] = opts.TemplateURL
247 } else {
Pratik Mallya7e6b7b92015-09-30 19:03:08 -0500248 return s, errors.New("One of AdoptStackData, Template, TemplateURL or TemplateOpts must be provided.")
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500249 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700250 } else {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500251 if err := opts.TemplateOpts.Parse(); err != nil {
252 return nil, err
253 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700254
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500255 if err := opts.TemplateOpts.getFileContents(opts.TemplateOpts.Parsed, ignoreIfTemplate, true); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500256 return nil, err
257 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500258 opts.TemplateOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500259 s["template"] = string(opts.TemplateOpts.Bin)
260
261 for k, v := range opts.TemplateOpts.Files {
262 Files[k] = v
263 }
264 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700265
266 if opts.DisableRollback != nil {
267 s["disable_rollback"] = &opts.DisableRollback
268 }
269
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500270 if opts.EnvironmentOpts != nil {
271 if err := opts.EnvironmentOpts.Parse(); err != nil {
272 return nil, err
273 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500274 if err := opts.EnvironmentOpts.getRRFileContents(ignoreIfEnvironment); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500275 return nil, err
276 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500277 opts.EnvironmentOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500278 for k, v := range opts.EnvironmentOpts.Files {
279 Files[k] = v
280 }
281 s["environment"] = string(opts.EnvironmentOpts.Bin)
282 } else if opts.Environment != "" {
Jon Perritt35e27e42014-12-05 11:10:46 -0700283 s["environment"] = opts.Environment
284 }
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500285
Jon Perritt35e27e42014-12-05 11:10:46 -0700286 if opts.Files != nil {
287 s["files"] = opts.Files
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500288 } else {
289 s["files"] = Files
Jon Perritt35e27e42014-12-05 11:10:46 -0700290 }
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500291
Jon Perritt35e27e42014-12-05 11:10:46 -0700292 if opts.Parameters != nil {
293 s["parameters"] = opts.Parameters
294 }
295
Pratik Mallya827c03e2015-09-17 00:10:47 -0500296 if opts.Timeout != 0 {
297 s["timeout"] = opts.Timeout
Jon Perritt35e27e42014-12-05 11:10:46 -0700298 }
Jon Perritt9741dd92015-02-04 12:05:47 -0700299 s["timeout_mins"] = opts.Timeout
Jon Perritt35e27e42014-12-05 11:10:46 -0700300
Pratik Mallya827c03e2015-09-17 00:10:47 -0500301 return s, nil
Jon Perritt35e27e42014-12-05 11:10:46 -0700302}
303
304// Adopt accepts an AdoptOpts struct and creates a new stack using the resources
305// from another stack.
Jon Perritt9741dd92015-02-04 12:05:47 -0700306func Adopt(c *gophercloud.ServiceClient, opts AdoptOptsBuilder) AdoptResult {
307 var res AdoptResult
Jon Perritt35e27e42014-12-05 11:10:46 -0700308
309 reqBody, err := opts.ToStackAdoptMap()
310 if err != nil {
311 res.Err = err
312 return res
313 }
314
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100315 _, res.Err = c.Post(adoptURL(c), reqBody, &res.Body, nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700316 return res
317}
318
319// SortDir is a type for specifying in which direction to sort a list of stacks.
320type SortDir string
321
322// SortKey is a type for specifying by which key to sort a list of stacks.
323type SortKey string
324
325var (
326 // SortAsc is used to sort a list of stacks in ascending order.
327 SortAsc SortDir = "asc"
328 // SortDesc is used to sort a list of stacks in descending order.
329 SortDesc SortDir = "desc"
330 // SortName is used to sort a list of stacks by name.
331 SortName SortKey = "name"
332 // SortStatus is used to sort a list of stacks by status.
333 SortStatus SortKey = "status"
334 // SortCreatedAt is used to sort a list of stacks by date created.
335 SortCreatedAt SortKey = "created_at"
336 // SortUpdatedAt is used to sort a list of stacks by date updated.
337 SortUpdatedAt SortKey = "updated_at"
338)
339
340// ListOptsBuilder allows extensions to add additional parameters to the
341// List request.
342type ListOptsBuilder interface {
343 ToStackListQuery() (string, error)
344}
345
346// ListOpts allows the filtering and sorting of paginated collections through
347// the API. Filtering is achieved by passing in struct field values that map to
348// the network attributes you want to see returned. SortKey allows you to sort
349// by a particular network attribute. SortDir sets the direction, and is either
350// `asc' or `desc'. Marker and Limit are used for pagination.
351type ListOpts struct {
352 Status string `q:"status"`
353 Name string `q:"name"`
354 Marker string `q:"marker"`
355 Limit int `q:"limit"`
356 SortKey SortKey `q:"sort_keys"`
357 SortDir SortDir `q:"sort_dir"`
358}
359
360// ToStackListQuery formats a ListOpts into a query string.
361func (opts ListOpts) ToStackListQuery() (string, error) {
362 q, err := gophercloud.BuildQueryString(opts)
363 if err != nil {
364 return "", err
365 }
366 return q.String(), nil
367}
368
369// List returns a Pager which allows you to iterate over a collection of
370// stacks. It accepts a ListOpts struct, which allows you to filter and sort
371// the returned collection for greater efficiency.
372func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
373 url := listURL(c)
374 if opts != nil {
375 query, err := opts.ToStackListQuery()
376 if err != nil {
377 return pagination.Pager{Err: err}
378 }
379 url += query
380 }
381
382 createPage := func(r pagination.PageResult) pagination.Page {
383 return StackPage{pagination.SinglePageBase(r)}
384 }
385 return pagination.NewPager(c, url, createPage)
386}
387
388// Get retreives a stack based on the stack name and stack ID.
389func Get(c *gophercloud.ServiceClient, stackName, stackID string) GetResult {
390 var res GetResult
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100391 _, res.Err = c.Get(getURL(c, stackName, stackID), &res.Body, nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700392 return res
393}
394
395// UpdateOptsBuilder is the interface options structs have to satisfy in order
396// to be used in the Update operation in this package.
397type UpdateOptsBuilder interface {
398 ToStackUpdateMap() (map[string]interface{}, error)
399}
400
401// UpdateOpts contains the common options struct used in this package's Update
402// operation.
403type UpdateOpts struct {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500404 // (REQUIRED) A structure that contains either the template file or url. Call the
405 // associated methods to extract the information relevant to send in a create request.
406 TemplateOpts *Template
407 // (DEPRECATED): Please use TemplateOpts for providing the template. If
408 // TemplateOpts is provided, TemplateURL will be ignored
Jon Perritt37f97742015-02-04 18:55:05 -0700409 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
410 // This value is ignored if Template is supplied inline.
Jon Perritt35e27e42014-12-05 11:10:46 -0700411 TemplateURL string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500412 // (DEPRECATED): Please use TemplateOpts for providing the template. If
413 // TemplateOpts is provided, Template will be ignored
Jon Perritt37f97742015-02-04 18:55:05 -0700414 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
415 // is a stringified version of the JSON/YAML template. Since the template will likely
416 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
417 // import "io/ioutil"
418 // var opts stacks.CreateOpts
419 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
420 // if err != nil {
421 // // handle error...
422 // }
423 // opts.Template = string(b)
424 Template string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500425 // (OPTIONAL) A structure that contains details for the environment of the stack.
426 EnvironmentOpts *Environment
427 // (DEPRECATED): Please use EnvironmentOpts to provide Environment data
Jon Perritt37f97742015-02-04 18:55:05 -0700428 // (OPTIONAL) A stringified JSON environment for the stack.
429 Environment string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500430 // (DEPRECATED): Files is automatically determined
431 // by parsing the template and environment passed as TemplateOpts and
432 // EnvironmentOpts respectively.
Jon Perritt37f97742015-02-04 18:55:05 -0700433 // (OPTIONAL) A map that maps file names to file contents. It can also be used
434 // to pass provider template contents. Example:
435 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
436 Files map[string]interface{}
437 // (OPTIONAL) User-defined parameters to pass to the template.
438 Parameters map[string]string
Jon Perritt51107182015-02-11 18:18:19 -0700439 // (OPTIONAL) The timeout for stack creation in minutes.
440 Timeout int
Pratik Mallya827c03e2015-09-17 00:10:47 -0500441 // (OPTIONAL) A list of tags to assosciate with the Stack
442 Tags []string
Jon Perritt35e27e42014-12-05 11:10:46 -0700443}
444
445// ToStackUpdateMap casts a CreateOpts struct to a map.
446func (opts UpdateOpts) ToStackUpdateMap() (map[string]interface{}, error) {
447 s := make(map[string]interface{})
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500448 Files := make(map[string]string)
449 if opts.TemplateOpts == nil {
450 if opts.Template != "" {
451 s["template"] = opts.Template
452 } else if opts.TemplateURL != "" {
453 s["template_url"] = opts.TemplateURL
454 } else {
455 return s, errors.New("Either Template or TemplateURL must be provided.")
456 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700457 } else {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500458 if err := opts.TemplateOpts.Parse(); err != nil {
459 return nil, err
460 }
461
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500462 if err := opts.TemplateOpts.getFileContents(opts.TemplateOpts.Parsed, ignoreIfTemplate, true); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500463 return nil, err
464 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500465 opts.TemplateOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500466 s["template"] = string(opts.TemplateOpts.Bin)
467
468 for k, v := range opts.TemplateOpts.Files {
469 Files[k] = v
470 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700471 }
472
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500473 if opts.EnvironmentOpts != nil {
474 if err := opts.EnvironmentOpts.Parse(); err != nil {
475 return nil, err
476 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500477 if err := opts.EnvironmentOpts.getRRFileContents(ignoreIfEnvironment); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500478 return nil, err
479 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500480 opts.EnvironmentOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500481 for k, v := range opts.EnvironmentOpts.Files {
482 Files[k] = v
483 }
484 s["environment"] = string(opts.EnvironmentOpts.Bin)
485 } else if opts.Environment != "" {
Jon Perritt35e27e42014-12-05 11:10:46 -0700486 s["environment"] = opts.Environment
487 }
488
489 if opts.Files != nil {
490 s["files"] = opts.Files
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500491 } else {
492 s["files"] = Files
Jon Perritt35e27e42014-12-05 11:10:46 -0700493 }
494
495 if opts.Parameters != nil {
496 s["parameters"] = opts.Parameters
497 }
498
499 if opts.Timeout != 0 {
500 s["timeout_mins"] = opts.Timeout
501 }
502
Pratik Mallya827c03e2015-09-17 00:10:47 -0500503 if opts.Tags != nil {
504 s["tags"] = strings.Join(opts.Tags, ",")
505 }
506
Jon Perritt35e27e42014-12-05 11:10:46 -0700507 return s, nil
508}
509
510// Update accepts an UpdateOpts struct and updates an existing stack using the values
511// provided.
512func Update(c *gophercloud.ServiceClient, stackName, stackID string, opts UpdateOptsBuilder) UpdateResult {
513 var res UpdateResult
514
515 reqBody, err := opts.ToStackUpdateMap()
516 if err != nil {
517 res.Err = err
518 return res
519 }
520
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100521 _, res.Err = c.Put(updateURL(c, stackName, stackID), reqBody, nil, nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700522 return res
523}
524
525// Delete deletes a stack based on the stack name and stack ID.
526func Delete(c *gophercloud.ServiceClient, stackName, stackID string) DeleteResult {
527 var res DeleteResult
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100528 _, res.Err = c.Delete(deleteURL(c, stackName, stackID), nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700529 return res
530}
531
532// PreviewOptsBuilder is the interface options structs have to satisfy in order
533// to be used in the Preview operation in this package.
534type PreviewOptsBuilder interface {
535 ToStackPreviewMap() (map[string]interface{}, error)
536}
537
538// PreviewOpts contains the common options struct used in this package's Preview
539// operation.
540type PreviewOpts struct {
Jon Perritt37f97742015-02-04 18:55:05 -0700541 // (REQUIRED) The name of the stack. It must start with an alphabetic character.
542 Name string
543 // (REQUIRED) The timeout for stack creation in minutes.
544 Timeout int
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500545 // (REQUIRED) A structure that contains either the template file or url. Call the
546 // associated methods to extract the information relevant to send in a create request.
547 TemplateOpts *Template
548 // (DEPRECATED): Please use TemplateOpts for providing the template. If
549 // TemplateOpts is provided, TemplateURL will be ignored
Jon Perritt37f97742015-02-04 18:55:05 -0700550 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
551 // This value is ignored if Template is supplied inline.
552 TemplateURL string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500553 // (DEPRECATED): Please use TemplateOpts for providing the template. If
554 // TemplateOpts is provided, Template will be ignored
Jon Perritt37f97742015-02-04 18:55:05 -0700555 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
556 // is a stringified version of the JSON/YAML template. Since the template will likely
557 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
558 // import "io/ioutil"
559 // var opts stacks.CreateOpts
560 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
561 // if err != nil {
562 // // handle error...
563 // }
564 // opts.Template = string(b)
565 Template string
566 // (OPTIONAL) Enables or disables deletion of all stack resources when a stack
567 // creation fails. Default is true, meaning all resources are not deleted when
568 // stack creation fails.
569 DisableRollback Rollback
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500570 // (OPTIONAL) A structure that contains details for the environment of the stack.
571 EnvironmentOpts *Environment
572 // (DEPRECATED): Please use EnvironmentOpts to provide Environment data
Jon Perritt37f97742015-02-04 18:55:05 -0700573 // (OPTIONAL) A stringified JSON environment for the stack.
574 Environment string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500575 // (DEPRECATED): Files is automatically determined
576 // by parsing the template and environment passed as TemplateOpts and
577 // EnvironmentOpts respectively.
Jon Perritt37f97742015-02-04 18:55:05 -0700578 // (OPTIONAL) A map that maps file names to file contents. It can also be used
579 // to pass provider template contents. Example:
580 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
581 Files map[string]interface{}
582 // (OPTIONAL) User-defined parameters to pass to the template.
583 Parameters map[string]string
Jon Perritt35e27e42014-12-05 11:10:46 -0700584}
585
586// ToStackPreviewMap casts a PreviewOpts struct to a map.
587func (opts PreviewOpts) ToStackPreviewMap() (map[string]interface{}, error) {
588 s := make(map[string]interface{})
589
590 if opts.Name == "" {
591 return s, errors.New("Required field 'Name' not provided.")
592 }
593 s["stack_name"] = opts.Name
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500594 Files := make(map[string]string)
595 if opts.TemplateOpts == nil {
596 if opts.Template != "" {
597 s["template"] = opts.Template
598 } else if opts.TemplateURL != "" {
599 s["template_url"] = opts.TemplateURL
600 } else {
601 return s, errors.New("Either Template or TemplateURL must be provided.")
602 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700603 } else {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500604 if err := opts.TemplateOpts.Parse(); err != nil {
605 return nil, err
606 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700607
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500608 if err := opts.TemplateOpts.getFileContents(opts.TemplateOpts.Parsed, ignoreIfTemplate, true); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500609 return nil, err
610 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500611 opts.TemplateOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500612 s["template"] = string(opts.TemplateOpts.Bin)
613
614 for k, v := range opts.TemplateOpts.Files {
615 Files[k] = v
616 }
617 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700618 if opts.DisableRollback != nil {
619 s["disable_rollback"] = &opts.DisableRollback
620 }
621
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500622 if opts.EnvironmentOpts != nil {
623 if err := opts.EnvironmentOpts.Parse(); err != nil {
624 return nil, err
625 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500626 if err := opts.EnvironmentOpts.getRRFileContents(ignoreIfEnvironment); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500627 return nil, err
628 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500629 opts.EnvironmentOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500630 for k, v := range opts.EnvironmentOpts.Files {
631 Files[k] = v
632 }
633 s["environment"] = string(opts.EnvironmentOpts.Bin)
634 } else if opts.Environment != "" {
Jon Perritt35e27e42014-12-05 11:10:46 -0700635 s["environment"] = opts.Environment
636 }
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500637
Jon Perritt35e27e42014-12-05 11:10:46 -0700638 if opts.Files != nil {
639 s["files"] = opts.Files
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500640 } else {
641 s["files"] = Files
Jon Perritt35e27e42014-12-05 11:10:46 -0700642 }
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500643
Jon Perritt35e27e42014-12-05 11:10:46 -0700644 if opts.Parameters != nil {
645 s["parameters"] = opts.Parameters
646 }
647
648 if opts.Timeout != 0 {
649 s["timeout_mins"] = opts.Timeout
650 }
651
652 return s, nil
653}
654
655// Preview accepts a PreviewOptsBuilder interface and creates a preview of a stack using the values
656// provided.
657func Preview(c *gophercloud.ServiceClient, opts PreviewOptsBuilder) PreviewResult {
658 var res PreviewResult
659
660 reqBody, err := opts.ToStackPreviewMap()
661 if err != nil {
662 res.Err = err
663 return res
664 }
665
666 // Send request to API
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100667 _, res.Err = c.Post(previewURL(c), reqBody, &res.Body, &gophercloud.RequestOpts{
668 OkCodes: []int{200},
Jon Perritt35e27e42014-12-05 11:10:46 -0700669 })
670 return res
671}
672
673// Abandon deletes the stack with the provided stackName and stackID, but leaves its
674// resources intact, and returns data describing the stack and its resources.
675func Abandon(c *gophercloud.ServiceClient, stackName, stackID string) AbandonResult {
676 var res AbandonResult
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100677 _, res.Err = c.Delete(abandonURL(c, stackName, stackID), &gophercloud.RequestOpts{
Ash Wilsondecfed72015-02-13 09:14:55 -0500678 JSONResponse: &res.Body,
679 OkCodes: []int{200},
Jon Perritt35e27e42014-12-05 11:10:46 -0700680 })
681 return res
682}