blob: 6ddc7660dd738d90150d5b8c5e2d05c1fd62fd5d [file] [log] [blame]
Jon Perritt3711cd02014-12-22 22:20:15 -07001package stackresources
2
3import (
Pratik Mallya827c03e2015-09-17 00:10:47 -05004 "encoding/json"
Jon Perritta11b5df2015-03-05 13:51:59 -07005 "fmt"
6 "reflect"
Jon Perritt3711cd02014-12-22 22:20:15 -07007 "time"
8
9 "github.com/mitchellh/mapstructure"
10 "github.com/rackspace/gophercloud"
11 "github.com/rackspace/gophercloud/pagination"
12)
13
Jon Perrittbba201b2015-02-08 21:12:38 -070014// Resource represents a stack resource.
Jon Perritt3711cd02014-12-22 22:20:15 -070015type Resource struct {
Pratik Mallya827c03e2015-09-17 00:10:47 -050016 Attributes map[string]interface{} `mapstructure:"attributes"`
17 CreationTime time.Time `mapstructure:"-"`
18 Description string `mapstructure:"description"`
19 Links []gophercloud.Link `mapstructure:"links"`
20 LogicalID string `mapstructure:"logical_resource_id"`
21 Name string `mapstructure:"resource_name"`
22 PhysicalID string `mapstructure:"physical_resource_id"`
23 RequiredBy []interface{} `mapstructure:"required_by"`
24 Status string `mapstructure:"resource_status"`
25 StatusReason string `mapstructure:"resource_status_reason"`
26 Type string `mapstructure:"resource_type"`
27 UpdatedTime time.Time `mapstructure:"-"`
Jon Perritt3711cd02014-12-22 22:20:15 -070028}
29
Jon Perrittbba201b2015-02-08 21:12:38 -070030// FindResult represents the result of a Find operation.
Jon Perritt3711cd02014-12-22 22:20:15 -070031type FindResult struct {
32 gophercloud.Result
33}
34
Jon Perrittbba201b2015-02-08 21:12:38 -070035// Extract returns a slice of Resource objects and is called after a
36// Find operation.
Jon Perritt3711cd02014-12-22 22:20:15 -070037func (r FindResult) Extract() ([]Resource, error) {
38 if r.Err != nil {
39 return nil, r.Err
40 }
41
42 var res struct {
43 Res []Resource `mapstructure:"resources"`
44 }
45
46 if err := mapstructure.Decode(r.Body, &res); err != nil {
47 return nil, err
48 }
49
Jon Perritta065da12015-02-06 10:20:16 -070050 resources := r.Body.(map[string]interface{})["resources"].([]interface{})
Jon Perritt3711cd02014-12-22 22:20:15 -070051
Jon Perritta065da12015-02-06 10:20:16 -070052 for i, resourceRaw := range resources {
53 resource := resourceRaw.(map[string]interface{})
Jon Perritt3711cd02014-12-22 22:20:15 -070054 if date, ok := resource["updated_time"]; ok && date != nil {
Pratik Mallyae1b6cbb2015-09-09 14:24:14 -050055 t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
Jon Perritt3711cd02014-12-22 22:20:15 -070056 if err != nil {
57 return nil, err
58 }
59 res.Res[i].UpdatedTime = t
60 }
Pratik Mallya827c03e2015-09-17 00:10:47 -050061 if date, ok := resource["creation_time"]; ok && date != nil {
62 t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
63 if err != nil {
64 return nil, err
65 }
66 res.Res[i].CreationTime = t
67 }
Jon Perritt3711cd02014-12-22 22:20:15 -070068 }
69
70 return res.Res, nil
71}
72
73// ResourcePage abstracts the raw results of making a List() request against the API.
74// As OpenStack extensions may freely alter the response bodies of structures returned to the client, you may only safely access the
75// data provided through the ExtractResources call.
76type ResourcePage struct {
Pratik Mallya5448f582015-08-21 12:21:09 -050077 pagination.SinglePageBase
Jon Perritt3711cd02014-12-22 22:20:15 -070078}
79
80// IsEmpty returns true if a page contains no Server results.
Jon Perrittc8717332015-02-08 20:14:29 -070081func (r ResourcePage) IsEmpty() (bool, error) {
82 resources, err := ExtractResources(r)
Jon Perritt3711cd02014-12-22 22:20:15 -070083 if err != nil {
84 return true, err
85 }
86 return len(resources) == 0, nil
87}
88
Jon Perritt3711cd02014-12-22 22:20:15 -070089// ExtractResources interprets the results of a single page from a List() call, producing a slice of Resource entities.
90func ExtractResources(page pagination.Page) ([]Resource, error) {
91 casted := page.(ResourcePage).Body
92
93 var response struct {
94 Resources []Resource `mapstructure:"resources"`
95 }
Pratik Mallya827c03e2015-09-17 00:10:47 -050096 if err := mapstructure.Decode(casted, &response); err != nil {
97 return nil, err
98 }
Jon Perritta11b5df2015-03-05 13:51:59 -070099 var resources []interface{}
100 switch casted.(type) {
101 case map[string]interface{}:
102 resources = casted.(map[string]interface{})["resources"].([]interface{})
103 case map[string][]interface{}:
104 resources = casted.(map[string][]interface{})["resources"]
105 default:
106 return response.Resources, fmt.Errorf("Unknown type: %v", reflect.TypeOf(casted))
107 }
Jon Perritta065da12015-02-06 10:20:16 -0700108
109 for i, resourceRaw := range resources {
110 resource := resourceRaw.(map[string]interface{})
111 if date, ok := resource["updated_time"]; ok && date != nil {
Pratik Mallyae1b6cbb2015-09-09 14:24:14 -0500112 t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
Jon Perritta065da12015-02-06 10:20:16 -0700113 if err != nil {
114 return nil, err
115 }
116 response.Resources[i].UpdatedTime = t
117 }
Pratik Mallya827c03e2015-09-17 00:10:47 -0500118 if date, ok := resource["creation_time"]; ok && date != nil {
119 t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
120 if err != nil {
121 return nil, err
122 }
123 response.Resources[i].CreationTime = t
124 }
Jon Perritta065da12015-02-06 10:20:16 -0700125 }
126
Pratik Mallya827c03e2015-09-17 00:10:47 -0500127 return response.Resources, nil
Jon Perritt3711cd02014-12-22 22:20:15 -0700128}
129
Jon Perrittbba201b2015-02-08 21:12:38 -0700130// GetResult represents the result of a Get operation.
Jon Perritt3711cd02014-12-22 22:20:15 -0700131type GetResult struct {
132 gophercloud.Result
133}
134
Jon Perrittbba201b2015-02-08 21:12:38 -0700135// Extract returns a pointer to a Resource object and is called after a
136// Get operation.
Jon Perritt3711cd02014-12-22 22:20:15 -0700137func (r GetResult) Extract() (*Resource, error) {
138 if r.Err != nil {
139 return nil, r.Err
140 }
141
142 var res struct {
143 Res *Resource `mapstructure:"resource"`
144 }
145
146 if err := mapstructure.Decode(r.Body, &res); err != nil {
147 return nil, err
148 }
149
150 resource := r.Body.(map[string]interface{})["resource"].(map[string]interface{})
151
152 if date, ok := resource["updated_time"]; ok && date != nil {
Pratik Mallyae1b6cbb2015-09-09 14:24:14 -0500153 t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
Jon Perritt3711cd02014-12-22 22:20:15 -0700154 if err != nil {
155 return nil, err
156 }
157 res.Res.UpdatedTime = t
158 }
Pratik Mallya827c03e2015-09-17 00:10:47 -0500159 if date, ok := resource["creation_time"]; ok && date != nil {
160 t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
161 if err != nil {
162 return nil, err
163 }
164 res.Res.CreationTime = t
165 }
Jon Perritt3711cd02014-12-22 22:20:15 -0700166
167 return res.Res, nil
168}
169
Jon Perrittbba201b2015-02-08 21:12:38 -0700170// MetadataResult represents the result of a Metadata operation.
Jon Perritt3711cd02014-12-22 22:20:15 -0700171type MetadataResult struct {
172 gophercloud.Result
173}
174
Jon Perrittbba201b2015-02-08 21:12:38 -0700175// Extract returns a map object and is called after a
176// Metadata operation.
Jon Perritt3711cd02014-12-22 22:20:15 -0700177func (r MetadataResult) Extract() (map[string]string, error) {
178 if r.Err != nil {
179 return nil, r.Err
180 }
181
182 var res struct {
183 Meta map[string]string `mapstructure:"metadata"`
184 }
185
186 if err := mapstructure.Decode(r.Body, &res); err != nil {
187 return nil, err
188 }
189
190 return res.Meta, nil
191}
Jon Perritta065da12015-02-06 10:20:16 -0700192
193// ResourceTypePage abstracts the raw results of making a ListTypes() request against the API.
194// As OpenStack extensions may freely alter the response bodies of structures returned to the client, you may only safely access the
195// data provided through the ExtractResourceTypes call.
196type ResourceTypePage struct {
197 pagination.SinglePageBase
198}
199
200// IsEmpty returns true if a ResourceTypePage contains no resource types.
201func (r ResourceTypePage) IsEmpty() (bool, error) {
202 rts, err := ExtractResourceTypes(r)
203 if err != nil {
204 return true, err
205 }
206 return len(rts) == 0, nil
207}
208
Pratik Mallya3de347f2015-09-22 12:25:59 -0500209// ResourceTypes represents the type that holds the result of ExtractResourceTypes.
Pratik Mallya827c03e2015-09-17 00:10:47 -0500210// We define methods on this type to sort it before output
Pratik Mallya3de347f2015-09-22 12:25:59 -0500211type ResourceTypes []string
Pratik Mallya827c03e2015-09-17 00:10:47 -0500212
Pratik Mallya3de347f2015-09-22 12:25:59 -0500213func (r ResourceTypes) Len() int {
Pratik Mallya827c03e2015-09-17 00:10:47 -0500214 return len(r)
215}
216
Pratik Mallya3de347f2015-09-22 12:25:59 -0500217func (r ResourceTypes) Swap(i, j int) {
Pratik Mallya827c03e2015-09-17 00:10:47 -0500218 r[i], r[j] = r[j], r[i]
219}
220
Pratik Mallya3de347f2015-09-22 12:25:59 -0500221func (r ResourceTypes) Less(i, j int) bool {
Pratik Mallya827c03e2015-09-17 00:10:47 -0500222 return r[i] < r[j]
223}
224
Jon Perritta065da12015-02-06 10:20:16 -0700225// ExtractResourceTypes extracts and returns resource types.
Pratik Mallya3de347f2015-09-22 12:25:59 -0500226func ExtractResourceTypes(page pagination.Page) (ResourceTypes, error) {
Pratik Mallya827c03e2015-09-17 00:10:47 -0500227 casted := page.(ResourceTypePage).Body
228
Jon Perritta065da12015-02-06 10:20:16 -0700229 var response struct {
Pratik Mallya3de347f2015-09-22 12:25:59 -0500230 ResourceTypes ResourceTypes `mapstructure:"resource_types"`
Jon Perritta065da12015-02-06 10:20:16 -0700231 }
232
Pratik Mallya827c03e2015-09-17 00:10:47 -0500233 if err := mapstructure.Decode(casted, &response); err != nil {
234 return nil, err
235 }
236 return response.ResourceTypes, nil
Jon Perritta065da12015-02-06 10:20:16 -0700237}
Jon Perritt1d4aca02015-02-06 12:29:16 -0700238
Jon Perrittbba201b2015-02-08 21:12:38 -0700239// TypeSchema represents a stack resource schema.
Jon Perritt1d4aca02015-02-06 12:29:16 -0700240type TypeSchema struct {
Pratik Mallya827c03e2015-09-17 00:10:47 -0500241 Attributes map[string]interface{} `mapstructure:"attributes"`
242 Properties map[string]interface{} `mapstrucutre:"properties"`
243 ResourceType string `mapstructure:"resource_type"`
244 SupportStatus map[string]interface{} `mapstructure:"support_status"`
Jon Perritt1d4aca02015-02-06 12:29:16 -0700245}
246
Jon Perrittbba201b2015-02-08 21:12:38 -0700247// SchemaResult represents the result of a Schema operation.
Jon Perritt1d4aca02015-02-06 12:29:16 -0700248type SchemaResult struct {
249 gophercloud.Result
250}
251
Jon Perrittbba201b2015-02-08 21:12:38 -0700252// Extract returns a pointer to a TypeSchema object and is called after a
253// Schema operation.
Jon Perritt1d4aca02015-02-06 12:29:16 -0700254func (r SchemaResult) Extract() (*TypeSchema, error) {
255 if r.Err != nil {
256 return nil, r.Err
257 }
258
259 var res TypeSchema
260
261 if err := mapstructure.Decode(r.Body, &res); err != nil {
262 return nil, err
263 }
264
265 return &res, nil
266}
Jon Perrittb1e303a2015-02-06 22:15:44 -0700267
Jon Perrittbba201b2015-02-08 21:12:38 -0700268// TemplateResult represents the result of a Template operation.
Jon Perrittb1e303a2015-02-06 22:15:44 -0700269type TemplateResult struct {
270 gophercloud.Result
271}
272
Pratik Mallya827c03e2015-09-17 00:10:47 -0500273// Extract returns the template and is called after a
Jon Perrittbba201b2015-02-08 21:12:38 -0700274// Template operation.
Pratik Mallya827c03e2015-09-17 00:10:47 -0500275func (r TemplateResult) Extract() ([]byte, error) {
Jon Perrittb1e303a2015-02-06 22:15:44 -0700276 if r.Err != nil {
277 return nil, r.Err
278 }
Pratik Mallya827c03e2015-09-17 00:10:47 -0500279 template, err := json.MarshalIndent(r.Body, "", " ")
280 if err != nil {
Jon Perrittb1e303a2015-02-06 22:15:44 -0700281 return nil, err
282 }
Pratik Mallya827c03e2015-09-17 00:10:47 -0500283 return template, nil
Jon Perrittb1e303a2015-02-06 22:15:44 -0700284}