blob: a23e173f6ab33e31da2e19e2f855a5d29cb79440 [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
Mate Lakat23a58a32013-08-23 02:06:22 +010020from tempest.common import http
Eiichi Aikawaca3d9bd2014-03-06 15:06:21 +090021from tempest.common import rest_client
Matthew Treinish684d8992014-01-30 16:27:40 +000022from tempest import config
harika-vakadi2daed0a2013-01-01 20:51:39 +053023from tempest import exceptions
dwalleck5d734432012-10-04 01:11:47 -050024
Matthew Treinish684d8992014-01-30 16:27:40 +000025CONF = config.CONF
26
dwalleck5d734432012-10-04 01:11:47 -050027
Eiichi Aikawaca3d9bd2014-03-06 15:06:21 +090028class AccountClient(rest_client.RestClient):
Andrea Frittoli8bbdb162014-01-06 11:06:13 +000029 def __init__(self, auth_provider):
30 super(AccountClient, self).__init__(auth_provider)
Matthew Treinish684d8992014-01-30 16:27:40 +000031 self.service = CONF.object_storage.catalog_type
dwalleck5d734432012-10-04 01:11:47 -050032
Daisuke Morita499bba32013-11-28 18:44:49 +090033 def create_account(self, data=None,
34 params=None,
Ghanshyam2a180b82014-06-16 13:54:22 +090035 metadata=None,
36 remove_metadata=None,
Daisuke Morita499bba32013-11-28 18:44:49 +090037 metadata_prefix='X-Account-Meta-',
38 remove_metadata_prefix='X-Remove-Account-Meta-'):
39 """Create an account."""
Ghanshyam2a180b82014-06-16 13:54:22 +090040 if metadata is None:
41 metadata = {}
42 if remove_metadata is None:
43 remove_metadata = {}
Daisuke Morita499bba32013-11-28 18:44:49 +090044 url = ''
45 if params:
46 url += '?%s' % urllib.urlencode(params)
47
48 headers = {}
49 for key in metadata:
50 headers[metadata_prefix + key] = metadata[key]
51 for key in remove_metadata:
52 headers[remove_metadata_prefix + key] = remove_metadata[key]
53
54 resp, body = self.put(url, data, headers)
JordanPa84dde32014-11-14 15:47:42 +010055 self.expected_success(200, resp.status)
Daisuke Morita499bba32013-11-28 18:44:49 +090056 return resp, body
57
58 def delete_account(self, data=None, params=None):
59 """Delete an account."""
60 url = ''
61 if params:
Daisuke Morita499bba32013-11-28 18:44:49 +090062 url = '?%s%s' % (url, urllib.urlencode(params))
63
vponomaryov67b58fe2014-02-06 19:05:41 +020064 resp, body = self.delete(url, headers={}, body=data)
JordanPa84dde32014-11-14 15:47:42 +010065 self.expected_success(200, resp.status)
Daisuke Morita499bba32013-11-28 18:44:49 +090066 return resp, body
67
dwalleck5d734432012-10-04 01:11:47 -050068 def list_account_metadata(self):
69 """
70 HEAD on the storage URL
71 Returns all account metadata headers
72 """
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -080073 resp, body = self.head('')
JordanPa84dde32014-11-14 15:47:42 +010074 self.expected_success(204, resp.status)
dwalleck5d734432012-10-04 01:11:47 -050075 return resp, body
76
77 def create_account_metadata(self, metadata,
Daisuke Moritae3f6ed32014-08-25 11:34:21 +090078 metadata_prefix='X-Account-Meta-',
79 data=None, params=None):
Sean Daguef237ccb2013-01-04 15:19:14 -050080 """Creates an account metadata entry."""
dwalleck5d734432012-10-04 01:11:47 -050081 headers = {}
Daisuke Moritae3f6ed32014-08-25 11:34:21 +090082 if metadata:
83 for key in metadata:
84 headers[metadata_prefix + key] = metadata[key]
dwalleck5d734432012-10-04 01:11:47 -050085
Daisuke Moritae3f6ed32014-08-25 11:34:21 +090086 url = ''
87 if params:
88 url = '?%s%s' % (url, urllib.urlencode(params))
89
90 resp, body = self.post(url, headers=headers, body=data)
JordanPa84dde32014-11-14 15:47:42 +010091 self.expected_success([200, 204], resp.status)
dwalleck5d734432012-10-04 01:11:47 -050092 return resp, body
93
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020094 def delete_account_metadata(self, metadata,
95 metadata_prefix='X-Remove-Account-Meta-'):
96 """
97 Deletes an account metadata entry.
98 """
99
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -0800100 headers = {}
Larisa Ustalov6c3c7802012-11-05 12:25:19 +0200101 for item in metadata:
Daisuke Morita83441282014-01-14 18:56:17 +0900102 headers[metadata_prefix + item] = metadata[item]
103 resp, body = self.post('', headers=headers, body=None)
JordanPa84dde32014-11-14 15:47:42 +0100104 self.expected_success(204, resp.status)
Daisuke Morita83441282014-01-14 18:56:17 +0900105 return resp, body
106
107 def create_and_delete_account_metadata(
108 self,
109 create_metadata=None,
110 delete_metadata=None,
111 create_metadata_prefix='X-Account-Meta-',
112 delete_metadata_prefix='X-Remove-Account-Meta-'):
113 """
114 Creates and deletes an account metadata entry.
115 """
116 headers = {}
117 for key in create_metadata:
118 headers[create_metadata_prefix + key] = create_metadata[key]
119 for key in delete_metadata:
120 headers[delete_metadata_prefix + key] = delete_metadata[key]
121
Larisa Ustalov6c3c7802012-11-05 12:25:19 +0200122 resp, body = self.post('', headers=headers, body=None)
JordanPa84dde32014-11-14 15:47:42 +0100123 self.expected_success(204, resp.status)
Larisa Ustalov6c3c7802012-11-05 12:25:19 +0200124 return resp, body
125
dwalleck5d734432012-10-04 01:11:47 -0500126 def list_account_containers(self, params=None):
127 """
128 GET on the (base) storage URL
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -0800129 Given valid X-Auth-Token, returns a list of all containers for the
130 account.
dwalleck5d734432012-10-04 01:11:47 -0500131
132 Optional Arguments:
133 limit=[integer value N]
134 Limits the number of results to at most N values
135 DEFAULT: 10,000
136
137 marker=[string value X]
138 Given string value X, return object names greater in value
139 than the specified marker.
140 DEFAULT: No Marker
141
142 format=[string value, either 'json' or 'xml']
143 Specify either json or xml to return the respective serialized
144 response.
145 DEFAULT: Python-List returned in response body
146 """
Daisuke Morita83441282014-01-14 18:56:17 +0900147 url = '?%s' % urllib.urlencode(params) if params else ''
dwalleck5d734432012-10-04 01:11:47 -0500148
Daisuke Morita83441282014-01-14 18:56:17 +0900149 resp, body = self.get(url, headers={})
Daisuke Morita499bba32013-11-28 18:44:49 +0900150 if params and params.get('format') == 'json':
151 body = json.loads(body)
Daisuke Morita83441282014-01-14 18:56:17 +0900152 elif params and params.get('format') == 'xml':
153 body = etree.fromstring(body)
154 else:
155 body = body.strip().splitlines()
JordanPa84dde32014-11-14 15:47:42 +0100156 self.expected_success([200, 204], resp.status)
dwalleck5d734432012-10-04 01:11:47 -0500157 return resp, body
harika-vakadi2daed0a2013-01-01 20:51:39 +0530158
Joe H. Rahme9e07bf02014-01-13 18:58:02 +0100159 def list_extensions(self):
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000160 self.skip_path()
Daisuke Morita83441282014-01-14 18:56:17 +0900161 try:
162 resp, body = self.get('info')
163 finally:
164 self.reset_path()
Joe H. Rahme9e07bf02014-01-13 18:58:02 +0100165 body = json.loads(body)
JordanPa84dde32014-11-14 15:47:42 +0100166 self.expected_success(200, resp.status)
Joe H. Rahme9e07bf02014-01-13 18:58:02 +0100167 return resp, body
168
harika-vakadi2daed0a2013-01-01 20:51:39 +0530169
Eiichi Aikawaca3d9bd2014-03-06 15:06:21 +0900170class AccountClientCustomizedHeader(rest_client.RestClient):
harika-vakadi2daed0a2013-01-01 20:51:39 +0530171
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000172 # TODO(andreaf) This class is now redundant, to be removed in next patch
173
174 def __init__(self, auth_provider):
175 super(AccountClientCustomizedHeader, self).__init__(
176 auth_provider)
Eiichi Aikawaca3d9bd2014-03-06 15:06:21 +0900177 # Overwrites json-specific header encoding in rest_client.RestClient
Matthew Treinish684d8992014-01-30 16:27:40 +0000178 self.service = CONF.object_storage.catalog_type
harika-vakadi2daed0a2013-01-01 20:51:39 +0530179 self.format = 'json'
180
Sergey Murashov4fccd322014-03-22 09:58:52 +0400181 def request(self, method, url, extra_headers=False, headers=None,
182 body=None):
harika-vakadi2daed0a2013-01-01 20:51:39 +0530183 """A simple HTTP request interface."""
Mate Lakat23a58a32013-08-23 02:06:22 +0100184 self.http_obj = http.ClosingHttp()
harika-vakadi2daed0a2013-01-01 20:51:39 +0530185 if headers is None:
186 headers = {}
Sergey Murashov4fccd322014-03-22 09:58:52 +0400187 elif extra_headers:
188 try:
189 headers.update(self.get_headers())
190 except (ValueError, TypeError):
191 headers = {}
harika-vakadi2daed0a2013-01-01 20:51:39 +0530192
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000193 # Authorize the request
194 req_url, req_headers, req_body = self.auth_provider.auth_request(
195 method=method, url=url, headers=headers, body=body,
196 filters=self.filters
197 )
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000198 # use original body
harika-vakadi2daed0a2013-01-01 20:51:39 +0530199 resp, resp_body = self.http_obj.request(req_url, method,
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000200 headers=req_headers,
201 body=req_body)
Sean Dague89a85912014-03-19 16:37:29 -0400202 self._log_request(method, req_url, resp)
harika-vakadi2daed0a2013-01-01 20:51:39 +0530203
204 if resp.status == 401 or resp.status == 403:
harika-vakadi2daed0a2013-01-01 20:51:39 +0530205 raise exceptions.Unauthorized()
206
207 return resp, resp_body
208
209 def list_account_containers(self, params=None, metadata=None):
210 """
211 GET on the (base) storage URL
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -0800212 Given a valid X-Auth-Token, returns a list of all containers for the
213 account.
harika-vakadi2daed0a2013-01-01 20:51:39 +0530214
215 Optional Arguments:
216 limit=[integer value N]
217 Limits the number of results to at most N values
218 DEFAULT: 10,000
219
220 marker=[string value X]
221 Given string value X, return object names greater in value
222 than the specified marker.
223 DEFAULT: No Marker
224
225 format=[string value, either 'json' or 'xml']
226 Specify either json or xml to return the respective serialized
227 response.
228 DEFAULT: Python-List returned in response body
229 """
230
231 url = '?format=%s' % self.format
232 if params:
233 url += '&%s' + urllib.urlencode(params)
234
235 headers = {}
236 if metadata:
237 for key in metadata:
238 headers[str(key)] = metadata[key]
239
240 resp, body = self.get(url, headers=headers)
JordanPa84dde32014-11-14 15:47:42 +0100241 self.expected_success(200, resp.status)
harika-vakadi2daed0a2013-01-01 20:51:39 +0530242 return resp, body