blob: 8a65793a225e7ec4141a6da76d9d4b11074ff62f [file] [log] [blame]
Jon Perritt35e27e42014-12-05 11:10:46 -07001package stacks
2
3import (
4 "errors"
5
6 "github.com/racker/perigee"
7 "github.com/rackspace/gophercloud"
8 "github.com/rackspace/gophercloud/pagination"
9)
10
Jon Perrittb20ba0b2015-02-03 13:13:42 -070011type Rollback *bool
12
13var (
14 disable = true
15 Disable Rollback = &disable
16 enable = false
17 Enable Rollback = &enable
18)
19
Jon Perritt35e27e42014-12-05 11:10:46 -070020// CreateOptsBuilder is the interface options structs have to satisfy in order
21// to be used in the main Create operation in this package. Since many
22// extensions decorate or modify the common logic, it is useful for them to
23// satisfy a basic interface in order for them to be used.
24type CreateOptsBuilder interface {
25 ToStackCreateMap() (map[string]interface{}, error)
26}
27
28// CreateOpts is the common options struct used in this package's Create
29// operation.
30type CreateOpts struct {
Jon Perritt952f3e12015-02-03 12:13:24 -070031 // (REQUIRED) The name of the stack. It must start with an alphabetic character.
32 Name string
33 // (REQUIRED) The timeout for stack creation in minutes.
34 Timeout int
35 // (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 Perritt35e27e42014-12-05 11:10:46 -070052 DisableRollback *bool
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 Perritt35e27e42014-12-05 11:10:46 -070061}
62
63// ToStackCreateMap casts a CreateOpts struct to a map.
64func (opts CreateOpts) ToStackCreateMap() (map[string]interface{}, error) {
65 s := make(map[string]interface{})
66
67 if opts.Name == "" {
68 return s, errors.New("Required field 'Name' not provided.")
69 }
70 s["stack_name"] = opts.Name
71
72 if opts.Template != "" {
73 s["template"] = opts.Template
74 } else if opts.TemplateURL != "" {
75 s["template_url"] = opts.TemplateURL
76 } else {
77 return s, errors.New("Either Template or TemplateURL must be provided.")
78 }
79
80 if opts.DisableRollback != nil {
81 s["disable_rollback"] = &opts.DisableRollback
82 }
83
84 if opts.Environment != "" {
85 s["environment"] = opts.Environment
86 }
87 if opts.Files != nil {
88 s["files"] = opts.Files
89 }
90 if opts.Parameters != nil {
91 s["parameters"] = opts.Parameters
92 }
93
Jon Perrittb20ba0b2015-02-03 13:13:42 -070094 if opts.Timeout == 0 {
95 return nil, errors.New("Required field 'Timeout' not provided.")
Jon Perritt35e27e42014-12-05 11:10:46 -070096 }
Jon Perrittb20ba0b2015-02-03 13:13:42 -070097 s["timeout_mins"] = opts.Timeout
Jon Perritt35e27e42014-12-05 11:10:46 -070098
99 return s, nil
100}
101
102// Create accepts a CreateOpts struct and creates a new stack using the values
103// provided.
104func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
105 var res CreateResult
106
107 reqBody, err := opts.ToStackCreateMap()
108 if err != nil {
109 res.Err = err
110 return res
111 }
112
113 // Send request to API
114 _, res.Err = perigee.Request("POST", createURL(c), perigee.Options{
115 MoreHeaders: c.AuthenticatedHeaders(),
116 ReqBody: &reqBody,
117 Results: &res.Body,
118 OkCodes: []int{201},
119 })
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 {
134 AdoptStackData string
135 DisableRollback *bool
136 Environment string
137 Files map[string]interface{}
138 Name string
139 Parameters map[string]string
140 Template string
141 TemplateURL string
142 Timeout int
143}
144
145// ToStackAdoptMap casts a CreateOpts struct to a map.
146func (opts AdoptOpts) ToStackAdoptMap() (map[string]interface{}, error) {
147 s := make(map[string]interface{})
148
149 if opts.Name == "" {
150 return s, errors.New("Required field 'Name' not provided.")
151 }
152 s["stack_name"] = opts.Name
153
154 if opts.Template != "" {
155 s["template"] = opts.Template
156 } else if opts.TemplateURL != "" {
157 s["template_url"] = opts.TemplateURL
158 } else {
159 return s, errors.New("Either Template or TemplateURL must be provided.")
160 }
161
162 if opts.AdoptStackData == "" {
163 return s, errors.New("Required field 'AdoptStackData' not provided.")
164 }
165 s["adopt_stack_data"] = opts.AdoptStackData
166
167 if opts.DisableRollback != nil {
168 s["disable_rollback"] = &opts.DisableRollback
169 }
170
171 if opts.Environment != "" {
172 s["environment"] = opts.Environment
173 }
174 if opts.Files != nil {
175 s["files"] = opts.Files
176 }
177 if opts.Parameters != nil {
178 s["parameters"] = opts.Parameters
179 }
180
181 if opts.Timeout != 0 {
182 s["timeout_mins"] = opts.Timeout
183 }
184
185 return map[string]interface{}{"stack": s}, nil
186}
187
188// Adopt accepts an AdoptOpts struct and creates a new stack using the resources
189// from another stack.
190func Adopt(c *gophercloud.ServiceClient, opts AdoptOptsBuilder) CreateResult {
191 var res CreateResult
192
193 reqBody, err := opts.ToStackAdoptMap()
194 if err != nil {
195 res.Err = err
196 return res
197 }
198
199 // Send request to API
200 _, res.Err = perigee.Request("POST", adoptURL(c), perigee.Options{
201 MoreHeaders: c.AuthenticatedHeaders(),
202 ReqBody: &reqBody,
203 Results: &res.Body,
204 OkCodes: []int{201},
205 })
206 return res
207}
208
209// SortDir is a type for specifying in which direction to sort a list of stacks.
210type SortDir string
211
212// SortKey is a type for specifying by which key to sort a list of stacks.
213type SortKey string
214
215var (
216 // SortAsc is used to sort a list of stacks in ascending order.
217 SortAsc SortDir = "asc"
218 // SortDesc is used to sort a list of stacks in descending order.
219 SortDesc SortDir = "desc"
220 // SortName is used to sort a list of stacks by name.
221 SortName SortKey = "name"
222 // SortStatus is used to sort a list of stacks by status.
223 SortStatus SortKey = "status"
224 // SortCreatedAt is used to sort a list of stacks by date created.
225 SortCreatedAt SortKey = "created_at"
226 // SortUpdatedAt is used to sort a list of stacks by date updated.
227 SortUpdatedAt SortKey = "updated_at"
228)
229
230// ListOptsBuilder allows extensions to add additional parameters to the
231// List request.
232type ListOptsBuilder interface {
233 ToStackListQuery() (string, error)
234}
235
236// ListOpts allows the filtering and sorting of paginated collections through
237// the API. Filtering is achieved by passing in struct field values that map to
238// the network attributes you want to see returned. SortKey allows you to sort
239// by a particular network attribute. SortDir sets the direction, and is either
240// `asc' or `desc'. Marker and Limit are used for pagination.
241type ListOpts struct {
242 Status string `q:"status"`
243 Name string `q:"name"`
244 Marker string `q:"marker"`
245 Limit int `q:"limit"`
246 SortKey SortKey `q:"sort_keys"`
247 SortDir SortDir `q:"sort_dir"`
248}
249
250// ToStackListQuery formats a ListOpts into a query string.
251func (opts ListOpts) ToStackListQuery() (string, error) {
252 q, err := gophercloud.BuildQueryString(opts)
253 if err != nil {
254 return "", err
255 }
256 return q.String(), nil
257}
258
259// List returns a Pager which allows you to iterate over a collection of
260// stacks. It accepts a ListOpts struct, which allows you to filter and sort
261// the returned collection for greater efficiency.
262func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
263 url := listURL(c)
264 if opts != nil {
265 query, err := opts.ToStackListQuery()
266 if err != nil {
267 return pagination.Pager{Err: err}
268 }
269 url += query
270 }
271
272 createPage := func(r pagination.PageResult) pagination.Page {
273 return StackPage{pagination.SinglePageBase(r)}
274 }
275 return pagination.NewPager(c, url, createPage)
276}
277
278// Get retreives a stack based on the stack name and stack ID.
279func Get(c *gophercloud.ServiceClient, stackName, stackID string) GetResult {
280 var res GetResult
281
282 // Send request to API
283 _, res.Err = perigee.Request("GET", getURL(c, stackName, stackID), perigee.Options{
284 MoreHeaders: c.AuthenticatedHeaders(),
285 Results: &res.Body,
286 OkCodes: []int{200},
287 })
288 return res
289}
290
291// UpdateOptsBuilder is the interface options structs have to satisfy in order
292// to be used in the Update operation in this package.
293type UpdateOptsBuilder interface {
294 ToStackUpdateMap() (map[string]interface{}, error)
295}
296
297// UpdateOpts contains the common options struct used in this package's Update
298// operation.
299type UpdateOpts struct {
300 Environment string
301 Files map[string]interface{}
302 Parameters map[string]string
303 Template string
304 TemplateURL string
305 Timeout int
306}
307
308// ToStackUpdateMap casts a CreateOpts struct to a map.
309func (opts UpdateOpts) ToStackUpdateMap() (map[string]interface{}, error) {
310 s := make(map[string]interface{})
311
312 if opts.Template != "" {
313 s["template"] = opts.Template
314 } else if opts.TemplateURL != "" {
315 s["template_url"] = opts.TemplateURL
316 } else {
317 return s, errors.New("Either Template or TemplateURL must be provided.")
318 }
319
320 if opts.Environment != "" {
321 s["environment"] = opts.Environment
322 }
323
324 if opts.Files != nil {
325 s["files"] = opts.Files
326 }
327
328 if opts.Parameters != nil {
329 s["parameters"] = opts.Parameters
330 }
331
332 if opts.Timeout != 0 {
333 s["timeout_mins"] = opts.Timeout
334 }
335
336 return s, nil
337}
338
339// Update accepts an UpdateOpts struct and updates an existing stack using the values
340// provided.
341func Update(c *gophercloud.ServiceClient, stackName, stackID string, opts UpdateOptsBuilder) UpdateResult {
342 var res UpdateResult
343
344 reqBody, err := opts.ToStackUpdateMap()
345 if err != nil {
346 res.Err = err
347 return res
348 }
349
350 // Send request to API
351 _, res.Err = perigee.Request("PUT", updateURL(c, stackName, stackID), perigee.Options{
352 MoreHeaders: c.AuthenticatedHeaders(),
353 ReqBody: &reqBody,
354 OkCodes: []int{202},
355 })
356 return res
357}
358
359// Delete deletes a stack based on the stack name and stack ID.
360func Delete(c *gophercloud.ServiceClient, stackName, stackID string) DeleteResult {
361 var res DeleteResult
362
363 // Send request to API
364 _, res.Err = perigee.Request("DELETE", deleteURL(c, stackName, stackID), perigee.Options{
365 MoreHeaders: c.AuthenticatedHeaders(),
366 OkCodes: []int{204},
367 })
368 return res
369}
370
371// PreviewOptsBuilder is the interface options structs have to satisfy in order
372// to be used in the Preview operation in this package.
373type PreviewOptsBuilder interface {
374 ToStackPreviewMap() (map[string]interface{}, error)
375}
376
377// PreviewOpts contains the common options struct used in this package's Preview
378// operation.
379type PreviewOpts struct {
380 DisableRollback *bool
381 Environment string
382 Files map[string]interface{}
383 Name string
384 Parameters map[string]string
385 Template string
386 TemplateURL string
387 Timeout int
388}
389
390// ToStackPreviewMap casts a PreviewOpts struct to a map.
391func (opts PreviewOpts) ToStackPreviewMap() (map[string]interface{}, error) {
392 s := make(map[string]interface{})
393
394 if opts.Name == "" {
395 return s, errors.New("Required field 'Name' not provided.")
396 }
397 s["stack_name"] = opts.Name
398
399 if opts.Template != "" {
400 s["template"] = opts.Template
401 } else if opts.TemplateURL != "" {
402 s["template_url"] = opts.TemplateURL
403 } else {
404 return s, errors.New("Either Template or TemplateURL must be provided.")
405 }
406
407 if opts.DisableRollback != nil {
408 s["disable_rollback"] = &opts.DisableRollback
409 }
410
411 if opts.Environment != "" {
412 s["environment"] = opts.Environment
413 }
414 if opts.Files != nil {
415 s["files"] = opts.Files
416 }
417 if opts.Parameters != nil {
418 s["parameters"] = opts.Parameters
419 }
420
421 if opts.Timeout != 0 {
422 s["timeout_mins"] = opts.Timeout
423 }
424
425 return s, nil
426}
427
428// Preview accepts a PreviewOptsBuilder interface and creates a preview of a stack using the values
429// provided.
430func Preview(c *gophercloud.ServiceClient, opts PreviewOptsBuilder) PreviewResult {
431 var res PreviewResult
432
433 reqBody, err := opts.ToStackPreviewMap()
434 if err != nil {
435 res.Err = err
436 return res
437 }
438
439 // Send request to API
440 _, res.Err = perigee.Request("POST", previewURL(c), perigee.Options{
441 MoreHeaders: c.AuthenticatedHeaders(),
442 ReqBody: &reqBody,
443 Results: &res.Body,
444 OkCodes: []int{200},
445 })
446 return res
447}
448
449// Abandon deletes the stack with the provided stackName and stackID, but leaves its
450// resources intact, and returns data describing the stack and its resources.
451func Abandon(c *gophercloud.ServiceClient, stackName, stackID string) AbandonResult {
452 var res AbandonResult
453
454 // Send request to API
Jon Perritt6e844732015-01-29 14:49:34 -0700455 _, res.Err = perigee.Request("POST", abandonURL(c, stackName, stackID), perigee.Options{
Jon Perritt35e27e42014-12-05 11:10:46 -0700456 MoreHeaders: c.AuthenticatedHeaders(),
457 Results: &res.Body,
458 OkCodes: []int{200},
459 })
460 return res
461}