blob: 182c4d044fc05b4b999e24834fa730ca659196d9 [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
Eiichi Aikawaca3d9bd2014-03-06 15:06:21 +090020from tempest.common import rest_client
Matthew Treinish684d8992014-01-30 16:27:40 +000021from tempest import config
22
23CONF = config.CONF
dwalleck5d734432012-10-04 01:11:47 -050024
25
Eiichi Aikawaca3d9bd2014-03-06 15:06:21 +090026class ContainerClient(rest_client.RestClient):
Andrea Frittoli8bbdb162014-01-06 11:06:13 +000027 def __init__(self, auth_provider):
28 super(ContainerClient, self).__init__(auth_provider)
dwalleck5d734432012-10-04 01:11:47 -050029
Eiichi Aikawaca3d9bd2014-03-06 15:06:21 +090030 # Overwrites json-specific header encoding in rest_client.RestClient
dwalleck5d734432012-10-04 01:11:47 -050031 self.headers = {}
Matthew Treinish684d8992014-01-30 16:27:40 +000032 self.service = CONF.object_storage.catalog_type
dwalleck5d734432012-10-04 01:11:47 -050033 self.format = 'json'
34
Daisuke Morita1d591582014-01-14 19:49:23 +090035 def create_container(
36 self, container_name,
37 metadata=None,
38 remove_metadata=None,
39 metadata_prefix='X-Container-Meta-',
40 remove_metadata_prefix='X-Remove-Container-Meta-'):
dwalleck5d734432012-10-04 01:11:47 -050041 """
42 Creates a container, with optional metadata passed in as a
Chang Bo Guocc1623c2013-09-13 20:11:27 -070043 dictionary
dwalleck5d734432012-10-04 01:11:47 -050044 """
Matthew Treinish26dd0fa2012-12-04 17:14:37 -050045 url = str(container_name)
dwalleck5d734432012-10-04 01:11:47 -050046 headers = {}
47
48 if metadata is not None:
49 for key in metadata:
50 headers[metadata_prefix + key] = metadata[key]
Daisuke Morita1d591582014-01-14 19:49:23 +090051 if remove_metadata is not None:
52 for key in remove_metadata:
53 headers[remove_metadata_prefix + key] = remove_metadata[key]
dwalleck5d734432012-10-04 01:11:47 -050054
55 resp, body = self.put(url, body=None, headers=headers)
JordanPa84dde32014-11-14 15:47:42 +010056 self.expected_success([201, 202], resp.status)
dwalleck5d734432012-10-04 01:11:47 -050057 return resp, body
58
59 def delete_container(self, container_name):
Sean Daguef237ccb2013-01-04 15:19:14 -050060 """Deletes the container (if it's empty)."""
Matthew Treinish26dd0fa2012-12-04 17:14:37 -050061 url = str(container_name)
dwalleck5d734432012-10-04 01:11:47 -050062 resp, body = self.delete(url)
JordanPa84dde32014-11-14 15:47:42 +010063 self.expected_success(204, resp.status)
dwalleck5d734432012-10-04 01:11:47 -050064 return resp, body
65
Daisuke Morita1d591582014-01-14 19:49:23 +090066 def update_container_metadata(
67 self, container_name,
68 metadata=None,
69 remove_metadata=None,
70 metadata_prefix='X-Container-Meta-',
71 remove_metadata_prefix='X-Remove-Container-Meta-'):
Sean Daguef237ccb2013-01-04 15:19:14 -050072 """Updates arbitrary metadata on container."""
Matthew Treinish26dd0fa2012-12-04 17:14:37 -050073 url = str(container_name)
dwalleck5d734432012-10-04 01:11:47 -050074 headers = {}
75
76 if metadata is not None:
77 for key in metadata:
78 headers[metadata_prefix + key] = metadata[key]
Daisuke Morita1d591582014-01-14 19:49:23 +090079 if remove_metadata is not None:
80 for key in remove_metadata:
81 headers[remove_metadata_prefix + key] = remove_metadata[key]
dwalleck5d734432012-10-04 01:11:47 -050082
83 resp, body = self.post(url, body=None, headers=headers)
JordanPa84dde32014-11-14 15:47:42 +010084 self.expected_success(204, resp.status)
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020085 return resp, body
dwalleck5d734432012-10-04 01:11:47 -050086
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020087 def delete_container_metadata(self, container_name, metadata,
88 metadata_prefix='X-Remove-Container-Meta-'):
Sean Daguef237ccb2013-01-04 15:19:14 -050089 """Deletes arbitrary metadata on container."""
Matthew Treinish26dd0fa2012-12-04 17:14:37 -050090 url = str(container_name)
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020091 headers = {}
92
93 if metadata is not None:
94 for item in metadata:
Daisuke Morita1d591582014-01-14 19:49:23 +090095 headers[metadata_prefix + item] = metadata[item]
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020096
97 resp, body = self.post(url, body=None, headers=headers)
JordanPa84dde32014-11-14 15:47:42 +010098 self.expected_success(204, resp.status)
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020099 return resp, body
100
101 def list_container_metadata(self, container_name):
102 """
103 Retrieves container metadata headers
104 """
Matthew Treinish26dd0fa2012-12-04 17:14:37 -0500105 url = str(container_name)
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -0800106 resp, body = self.head(url)
JordanPa84dde32014-11-14 15:47:42 +0100107 self.expected_success(204, resp.status)
Larisa Ustalov6c3c7802012-11-05 12:25:19 +0200108 return resp, body
dwalleck5d734432012-10-04 01:11:47 -0500109
110 def list_all_container_objects(self, container, params=None):
111 """
112 Returns complete list of all objects in the container, even if
113 item count is beyond 10,000 item listing limit.
Chang Bo Guocc1623c2013-09-13 20:11:27 -0700114 Does not require any parameters aside from container name.
dwalleck5d734432012-10-04 01:11:47 -0500115 """
Chang Bo Guocc1623c2013-09-13 20:11:27 -0700116 # TODO(dwalleck): Rewrite using json format to avoid newlines at end of
Attila Fazekasa8b5fe72013-08-01 16:59:06 +0200117 # obj names. Set limit to API limit - 1 (max returned items = 9999)
dwalleck5d734432012-10-04 01:11:47 -0500118 limit = 9999
dwalleck5d734432012-10-04 01:11:47 -0500119 if params is not None:
120 if 'limit' in params:
121 limit = params['limit']
122
123 if 'marker' in params:
124 limit = params['marker']
125
Daisuke Morita1d591582014-01-14 19:49:23 +0900126 resp, objlist = self.list_container_contents(
127 container,
128 params={'limit': limit, 'format': 'json'})
JordanPa84dde32014-11-14 15:47:42 +0100129 self.expected_success(200, resp.status)
dwalleck5d734432012-10-04 01:11:47 -0500130 return objlist
131 """tmp = []
132 for obj in objlist:
133 tmp.append(obj['name'])
134 objlist = tmp
135
136 if len(objlist) >= limit:
137
Attila Fazekasa8b5fe72013-08-01 16:59:06 +0200138 # Increment marker
dwalleck5d734432012-10-04 01:11:47 -0500139 marker = objlist[len(objlist) - 1]
140
Attila Fazekasa8b5fe72013-08-01 16:59:06 +0200141 # Get the next chunk of the list
dwalleck5d734432012-10-04 01:11:47 -0500142 objlist.extend(_list_all_container_objects(container,
143 params={'marker': marker,
144 'limit': limit}))
145 return objlist
146 else:
Attila Fazekasa8b5fe72013-08-01 16:59:06 +0200147 # Return final, complete list
dwalleck5d734432012-10-04 01:11:47 -0500148 return objlist"""
149
150 def list_container_contents(self, container, params=None):
151 """
152 List the objects in a container, given the container name
153
154 Returns the container object listing as a plain text list, or as
155 xml or json if that option is specified via the 'format' argument.
156
157 Optional Arguments:
158 limit = integer
159 For an integer value n, limits the number of results to at most
160 n values.
161
162 marker = 'string'
163 Given a string value x, return object names greater in value
164 than the specified marker.
165
166 prefix = 'string'
167 For a string value x, causes the results to be limited to names
168 beginning with the substring x.
169
170 format = 'json' or 'xml'
171 Specify either json or xml to return the respective serialized
172 response.
173 If json, returns a list of json objects
174 if xml, returns a string of xml
175
176 path = 'string'
177 For a string value x, return the object names nested in the
178 pseudo path (assuming preconditions are met - see below).
179
180 delimiter = 'character'
181 For a character c, return all the object names nested in the
182 container (without the need for the directory marker objects).
183 """
184
185 url = str(container)
Matthew Treinish26dd0fa2012-12-04 17:14:37 -0500186 if params:
Daisuke Morita1d591582014-01-14 19:49:23 +0900187 url += '?'
Matthew Treinish26dd0fa2012-12-04 17:14:37 -0500188 url += '&%s' % urllib.urlencode(params)
dwalleck5d734432012-10-04 01:11:47 -0500189
vponomaryov67b58fe2014-02-06 19:05:41 +0200190 resp, body = self.get(url, headers={})
Daisuke Morita1d591582014-01-14 19:49:23 +0900191 if params and params.get('format') == 'json':
192 body = json.loads(body)
193 elif params and params.get('format') == 'xml':
194 body = etree.fromstring(body)
JordanPa84dde32014-11-14 15:47:42 +0100195 self.expected_success([200, 204], resp.status)
dwalleck5d734432012-10-04 01:11:47 -0500196 return resp, body