blob: e682b8dccbfbdbd6324e3c3254903185ce85a2f7 [file] [log] [blame]
Jon Perritt8c93a302014-09-28 22:35:57 -05001package containers
2
3import (
4 "fmt"
Jon Perritt8c93a302014-09-28 22:35:57 -05005 "strings"
Jon Perritt8314f4e2014-12-01 10:58:40 -07006 "time"
Jon Perritt5db08922014-09-30 21:32:48 -05007
Ash Wilsonaf262872014-10-20 09:32:29 -04008 "github.com/rackspace/gophercloud"
Jon Perritt5db08922014-09-30 21:32:48 -05009 "github.com/rackspace/gophercloud/pagination"
Jon Perrittb3461402014-10-09 21:36:17 -050010
11 "github.com/mitchellh/mapstructure"
Jon Perritt8c93a302014-09-28 22:35:57 -050012)
13
Jamie Hannaford4ff79962014-10-06 16:28:23 +020014// Container represents a container resource.
Jon Perritt8aa40262014-09-29 15:41:32 -050015type Container struct {
Jamie Hannaford4ff79962014-10-06 16:28:23 +020016 // The total number of bytes stored in the container.
17 Bytes int `json:"bytes" mapstructure:"bytes"`
18
19 // The total number of objects stored in the container.
20 Count int `json:"count" mapstructure:"count"`
21
22 // The name of the container.
23 Name string `json:"name" mapstructure:"name"`
Jon Perritt8aa40262014-09-29 15:41:32 -050024}
Jon Perritt8c93a302014-09-28 22:35:57 -050025
Jamie Hannaford4ff79962014-10-06 16:28:23 +020026// ContainerPage is the page returned by a pager when traversing over a
27// collection of containers.
Jon Perritt8c93a302014-09-28 22:35:57 -050028type ContainerPage struct {
29 pagination.MarkerPageBase
30}
31
32// IsEmpty returns true if a ListResult contains no container names.
33func (r ContainerPage) IsEmpty() (bool, error) {
34 names, err := ExtractNames(r)
35 if err != nil {
36 return true, err
37 }
38 return len(names) == 0, nil
39}
40
41// LastMarker returns the last container name in a ListResult.
42func (r ContainerPage) LastMarker() (string, error) {
43 names, err := ExtractNames(r)
44 if err != nil {
45 return "", err
46 }
47 if len(names) == 0 {
48 return "", nil
49 }
50 return names[len(names)-1], nil
51}
52
53// ExtractInfo is a function that takes a ListResult and returns the containers' information.
54func ExtractInfo(page pagination.Page) ([]Container, error) {
55 untyped := page.(ContainerPage).Body.([]interface{})
56 results := make([]Container, len(untyped))
57 for index, each := range untyped {
Jon Perritt8aa40262014-09-29 15:41:32 -050058 container := each.(map[string]interface{})
Jon Perrittfdac6e52014-09-29 19:43:45 -050059 err := mapstructure.Decode(container, &results[index])
Jon Perritt8aa40262014-09-29 15:41:32 -050060 if err != nil {
61 return results, err
62 }
Jon Perritt8c93a302014-09-28 22:35:57 -050063 }
64 return results, nil
65}
66
67// ExtractNames is a function that takes a ListResult and returns the containers' names.
68func ExtractNames(page pagination.Page) ([]string, error) {
69 casted := page.(ContainerPage)
Ash Wilson72e4d2c2014-10-20 10:27:30 -040070 ct := casted.Header.Get("Content-Type")
Jon Perritt8c93a302014-09-28 22:35:57 -050071
72 switch {
73 case strings.HasPrefix(ct, "application/json"):
74 parsed, err := ExtractInfo(page)
75 if err != nil {
76 return nil, err
77 }
78
79 names := make([]string, 0, len(parsed))
80 for _, container := range parsed {
Jon Perritt8aa40262014-09-29 15:41:32 -050081 names = append(names, container.Name)
Jon Perritt8c93a302014-09-28 22:35:57 -050082 }
83 return names, nil
84 case strings.HasPrefix(ct, "text/plain"):
85 names := make([]string, 0, 50)
86
87 body := string(page.(ContainerPage).Body.([]uint8))
88 for _, name := range strings.Split(body, "\n") {
89 if len(name) > 0 {
90 names = append(names, name)
91 }
92 }
93
94 return names, nil
95 default:
96 return nil, fmt.Errorf("Cannot extract names from response with content-type: [%s]", ct)
97 }
98}
99
Jon Perritt8314f4e2014-12-01 10:58:40 -0700100// GetHeader represents the headers returned in the response from a Get request.
101type GetHeader struct {
Jon Perritt8949d8f2014-12-15 14:52:18 -0700102 AcceptRanges string `mapstructure:"Accept-Ranges"`
103 BytesUsed int64 `mapstructure:"X-Account-Bytes-Used"`
104 ContentLength int64 `mapstructure:"Content-Length"`
105 ContentType string `mapstructure:"Content-Type"`
106 Date time.Time `mapstructure:"-"`
107 ObjectCount int64 `mapstructure:"X-Container-Object-Count"`
108 Read string `mapstructure:"X-Container-Read"`
109 TransID string `mapstructure:"X-Trans-Id"`
110 VersionsLocation string `mapstructure:"X-Versions-Location"`
111 Write string `mapstructure:"X-Container-Write"`
Jon Perritt8314f4e2014-12-01 10:58:40 -0700112}
113
Jon Perritt5db08922014-09-30 21:32:48 -0500114// GetResult represents the result of a get operation.
115type GetResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500116 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500117}
118
Jon Perritt8314f4e2014-12-01 10:58:40 -0700119// Extract will return a struct of headers returned from a call to Get. To obtain
120// a map of headers, call the ExtractHeader method on the GetResult.
121func (gr GetResult) Extract() (GetHeader, error) {
122 var gh GetHeader
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700123 if gr.Err != nil {
124 return gh, gr.Err
125 }
Jon Perritt8314f4e2014-12-01 10:58:40 -0700126
Jon Perritt63e7a482014-12-04 09:47:23 -0700127 if err := gophercloud.DecodeHeader(gr.Header, &gh); err != nil {
Jon Perritt8314f4e2014-12-01 10:58:40 -0700128 return gh, err
129 }
130
131 if date, ok := gr.Header["Date"]; ok && len(date) > 0 {
132 t, err := time.Parse(time.RFC1123, gr.Header["Date"][0])
133 if err != nil {
134 return gh, err
135 }
136 gh.Date = t
137 }
138
139 return gh, nil
140}
141
Jon Perritt8c93a302014-09-28 22:35:57 -0500142// ExtractMetadata is a function that takes a GetResult (of type *http.Response)
143// and returns the custom metadata associated with the container.
144func (gr GetResult) ExtractMetadata() (map[string]string, error) {
145 if gr.Err != nil {
146 return nil, gr.Err
147 }
148 metadata := make(map[string]string)
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400149 for k, v := range gr.Header {
Jon Perritt8c93a302014-09-28 22:35:57 -0500150 if strings.HasPrefix(k, "X-Container-Meta-") {
151 key := strings.TrimPrefix(k, "X-Container-Meta-")
152 metadata[key] = v[0]
153 }
154 }
155 return metadata, nil
156}
Jon Perritt5db08922014-09-30 21:32:48 -0500157
Jon Perritt8314f4e2014-12-01 10:58:40 -0700158// CreateHeader represents the headers returned in the response from a Create request.
159type CreateHeader struct {
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700160 ContentLength int64 `mapstructure:"Content-Length"`
161 ContentType string `mapstructure:"Content-Type"`
162 Date time.Time `mapstructure:"-"`
163 TransID string `mapstructure:"X-Trans-Id"`
Jon Perritt8314f4e2014-12-01 10:58:40 -0700164}
165
Jamie Hannaford22ec4792014-10-07 10:07:41 +0200166// CreateResult represents the result of a create operation. To extract the
Jon Perritt9856a342014-10-27 13:44:06 -0500167// the headers from the HTTP response, you can invoke the 'ExtractHeader'
Jamie Hannaford22ec4792014-10-07 10:07:41 +0200168// method on the result struct.
Jon Perritt5db08922014-09-30 21:32:48 -0500169type CreateResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500170 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500171}
172
Jon Perritt8314f4e2014-12-01 10:58:40 -0700173// Extract will return a struct of headers returned from a call to Create. To obtain
174// a map of headers, call the ExtractHeader method on the CreateResult.
175func (cr CreateResult) Extract() (CreateHeader, error) {
176 var ch CreateHeader
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700177 if cr.Err != nil {
178 return ch, cr.Err
179 }
Jon Perritt8314f4e2014-12-01 10:58:40 -0700180
Jon Perritt63e7a482014-12-04 09:47:23 -0700181 if err := gophercloud.DecodeHeader(cr.Header, &ch); err != nil {
Jon Perritt8314f4e2014-12-01 10:58:40 -0700182 return ch, err
183 }
184
185 if date, ok := cr.Header["Date"]; ok && len(date) > 0 {
186 t, err := time.Parse(time.RFC1123, cr.Header["Date"][0])
187 if err != nil {
188 return ch, err
189 }
190 ch.Date = t
191 }
192
193 return ch, nil
194}
195
196// UpdateHeader represents the headers returned in the response from a Update request.
197type UpdateHeader struct {
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700198 ContentLength int64 `mapstructure:"Content-Length"`
199 ContentType string `mapstructure:"Content-Type"`
200 Date time.Time `mapstructure:"-"`
201 TransID string `mapstructure:"X-Trans-Id"`
Jon Perritt8314f4e2014-12-01 10:58:40 -0700202}
203
Jamie Hannaford22ec4792014-10-07 10:07:41 +0200204// UpdateResult represents the result of an update operation. To extract the
Jon Perritt9856a342014-10-27 13:44:06 -0500205// the headers from the HTTP response, you can invoke the 'ExtractHeader'
Jamie Hannaford22ec4792014-10-07 10:07:41 +0200206// method on the result struct.
Jon Perritt5db08922014-09-30 21:32:48 -0500207type UpdateResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500208 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500209}
210
Jon Perritt8314f4e2014-12-01 10:58:40 -0700211// Extract will return a struct of headers returned from a call to Update. To obtain
212// a map of headers, call the ExtractHeader method on the UpdateResult.
213func (ur UpdateResult) Extract() (UpdateHeader, error) {
214 var uh UpdateHeader
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700215 if ur.Err != nil {
216 return uh, ur.Err
217 }
Jon Perritt8314f4e2014-12-01 10:58:40 -0700218
Jon Perritt63e7a482014-12-04 09:47:23 -0700219 if err := gophercloud.DecodeHeader(ur.Header, &uh); err != nil {
Jon Perritt8314f4e2014-12-01 10:58:40 -0700220 return uh, err
221 }
222
223 if date, ok := ur.Header["Date"]; ok && len(date) > 0 {
224 t, err := time.Parse(time.RFC1123, ur.Header["Date"][0])
225 if err != nil {
226 return uh, err
227 }
228 uh.Date = t
229 }
230
231 return uh, nil
232}
233
234// DeleteHeader represents the headers returned in the response from a Delete request.
235type DeleteHeader struct {
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700236 ContentLength int64 `mapstructure:"Content-Length"`
237 ContentType string `mapstructure:"Content-Type"`
238 Date time.Time `mapstructure:"-"`
239 TransID string `mapstructure:"X-Trans-Id"`
Jon Perritt8314f4e2014-12-01 10:58:40 -0700240}
241
Jamie Hannaford22ec4792014-10-07 10:07:41 +0200242// DeleteResult represents the result of a delete operation. To extract the
Jon Perritt9856a342014-10-27 13:44:06 -0500243// the headers from the HTTP response, you can invoke the 'ExtractHeader'
Jamie Hannaford22ec4792014-10-07 10:07:41 +0200244// method on the result struct.
Jon Perritt5db08922014-09-30 21:32:48 -0500245type DeleteResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500246 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500247}
Jon Perritt8314f4e2014-12-01 10:58:40 -0700248
249// Extract will return a struct of headers returned from a call to Delete. To obtain
250// a map of headers, call the ExtractHeader method on the DeleteResult.
251func (dr DeleteResult) Extract() (DeleteHeader, error) {
252 var dh DeleteHeader
Jon Perritt8c31b2a2014-12-03 10:21:11 -0700253 if dr.Err != nil {
254 return dh, dr.Err
255 }
Jon Perritt8314f4e2014-12-01 10:58:40 -0700256
Jon Perritt63e7a482014-12-04 09:47:23 -0700257 if err := gophercloud.DecodeHeader(dr.Header, &dh); err != nil {
Jon Perritt8314f4e2014-12-01 10:58:40 -0700258 return dh, err
259 }
260
261 if date, ok := dr.Header["Date"]; ok && len(date) > 0 {
262 t, err := time.Parse(time.RFC1123, dr.Header["Date"][0])
263 if err != nil {
264 return dh, err
265 }
266 dh.Date = t
267 }
268
269 return dh, nil
270}