blob: 432bc8e0cc5ca7cd6079ed711b3c050e052f8edc [file] [log] [blame]
Jon Perritt35e27e42014-12-05 11:10:46 -07001package stacks
2
3import (
Jon Perritt3d381d52015-02-09 13:04:48 -07004 "encoding/json"
Jon Perritta11b5df2015-03-05 13:51:59 -07005 "fmt"
6 "reflect"
Jon Perritt35e27e42014-12-05 11:10:46 -07007 "time"
8
9 "github.com/mitchellh/mapstructure"
10 "github.com/rackspace/gophercloud"
11 "github.com/rackspace/gophercloud/pagination"
12)
13
Jon Perritt7726e492015-02-04 17:54:28 -070014// CreatedStack represents the object extracted from a Create operation.
Jon Perritt01972e22015-01-28 10:30:45 -070015type CreatedStack struct {
Jon Perritt35e27e42014-12-05 11:10:46 -070016 ID string `mapstructure:"id"`
17 Links []gophercloud.Link `mapstructure:"links"`
18}
19
Jon Perritt7726e492015-02-04 17:54:28 -070020// CreateResult represents the result of a Create operation.
Jon Perritt35e27e42014-12-05 11:10:46 -070021type CreateResult struct {
22 gophercloud.Result
23}
24
Jon Perritt7726e492015-02-04 17:54:28 -070025// Extract returns a pointer to a CreatedStack object and is called after a
26// Create operation.
Jon Perritt22325f42015-01-29 14:48:18 -070027func (r CreateResult) Extract() (*CreatedStack, error) {
Jon Perritt35e27e42014-12-05 11:10:46 -070028 if r.Err != nil {
29 return nil, r.Err
30 }
31
32 var res struct {
Jon Perritt22325f42015-01-29 14:48:18 -070033 Stack *CreatedStack `mapstructure:"stack"`
Jon Perritt35e27e42014-12-05 11:10:46 -070034 }
35
36 if err := mapstructure.Decode(r.Body, &res); err != nil {
37 return nil, err
38 }
39
40 return res.Stack, nil
41}
42
Jon Perritt7726e492015-02-04 17:54:28 -070043// AdoptResult represents the result of an Adopt operation. AdoptResult has the
44// same form as CreateResult.
Jon Perritt35e27e42014-12-05 11:10:46 -070045type AdoptResult struct {
Jon Perritt9741dd92015-02-04 12:05:47 -070046 CreateResult
Jon Perritt35e27e42014-12-05 11:10:46 -070047}
48
49// StackPage is a pagination.Pager that is returned from a call to the List function.
50type StackPage struct {
51 pagination.SinglePageBase
52}
53
54// IsEmpty returns true if a ListResult contains no Stacks.
55func (r StackPage) IsEmpty() (bool, error) {
56 stacks, err := ExtractStacks(r)
57 if err != nil {
58 return true, err
59 }
60 return len(stacks) == 0, nil
61}
62
Jon Perritt7726e492015-02-04 17:54:28 -070063// ListedStack represents an element in the slice extracted from a List operation.
Jon Perritt01972e22015-01-28 10:30:45 -070064type ListedStack struct {
Jon Perritt35e27e42014-12-05 11:10:46 -070065 CreationTime time.Time `mapstructure:"-"`
66 Description string `mapstructure:"description"`
67 ID string `mapstructure:"id"`
68 Links []gophercloud.Link `mapstructure:"links"`
69 Name string `mapstructure:"stack_name"`
70 Status string `mapstructure:"stack_status"`
Jon Perritt01972e22015-01-28 10:30:45 -070071 StatusReason string `mapstructure:"stack_status_reason"`
Pratik Mallya827c03e2015-09-17 00:10:47 -050072 Tags []string `mapstructure:"tags"`
Jon Perritt35e27e42014-12-05 11:10:46 -070073 UpdatedTime time.Time `mapstructure:"-"`
74}
75
Jon Perritt7726e492015-02-04 17:54:28 -070076// ExtractStacks extracts and returns a slice of ListedStack. It is used while iterating
Jon Perritt35e27e42014-12-05 11:10:46 -070077// over a stacks.List call.
Jon Perritt22325f42015-01-29 14:48:18 -070078func ExtractStacks(page pagination.Page) ([]ListedStack, error) {
Jon Perritta11b5df2015-03-05 13:51:59 -070079 casted := page.(StackPage).Body
80
Jon Perritt35e27e42014-12-05 11:10:46 -070081 var res struct {
Jon Perritt22325f42015-01-29 14:48:18 -070082 Stacks []ListedStack `mapstructure:"stacks"`
Jon Perritt35e27e42014-12-05 11:10:46 -070083 }
84
Pratik Mallya827c03e2015-09-17 00:10:47 -050085 err := mapstructure.Decode(casted, &res)
Jon Perritt01972e22015-01-28 10:30:45 -070086 if err != nil {
87 return nil, err
88 }
89
Jon Perritta11b5df2015-03-05 13:51:59 -070090 var rawStacks []interface{}
91 switch casted.(type) {
92 case map[string]interface{}:
93 rawStacks = casted.(map[string]interface{})["stacks"].([]interface{})
94 case map[string][]interface{}:
95 rawStacks = casted.(map[string][]interface{})["stacks"]
96 default:
97 return res.Stacks, fmt.Errorf("Unknown type: %v", reflect.TypeOf(casted))
98 }
99
Jon Perritt01972e22015-01-28 10:30:45 -0700100 for i := range rawStacks {
Jon Perritt9cd3d382015-02-04 15:49:41 -0700101 thisStack := (rawStacks[i]).(map[string]interface{})
Jon Perritt01972e22015-01-28 10:30:45 -0700102
Jon Perritt9cd3d382015-02-04 15:49:41 -0700103 if t, ok := thisStack["creation_time"].(string); ok && t != "" {
Pratik Mallyae1b6cbb2015-09-09 14:24:14 -0500104 creationTime, err := time.Parse(gophercloud.STACK_TIME_FMT, t)
Jon Perritt9cd3d382015-02-04 15:49:41 -0700105 if err != nil {
106 return res.Stacks, err
107 }
108 res.Stacks[i].CreationTime = creationTime
Jon Perritt01972e22015-01-28 10:30:45 -0700109 }
Jon Perritt9cd3d382015-02-04 15:49:41 -0700110
111 if t, ok := thisStack["updated_time"].(string); ok && t != "" {
Pratik Mallyae1b6cbb2015-09-09 14:24:14 -0500112 updatedTime, err := time.Parse(gophercloud.STACK_TIME_FMT, t)
Jon Perritt9cd3d382015-02-04 15:49:41 -0700113 if err != nil {
114 return res.Stacks, err
115 }
116 res.Stacks[i].UpdatedTime = updatedTime
117 }
Jon Perritt01972e22015-01-28 10:30:45 -0700118 }
119
120 return res.Stacks, nil
Jon Perritt35e27e42014-12-05 11:10:46 -0700121}
122
Jon Perritt7726e492015-02-04 17:54:28 -0700123// RetrievedStack represents the object extracted from a Get operation.
Jon Perritt01972e22015-01-28 10:30:45 -0700124type RetrievedStack struct {
Jon Perritt7726e492015-02-04 17:54:28 -0700125 Capabilities []interface{} `mapstructure:"capabilities"`
126 CreationTime time.Time `mapstructure:"-"`
127 Description string `mapstructure:"description"`
128 DisableRollback bool `mapstructure:"disable_rollback"`
129 ID string `mapstructure:"id"`
130 Links []gophercloud.Link `mapstructure:"links"`
131 NotificationTopics []interface{} `mapstructure:"notification_topics"`
132 Outputs []map[string]interface{} `mapstructure:"outputs"`
133 Parameters map[string]string `mapstructure:"parameters"`
134 Name string `mapstructure:"stack_name"`
135 Status string `mapstructure:"stack_status"`
136 StatusReason string `mapstructure:"stack_status_reason"`
Pratik Mallya827c03e2015-09-17 00:10:47 -0500137 Tags []string `mapstructure:"tags"`
Jon Perritt7726e492015-02-04 17:54:28 -0700138 TemplateDescription string `mapstructure:"template_description"`
139 Timeout int `mapstructure:"timeout_mins"`
140 UpdatedTime time.Time `mapstructure:"-"`
Jon Perritt35e27e42014-12-05 11:10:46 -0700141}
142
Jon Perritt7726e492015-02-04 17:54:28 -0700143// GetResult represents the result of a Get operation.
Jon Perritt35e27e42014-12-05 11:10:46 -0700144type GetResult struct {
145 gophercloud.Result
146}
147
Jon Perritt7726e492015-02-04 17:54:28 -0700148// Extract returns a pointer to a RetrievedStack object and is called after a
149// Get operation.
Jon Perritt22325f42015-01-29 14:48:18 -0700150func (r GetResult) Extract() (*RetrievedStack, error) {
Jon Perritt35e27e42014-12-05 11:10:46 -0700151 if r.Err != nil {
152 return nil, r.Err
153 }
154
155 var res struct {
Jon Perritt22325f42015-01-29 14:48:18 -0700156 Stack *RetrievedStack `mapstructure:"stack"`
Jon Perritt35e27e42014-12-05 11:10:46 -0700157 }
158
159 config := &mapstructure.DecoderConfig{
160 Result: &res,
161 WeaklyTypedInput: true,
162 }
163 decoder, err := mapstructure.NewDecoder(config)
164 if err != nil {
165 return nil, err
166 }
167
168 if err := decoder.Decode(r.Body); err != nil {
169 return nil, err
170 }
171
172 b := r.Body.(map[string]interface{})["stack"].(map[string]interface{})
173
174 if date, ok := b["creation_time"]; ok && date != nil {
Pratik Mallyae1b6cbb2015-09-09 14:24:14 -0500175 t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
Jon Perritt35e27e42014-12-05 11:10:46 -0700176 if err != nil {
177 return nil, err
178 }
179 res.Stack.CreationTime = t
180 }
181
182 if date, ok := b["updated_time"]; ok && date != nil {
Pratik Mallyae1b6cbb2015-09-09 14:24:14 -0500183 t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
Jon Perritt35e27e42014-12-05 11:10:46 -0700184 if err != nil {
185 return nil, err
186 }
187 res.Stack.UpdatedTime = t
188 }
189
190 return res.Stack, err
191}
192
Jon Perritt7726e492015-02-04 17:54:28 -0700193// UpdateResult represents the result of a Update operation.
Jon Perritt35e27e42014-12-05 11:10:46 -0700194type UpdateResult struct {
195 gophercloud.ErrResult
196}
197
Jon Perritt7726e492015-02-04 17:54:28 -0700198// DeleteResult represents the result of a Delete operation.
Jon Perritt35e27e42014-12-05 11:10:46 -0700199type DeleteResult struct {
200 gophercloud.ErrResult
201}
202
Jon Perritt37f97742015-02-04 18:55:05 -0700203// PreviewedStack represents the result of a Preview operation.
Jon Perritt01972e22015-01-28 10:30:45 -0700204type PreviewedStack struct {
Pratik Mallya827c03e2015-09-17 00:10:47 -0500205 Capabilities []interface{} `mapstructure:"capabilities"`
206 CreationTime time.Time `mapstructure:"-"`
207 Description string `mapstructure:"description"`
208 DisableRollback bool `mapstructure:"disable_rollback"`
209 ID string `mapstructure:"id"`
210 Links []gophercloud.Link `mapstructure:"links"`
211 Name string `mapstructure:"stack_name"`
212 NotificationTopics []interface{} `mapstructure:"notification_topics"`
213 Parameters map[string]string `mapstructure:"parameters"`
214 Resources []interface{} `mapstructure:"resources"`
215 TemplateDescription string `mapstructure:"template_description"`
216 Timeout int `mapstructure:"timeout_mins"`
217 UpdatedTime time.Time `mapstructure:"-"`
Jon Perritt35e27e42014-12-05 11:10:46 -0700218}
219
Jon Perritt37f97742015-02-04 18:55:05 -0700220// PreviewResult represents the result of a Preview operation.
Jon Perritt35e27e42014-12-05 11:10:46 -0700221type PreviewResult struct {
222 gophercloud.Result
223}
224
Jon Perritt37f97742015-02-04 18:55:05 -0700225// Extract returns a pointer to a PreviewedStack object and is called after a
226// Preview operation.
Jon Perritt22325f42015-01-29 14:48:18 -0700227func (r PreviewResult) Extract() (*PreviewedStack, error) {
Jon Perritt35e27e42014-12-05 11:10:46 -0700228 if r.Err != nil {
229 return nil, r.Err
230 }
231
232 var res struct {
Jon Perritt22325f42015-01-29 14:48:18 -0700233 Stack *PreviewedStack `mapstructure:"stack"`
Jon Perritt35e27e42014-12-05 11:10:46 -0700234 }
235
236 config := &mapstructure.DecoderConfig{
237 Result: &res,
238 WeaklyTypedInput: true,
239 }
240 decoder, err := mapstructure.NewDecoder(config)
241 if err != nil {
242 return nil, err
243 }
244
245 if err := decoder.Decode(r.Body); err != nil {
246 return nil, err
247 }
248
249 b := r.Body.(map[string]interface{})["stack"].(map[string]interface{})
250
251 if date, ok := b["creation_time"]; ok && date != nil {
Pratik Mallyae1b6cbb2015-09-09 14:24:14 -0500252 t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
Jon Perritt35e27e42014-12-05 11:10:46 -0700253 if err != nil {
254 return nil, err
255 }
256 res.Stack.CreationTime = t
257 }
258
259 if date, ok := b["updated_time"]; ok && date != nil {
Pratik Mallyae1b6cbb2015-09-09 14:24:14 -0500260 t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
Jon Perritt35e27e42014-12-05 11:10:46 -0700261 if err != nil {
262 return nil, err
263 }
264 res.Stack.UpdatedTime = t
265 }
266
267 return res.Stack, err
268}
269
Jon Perritt9209df42015-02-05 12:55:33 -0700270// AbandonedStack represents the result of an Abandon operation.
Jon Perritt01972e22015-01-28 10:30:45 -0700271type AbandonedStack struct {
Pratik Mallya827c03e2015-09-17 00:10:47 -0500272 Status string `mapstructure:"status"`
273 Name string `mapstructure:"name"`
274 Template map[string]interface{} `mapstructure:"template"`
275 Action string `mapstructure:"action"`
276 ID string `mapstructure:"id"`
277 Resources map[string]interface{} `mapstructure:"resources"`
278 Files map[string]string `mapstructure:"files"`
279 StackUserProjectID string `mapstructure:"stack_user_project_id"`
280 ProjectID string `mapstructure:"project_id"`
281 Environment map[string]interface{} `mapstructure:"environment"`
Jon Perritt35e27e42014-12-05 11:10:46 -0700282}
283
Jon Perritt9209df42015-02-05 12:55:33 -0700284// AbandonResult represents the result of an Abandon operation.
Jon Perritt35e27e42014-12-05 11:10:46 -0700285type AbandonResult struct {
286 gophercloud.Result
287}
Jon Perritt9209df42015-02-05 12:55:33 -0700288
289// Extract returns a pointer to an AbandonedStack object and is called after an
290// Abandon operation.
291func (r AbandonResult) Extract() (*AbandonedStack, error) {
292 if r.Err != nil {
293 return nil, r.Err
294 }
295
296 var res AbandonedStack
297
298 if err := mapstructure.Decode(r.Body, &res); err != nil {
299 return nil, err
300 }
301
302 return &res, nil
303}
Jon Perritt3d381d52015-02-09 13:04:48 -0700304
Jon Perrittdb0d26a2015-02-09 13:06:16 -0700305// String converts an AbandonResult to a string. This is useful to when passing
306// the result of an Abandon operation to an AdoptOpts AdoptStackData field.
Jon Perritt3d381d52015-02-09 13:04:48 -0700307func (r AbandonResult) String() (string, error) {
308 out, err := json.Marshal(r)
309 if err != nil {
310 return "", err
311 }
312 return string(out), nil
313}