blob: 650763cc6577842b638b04ffcfe006690bf644a4 [file] [log] [blame]
Jon Perritt35e27e42014-12-05 11:10:46 -07001package stacks
2
3import (
Pratik Mallya827c03e2015-09-17 00:10:47 -05004 "strings"
Jon Perritt35e27e42014-12-05 11:10:46 -07005
Jon Perritt27249f42016-02-18 10:35:59 -06006 "github.com/gophercloud/gophercloud"
7 "github.com/gophercloud/gophercloud/pagination"
Jon Perritt35e27e42014-12-05 11:10:46 -07008)
9
Jon Perritt9209df42015-02-05 12:55:33 -070010// Rollback is used to specify whether or not a stack can be rolled back.
Jon Perrittb20ba0b2015-02-03 13:13:42 -070011type Rollback *bool
12
13var (
Jon Perritt9209df42015-02-05 12:55:33 -070014 disable = true
15 // Disable is used to specify that a stack cannot be rolled back.
Jon Perrittb20ba0b2015-02-03 13:13:42 -070016 Disable Rollback = &disable
17 enable = false
Jon Perritt9209df42015-02-05 12:55:33 -070018 // Enable is used to specify that a stack can be rolled back.
19 Enable Rollback = &enable
Jon Perrittb20ba0b2015-02-03 13:13:42 -070020)
21
Jon Perritt35e27e42014-12-05 11:10:46 -070022// CreateOptsBuilder is the interface options structs have to satisfy in order
23// to be used in the main Create operation in this package. Since many
24// extensions decorate or modify the common logic, it is useful for them to
25// satisfy a basic interface in order for them to be used.
26type CreateOptsBuilder interface {
27 ToStackCreateMap() (map[string]interface{}, error)
28}
29
30// CreateOpts is the common options struct used in this package's Create
31// operation.
32type CreateOpts struct {
Jon Perritt952f3e12015-02-03 12:13:24 -070033 // (REQUIRED) The name of the stack. It must start with an alphabetic character.
34 Name string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050035 // (REQUIRED) A structure that contains either the template file or url. Call the
36 // associated methods to extract the information relevant to send in a create request.
37 TemplateOpts *Template
38 // (DEPRECATED): Please use TemplateOpts for providing the template. If
39 // TemplateOpts is provided, TemplateURL will be ignored
Jon Perritt952f3e12015-02-03 12:13:24 -070040 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
41 // This value is ignored if Template is supplied inline.
42 TemplateURL string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050043 // (DEPRECATED): Please use TemplateOpts for providing the template. If
44 // TemplateOpts is provided, Template will be ignored
Jon Perritt952f3e12015-02-03 12:13:24 -070045 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
46 // is a stringified version of the JSON/YAML template. Since the template will likely
47 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
48 // import "io/ioutil"
49 // var opts stacks.CreateOpts
50 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
51 // if err != nil {
52 // // handle error...
53 // }
54 // opts.Template = string(b)
55 Template string
56 // (OPTIONAL) Enables or disables deletion of all stack resources when a stack
57 // creation fails. Default is true, meaning all resources are not deleted when
58 // stack creation fails.
Jon Perritt37f97742015-02-04 18:55:05 -070059 DisableRollback Rollback
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050060 // (OPTIONAL) A structure that contains details for the environment of the stack.
61 EnvironmentOpts *Environment
62 // (DEPRECATED): Please use EnvironmentOpts to provide Environment data
Jon Perritt952f3e12015-02-03 12:13:24 -070063 // (OPTIONAL) A stringified JSON environment for the stack.
64 Environment string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050065 // (DEPRECATED): Files is automatically determined
66 // by parsing the template and environment passed as TemplateOpts and
67 // EnvironmentOpts respectively.
Jon Perritt952f3e12015-02-03 12:13:24 -070068 // (OPTIONAL) A map that maps file names to file contents. It can also be used
69 // to pass provider template contents. Example:
70 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
71 Files map[string]interface{}
72 // (OPTIONAL) User-defined parameters to pass to the template.
73 Parameters map[string]string
Jon Perritt91709892015-02-11 17:53:43 -070074 // (OPTIONAL) The timeout for stack creation in minutes.
75 Timeout int
Pratik Mallya827c03e2015-09-17 00:10:47 -050076 // (OPTIONAL) A list of tags to assosciate with the Stack
77 Tags []string
Jon Perritt35e27e42014-12-05 11:10:46 -070078}
79
80// ToStackCreateMap casts a CreateOpts struct to a map.
81func (opts CreateOpts) ToStackCreateMap() (map[string]interface{}, error) {
82 s := make(map[string]interface{})
83
84 if opts.Name == "" {
Jon Perritt58611da2016-03-09 00:49:57 -060085 err := gophercloud.ErrMissingInput{}
86 err.Argument = "stacks.CreateOpts.Name"
87 return nil, err
Jon Perritt35e27e42014-12-05 11:10:46 -070088 }
89 s["stack_name"] = opts.Name
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050090 Files := make(map[string]string)
91 if opts.TemplateOpts == nil {
92 if opts.Template != "" {
93 s["template"] = opts.Template
94 } else if opts.TemplateURL != "" {
95 s["template_url"] = opts.TemplateURL
96 } else {
Jon Perritt58611da2016-03-09 00:49:57 -060097 err := gophercloud.ErrMissingInput{}
98 err.Argument = "stacks.CreateOpts.Template/stacks.CreateOpts.TemplateURL"
99 err.Info = "Either Template or TemplateURL must be provided"
100 return nil, err
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500101 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700102 } else {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500103 if err := opts.TemplateOpts.Parse(); err != nil {
104 return nil, err
105 }
106
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500107 if err := opts.TemplateOpts.getFileContents(opts.TemplateOpts.Parsed, ignoreIfTemplate, true); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500108 return nil, err
109 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500110 opts.TemplateOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500111 s["template"] = string(opts.TemplateOpts.Bin)
112
113 for k, v := range opts.TemplateOpts.Files {
114 Files[k] = v
115 }
116 }
117 if opts.DisableRollback != nil {
118 s["disable_rollback"] = &opts.DisableRollback
119 }
120
121 if opts.EnvironmentOpts != nil {
122 if err := opts.EnvironmentOpts.Parse(); err != nil {
123 return nil, err
124 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500125 if err := opts.EnvironmentOpts.getRRFileContents(ignoreIfEnvironment); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500126 return nil, err
127 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500128 opts.EnvironmentOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500129 for k, v := range opts.EnvironmentOpts.Files {
130 Files[k] = v
131 }
132 s["environment"] = string(opts.EnvironmentOpts.Bin)
133 } else if opts.Environment != "" {
134 s["environment"] = opts.Environment
135 }
136
137 if opts.Files != nil {
138 s["files"] = opts.Files
139 } else {
140 s["files"] = Files
Jon Perritt35e27e42014-12-05 11:10:46 -0700141 }
142
143 if opts.DisableRollback != nil {
144 s["disable_rollback"] = &opts.DisableRollback
145 }
146
Jon Perritt35e27e42014-12-05 11:10:46 -0700147 if opts.Parameters != nil {
148 s["parameters"] = opts.Parameters
149 }
150
Jon Perritt91709892015-02-11 17:53:43 -0700151 if opts.Timeout != 0 {
152 s["timeout_mins"] = opts.Timeout
Jon Perritt35e27e42014-12-05 11:10:46 -0700153 }
154
Pratik Mallya827c03e2015-09-17 00:10:47 -0500155 if opts.Tags != nil {
156 s["tags"] = strings.Join(opts.Tags, ",")
157 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700158 return s, nil
159}
160
161// Create accepts a CreateOpts struct and creates a new stack using the values
162// provided.
163func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
164 var res CreateResult
165
166 reqBody, err := opts.ToStackCreateMap()
167 if err != nil {
168 res.Err = err
169 return res
170 }
171
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100172 _, res.Err = c.Post(createURL(c), reqBody, &res.Body, nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700173 return res
174}
175
176// AdoptOptsBuilder is the interface options structs have to satisfy in order
177// to be used in the Adopt function in this package. Since many
178// extensions decorate or modify the common logic, it is useful for them to
179// satisfy a basic interface in order for them to be used.
180type AdoptOptsBuilder interface {
181 ToStackAdoptMap() (map[string]interface{}, error)
182}
183
184// AdoptOpts is the common options struct used in this package's Adopt
185// operation.
186type AdoptOpts struct {
Jon Perritt9741dd92015-02-04 12:05:47 -0700187 // (REQUIRED) Existing resources data represented as a string to add to the
188 // new stack. Data returned by Abandon could be provided as AdoptsStackData.
189 AdoptStackData string
190 // (REQUIRED) The name of the stack. It must start with an alphabetic character.
191 Name string
192 // (REQUIRED) The timeout for stack creation in minutes.
193 Timeout int
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500194 // (REQUIRED) A structure that contains either the template file or url. Call the
195 // associated methods to extract the information relevant to send in a create request.
196 TemplateOpts *Template
197 // (DEPRECATED): Please use TemplateOpts for providing the template. If
198 // TemplateOpts is provided, TemplateURL will be ignored
Jon Perritt9741dd92015-02-04 12:05:47 -0700199 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
200 // This value is ignored if Template is supplied inline.
201 TemplateURL string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500202 // (DEPRECATED): Please use TemplateOpts for providing the template. If
203 // TemplateOpts is provided, Template will be ignored
Jon Perritt9741dd92015-02-04 12:05:47 -0700204 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
205 // is a stringified version of the JSON/YAML template. Since the template will likely
206 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
207 // import "io/ioutil"
208 // var opts stacks.CreateOpts
209 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
210 // if err != nil {
211 // // handle error...
212 // }
213 // opts.Template = string(b)
214 Template string
215 // (OPTIONAL) Enables or disables deletion of all stack resources when a stack
216 // creation fails. Default is true, meaning all resources are not deleted when
217 // stack creation fails.
Jon Perritt37f97742015-02-04 18:55:05 -0700218 DisableRollback Rollback
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500219 // (OPTIONAL) A structure that contains details for the environment of the stack.
220 EnvironmentOpts *Environment
221 // (DEPRECATED): Please use EnvironmentOpts to provide Environment data
Jon Perritt9741dd92015-02-04 12:05:47 -0700222 // (OPTIONAL) A stringified JSON environment for the stack.
223 Environment string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500224 // (DEPRECATED): Files is automatically determined
225 // by parsing the template and environment passed as TemplateOpts and
226 // EnvironmentOpts respectively.
Jon Perritt9741dd92015-02-04 12:05:47 -0700227 // (OPTIONAL) A map that maps file names to file contents. It can also be used
228 // to pass provider template contents. Example:
229 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
230 Files map[string]interface{}
231 // (OPTIONAL) User-defined parameters to pass to the template.
232 Parameters map[string]string
Jon Perritt35e27e42014-12-05 11:10:46 -0700233}
234
235// ToStackAdoptMap casts a CreateOpts struct to a map.
236func (opts AdoptOpts) ToStackAdoptMap() (map[string]interface{}, error) {
237 s := make(map[string]interface{})
238
239 if opts.Name == "" {
Jon Perritt58611da2016-03-09 00:49:57 -0600240 err := gophercloud.ErrMissingInput{}
241 err.Argument = "stacks.AdoptOpts.Name"
242 return nil, err
Jon Perritt35e27e42014-12-05 11:10:46 -0700243 }
244 s["stack_name"] = opts.Name
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500245 Files := make(map[string]string)
Pratik Mallya7e6b7b92015-09-30 19:03:08 -0500246 if opts.AdoptStackData != "" {
247 s["adopt_stack_data"] = opts.AdoptStackData
248 } else if opts.TemplateOpts == nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500249 if opts.Template != "" {
250 s["template"] = opts.Template
251 } else if opts.TemplateURL != "" {
252 s["template_url"] = opts.TemplateURL
253 } else {
Jon Perritt58611da2016-03-09 00:49:57 -0600254 err := gophercloud.ErrMissingInput{}
255 err.Argument = "stacks.AdoptOpts"
256 err.Info = "One of AdoptStackData, Template, TemplateURL or TemplateOpts must be provided"
257 return nil, err
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500258 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700259 } else {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500260 if err := opts.TemplateOpts.Parse(); err != nil {
261 return nil, err
262 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700263
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500264 if err := opts.TemplateOpts.getFileContents(opts.TemplateOpts.Parsed, ignoreIfTemplate, true); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500265 return nil, err
266 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500267 opts.TemplateOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500268 s["template"] = string(opts.TemplateOpts.Bin)
269
270 for k, v := range opts.TemplateOpts.Files {
271 Files[k] = v
272 }
273 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700274
275 if opts.DisableRollback != nil {
276 s["disable_rollback"] = &opts.DisableRollback
277 }
278
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500279 if opts.EnvironmentOpts != nil {
280 if err := opts.EnvironmentOpts.Parse(); err != nil {
281 return nil, err
282 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500283 if err := opts.EnvironmentOpts.getRRFileContents(ignoreIfEnvironment); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500284 return nil, err
285 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500286 opts.EnvironmentOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500287 for k, v := range opts.EnvironmentOpts.Files {
288 Files[k] = v
289 }
290 s["environment"] = string(opts.EnvironmentOpts.Bin)
291 } else if opts.Environment != "" {
Jon Perritt35e27e42014-12-05 11:10:46 -0700292 s["environment"] = opts.Environment
293 }
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500294
Jon Perritt35e27e42014-12-05 11:10:46 -0700295 if opts.Files != nil {
296 s["files"] = opts.Files
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500297 } else {
298 s["files"] = Files
Jon Perritt35e27e42014-12-05 11:10:46 -0700299 }
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500300
Jon Perritt35e27e42014-12-05 11:10:46 -0700301 if opts.Parameters != nil {
302 s["parameters"] = opts.Parameters
303 }
304
Pratik Mallya827c03e2015-09-17 00:10:47 -0500305 if opts.Timeout != 0 {
306 s["timeout"] = opts.Timeout
Jon Perritt35e27e42014-12-05 11:10:46 -0700307 }
Jon Perritt9741dd92015-02-04 12:05:47 -0700308 s["timeout_mins"] = opts.Timeout
Jon Perritt35e27e42014-12-05 11:10:46 -0700309
Pratik Mallya827c03e2015-09-17 00:10:47 -0500310 return s, nil
Jon Perritt35e27e42014-12-05 11:10:46 -0700311}
312
313// Adopt accepts an AdoptOpts struct and creates a new stack using the resources
314// from another stack.
Jon Perritt9741dd92015-02-04 12:05:47 -0700315func Adopt(c *gophercloud.ServiceClient, opts AdoptOptsBuilder) AdoptResult {
316 var res AdoptResult
Jon Perritt35e27e42014-12-05 11:10:46 -0700317
318 reqBody, err := opts.ToStackAdoptMap()
319 if err != nil {
320 res.Err = err
321 return res
322 }
323
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100324 _, res.Err = c.Post(adoptURL(c), reqBody, &res.Body, nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700325 return res
326}
327
328// SortDir is a type for specifying in which direction to sort a list of stacks.
329type SortDir string
330
331// SortKey is a type for specifying by which key to sort a list of stacks.
332type SortKey string
333
334var (
335 // SortAsc is used to sort a list of stacks in ascending order.
336 SortAsc SortDir = "asc"
337 // SortDesc is used to sort a list of stacks in descending order.
338 SortDesc SortDir = "desc"
339 // SortName is used to sort a list of stacks by name.
340 SortName SortKey = "name"
341 // SortStatus is used to sort a list of stacks by status.
342 SortStatus SortKey = "status"
343 // SortCreatedAt is used to sort a list of stacks by date created.
344 SortCreatedAt SortKey = "created_at"
345 // SortUpdatedAt is used to sort a list of stacks by date updated.
346 SortUpdatedAt SortKey = "updated_at"
347)
348
349// ListOptsBuilder allows extensions to add additional parameters to the
350// List request.
351type ListOptsBuilder interface {
352 ToStackListQuery() (string, error)
353}
354
355// ListOpts allows the filtering and sorting of paginated collections through
356// the API. Filtering is achieved by passing in struct field values that map to
357// the network attributes you want to see returned. SortKey allows you to sort
358// by a particular network attribute. SortDir sets the direction, and is either
359// `asc' or `desc'. Marker and Limit are used for pagination.
360type ListOpts struct {
361 Status string `q:"status"`
362 Name string `q:"name"`
363 Marker string `q:"marker"`
364 Limit int `q:"limit"`
365 SortKey SortKey `q:"sort_keys"`
366 SortDir SortDir `q:"sort_dir"`
367}
368
369// ToStackListQuery formats a ListOpts into a query string.
370func (opts ListOpts) ToStackListQuery() (string, error) {
371 q, err := gophercloud.BuildQueryString(opts)
372 if err != nil {
373 return "", err
374 }
375 return q.String(), nil
376}
377
378// List returns a Pager which allows you to iterate over a collection of
379// stacks. It accepts a ListOpts struct, which allows you to filter and sort
380// the returned collection for greater efficiency.
381func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
382 url := listURL(c)
383 if opts != nil {
384 query, err := opts.ToStackListQuery()
385 if err != nil {
386 return pagination.Pager{Err: err}
387 }
388 url += query
389 }
390
391 createPage := func(r pagination.PageResult) pagination.Page {
392 return StackPage{pagination.SinglePageBase(r)}
393 }
394 return pagination.NewPager(c, url, createPage)
395}
396
397// Get retreives a stack based on the stack name and stack ID.
398func Get(c *gophercloud.ServiceClient, stackName, stackID string) GetResult {
399 var res GetResult
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100400 _, res.Err = c.Get(getURL(c, stackName, stackID), &res.Body, nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700401 return res
402}
403
404// UpdateOptsBuilder is the interface options structs have to satisfy in order
405// to be used in the Update operation in this package.
406type UpdateOptsBuilder interface {
407 ToStackUpdateMap() (map[string]interface{}, error)
408}
409
410// UpdateOpts contains the common options struct used in this package's Update
411// operation.
412type UpdateOpts struct {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500413 // (REQUIRED) A structure that contains either the template file or url. Call the
414 // associated methods to extract the information relevant to send in a create request.
415 TemplateOpts *Template
416 // (DEPRECATED): Please use TemplateOpts for providing the template. If
417 // TemplateOpts is provided, TemplateURL will be ignored
Jon Perritt37f97742015-02-04 18:55:05 -0700418 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
419 // This value is ignored if Template is supplied inline.
Jon Perritt35e27e42014-12-05 11:10:46 -0700420 TemplateURL string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500421 // (DEPRECATED): Please use TemplateOpts for providing the template. If
422 // TemplateOpts is provided, Template will be ignored
Jon Perritt37f97742015-02-04 18:55:05 -0700423 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
424 // is a stringified version of the JSON/YAML template. Since the template will likely
425 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
426 // import "io/ioutil"
427 // var opts stacks.CreateOpts
428 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
429 // if err != nil {
430 // // handle error...
431 // }
432 // opts.Template = string(b)
433 Template string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500434 // (OPTIONAL) A structure that contains details for the environment of the stack.
435 EnvironmentOpts *Environment
436 // (DEPRECATED): Please use EnvironmentOpts to provide Environment data
Jon Perritt37f97742015-02-04 18:55:05 -0700437 // (OPTIONAL) A stringified JSON environment for the stack.
438 Environment string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500439 // (DEPRECATED): Files is automatically determined
440 // by parsing the template and environment passed as TemplateOpts and
441 // EnvironmentOpts respectively.
Jon Perritt37f97742015-02-04 18:55:05 -0700442 // (OPTIONAL) A map that maps file names to file contents. It can also be used
443 // to pass provider template contents. Example:
444 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
445 Files map[string]interface{}
446 // (OPTIONAL) User-defined parameters to pass to the template.
447 Parameters map[string]string
Jon Perritt51107182015-02-11 18:18:19 -0700448 // (OPTIONAL) The timeout for stack creation in minutes.
449 Timeout int
Pratik Mallya827c03e2015-09-17 00:10:47 -0500450 // (OPTIONAL) A list of tags to assosciate with the Stack
451 Tags []string
Jon Perritt35e27e42014-12-05 11:10:46 -0700452}
453
454// ToStackUpdateMap casts a CreateOpts struct to a map.
455func (opts UpdateOpts) ToStackUpdateMap() (map[string]interface{}, error) {
456 s := make(map[string]interface{})
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500457 Files := make(map[string]string)
458 if opts.TemplateOpts == nil {
459 if opts.Template != "" {
460 s["template"] = opts.Template
461 } else if opts.TemplateURL != "" {
462 s["template_url"] = opts.TemplateURL
463 } else {
Jon Perritt58611da2016-03-09 00:49:57 -0600464 err := gophercloud.ErrMissingInput{}
465 err.Argument = "stacks.UpdateOpts"
466 err.Info = "Either Template or TemplateURL must be provided"
467 return nil, err
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500468 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700469 } else {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500470 if err := opts.TemplateOpts.Parse(); err != nil {
471 return nil, err
472 }
473
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500474 if err := opts.TemplateOpts.getFileContents(opts.TemplateOpts.Parsed, ignoreIfTemplate, true); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500475 return nil, err
476 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500477 opts.TemplateOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500478 s["template"] = string(opts.TemplateOpts.Bin)
479
480 for k, v := range opts.TemplateOpts.Files {
481 Files[k] = v
482 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700483 }
484
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500485 if opts.EnvironmentOpts != nil {
486 if err := opts.EnvironmentOpts.Parse(); err != nil {
487 return nil, err
488 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500489 if err := opts.EnvironmentOpts.getRRFileContents(ignoreIfEnvironment); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500490 return nil, err
491 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500492 opts.EnvironmentOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500493 for k, v := range opts.EnvironmentOpts.Files {
494 Files[k] = v
495 }
496 s["environment"] = string(opts.EnvironmentOpts.Bin)
497 } else if opts.Environment != "" {
Jon Perritt35e27e42014-12-05 11:10:46 -0700498 s["environment"] = opts.Environment
499 }
500
501 if opts.Files != nil {
502 s["files"] = opts.Files
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500503 } else {
504 s["files"] = Files
Jon Perritt35e27e42014-12-05 11:10:46 -0700505 }
506
507 if opts.Parameters != nil {
508 s["parameters"] = opts.Parameters
509 }
510
511 if opts.Timeout != 0 {
512 s["timeout_mins"] = opts.Timeout
513 }
514
Pratik Mallya827c03e2015-09-17 00:10:47 -0500515 if opts.Tags != nil {
516 s["tags"] = strings.Join(opts.Tags, ",")
517 }
518
Jon Perritt35e27e42014-12-05 11:10:46 -0700519 return s, nil
520}
521
522// Update accepts an UpdateOpts struct and updates an existing stack using the values
523// provided.
524func Update(c *gophercloud.ServiceClient, stackName, stackID string, opts UpdateOptsBuilder) UpdateResult {
525 var res UpdateResult
526
527 reqBody, err := opts.ToStackUpdateMap()
528 if err != nil {
529 res.Err = err
530 return res
531 }
532
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100533 _, res.Err = c.Put(updateURL(c, stackName, stackID), reqBody, nil, nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700534 return res
535}
536
537// Delete deletes a stack based on the stack name and stack ID.
538func Delete(c *gophercloud.ServiceClient, stackName, stackID string) DeleteResult {
539 var res DeleteResult
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100540 _, res.Err = c.Delete(deleteURL(c, stackName, stackID), nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700541 return res
542}
543
544// PreviewOptsBuilder is the interface options structs have to satisfy in order
545// to be used in the Preview operation in this package.
546type PreviewOptsBuilder interface {
547 ToStackPreviewMap() (map[string]interface{}, error)
548}
549
550// PreviewOpts contains the common options struct used in this package's Preview
551// operation.
552type PreviewOpts struct {
Jon Perritt37f97742015-02-04 18:55:05 -0700553 // (REQUIRED) The name of the stack. It must start with an alphabetic character.
554 Name string
555 // (REQUIRED) The timeout for stack creation in minutes.
556 Timeout int
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500557 // (REQUIRED) A structure that contains either the template file or url. Call the
558 // associated methods to extract the information relevant to send in a create request.
559 TemplateOpts *Template
560 // (DEPRECATED): Please use TemplateOpts for providing the template. If
561 // TemplateOpts is provided, TemplateURL will be ignored
Jon Perritt37f97742015-02-04 18:55:05 -0700562 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
563 // This value is ignored if Template is supplied inline.
564 TemplateURL string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500565 // (DEPRECATED): Please use TemplateOpts for providing the template. If
566 // TemplateOpts is provided, Template will be ignored
Jon Perritt37f97742015-02-04 18:55:05 -0700567 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
568 // is a stringified version of the JSON/YAML template. Since the template will likely
569 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
570 // import "io/ioutil"
571 // var opts stacks.CreateOpts
572 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
573 // if err != nil {
574 // // handle error...
575 // }
576 // opts.Template = string(b)
577 Template string
578 // (OPTIONAL) Enables or disables deletion of all stack resources when a stack
579 // creation fails. Default is true, meaning all resources are not deleted when
580 // stack creation fails.
581 DisableRollback Rollback
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500582 // (OPTIONAL) A structure that contains details for the environment of the stack.
583 EnvironmentOpts *Environment
584 // (DEPRECATED): Please use EnvironmentOpts to provide Environment data
Jon Perritt37f97742015-02-04 18:55:05 -0700585 // (OPTIONAL) A stringified JSON environment for the stack.
586 Environment string
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500587 // (DEPRECATED): Files is automatically determined
588 // by parsing the template and environment passed as TemplateOpts and
589 // EnvironmentOpts respectively.
Jon Perritt37f97742015-02-04 18:55:05 -0700590 // (OPTIONAL) A map that maps file names to file contents. It can also be used
591 // to pass provider template contents. Example:
592 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
593 Files map[string]interface{}
594 // (OPTIONAL) User-defined parameters to pass to the template.
595 Parameters map[string]string
Jon Perritt35e27e42014-12-05 11:10:46 -0700596}
597
598// ToStackPreviewMap casts a PreviewOpts struct to a map.
599func (opts PreviewOpts) ToStackPreviewMap() (map[string]interface{}, error) {
600 s := make(map[string]interface{})
601
602 if opts.Name == "" {
Jon Perritt58611da2016-03-09 00:49:57 -0600603 err := gophercloud.ErrMissingInput{}
604 err.Argument = "stacks.PreviewOpts.Name"
605 return nil, err
Jon Perritt35e27e42014-12-05 11:10:46 -0700606 }
607 s["stack_name"] = opts.Name
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500608 Files := make(map[string]string)
609 if opts.TemplateOpts == nil {
610 if opts.Template != "" {
611 s["template"] = opts.Template
612 } else if opts.TemplateURL != "" {
613 s["template_url"] = opts.TemplateURL
614 } else {
Jon Perritt58611da2016-03-09 00:49:57 -0600615 err := gophercloud.ErrMissingInput{}
616 err.Argument = "stacks.PreviewOpts"
617 err.Info = "Either Template or TemplateURL must be provided"
618 return nil, err
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500619 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700620 } else {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500621 if err := opts.TemplateOpts.Parse(); err != nil {
622 return nil, err
623 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700624
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500625 if err := opts.TemplateOpts.getFileContents(opts.TemplateOpts.Parsed, ignoreIfTemplate, true); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500626 return nil, err
627 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500628 opts.TemplateOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500629 s["template"] = string(opts.TemplateOpts.Bin)
630
631 for k, v := range opts.TemplateOpts.Files {
632 Files[k] = v
633 }
634 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700635 if opts.DisableRollback != nil {
636 s["disable_rollback"] = &opts.DisableRollback
637 }
638
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500639 if opts.EnvironmentOpts != nil {
640 if err := opts.EnvironmentOpts.Parse(); err != nil {
641 return nil, err
642 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500643 if err := opts.EnvironmentOpts.getRRFileContents(ignoreIfEnvironment); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500644 return nil, err
645 }
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500646 opts.EnvironmentOpts.fixFileRefs()
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500647 for k, v := range opts.EnvironmentOpts.Files {
648 Files[k] = v
649 }
650 s["environment"] = string(opts.EnvironmentOpts.Bin)
651 } else if opts.Environment != "" {
Jon Perritt35e27e42014-12-05 11:10:46 -0700652 s["environment"] = opts.Environment
653 }
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500654
Jon Perritt35e27e42014-12-05 11:10:46 -0700655 if opts.Files != nil {
656 s["files"] = opts.Files
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500657 } else {
658 s["files"] = Files
Jon Perritt35e27e42014-12-05 11:10:46 -0700659 }
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500660
Jon Perritt35e27e42014-12-05 11:10:46 -0700661 if opts.Parameters != nil {
662 s["parameters"] = opts.Parameters
663 }
664
665 if opts.Timeout != 0 {
666 s["timeout_mins"] = opts.Timeout
667 }
668
669 return s, nil
670}
671
672// Preview accepts a PreviewOptsBuilder interface and creates a preview of a stack using the values
673// provided.
674func Preview(c *gophercloud.ServiceClient, opts PreviewOptsBuilder) PreviewResult {
675 var res PreviewResult
676
677 reqBody, err := opts.ToStackPreviewMap()
678 if err != nil {
679 res.Err = err
680 return res
681 }
682
683 // Send request to API
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100684 _, res.Err = c.Post(previewURL(c), reqBody, &res.Body, &gophercloud.RequestOpts{
685 OkCodes: []int{200},
Jon Perritt35e27e42014-12-05 11:10:46 -0700686 })
687 return res
688}
689
690// Abandon deletes the stack with the provided stackName and stackID, but leaves its
691// resources intact, and returns data describing the stack and its resources.
692func Abandon(c *gophercloud.ServiceClient, stackName, stackID string) AbandonResult {
693 var res AbandonResult
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100694 _, res.Err = c.Delete(abandonURL(c, stackName, stackID), &gophercloud.RequestOpts{
Ash Wilsondecfed72015-02-13 09:14:55 -0500695 JSONResponse: &res.Body,
696 OkCodes: []int{200},
Jon Perritt35e27e42014-12-05 11:10:46 -0700697 })
698 return res
699}