blob: c55826b7bf805a48d33c1a15a16bcc710e2c2652 [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
dwalleck5d734432012-10-04 01:11:47 -05002# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import json
Matthew Treinish26dd0fa2012-12-04 17:14:37 -050017import urllib
Matthew Treinish96e9e882014-06-09 18:37:19 -040018from xml.etree import ElementTree as etree
dwalleck5d734432012-10-04 01:11:47 -050019
Ken'ichi Ohmichide398ac2014-12-17 08:34:34 +000020from tempest.services.object_storage import base
dwalleck5d734432012-10-04 01:11:47 -050021
22
Ken'ichi Ohmichide398ac2014-12-17 08:34:34 +000023class ContainerClient(base.ObjectStorageClient):
dwalleck5d734432012-10-04 01:11:47 -050024
Daisuke Morita1d591582014-01-14 19:49:23 +090025 def create_container(
26 self, container_name,
27 metadata=None,
28 remove_metadata=None,
29 metadata_prefix='X-Container-Meta-',
30 remove_metadata_prefix='X-Remove-Container-Meta-'):
dwalleck5d734432012-10-04 01:11:47 -050031 """
32 Creates a container, with optional metadata passed in as a
Chang Bo Guocc1623c2013-09-13 20:11:27 -070033 dictionary
dwalleck5d734432012-10-04 01:11:47 -050034 """
Matthew Treinish26dd0fa2012-12-04 17:14:37 -050035 url = str(container_name)
dwalleck5d734432012-10-04 01:11:47 -050036 headers = {}
37
38 if metadata is not None:
39 for key in metadata:
40 headers[metadata_prefix + key] = metadata[key]
Daisuke Morita1d591582014-01-14 19:49:23 +090041 if remove_metadata is not None:
42 for key in remove_metadata:
43 headers[remove_metadata_prefix + key] = remove_metadata[key]
dwalleck5d734432012-10-04 01:11:47 -050044
45 resp, body = self.put(url, body=None, headers=headers)
JordanPa84dde32014-11-14 15:47:42 +010046 self.expected_success([201, 202], resp.status)
dwalleck5d734432012-10-04 01:11:47 -050047 return resp, body
48
49 def delete_container(self, container_name):
Sean Daguef237ccb2013-01-04 15:19:14 -050050 """Deletes the container (if it's empty)."""
Matthew Treinish26dd0fa2012-12-04 17:14:37 -050051 url = str(container_name)
dwalleck5d734432012-10-04 01:11:47 -050052 resp, body = self.delete(url)
JordanPa84dde32014-11-14 15:47:42 +010053 self.expected_success(204, resp.status)
dwalleck5d734432012-10-04 01:11:47 -050054 return resp, body
55
Daisuke Morita1d591582014-01-14 19:49:23 +090056 def update_container_metadata(
57 self, container_name,
58 metadata=None,
59 remove_metadata=None,
60 metadata_prefix='X-Container-Meta-',
61 remove_metadata_prefix='X-Remove-Container-Meta-'):
Sean Daguef237ccb2013-01-04 15:19:14 -050062 """Updates arbitrary metadata on container."""
Matthew Treinish26dd0fa2012-12-04 17:14:37 -050063 url = str(container_name)
dwalleck5d734432012-10-04 01:11:47 -050064 headers = {}
65
66 if metadata is not None:
67 for key in metadata:
68 headers[metadata_prefix + key] = metadata[key]
Daisuke Morita1d591582014-01-14 19:49:23 +090069 if remove_metadata is not None:
70 for key in remove_metadata:
71 headers[remove_metadata_prefix + key] = remove_metadata[key]
dwalleck5d734432012-10-04 01:11:47 -050072
73 resp, body = self.post(url, body=None, headers=headers)
JordanPa84dde32014-11-14 15:47:42 +010074 self.expected_success(204, resp.status)
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020075 return resp, body
dwalleck5d734432012-10-04 01:11:47 -050076
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020077 def delete_container_metadata(self, container_name, metadata,
78 metadata_prefix='X-Remove-Container-Meta-'):
Sean Daguef237ccb2013-01-04 15:19:14 -050079 """Deletes arbitrary metadata on container."""
Matthew Treinish26dd0fa2012-12-04 17:14:37 -050080 url = str(container_name)
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020081 headers = {}
82
83 if metadata is not None:
84 for item in metadata:
Daisuke Morita1d591582014-01-14 19:49:23 +090085 headers[metadata_prefix + item] = metadata[item]
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020086
87 resp, body = self.post(url, body=None, headers=headers)
JordanPa84dde32014-11-14 15:47:42 +010088 self.expected_success(204, resp.status)
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020089 return resp, body
90
91 def list_container_metadata(self, container_name):
92 """
93 Retrieves container metadata headers
94 """
Matthew Treinish26dd0fa2012-12-04 17:14:37 -050095 url = str(container_name)
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -080096 resp, body = self.head(url)
JordanPa84dde32014-11-14 15:47:42 +010097 self.expected_success(204, resp.status)
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020098 return resp, body
dwalleck5d734432012-10-04 01:11:47 -050099
100 def list_all_container_objects(self, container, params=None):
101 """
102 Returns complete list of all objects in the container, even if
103 item count is beyond 10,000 item listing limit.
Chang Bo Guocc1623c2013-09-13 20:11:27 -0700104 Does not require any parameters aside from container name.
dwalleck5d734432012-10-04 01:11:47 -0500105 """
Chang Bo Guocc1623c2013-09-13 20:11:27 -0700106 # TODO(dwalleck): Rewrite using json format to avoid newlines at end of
Attila Fazekasa8b5fe72013-08-01 16:59:06 +0200107 # obj names. Set limit to API limit - 1 (max returned items = 9999)
dwalleck5d734432012-10-04 01:11:47 -0500108 limit = 9999
dwalleck5d734432012-10-04 01:11:47 -0500109 if params is not None:
110 if 'limit' in params:
111 limit = params['limit']
112
113 if 'marker' in params:
114 limit = params['marker']
115
Daisuke Morita1d591582014-01-14 19:49:23 +0900116 resp, objlist = self.list_container_contents(
117 container,
118 params={'limit': limit, 'format': 'json'})
JordanPa84dde32014-11-14 15:47:42 +0100119 self.expected_success(200, resp.status)
dwalleck5d734432012-10-04 01:11:47 -0500120 return objlist
121 """tmp = []
122 for obj in objlist:
123 tmp.append(obj['name'])
124 objlist = tmp
125
126 if len(objlist) >= limit:
127
Attila Fazekasa8b5fe72013-08-01 16:59:06 +0200128 # Increment marker
dwalleck5d734432012-10-04 01:11:47 -0500129 marker = objlist[len(objlist) - 1]
130
Attila Fazekasa8b5fe72013-08-01 16:59:06 +0200131 # Get the next chunk of the list
dwalleck5d734432012-10-04 01:11:47 -0500132 objlist.extend(_list_all_container_objects(container,
133 params={'marker': marker,
134 'limit': limit}))
135 return objlist
136 else:
Attila Fazekasa8b5fe72013-08-01 16:59:06 +0200137 # Return final, complete list
dwalleck5d734432012-10-04 01:11:47 -0500138 return objlist"""
139
140 def list_container_contents(self, container, params=None):
141 """
142 List the objects in a container, given the container name
143
144 Returns the container object listing as a plain text list, or as
145 xml or json if that option is specified via the 'format' argument.
146
147 Optional Arguments:
148 limit = integer
149 For an integer value n, limits the number of results to at most
150 n values.
151
152 marker = 'string'
153 Given a string value x, return object names greater in value
154 than the specified marker.
155
156 prefix = 'string'
157 For a string value x, causes the results to be limited to names
158 beginning with the substring x.
159
160 format = 'json' or 'xml'
161 Specify either json or xml to return the respective serialized
162 response.
163 If json, returns a list of json objects
164 if xml, returns a string of xml
165
166 path = 'string'
167 For a string value x, return the object names nested in the
168 pseudo path (assuming preconditions are met - see below).
169
170 delimiter = 'character'
171 For a character c, return all the object names nested in the
172 container (without the need for the directory marker objects).
173 """
174
175 url = str(container)
Matthew Treinish26dd0fa2012-12-04 17:14:37 -0500176 if params:
Daisuke Morita1d591582014-01-14 19:49:23 +0900177 url += '?'
Matthew Treinish26dd0fa2012-12-04 17:14:37 -0500178 url += '&%s' % urllib.urlencode(params)
dwalleck5d734432012-10-04 01:11:47 -0500179
vponomaryov67b58fe2014-02-06 19:05:41 +0200180 resp, body = self.get(url, headers={})
Daisuke Morita1d591582014-01-14 19:49:23 +0900181 if params and params.get('format') == 'json':
182 body = json.loads(body)
183 elif params and params.get('format') == 'xml':
184 body = etree.fromstring(body)
JordanPa84dde32014-11-14 15:47:42 +0100185 self.expected_success([200, 204], resp.status)
dwalleck5d734432012-10-04 01:11:47 -0500186 return resp, body