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