blob: 69f21daef39aa0a656a12e12eada2711afd01483 [file] [log] [blame]
Jon Perritt3711cd02014-12-22 22:20:15 -07001package stackresources
2
3import (
Jon Perritta11b5df2015-03-05 13:51:59 -07004 "fmt"
5 "reflect"
Jon Perritt3711cd02014-12-22 22:20:15 -07006 "time"
7
8 "github.com/mitchellh/mapstructure"
9 "github.com/rackspace/gophercloud"
10 "github.com/rackspace/gophercloud/pagination"
11)
12
Jon Perrittbba201b2015-02-08 21:12:38 -070013// Resource represents a stack resource.
Jon Perritt3711cd02014-12-22 22:20:15 -070014type Resource struct {
15 Links []gophercloud.Link `mapstructure:"links"`
16 LogicalID string `mapstructure:"logical_resource_id"`
17 Name string `mapstructure:"resource_name"`
18 PhysicalID string `mapstructure:"physical_resource_id"`
19 RequiredBy []interface{} `mapstructure:"required_by"`
20 Status string `mapstructure:"resource_status"`
21 StatusReason string `mapstructure:"resource_status_reason"`
22 Type string `mapstructure:"resource_type"`
23 UpdatedTime time.Time `mapstructure:"-"`
24}
25
Jon Perrittbba201b2015-02-08 21:12:38 -070026// FindResult represents the result of a Find operation.
Jon Perritt3711cd02014-12-22 22:20:15 -070027type FindResult struct {
28 gophercloud.Result
29}
30
Jon Perrittbba201b2015-02-08 21:12:38 -070031// Extract returns a slice of Resource objects and is called after a
32// Find operation.
Jon Perritt3711cd02014-12-22 22:20:15 -070033func (r FindResult) Extract() ([]Resource, error) {
34 if r.Err != nil {
35 return nil, r.Err
36 }
37
38 var res struct {
39 Res []Resource `mapstructure:"resources"`
40 }
41
42 if err := mapstructure.Decode(r.Body, &res); err != nil {
43 return nil, err
44 }
45
Jon Perritta065da12015-02-06 10:20:16 -070046 resources := r.Body.(map[string]interface{})["resources"].([]interface{})
Jon Perritt3711cd02014-12-22 22:20:15 -070047
Jon Perritta065da12015-02-06 10:20:16 -070048 for i, resourceRaw := range resources {
49 resource := resourceRaw.(map[string]interface{})
Jon Perritt3711cd02014-12-22 22:20:15 -070050 if date, ok := resource["updated_time"]; ok && date != nil {
51 t, err := time.Parse(time.RFC3339, date.(string))
52 if err != nil {
53 return nil, err
54 }
55 res.Res[i].UpdatedTime = t
56 }
57 }
58
59 return res.Res, nil
60}
61
62// ResourcePage abstracts the raw results of making a List() request against the API.
63// As OpenStack extensions may freely alter the response bodies of structures returned to the client, you may only safely access the
64// data provided through the ExtractResources call.
65type ResourcePage struct {
Jon Perrittc8717332015-02-08 20:14:29 -070066 pagination.MarkerPageBase
Jon Perritt3711cd02014-12-22 22:20:15 -070067}
68
69// IsEmpty returns true if a page contains no Server results.
Jon Perrittc8717332015-02-08 20:14:29 -070070func (r ResourcePage) IsEmpty() (bool, error) {
71 resources, err := ExtractResources(r)
Jon Perritt3711cd02014-12-22 22:20:15 -070072 if err != nil {
73 return true, err
74 }
75 return len(resources) == 0, nil
76}
77
Jon Perrittc8717332015-02-08 20:14:29 -070078// LastMarker returns the last container name in a ListResult.
79func (r ResourcePage) LastMarker() (string, error) {
80 resources, err := ExtractResources(r)
Jon Perritt3711cd02014-12-22 22:20:15 -070081 if err != nil {
82 return "", err
83 }
Jon Perrittc8717332015-02-08 20:14:29 -070084 if len(resources) == 0 {
85 return "", nil
86 }
87 return resources[len(resources)-1].PhysicalID, nil
Jon Perritt3711cd02014-12-22 22:20:15 -070088}
89
90// ExtractResources interprets the results of a single page from a List() call, producing a slice of Resource entities.
91func ExtractResources(page pagination.Page) ([]Resource, error) {
92 casted := page.(ResourcePage).Body
93
94 var response struct {
95 Resources []Resource `mapstructure:"resources"`
96 }
97 err := mapstructure.Decode(casted, &response)
Jon Perritta065da12015-02-06 10:20:16 -070098
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 {
112 t, err := time.Parse(time.RFC3339, date.(string))
113 if err != nil {
114 return nil, err
115 }
116 response.Resources[i].UpdatedTime = t
117 }
118 }
119
Jon Perritt3711cd02014-12-22 22:20:15 -0700120 return response.Resources, err
121}
122
Jon Perrittbba201b2015-02-08 21:12:38 -0700123// GetResult represents the result of a Get operation.
Jon Perritt3711cd02014-12-22 22:20:15 -0700124type GetResult struct {
125 gophercloud.Result
126}
127
Jon Perrittbba201b2015-02-08 21:12:38 -0700128// Extract returns a pointer to a Resource object and is called after a
129// Get operation.
Jon Perritt3711cd02014-12-22 22:20:15 -0700130func (r GetResult) Extract() (*Resource, error) {
131 if r.Err != nil {
132 return nil, r.Err
133 }
134
135 var res struct {
136 Res *Resource `mapstructure:"resource"`
137 }
138
139 if err := mapstructure.Decode(r.Body, &res); err != nil {
140 return nil, err
141 }
142
143 resource := r.Body.(map[string]interface{})["resource"].(map[string]interface{})
144
145 if date, ok := resource["updated_time"]; ok && date != nil {
146 t, err := time.Parse(time.RFC3339, date.(string))
147 if err != nil {
148 return nil, err
149 }
150 res.Res.UpdatedTime = t
151 }
152
153 return res.Res, nil
154}
155
Jon Perrittbba201b2015-02-08 21:12:38 -0700156// MetadataResult represents the result of a Metadata operation.
Jon Perritt3711cd02014-12-22 22:20:15 -0700157type MetadataResult struct {
158 gophercloud.Result
159}
160
Jon Perrittbba201b2015-02-08 21:12:38 -0700161// Extract returns a map object and is called after a
162// Metadata operation.
Jon Perritt3711cd02014-12-22 22:20:15 -0700163func (r MetadataResult) Extract() (map[string]string, error) {
164 if r.Err != nil {
165 return nil, r.Err
166 }
167
168 var res struct {
169 Meta map[string]string `mapstructure:"metadata"`
170 }
171
172 if err := mapstructure.Decode(r.Body, &res); err != nil {
173 return nil, err
174 }
175
176 return res.Meta, nil
177}
Jon Perritta065da12015-02-06 10:20:16 -0700178
179// ResourceTypePage abstracts the raw results of making a ListTypes() request against the API.
180// As OpenStack extensions may freely alter the response bodies of structures returned to the client, you may only safely access the
181// data provided through the ExtractResourceTypes call.
182type ResourceTypePage struct {
183 pagination.SinglePageBase
184}
185
186// IsEmpty returns true if a ResourceTypePage contains no resource types.
187func (r ResourceTypePage) IsEmpty() (bool, error) {
188 rts, err := ExtractResourceTypes(r)
189 if err != nil {
190 return true, err
191 }
192 return len(rts) == 0, nil
193}
194
195// ExtractResourceTypes extracts and returns resource types.
196func ExtractResourceTypes(page pagination.Page) ([]string, error) {
197 var response struct {
198 ResourceTypes []string `mapstructure:"resource_types"`
199 }
200
201 err := mapstructure.Decode(page.(ResourceTypePage).Body, &response)
202 return response.ResourceTypes, err
203}
Jon Perritt1d4aca02015-02-06 12:29:16 -0700204
Jon Perrittbba201b2015-02-08 21:12:38 -0700205// TypeSchema represents a stack resource schema.
Jon Perritt1d4aca02015-02-06 12:29:16 -0700206type TypeSchema struct {
207 Attributes map[string]interface{} `mapstructure:"attributes"`
208 Properties map[string]interface{} `mapstrucutre:"properties"`
209 ResourceType string `mapstructure:"resource_type"`
210}
211
Jon Perrittbba201b2015-02-08 21:12:38 -0700212// SchemaResult represents the result of a Schema operation.
Jon Perritt1d4aca02015-02-06 12:29:16 -0700213type SchemaResult struct {
214 gophercloud.Result
215}
216
Jon Perrittbba201b2015-02-08 21:12:38 -0700217// Extract returns a pointer to a TypeSchema object and is called after a
218// Schema operation.
Jon Perritt1d4aca02015-02-06 12:29:16 -0700219func (r SchemaResult) Extract() (*TypeSchema, error) {
220 if r.Err != nil {
221 return nil, r.Err
222 }
223
224 var res TypeSchema
225
226 if err := mapstructure.Decode(r.Body, &res); err != nil {
227 return nil, err
228 }
229
230 return &res, nil
231}
Jon Perrittb1e303a2015-02-06 22:15:44 -0700232
Jon Perrittbba201b2015-02-08 21:12:38 -0700233// TypeTemplate represents a stack resource template.
Jon Perrittb1e303a2015-02-06 22:15:44 -0700234type TypeTemplate struct {
235 HeatTemplateFormatVersion string
236 Outputs map[string]interface{}
237 Parameters map[string]interface{}
238 Resources map[string]interface{}
239}
240
Jon Perrittbba201b2015-02-08 21:12:38 -0700241// TemplateResult represents the result of a Template operation.
Jon Perrittb1e303a2015-02-06 22:15:44 -0700242type TemplateResult struct {
243 gophercloud.Result
244}
245
Jon Perrittbba201b2015-02-08 21:12:38 -0700246// Extract returns a pointer to a TypeTemplate object and is called after a
247// Template operation.
Jon Perrittb1e303a2015-02-06 22:15:44 -0700248func (r TemplateResult) Extract() (*TypeTemplate, error) {
249 if r.Err != nil {
250 return nil, r.Err
251 }
252
253 var res TypeTemplate
254
255 if err := mapstructure.Decode(r.Body, &res); err != nil {
256 return nil, err
257 }
258
259 return &res, nil
260}