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