blob: 68ba7874caac340e1a364e9ff54b03ba7f9ae5ad [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
114 // Send request to API
Ash Wilsondecfed72015-02-13 09:14:55 -0500115 _, res.Err = c.Request("POST", createURL(c), gophercloud.RequestOpts{
116 JSONBody: &reqBody,
117 JSONResponse: &res.Body,
Jon Perritt35e27e42014-12-05 11:10:46 -0700118 })
119 return res
120}
121
122// AdoptOptsBuilder is the interface options structs have to satisfy in order
123// to be used in the Adopt function in this package. Since many
124// extensions decorate or modify the common logic, it is useful for them to
125// satisfy a basic interface in order for them to be used.
126type AdoptOptsBuilder interface {
127 ToStackAdoptMap() (map[string]interface{}, error)
128}
129
130// AdoptOpts is the common options struct used in this package's Adopt
131// operation.
132type AdoptOpts struct {
Jon Perritt9741dd92015-02-04 12:05:47 -0700133 // (REQUIRED) Existing resources data represented as a string to add to the
134 // new stack. Data returned by Abandon could be provided as AdoptsStackData.
135 AdoptStackData string
136 // (REQUIRED) The name of the stack. It must start with an alphabetic character.
137 Name string
138 // (REQUIRED) The timeout for stack creation in minutes.
139 Timeout int
140 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
141 // This value is ignored if Template is supplied inline.
142 TemplateURL string
143 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
144 // is a stringified version of the JSON/YAML template. Since the template will likely
145 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
146 // import "io/ioutil"
147 // var opts stacks.CreateOpts
148 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
149 // if err != nil {
150 // // handle error...
151 // }
152 // opts.Template = string(b)
153 Template string
154 // (OPTIONAL) Enables or disables deletion of all stack resources when a stack
155 // creation fails. Default is true, meaning all resources are not deleted when
156 // stack creation fails.
Jon Perritt37f97742015-02-04 18:55:05 -0700157 DisableRollback Rollback
Jon Perritt9741dd92015-02-04 12:05:47 -0700158 // (OPTIONAL) A stringified JSON environment for the stack.
159 Environment string
160 // (OPTIONAL) A map that maps file names to file contents. It can also be used
161 // to pass provider template contents. Example:
162 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
163 Files map[string]interface{}
164 // (OPTIONAL) User-defined parameters to pass to the template.
165 Parameters map[string]string
Jon Perritt35e27e42014-12-05 11:10:46 -0700166}
167
168// ToStackAdoptMap casts a CreateOpts struct to a map.
169func (opts AdoptOpts) ToStackAdoptMap() (map[string]interface{}, error) {
170 s := make(map[string]interface{})
171
172 if opts.Name == "" {
173 return s, errors.New("Required field 'Name' not provided.")
174 }
175 s["stack_name"] = opts.Name
176
177 if opts.Template != "" {
178 s["template"] = opts.Template
179 } else if opts.TemplateURL != "" {
180 s["template_url"] = opts.TemplateURL
181 } else {
182 return s, errors.New("Either Template or TemplateURL must be provided.")
183 }
184
185 if opts.AdoptStackData == "" {
186 return s, errors.New("Required field 'AdoptStackData' not provided.")
187 }
188 s["adopt_stack_data"] = opts.AdoptStackData
189
190 if opts.DisableRollback != nil {
191 s["disable_rollback"] = &opts.DisableRollback
192 }
193
194 if opts.Environment != "" {
195 s["environment"] = opts.Environment
196 }
197 if opts.Files != nil {
198 s["files"] = opts.Files
199 }
200 if opts.Parameters != nil {
201 s["parameters"] = opts.Parameters
202 }
203
Jon Perritt9741dd92015-02-04 12:05:47 -0700204 if opts.Timeout == 0 {
205 return nil, errors.New("Required field 'Timeout' not provided.")
Jon Perritt35e27e42014-12-05 11:10:46 -0700206 }
Jon Perritt9741dd92015-02-04 12:05:47 -0700207 s["timeout_mins"] = opts.Timeout
Jon Perritt35e27e42014-12-05 11:10:46 -0700208
209 return map[string]interface{}{"stack": s}, nil
210}
211
212// Adopt accepts an AdoptOpts struct and creates a new stack using the resources
213// from another stack.
Jon Perritt9741dd92015-02-04 12:05:47 -0700214func Adopt(c *gophercloud.ServiceClient, opts AdoptOptsBuilder) AdoptResult {
215 var res AdoptResult
Jon Perritt35e27e42014-12-05 11:10:46 -0700216
217 reqBody, err := opts.ToStackAdoptMap()
218 if err != nil {
219 res.Err = err
220 return res
221 }
222
223 // Send request to API
Ash Wilsondecfed72015-02-13 09:14:55 -0500224 _, res.Err = c.Request("POST", adoptURL(c), gophercloud.RequestOpts{
225 JSONBody: &reqBody,
226 JSONResponse: &res.Body,
Jon Perritt35e27e42014-12-05 11:10:46 -0700227 })
228 return res
229}
230
231// SortDir is a type for specifying in which direction to sort a list of stacks.
232type SortDir string
233
234// SortKey is a type for specifying by which key to sort a list of stacks.
235type SortKey string
236
237var (
238 // SortAsc is used to sort a list of stacks in ascending order.
239 SortAsc SortDir = "asc"
240 // SortDesc is used to sort a list of stacks in descending order.
241 SortDesc SortDir = "desc"
242 // SortName is used to sort a list of stacks by name.
243 SortName SortKey = "name"
244 // SortStatus is used to sort a list of stacks by status.
245 SortStatus SortKey = "status"
246 // SortCreatedAt is used to sort a list of stacks by date created.
247 SortCreatedAt SortKey = "created_at"
248 // SortUpdatedAt is used to sort a list of stacks by date updated.
249 SortUpdatedAt SortKey = "updated_at"
250)
251
252// ListOptsBuilder allows extensions to add additional parameters to the
253// List request.
254type ListOptsBuilder interface {
255 ToStackListQuery() (string, error)
256}
257
258// ListOpts allows the filtering and sorting of paginated collections through
259// the API. Filtering is achieved by passing in struct field values that map to
260// the network attributes you want to see returned. SortKey allows you to sort
261// by a particular network attribute. SortDir sets the direction, and is either
262// `asc' or `desc'. Marker and Limit are used for pagination.
263type ListOpts struct {
264 Status string `q:"status"`
265 Name string `q:"name"`
266 Marker string `q:"marker"`
267 Limit int `q:"limit"`
268 SortKey SortKey `q:"sort_keys"`
269 SortDir SortDir `q:"sort_dir"`
270}
271
272// ToStackListQuery formats a ListOpts into a query string.
273func (opts ListOpts) ToStackListQuery() (string, error) {
274 q, err := gophercloud.BuildQueryString(opts)
275 if err != nil {
276 return "", err
277 }
278 return q.String(), nil
279}
280
281// List returns a Pager which allows you to iterate over a collection of
282// stacks. It accepts a ListOpts struct, which allows you to filter and sort
283// the returned collection for greater efficiency.
284func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
285 url := listURL(c)
286 if opts != nil {
287 query, err := opts.ToStackListQuery()
288 if err != nil {
289 return pagination.Pager{Err: err}
290 }
291 url += query
292 }
293
294 createPage := func(r pagination.PageResult) pagination.Page {
295 return StackPage{pagination.SinglePageBase(r)}
296 }
297 return pagination.NewPager(c, url, createPage)
298}
299
300// Get retreives a stack based on the stack name and stack ID.
301func Get(c *gophercloud.ServiceClient, stackName, stackID string) GetResult {
302 var res GetResult
303
304 // Send request to API
Ash Wilsondecfed72015-02-13 09:14:55 -0500305 _, res.Err = c.Request("GET", getURL(c, stackName, stackID), gophercloud.RequestOpts{
306 JSONResponse: &res.Body,
Jon Perritt35e27e42014-12-05 11:10:46 -0700307 })
308 return res
309}
310
311// UpdateOptsBuilder is the interface options structs have to satisfy in order
312// to be used in the Update operation in this package.
313type UpdateOptsBuilder interface {
314 ToStackUpdateMap() (map[string]interface{}, error)
315}
316
317// UpdateOpts contains the common options struct used in this package's Update
318// operation.
319type UpdateOpts struct {
Jon Perritt37f97742015-02-04 18:55:05 -0700320 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
321 // This value is ignored if Template is supplied inline.
Jon Perritt35e27e42014-12-05 11:10:46 -0700322 TemplateURL string
Jon Perritt37f97742015-02-04 18:55:05 -0700323 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
324 // is a stringified version of the JSON/YAML template. Since the template will likely
325 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
326 // import "io/ioutil"
327 // var opts stacks.CreateOpts
328 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
329 // if err != nil {
330 // // handle error...
331 // }
332 // opts.Template = string(b)
333 Template string
334 // (OPTIONAL) A stringified JSON environment for the stack.
335 Environment string
336 // (OPTIONAL) A map that maps file names to file contents. It can also be used
337 // to pass provider template contents. Example:
338 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
339 Files map[string]interface{}
340 // (OPTIONAL) User-defined parameters to pass to the template.
341 Parameters map[string]string
Jon Perritt51107182015-02-11 18:18:19 -0700342 // (OPTIONAL) The timeout for stack creation in minutes.
343 Timeout int
Jon Perritt35e27e42014-12-05 11:10:46 -0700344}
345
346// ToStackUpdateMap casts a CreateOpts struct to a map.
347func (opts UpdateOpts) ToStackUpdateMap() (map[string]interface{}, error) {
348 s := make(map[string]interface{})
349
350 if opts.Template != "" {
351 s["template"] = opts.Template
352 } else if opts.TemplateURL != "" {
353 s["template_url"] = opts.TemplateURL
354 } else {
355 return s, errors.New("Either Template or TemplateURL must be provided.")
356 }
357
358 if opts.Environment != "" {
359 s["environment"] = opts.Environment
360 }
361
362 if opts.Files != nil {
363 s["files"] = opts.Files
364 }
365
366 if opts.Parameters != nil {
367 s["parameters"] = opts.Parameters
368 }
369
370 if opts.Timeout != 0 {
371 s["timeout_mins"] = opts.Timeout
372 }
373
374 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
388 // Send request to API
Ash Wilsondecfed72015-02-13 09:14:55 -0500389 _, res.Err = c.Request("PUT", updateURL(c, stackName, stackID), gophercloud.RequestOpts{
390 JSONBody: &reqBody,
Jon Perritt35e27e42014-12-05 11:10:46 -0700391 })
392 return res
393}
394
395// Delete deletes a stack based on the stack name and stack ID.
396func Delete(c *gophercloud.ServiceClient, stackName, stackID string) DeleteResult {
397 var res DeleteResult
Jamie Hannafordc530ba12015-03-23 17:50:46 +0100398 _, res.Err = c.Request("DELETE", deleteURL(c, stackName, stackID), gophercloud.RequestOpts{})
Jon Perritt35e27e42014-12-05 11:10:46 -0700399 return res
400}
401
402// PreviewOptsBuilder is the interface options structs have to satisfy in order
403// to be used in the Preview operation in this package.
404type PreviewOptsBuilder interface {
405 ToStackPreviewMap() (map[string]interface{}, error)
406}
407
408// PreviewOpts contains the common options struct used in this package's Preview
409// operation.
410type PreviewOpts struct {
Jon Perritt37f97742015-02-04 18:55:05 -0700411 // (REQUIRED) The name of the stack. It must start with an alphabetic character.
412 Name string
413 // (REQUIRED) The timeout for stack creation in minutes.
414 Timeout int
415 // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate.
416 // This value is ignored if Template is supplied inline.
417 TemplateURL string
418 // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value
419 // is a stringified version of the JSON/YAML template. Since the template will likely
420 // be located in a file, one way to set this variable is by using ioutil.ReadFile:
421 // import "io/ioutil"
422 // var opts stacks.CreateOpts
423 // b, err := ioutil.ReadFile("path/to/you/template/file.json")
424 // if err != nil {
425 // // handle error...
426 // }
427 // opts.Template = string(b)
428 Template string
429 // (OPTIONAL) Enables or disables deletion of all stack resources when a stack
430 // creation fails. Default is true, meaning all resources are not deleted when
431 // stack creation fails.
432 DisableRollback Rollback
433 // (OPTIONAL) A stringified JSON environment for the stack.
434 Environment string
435 // (OPTIONAL) A map that maps file names to file contents. It can also be used
436 // to pass provider template contents. Example:
437 // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}`
438 Files map[string]interface{}
439 // (OPTIONAL) User-defined parameters to pass to the template.
440 Parameters map[string]string
Jon Perritt35e27e42014-12-05 11:10:46 -0700441}
442
443// ToStackPreviewMap casts a PreviewOpts struct to a map.
444func (opts PreviewOpts) ToStackPreviewMap() (map[string]interface{}, error) {
445 s := make(map[string]interface{})
446
447 if opts.Name == "" {
448 return s, errors.New("Required field 'Name' not provided.")
449 }
450 s["stack_name"] = opts.Name
451
452 if opts.Template != "" {
453 s["template"] = opts.Template
454 } else if opts.TemplateURL != "" {
455 s["template_url"] = opts.TemplateURL
456 } else {
457 return s, errors.New("Either Template or TemplateURL must be provided.")
458 }
459
460 if opts.DisableRollback != nil {
461 s["disable_rollback"] = &opts.DisableRollback
462 }
463
464 if opts.Environment != "" {
465 s["environment"] = opts.Environment
466 }
467 if opts.Files != nil {
468 s["files"] = opts.Files
469 }
470 if opts.Parameters != nil {
471 s["parameters"] = opts.Parameters
472 }
473
474 if opts.Timeout != 0 {
475 s["timeout_mins"] = opts.Timeout
476 }
477
478 return s, nil
479}
480
481// Preview accepts a PreviewOptsBuilder interface and creates a preview of a stack using the values
482// provided.
483func Preview(c *gophercloud.ServiceClient, opts PreviewOptsBuilder) PreviewResult {
484 var res PreviewResult
485
486 reqBody, err := opts.ToStackPreviewMap()
487 if err != nil {
488 res.Err = err
489 return res
490 }
491
492 // Send request to API
Ash Wilsondecfed72015-02-13 09:14:55 -0500493 _, res.Err = c.Request("POST", previewURL(c), gophercloud.RequestOpts{
494 JSONBody: &reqBody,
495 JSONResponse: &res.Body,
496 OkCodes: []int{200},
Jon Perritt35e27e42014-12-05 11:10:46 -0700497 })
498 return res
499}
500
501// Abandon deletes the stack with the provided stackName and stackID, but leaves its
502// resources intact, and returns data describing the stack and its resources.
503func Abandon(c *gophercloud.ServiceClient, stackName, stackID string) AbandonResult {
504 var res AbandonResult
505
506 // Send request to API
Ash Wilsondecfed72015-02-13 09:14:55 -0500507 _, res.Err = c.Request("DELETE", abandonURL(c, stackName, stackID), gophercloud.RequestOpts{
508 JSONResponse: &res.Body,
509 OkCodes: []int{200},
Jon Perritt35e27e42014-12-05 11:10:46 -0700510 })
511 return res
512}