blob: e5a3605acf4e8472b1e07d9c84de5b8f33b4dec8 [file] [log] [blame]
Jon Perritt8c93a302014-09-28 22:35:57 -05001package containers
2
3import (
jrperritt655245a2016-08-31 15:30:27 -05004 "encoding/json"
Jon Perritt8c93a302014-09-28 22:35:57 -05005 "fmt"
jrperritt655245a2016-08-31 15:30:27 -05006 "strconv"
Jon Perritt8c93a302014-09-28 22:35:57 -05007 "strings"
jrperritt98d01622017-01-12 14:24:42 -06008 "time"
Jon Perritt5db08922014-09-30 21:32:48 -05009
Jon Perritt27249f42016-02-18 10:35:59 -060010 "github.com/gophercloud/gophercloud"
Krzysztof Szukiełojć24a29ce2017-05-07 14:24:02 +020011 "gerrit.mcp.mirantis.net/debian/gophercloud.git/pagination"
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.
jrperritt655245a2016-08-31 15:30:27 -050017 Bytes int64 `json:"bytes"`
Jamie Hannaford4ff79962014-10-06 16:28:23 +020018
19 // The total number of objects stored in the container.
jrperritt655245a2016-08-31 15:30:27 -050020 Count int64 `json:"count"`
Jamie Hannaford4ff79962014-10-06 16:28:23 +020021
22 // The name of the container.
Jon Perritt3c166472016-02-25 03:07:41 -060023 Name string `json:"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
Jon Perritt3c166472016-02-25 03:07:41 -060032//IsEmpty returns true if a ListResult contains no container names.
Jon Perritt8c93a302014-09-28 22:35:57 -050033func (r ContainerPage) IsEmpty() (bool, error) {
34 names, err := ExtractNames(r)
Jon Perritt3c166472016-02-25 03:07:41 -060035 return len(names) == 0, err
Jon Perritt8c93a302014-09-28 22:35:57 -050036}
37
38// LastMarker returns the last container name in a ListResult.
39func (r ContainerPage) LastMarker() (string, error) {
40 names, err := ExtractNames(r)
41 if err != nil {
42 return "", err
43 }
44 if len(names) == 0 {
45 return "", nil
46 }
47 return names[len(names)-1], nil
48}
49
50// ExtractInfo is a function that takes a ListResult and returns the containers' information.
Jon Perritt3c166472016-02-25 03:07:41 -060051func ExtractInfo(r pagination.Page) ([]Container, error) {
52 var s []Container
53 err := (r.(ContainerPage)).ExtractInto(&s)
54 return s, err
Jon Perritt8c93a302014-09-28 22:35:57 -050055}
56
57// ExtractNames is a function that takes a ListResult and returns the containers' names.
58func ExtractNames(page pagination.Page) ([]string, error) {
59 casted := page.(ContainerPage)
Ash Wilson72e4d2c2014-10-20 10:27:30 -040060 ct := casted.Header.Get("Content-Type")
Jon Perritt8c93a302014-09-28 22:35:57 -050061
62 switch {
63 case strings.HasPrefix(ct, "application/json"):
64 parsed, err := ExtractInfo(page)
65 if err != nil {
66 return nil, err
67 }
68
69 names := make([]string, 0, len(parsed))
70 for _, container := range parsed {
Jon Perritt8aa40262014-09-29 15:41:32 -050071 names = append(names, container.Name)
Jon Perritt8c93a302014-09-28 22:35:57 -050072 }
73 return names, nil
74 case strings.HasPrefix(ct, "text/plain"):
75 names := make([]string, 0, 50)
76
77 body := string(page.(ContainerPage).Body.([]uint8))
78 for _, name := range strings.Split(body, "\n") {
79 if len(name) > 0 {
80 names = append(names, name)
81 }
82 }
83
84 return names, nil
85 default:
86 return nil, fmt.Errorf("Cannot extract names from response with content-type: [%s]", ct)
87 }
88}
89
Jon Perritt8314f4e2014-12-01 10:58:40 -070090// GetHeader represents the headers returned in the response from a Get request.
91type GetHeader struct {
jrperritt98d01622017-01-12 14:24:42 -060092 AcceptRanges string `json:"Accept-Ranges"`
93 BytesUsed int64 `json:"-"`
94 ContentLength int64 `json:"-"`
95 ContentType string `json:"Content-Type"`
96 Date time.Time `json:"-"`
97 ObjectCount int64 `json:"-"`
98 Read []string `json:"-"`
99 TransID string `json:"X-Trans-Id"`
100 VersionsLocation string `json:"X-Versions-Location"`
101 Write []string `json:"-"`
jrperritt655245a2016-08-31 15:30:27 -0500102}
103
jrperritt98d01622017-01-12 14:24:42 -0600104func (r *GetHeader) UnmarshalJSON(b []byte) error {
jrperritt655245a2016-08-31 15:30:27 -0500105 type tmp GetHeader
jrperritt98d01622017-01-12 14:24:42 -0600106 var s struct {
jrperritt655245a2016-08-31 15:30:27 -0500107 tmp
jrperritt98d01622017-01-12 14:24:42 -0600108 BytesUsed string `json:"X-Container-Bytes-Used"`
109 ContentLength string `json:"Content-Length"`
110 ObjectCount string `json:"X-Container-Object-Count"`
111 Write string `json:"X-Container-Write"`
112 Read string `json:"X-Container-Read"`
113 Date gophercloud.JSONRFC1123 `json:"Date"`
jrperritt655245a2016-08-31 15:30:27 -0500114 }
jrperritt98d01622017-01-12 14:24:42 -0600115 err := json.Unmarshal(b, &s)
jrperritt655245a2016-08-31 15:30:27 -0500116 if err != nil {
117 return err
118 }
119
jrperritt98d01622017-01-12 14:24:42 -0600120 *r = GetHeader(s.tmp)
jrperritt655245a2016-08-31 15:30:27 -0500121
jrperritt98d01622017-01-12 14:24:42 -0600122 switch s.BytesUsed {
jrperritt655245a2016-08-31 15:30:27 -0500123 case "":
jrperritt98d01622017-01-12 14:24:42 -0600124 r.BytesUsed = 0
jrperritt655245a2016-08-31 15:30:27 -0500125 default:
jrperritt98d01622017-01-12 14:24:42 -0600126 r.BytesUsed, err = strconv.ParseInt(s.BytesUsed, 10, 64)
jrperritt655245a2016-08-31 15:30:27 -0500127 if err != nil {
128 return err
129 }
130 }
131
jrperritt98d01622017-01-12 14:24:42 -0600132 switch s.ContentLength {
jrperritt655245a2016-08-31 15:30:27 -0500133 case "":
jrperritt98d01622017-01-12 14:24:42 -0600134 r.ContentLength = 0
jrperritt655245a2016-08-31 15:30:27 -0500135 default:
jrperritt98d01622017-01-12 14:24:42 -0600136 r.ContentLength, err = strconv.ParseInt(s.ContentLength, 10, 64)
jrperritt655245a2016-08-31 15:30:27 -0500137 if err != nil {
138 return err
139 }
140 }
141
jrperritt98d01622017-01-12 14:24:42 -0600142 switch s.ObjectCount {
jrperritt655245a2016-08-31 15:30:27 -0500143 case "":
jrperritt98d01622017-01-12 14:24:42 -0600144 r.ObjectCount = 0
jrperritt655245a2016-08-31 15:30:27 -0500145 default:
jrperritt98d01622017-01-12 14:24:42 -0600146 r.ObjectCount, err = strconv.ParseInt(s.ObjectCount, 10, 64)
jrperritt655245a2016-08-31 15:30:27 -0500147 if err != nil {
148 return err
149 }
150 }
151
jrperritt98d01622017-01-12 14:24:42 -0600152 r.Read = strings.Split(s.Read, ",")
153 r.Write = strings.Split(s.Write, ",")
jrperritt655245a2016-08-31 15:30:27 -0500154
jrperritt98d01622017-01-12 14:24:42 -0600155 r.Date = time.Time(s.Date)
156
157 return err
Jon Perritt8314f4e2014-12-01 10:58:40 -0700158}
159
Jon Perritt5db08922014-09-30 21:32:48 -0500160// GetResult represents the result of a get operation.
161type GetResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500162 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500163}
164
Jon Perritt8314f4e2014-12-01 10:58:40 -0700165// Extract will return a struct of headers returned from a call to Get. To obtain
166// a map of headers, call the ExtractHeader method on the GetResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600167func (r GetResult) Extract() (*GetHeader, error) {
168 var s *GetHeader
169 err := r.ExtractInto(&s)
170 return s, err
Jon Perritt8314f4e2014-12-01 10:58:40 -0700171}
172
jrperritt98d01622017-01-12 14:24:42 -0600173// ExtractMetadata is a function that takes a GetResult (of type *stts.Response)
Jon Perritt8c93a302014-09-28 22:35:57 -0500174// and returns the custom metadata associated with the container.
Jon Perritt3c166472016-02-25 03:07:41 -0600175func (r GetResult) ExtractMetadata() (map[string]string, error) {
176 if r.Err != nil {
177 return nil, r.Err
Jon Perritt8c93a302014-09-28 22:35:57 -0500178 }
179 metadata := make(map[string]string)
Jon Perritt3c166472016-02-25 03:07:41 -0600180 for k, v := range r.Header {
Jon Perritt8c93a302014-09-28 22:35:57 -0500181 if strings.HasPrefix(k, "X-Container-Meta-") {
182 key := strings.TrimPrefix(k, "X-Container-Meta-")
183 metadata[key] = v[0]
184 }
185 }
186 return metadata, nil
187}
Jon Perritt5db08922014-09-30 21:32:48 -0500188
Jon Perritt8314f4e2014-12-01 10:58:40 -0700189// CreateHeader represents the headers returned in the response from a Create request.
190type CreateHeader struct {
jrperritt98d01622017-01-12 14:24:42 -0600191 ContentLength int64 `json:"-"`
192 ContentType string `json:"Content-Type"`
193 Date time.Time `json:"-"`
194 TransID string `json:"X-Trans-Id"`
Jon Perritt8314f4e2014-12-01 10:58:40 -0700195}
196
jrperritt98d01622017-01-12 14:24:42 -0600197func (r *CreateHeader) UnmarshalJSON(b []byte) error {
jrperritt655245a2016-08-31 15:30:27 -0500198 type tmp CreateHeader
jrperritt98d01622017-01-12 14:24:42 -0600199 var s struct {
jrperritt655245a2016-08-31 15:30:27 -0500200 tmp
jrperritt98d01622017-01-12 14:24:42 -0600201 ContentLength string `json:"Content-Length"`
202 Date gophercloud.JSONRFC1123 `json:"Date"`
jrperritt655245a2016-08-31 15:30:27 -0500203 }
jrperritt98d01622017-01-12 14:24:42 -0600204 err := json.Unmarshal(b, &s)
jrperritt655245a2016-08-31 15:30:27 -0500205 if err != nil {
206 return err
207 }
208
jrperritt98d01622017-01-12 14:24:42 -0600209 *r = CreateHeader(s.tmp)
jrperritt655245a2016-08-31 15:30:27 -0500210
jrperritt98d01622017-01-12 14:24:42 -0600211 switch s.ContentLength {
jrperritt655245a2016-08-31 15:30:27 -0500212 case "":
jrperritt98d01622017-01-12 14:24:42 -0600213 r.ContentLength = 0
jrperritt655245a2016-08-31 15:30:27 -0500214 default:
jrperritt98d01622017-01-12 14:24:42 -0600215 r.ContentLength, err = strconv.ParseInt(s.ContentLength, 10, 64)
jrperritt655245a2016-08-31 15:30:27 -0500216 if err != nil {
217 return err
218 }
219 }
220
jrperritt98d01622017-01-12 14:24:42 -0600221 r.Date = time.Time(s.Date)
222
223 return err
jrperritt655245a2016-08-31 15:30:27 -0500224}
225
Jamie Hannaford22ec4792014-10-07 10:07:41 +0200226// CreateResult represents the result of a create operation. To extract the
Jon Perritt9856a342014-10-27 13:44:06 -0500227// the headers from the HTTP response, you can invoke the 'ExtractHeader'
Jamie Hannaford22ec4792014-10-07 10:07:41 +0200228// method on the result struct.
Jon Perritt5db08922014-09-30 21:32:48 -0500229type CreateResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500230 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500231}
232
Jon Perritt8314f4e2014-12-01 10:58:40 -0700233// Extract will return a struct of headers returned from a call to Create. To obtain
234// a map of headers, call the ExtractHeader method on the CreateResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600235func (r CreateResult) Extract() (*CreateHeader, error) {
236 var s *CreateHeader
237 err := r.ExtractInto(&s)
238 return s, err
Jon Perritt8314f4e2014-12-01 10:58:40 -0700239}
240
241// UpdateHeader represents the headers returned in the response from a Update request.
242type UpdateHeader struct {
jrperritt98d01622017-01-12 14:24:42 -0600243 ContentLength int64 `json:"-"`
244 ContentType string `json:"Content-Type"`
245 Date time.Time `json:"-"`
246 TransID string `json:"X-Trans-Id"`
Jon Perritt8314f4e2014-12-01 10:58:40 -0700247}
248
jrperritt98d01622017-01-12 14:24:42 -0600249func (r *UpdateHeader) UnmarshalJSON(b []byte) error {
jrperritt655245a2016-08-31 15:30:27 -0500250 type tmp UpdateHeader
jrperritt98d01622017-01-12 14:24:42 -0600251 var s struct {
jrperritt655245a2016-08-31 15:30:27 -0500252 tmp
jrperritt98d01622017-01-12 14:24:42 -0600253 ContentLength string `json:"Content-Length"`
254 Date gophercloud.JSONRFC1123 `json:"Date"`
jrperritt655245a2016-08-31 15:30:27 -0500255 }
jrperritt98d01622017-01-12 14:24:42 -0600256 err := json.Unmarshal(b, &s)
jrperritt655245a2016-08-31 15:30:27 -0500257 if err != nil {
258 return err
259 }
260
jrperritt98d01622017-01-12 14:24:42 -0600261 *r = UpdateHeader(s.tmp)
jrperritt655245a2016-08-31 15:30:27 -0500262
jrperritt98d01622017-01-12 14:24:42 -0600263 switch s.ContentLength {
jrperritt655245a2016-08-31 15:30:27 -0500264 case "":
jrperritt98d01622017-01-12 14:24:42 -0600265 r.ContentLength = 0
jrperritt655245a2016-08-31 15:30:27 -0500266 default:
jrperritt98d01622017-01-12 14:24:42 -0600267 r.ContentLength, err = strconv.ParseInt(s.ContentLength, 10, 64)
jrperritt655245a2016-08-31 15:30:27 -0500268 if err != nil {
269 return err
270 }
271 }
272
jrperritt98d01622017-01-12 14:24:42 -0600273 r.Date = time.Time(s.Date)
274
275 return err
jrperritt655245a2016-08-31 15:30:27 -0500276}
277
Jamie Hannaford22ec4792014-10-07 10:07:41 +0200278// UpdateResult represents the result of an update operation. To extract the
Jon Perritt9856a342014-10-27 13:44:06 -0500279// the headers from the HTTP response, you can invoke the 'ExtractHeader'
Jamie Hannaford22ec4792014-10-07 10:07:41 +0200280// method on the result struct.
Jon Perritt5db08922014-09-30 21:32:48 -0500281type UpdateResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500282 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500283}
284
Jon Perritt8314f4e2014-12-01 10:58:40 -0700285// Extract will return a struct of headers returned from a call to Update. To obtain
286// a map of headers, call the ExtractHeader method on the UpdateResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600287func (r UpdateResult) Extract() (*UpdateHeader, error) {
288 var s *UpdateHeader
289 err := r.ExtractInto(&s)
290 return s, err
Jon Perritt8314f4e2014-12-01 10:58:40 -0700291}
292
293// DeleteHeader represents the headers returned in the response from a Delete request.
294type DeleteHeader struct {
jrperritt98d01622017-01-12 14:24:42 -0600295 ContentLength int64 `json:"-"`
296 ContentType string `json:"Content-Type"`
297 Date time.Time `json:"-"`
298 TransID string `json:"X-Trans-Id"`
Jon Perritt8314f4e2014-12-01 10:58:40 -0700299}
300
jrperritt98d01622017-01-12 14:24:42 -0600301func (r *DeleteHeader) UnmarshalJSON(b []byte) error {
jrperritt655245a2016-08-31 15:30:27 -0500302 type tmp DeleteHeader
jrperritt98d01622017-01-12 14:24:42 -0600303 var s struct {
jrperritt655245a2016-08-31 15:30:27 -0500304 tmp
jrperritt98d01622017-01-12 14:24:42 -0600305 ContentLength string `json:"Content-Length"`
306 Date gophercloud.JSONRFC1123 `json:"Date"`
jrperritt655245a2016-08-31 15:30:27 -0500307 }
jrperritt98d01622017-01-12 14:24:42 -0600308 err := json.Unmarshal(b, &s)
jrperritt655245a2016-08-31 15:30:27 -0500309 if err != nil {
310 return err
311 }
312
jrperritt98d01622017-01-12 14:24:42 -0600313 *r = DeleteHeader(s.tmp)
jrperritt655245a2016-08-31 15:30:27 -0500314
jrperritt98d01622017-01-12 14:24:42 -0600315 switch s.ContentLength {
jrperritt655245a2016-08-31 15:30:27 -0500316 case "":
jrperritt98d01622017-01-12 14:24:42 -0600317 r.ContentLength = 0
jrperritt655245a2016-08-31 15:30:27 -0500318 default:
jrperritt98d01622017-01-12 14:24:42 -0600319 r.ContentLength, err = strconv.ParseInt(s.ContentLength, 10, 64)
jrperritt655245a2016-08-31 15:30:27 -0500320 if err != nil {
321 return err
322 }
323 }
324
jrperritt98d01622017-01-12 14:24:42 -0600325 r.Date = time.Time(s.Date)
326
327 return err
jrperritt655245a2016-08-31 15:30:27 -0500328}
329
Jamie Hannaford22ec4792014-10-07 10:07:41 +0200330// DeleteResult represents the result of a delete operation. To extract the
Jon Perritt9856a342014-10-27 13:44:06 -0500331// the headers from the HTTP response, you can invoke the 'ExtractHeader'
Jamie Hannaford22ec4792014-10-07 10:07:41 +0200332// method on the result struct.
Jon Perritt5db08922014-09-30 21:32:48 -0500333type DeleteResult struct {
Jon Perrittd50f93e2014-10-27 14:19:27 -0500334 gophercloud.HeaderResult
Jon Perritt5db08922014-09-30 21:32:48 -0500335}
Jon Perritt8314f4e2014-12-01 10:58:40 -0700336
337// Extract will return a struct of headers returned from a call to Delete. To obtain
338// a map of headers, call the ExtractHeader method on the DeleteResult.
Jon Perritt3c166472016-02-25 03:07:41 -0600339func (r DeleteResult) Extract() (*DeleteHeader, error) {
340 var s *DeleteHeader
341 err := r.ExtractInto(&s)
342 return s, err
Jon Perritt8314f4e2014-12-01 10:58:40 -0700343}