blob: bd8e59ef0750faad5f120c21d3fdb230bebabf6e [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 Perritt35e27e42014-12-05 11:10:46 -07007 "github.com/rackspace/gophercloud"
8 "github.com/rackspace/gophercloud/pagination"
9)
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
Jon Perritt952f3e12015-02-03 12:13:24 -070036 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
37 // This value is ignored if Template is supplied inline.
38 TemplateURL string
39 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
40 // is a stringified version of the JSON/YAML template. Since the template will likely
41 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
42 // import "io/ioutil"
43 // var opts stacks.CreateOpts
44 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
45 // if err != nil {
46 // // handle error...
47 // }
48 // opts.Template = string(b)
49 Template string
50 // (OPTIONAL) Enables or disables deletion of all stack resources when a stack
51 // creation fails. Default is true, meaning all resources are not deleted when
52 // stack creation fails.
Jon Perritt37f97742015-02-04 18:55:05 -070053 DisableRollback Rollback
Jon Perritt952f3e12015-02-03 12:13:24 -070054 // (OPTIONAL) A stringified JSON environment for the stack.
55 Environment string
56 // (OPTIONAL) A map that maps file names to file contents. It can also be used
57 // to pass provider template contents. Example:
58 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
59 Files map[string]interface{}
60 // (OPTIONAL) User-defined parameters to pass to the template.
61 Parameters map[string]string
Jon Perritt91709892015-02-11 17:53:43 -070062 // (OPTIONAL) The timeout for stack creation in minutes.
63 Timeout int
Pratik Mallya827c03e2015-09-17 00:10:47 -050064 // (OPTIONAL) A list of tags to assosciate with the Stack
65 Tags []string
Jon Perritt35e27e42014-12-05 11:10:46 -070066}
67
68// ToStackCreateMap casts a CreateOpts struct to a map.
69func (opts CreateOpts) ToStackCreateMap() (map[string]interface{}, error) {
70 s := make(map[string]interface{})
71
72 if opts.Name == "" {
73 return s, errors.New("Required field 'Name' not provided.")
74 }
75 s["stack_name"] = opts.Name
76
77 if opts.Template != "" {
78 s["template"] = opts.Template
79 } else if opts.TemplateURL != "" {
80 s["template_url"] = opts.TemplateURL
81 } else {
82 return s, errors.New("Either Template or TemplateURL must be provided.")
83 }
84
85 if opts.DisableRollback != nil {
86 s["disable_rollback"] = &opts.DisableRollback
87 }
88
89 if opts.Environment != "" {
90 s["environment"] = opts.Environment
91 }
92 if opts.Files != nil {
93 s["files"] = opts.Files
94 }
95 if opts.Parameters != nil {
96 s["parameters"] = opts.Parameters
97 }
98
Jon Perritt91709892015-02-11 17:53:43 -070099 if opts.Timeout != 0 {
100 s["timeout_mins"] = opts.Timeout
Jon Perritt35e27e42014-12-05 11:10:46 -0700101 }
102
Pratik Mallya827c03e2015-09-17 00:10:47 -0500103 if opts.Tags != nil {
104 s["tags"] = strings.Join(opts.Tags, ",")
105 }
Jon Perritt35e27e42014-12-05 11:10:46 -0700106 return s, nil
107}
108
109// Create accepts a CreateOpts struct and creates a new stack using the values
110// provided.
111func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
112 var res CreateResult
113
114 reqBody, err := opts.ToStackCreateMap()
115 if err != nil {
116 res.Err = err
117 return res
118 }
119
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100120 _, res.Err = c.Post(createURL(c), reqBody, &res.Body, nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700121 return res
122}
123
124// AdoptOptsBuilder is the interface options structs have to satisfy in order
125// to be used in the Adopt function in this package. Since many
126// extensions decorate or modify the common logic, it is useful for them to
127// satisfy a basic interface in order for them to be used.
128type AdoptOptsBuilder interface {
129 ToStackAdoptMap() (map[string]interface{}, error)
130}
131
132// AdoptOpts is the common options struct used in this package's Adopt
133// operation.
134type AdoptOpts struct {
Jon Perritt9741dd92015-02-04 12:05:47 -0700135 // (REQUIRED) Existing resources data represented as a string to add to the
136 // new stack. Data returned by Abandon could be provided as AdoptsStackData.
137 AdoptStackData string
138 // (REQUIRED) The name of the stack. It must start with an alphabetic character.
139 Name string
140 // (REQUIRED) The timeout for stack creation in minutes.
141 Timeout int
142 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
143 // This value is ignored if Template is supplied inline.
144 TemplateURL string
145 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
146 // is a stringified version of the JSON/YAML template. Since the template will likely
147 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
148 // import "io/ioutil"
149 // var opts stacks.CreateOpts
150 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
151 // if err != nil {
152 // // handle error...
153 // }
154 // opts.Template = string(b)
155 Template string
156 // (OPTIONAL) Enables or disables deletion of all stack resources when a stack
157 // creation fails. Default is true, meaning all resources are not deleted when
158 // stack creation fails.
Jon Perritt37f97742015-02-04 18:55:05 -0700159 DisableRollback Rollback
Jon Perritt9741dd92015-02-04 12:05:47 -0700160 // (OPTIONAL) A stringified JSON environment for the stack.
161 Environment string
162 // (OPTIONAL) A map that maps file names to file contents. It can also be used
163 // to pass provider template contents. Example:
164 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
165 Files map[string]interface{}
166 // (OPTIONAL) User-defined parameters to pass to the template.
167 Parameters map[string]string
Jon Perritt35e27e42014-12-05 11:10:46 -0700168}
169
170// ToStackAdoptMap casts a CreateOpts struct to a map.
171func (opts AdoptOpts) ToStackAdoptMap() (map[string]interface{}, error) {
172 s := make(map[string]interface{})
173
174 if opts.Name == "" {
175 return s, errors.New("Required field 'Name' not provided.")
176 }
177 s["stack_name"] = opts.Name
178
179 if opts.Template != "" {
180 s["template"] = opts.Template
181 } else if opts.TemplateURL != "" {
182 s["template_url"] = opts.TemplateURL
183 } else {
184 return s, errors.New("Either Template or TemplateURL must be provided.")
185 }
186
187 if opts.AdoptStackData == "" {
188 return s, errors.New("Required field 'AdoptStackData' not provided.")
189 }
190 s["adopt_stack_data"] = opts.AdoptStackData
191
192 if opts.DisableRollback != nil {
193 s["disable_rollback"] = &opts.DisableRollback
194 }
195
196 if opts.Environment != "" {
197 s["environment"] = opts.Environment
198 }
199 if opts.Files != nil {
200 s["files"] = opts.Files
201 }
202 if opts.Parameters != nil {
203 s["parameters"] = opts.Parameters
204 }
205
Pratik Mallya827c03e2015-09-17 00:10:47 -0500206 if opts.Timeout != 0 {
207 s["timeout"] = opts.Timeout
Jon Perritt35e27e42014-12-05 11:10:46 -0700208 }
Jon Perritt9741dd92015-02-04 12:05:47 -0700209 s["timeout_mins"] = opts.Timeout
Jon Perritt35e27e42014-12-05 11:10:46 -0700210
Pratik Mallya827c03e2015-09-17 00:10:47 -0500211 return s, nil
Jon Perritt35e27e42014-12-05 11:10:46 -0700212}
213
214// Adopt accepts an AdoptOpts struct and creates a new stack using the resources
215// from another stack.
Jon Perritt9741dd92015-02-04 12:05:47 -0700216func Adopt(c *gophercloud.ServiceClient, opts AdoptOptsBuilder) AdoptResult {
217 var res AdoptResult
Jon Perritt35e27e42014-12-05 11:10:46 -0700218
219 reqBody, err := opts.ToStackAdoptMap()
220 if err != nil {
221 res.Err = err
222 return res
223 }
224
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100225 _, res.Err = c.Post(adoptURL(c), reqBody, &res.Body, nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700226 return res
227}
228
229// SortDir is a type for specifying in which direction to sort a list of stacks.
230type SortDir string
231
232// SortKey is a type for specifying by which key to sort a list of stacks.
233type SortKey string
234
235var (
236 // SortAsc is used to sort a list of stacks in ascending order.
237 SortAsc SortDir = "asc"
238 // SortDesc is used to sort a list of stacks in descending order.
239 SortDesc SortDir = "desc"
240 // SortName is used to sort a list of stacks by name.
241 SortName SortKey = "name"
242 // SortStatus is used to sort a list of stacks by status.
243 SortStatus SortKey = "status"
244 // SortCreatedAt is used to sort a list of stacks by date created.
245 SortCreatedAt SortKey = "created_at"
246 // SortUpdatedAt is used to sort a list of stacks by date updated.
247 SortUpdatedAt SortKey = "updated_at"
248)
249
250// ListOptsBuilder allows extensions to add additional parameters to the
251// List request.
252type ListOptsBuilder interface {
253 ToStackListQuery() (string, error)
254}
255
256// ListOpts allows the filtering and sorting of paginated collections through
257// the API. Filtering is achieved by passing in struct field values that map to
258// the network attributes you want to see returned. SortKey allows you to sort
259// by a particular network attribute. SortDir sets the direction, and is either
260// `asc' or `desc'. Marker and Limit are used for pagination.
261type ListOpts struct {
262 Status string `q:"status"`
263 Name string `q:"name"`
264 Marker string `q:"marker"`
265 Limit int `q:"limit"`
266 SortKey SortKey `q:"sort_keys"`
267 SortDir SortDir `q:"sort_dir"`
268}
269
270// ToStackListQuery formats a ListOpts into a query string.
271func (opts ListOpts) ToStackListQuery() (string, error) {
272 q, err := gophercloud.BuildQueryString(opts)
273 if err != nil {
274 return "", err
275 }
276 return q.String(), nil
277}
278
279// List returns a Pager which allows you to iterate over a collection of
280// stacks. It accepts a ListOpts struct, which allows you to filter and sort
281// the returned collection for greater efficiency.
282func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
283 url := listURL(c)
284 if opts != nil {
285 query, err := opts.ToStackListQuery()
286 if err != nil {
287 return pagination.Pager{Err: err}
288 }
289 url += query
290 }
291
292 createPage := func(r pagination.PageResult) pagination.Page {
293 return StackPage{pagination.SinglePageBase(r)}
294 }
295 return pagination.NewPager(c, url, createPage)
296}
297
298// Get retreives a stack based on the stack name and stack ID.
299func Get(c *gophercloud.ServiceClient, stackName, stackID string) GetResult {
300 var res GetResult
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100301 _, res.Err = c.Get(getURL(c, stackName, stackID), &res.Body, nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700302 return res
303}
304
305// UpdateOptsBuilder is the interface options structs have to satisfy in order
306// to be used in the Update operation in this package.
307type UpdateOptsBuilder interface {
308 ToStackUpdateMap() (map[string]interface{}, error)
309}
310
311// UpdateOpts contains the common options struct used in this package's Update
312// operation.
313type UpdateOpts struct {
Jon Perritt37f97742015-02-04 18:55:05 -0700314 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
315 // This value is ignored if Template is supplied inline.
Jon Perritt35e27e42014-12-05 11:10:46 -0700316 TemplateURL string
Jon Perritt37f97742015-02-04 18:55:05 -0700317 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
318 // is a stringified version of the JSON/YAML template. Since the template will likely
319 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
320 // import "io/ioutil"
321 // var opts stacks.CreateOpts
322 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
323 // if err != nil {
324 // // handle error...
325 // }
326 // opts.Template = string(b)
327 Template string
328 // (OPTIONAL) A stringified JSON environment for the stack.
329 Environment string
330 // (OPTIONAL) A map that maps file names to file contents. It can also be used
331 // to pass provider template contents. Example:
332 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
333 Files map[string]interface{}
334 // (OPTIONAL) User-defined parameters to pass to the template.
335 Parameters map[string]string
Jon Perritt51107182015-02-11 18:18:19 -0700336 // (OPTIONAL) The timeout for stack creation in minutes.
337 Timeout int
Pratik Mallya827c03e2015-09-17 00:10:47 -0500338 // (OPTIONAL) A list of tags to assosciate with the Stack
339 Tags []string
Jon Perritt35e27e42014-12-05 11:10:46 -0700340}
341
342// ToStackUpdateMap casts a CreateOpts struct to a map.
343func (opts UpdateOpts) ToStackUpdateMap() (map[string]interface{}, error) {
344 s := make(map[string]interface{})
345
346 if opts.Template != "" {
347 s["template"] = opts.Template
348 } else if opts.TemplateURL != "" {
349 s["template_url"] = opts.TemplateURL
350 } else {
351 return s, errors.New("Either Template or TemplateURL must be provided.")
352 }
353
354 if opts.Environment != "" {
355 s["environment"] = opts.Environment
356 }
357
358 if opts.Files != nil {
359 s["files"] = opts.Files
360 }
361
362 if opts.Parameters != nil {
363 s["parameters"] = opts.Parameters
364 }
365
366 if opts.Timeout != 0 {
367 s["timeout_mins"] = opts.Timeout
368 }
369
Pratik Mallya827c03e2015-09-17 00:10:47 -0500370 if opts.Tags != nil {
371 s["tags"] = strings.Join(opts.Tags, ",")
372 }
373
Jon Perritt35e27e42014-12-05 11:10:46 -0700374 return s, nil
375}
376
377// Update accepts an UpdateOpts struct and updates an existing stack using the values
378// provided.
379func Update(c *gophercloud.ServiceClient, stackName, stackID string, opts UpdateOptsBuilder) UpdateResult {
380 var res UpdateResult
381
382 reqBody, err := opts.ToStackUpdateMap()
383 if err != nil {
384 res.Err = err
385 return res
386 }
387
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100388 _, res.Err = c.Put(updateURL(c, stackName, stackID), reqBody, nil, nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700389 return res
390}
391
392// Delete deletes a stack based on the stack name and stack ID.
393func Delete(c *gophercloud.ServiceClient, stackName, stackID string) DeleteResult {
394 var res DeleteResult
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100395 _, res.Err = c.Delete(deleteURL(c, stackName, stackID), nil)
Jon Perritt35e27e42014-12-05 11:10:46 -0700396 return res
397}
398
399// PreviewOptsBuilder is the interface options structs have to satisfy in order
400// to be used in the Preview operation in this package.
401type PreviewOptsBuilder interface {
402 ToStackPreviewMap() (map[string]interface{}, error)
403}
404
405// PreviewOpts contains the common options struct used in this package's Preview
406// operation.
407type PreviewOpts struct {
Jon Perritt37f97742015-02-04 18:55:05 -0700408 // (REQUIRED) The name of the stack. It must start with an alphabetic character.
409 Name string
410 // (REQUIRED) The timeout for stack creation in minutes.
411 Timeout int
412 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
413 // This value is ignored if Template is supplied inline.
414 TemplateURL string
415 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
416 // is a stringified version of the JSON/YAML template. Since the template will likely
417 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
418 // import "io/ioutil"
419 // var opts stacks.CreateOpts
420 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
421 // if err != nil {
422 // // handle error...
423 // }
424 // opts.Template = string(b)
425 Template string
426 // (OPTIONAL) Enables or disables deletion of all stack resources when a stack
427 // creation fails. Default is true, meaning all resources are not deleted when
428 // stack creation fails.
429 DisableRollback Rollback
430 // (OPTIONAL) A stringified JSON environment for the stack.
431 Environment string
432 // (OPTIONAL) A map that maps file names to file contents. It can also be used
433 // to pass provider template contents. Example:
434 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
435 Files map[string]interface{}
436 // (OPTIONAL) User-defined parameters to pass to the template.
437 Parameters map[string]string
Jon Perritt35e27e42014-12-05 11:10:46 -0700438}
439
440// ToStackPreviewMap casts a PreviewOpts struct to a map.
441func (opts PreviewOpts) ToStackPreviewMap() (map[string]interface{}, error) {
442 s := make(map[string]interface{})
443
444 if opts.Name == "" {
445 return s, errors.New("Required field 'Name' not provided.")
446 }
447 s["stack_name"] = opts.Name
448
449 if opts.Template != "" {
450 s["template"] = opts.Template
451 } else if opts.TemplateURL != "" {
452 s["template_url"] = opts.TemplateURL
453 } else {
454 return s, errors.New("Either Template or TemplateURL must be provided.")
455 }
456
457 if opts.DisableRollback != nil {
458 s["disable_rollback"] = &opts.DisableRollback
459 }
460
461 if opts.Environment != "" {
462 s["environment"] = opts.Environment
463 }
464 if opts.Files != nil {
465 s["files"] = opts.Files
466 }
467 if opts.Parameters != nil {
468 s["parameters"] = opts.Parameters
469 }
470
471 if opts.Timeout != 0 {
472 s["timeout_mins"] = opts.Timeout
473 }
474
475 return s, nil
476}
477
478// Preview accepts a PreviewOptsBuilder interface and creates a preview of a stack using the values
479// provided.
480func Preview(c *gophercloud.ServiceClient, opts PreviewOptsBuilder) PreviewResult {
481 var res PreviewResult
482
483 reqBody, err := opts.ToStackPreviewMap()
484 if err != nil {
485 res.Err = err
486 return res
487 }
488
489 // Send request to API
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100490 _, res.Err = c.Post(previewURL(c), reqBody, &res.Body, &gophercloud.RequestOpts{
491 OkCodes: []int{200},
Jon Perritt35e27e42014-12-05 11:10:46 -0700492 })
493 return res
494}
495
496// Abandon deletes the stack with the provided stackName and stackID, but leaves its
497// resources intact, and returns data describing the stack and its resources.
498func Abandon(c *gophercloud.ServiceClient, stackName, stackID string) AbandonResult {
499 var res AbandonResult
Jamie Hannaford1d27afa2015-03-24 16:20:45 +0100500 _, res.Err = c.Delete(abandonURL(c, stackName, stackID), &gophercloud.RequestOpts{
Ash Wilsondecfed72015-02-13 09:14:55 -0500501 JSONResponse: &res.Body,
502 OkCodes: []int{200},
Jon Perritt35e27e42014-12-05 11:10:46 -0700503 })
504 return res
505}