blob: 04d3f8ea964a67be00eca7196a23d628aee6e8d0 [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"`
Jon Perritt35e27e42014-12-05 11:10:46 -070072 UpdatedTime time.Time `mapstructure:"-"`
73}
74
Jon Perritt7726e492015-02-04 17:54:28 -070075// ExtractStacks extracts and returns a slice of ListedStack. It is used while iterating
Jon Perritt35e27e42014-12-05 11:10:46 -070076// over a stacks.List call.
Jon Perritt22325f42015-01-29 14:48:18 -070077func ExtractStacks(page pagination.Page) ([]ListedStack, error) {
Jon Perritta11b5df2015-03-05 13:51:59 -070078 casted := page.(StackPage).Body
79
Jon Perritt35e27e42014-12-05 11:10:46 -070080 var res struct {
Jon Perritt22325f42015-01-29 14:48:18 -070081 Stacks []ListedStack `mapstructure:"stacks"`
Jon Perritt35e27e42014-12-05 11:10:46 -070082 }
83
84 err := mapstructure.Decode(page.(StackPage).Body, &res)
Jon Perritt01972e22015-01-28 10:30:45 -070085 if err != nil {
86 return nil, err
87 }
88
Jon Perritta11b5df2015-03-05 13:51:59 -070089 var rawStacks []interface{}
90 switch casted.(type) {
91 case map[string]interface{}:
92 rawStacks = casted.(map[string]interface{})["stacks"].([]interface{})
93 case map[string][]interface{}:
94 rawStacks = casted.(map[string][]interface{})["stacks"]
95 default:
96 return res.Stacks, fmt.Errorf("Unknown type: %v", reflect.TypeOf(casted))
97 }
98
Jon Perritt01972e22015-01-28 10:30:45 -070099 for i := range rawStacks {
Jon Perritt9cd3d382015-02-04 15:49:41 -0700100 thisStack := (rawStacks[i]).(map[string]interface{})
Jon Perritt01972e22015-01-28 10:30:45 -0700101
Jon Perritt9cd3d382015-02-04 15:49:41 -0700102 if t, ok := thisStack["creation_time"].(string); ok && t != "" {
103 creationTime, err := time.Parse(time.RFC3339, t)
104 if err != nil {
105 return res.Stacks, err
106 }
107 res.Stacks[i].CreationTime = creationTime
Jon Perritt01972e22015-01-28 10:30:45 -0700108 }
Jon Perritt9cd3d382015-02-04 15:49:41 -0700109
110 if t, ok := thisStack["updated_time"].(string); ok && t != "" {
111 updatedTime, err := time.Parse(time.RFC3339, t)
112 if err != nil {
113 return res.Stacks, err
114 }
115 res.Stacks[i].UpdatedTime = updatedTime
116 }
Jon Perritt01972e22015-01-28 10:30:45 -0700117 }
118
119 return res.Stacks, nil
Jon Perritt35e27e42014-12-05 11:10:46 -0700120}
121
Jon Perritt7726e492015-02-04 17:54:28 -0700122// RetrievedStack represents the object extracted from a Get operation.
Jon Perritt01972e22015-01-28 10:30:45 -0700123type RetrievedStack struct {
Jon Perritt7726e492015-02-04 17:54:28 -0700124 Capabilities []interface{} `mapstructure:"capabilities"`
125 CreationTime time.Time `mapstructure:"-"`
126 Description string `mapstructure:"description"`
127 DisableRollback bool `mapstructure:"disable_rollback"`
128 ID string `mapstructure:"id"`
129 Links []gophercloud.Link `mapstructure:"links"`
130 NotificationTopics []interface{} `mapstructure:"notification_topics"`
131 Outputs []map[string]interface{} `mapstructure:"outputs"`
132 Parameters map[string]string `mapstructure:"parameters"`
133 Name string `mapstructure:"stack_name"`
134 Status string `mapstructure:"stack_status"`
135 StatusReason string `mapstructure:"stack_status_reason"`
136 TemplateDescription string `mapstructure:"template_description"`
137 Timeout int `mapstructure:"timeout_mins"`
138 UpdatedTime time.Time `mapstructure:"-"`
Jon Perritt35e27e42014-12-05 11:10:46 -0700139}
140
Jon Perritt7726e492015-02-04 17:54:28 -0700141// GetResult represents the result of a Get operation.
Jon Perritt35e27e42014-12-05 11:10:46 -0700142type GetResult struct {
143 gophercloud.Result
144}
145
Jon Perritt7726e492015-02-04 17:54:28 -0700146// Extract returns a pointer to a RetrievedStack object and is called after a
147// Get operation.
Jon Perritt22325f42015-01-29 14:48:18 -0700148func (r GetResult) Extract() (*RetrievedStack, error) {
Jon Perritt35e27e42014-12-05 11:10:46 -0700149 if r.Err != nil {
150 return nil, r.Err
151 }
152
153 var res struct {
Jon Perritt22325f42015-01-29 14:48:18 -0700154 Stack *RetrievedStack `mapstructure:"stack"`
Jon Perritt35e27e42014-12-05 11:10:46 -0700155 }
156
157 config := &mapstructure.DecoderConfig{
158 Result: &res,
159 WeaklyTypedInput: true,
160 }
161 decoder, err := mapstructure.NewDecoder(config)
162 if err != nil {
163 return nil, err
164 }
165
166 if err := decoder.Decode(r.Body); err != nil {
167 return nil, err
168 }
169
170 b := r.Body.(map[string]interface{})["stack"].(map[string]interface{})
171
172 if date, ok := b["creation_time"]; ok && date != nil {
173 t, err := time.Parse(time.RFC3339, date.(string))
174 if err != nil {
175 return nil, err
176 }
177 res.Stack.CreationTime = t
178 }
179
180 if date, ok := b["updated_time"]; ok && date != nil {
181 t, err := time.Parse(time.RFC3339, date.(string))
182 if err != nil {
183 return nil, err
184 }
185 res.Stack.UpdatedTime = t
186 }
187
188 return res.Stack, err
189}
190
Jon Perritt7726e492015-02-04 17:54:28 -0700191// UpdateResult represents the result of a Update operation.
Jon Perritt35e27e42014-12-05 11:10:46 -0700192type UpdateResult struct {
193 gophercloud.ErrResult
194}
195
Jon Perritt7726e492015-02-04 17:54:28 -0700196// DeleteResult represents the result of a Delete operation.
Jon Perritt35e27e42014-12-05 11:10:46 -0700197type DeleteResult struct {
198 gophercloud.ErrResult
199}
200
Jon Perritt37f97742015-02-04 18:55:05 -0700201// PreviewedStack represents the result of a Preview operation.
Jon Perritt01972e22015-01-28 10:30:45 -0700202type PreviewedStack struct {
Jon Perritt37f97742015-02-04 18:55:05 -0700203 Capabilities []interface{} `mapstructure:"capabilities"`
204 CreationTime time.Time `mapstructure:"-"`
205 Description string `mapstructure:"description"`
206 DisableRollback bool `mapstructure:"disable_rollback"`
207 ID string `mapstructure:"id"`
208 Links []gophercloud.Link `mapstructure:"links"`
209 Name string `mapstructure:"stack_name"`
210 NotificationTopics []interface{} `mapstructure:"notification_topics"`
211 Parameters map[string]string `mapstructure:"parameters"`
212 Resources []map[string]interface{} `mapstructure:"resources"`
213 Status string `mapstructure:"stack_status"`
214 StatusReason string `mapstructure:"stack_status_reason"`
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 {
252 t, err := time.Parse(time.RFC3339, date.(string))
253 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 {
260 t, err := time.Parse(time.RFC3339, date.(string))
261 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 {
Jon Perritt9209df42015-02-05 12:55:33 -0700272 Status string `mapstructure:"status"`
273 Name string `mapstructure:"name"`
Jon Perritt6ec27cf2015-02-09 12:51:41 -0700274 Template map[string]interface{} `mapstructure:"template"`
Jon Perritt9209df42015-02-05 12:55:33 -0700275 Action string `mapstructure:"action"`
276 ID string `mapstructure:"id"`
277 Resources map[string]interface{} `mapstructure:"resources"`
Jon Perritt35e27e42014-12-05 11:10:46 -0700278}
279
Jon Perritt9209df42015-02-05 12:55:33 -0700280// AbandonResult represents the result of an Abandon operation.
Jon Perritt35e27e42014-12-05 11:10:46 -0700281type AbandonResult struct {
282 gophercloud.Result
283}
Jon Perritt9209df42015-02-05 12:55:33 -0700284
285// Extract returns a pointer to an AbandonedStack object and is called after an
286// Abandon operation.
287func (r AbandonResult) Extract() (*AbandonedStack, error) {
288 if r.Err != nil {
289 return nil, r.Err
290 }
291
292 var res AbandonedStack
293
294 if err := mapstructure.Decode(r.Body, &res); err != nil {
295 return nil, err
296 }
297
298 return &res, nil
299}
Jon Perritt3d381d52015-02-09 13:04:48 -0700300
Jon Perrittdb0d26a2015-02-09 13:06:16 -0700301// String converts an AbandonResult to a string. This is useful to when passing
302// the result of an Abandon operation to an AdoptOpts AdoptStackData field.
Jon Perritt3d381d52015-02-09 13:04:48 -0700303func (r AbandonResult) String() (string, error) {
304 out, err := json.Marshal(r)
305 if err != nil {
306 return "", err
307 }
308 return string(out), nil
309}