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