blob: 4dc588f66658eb0d443c270701888684b42ae0f4 [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)
55 return resp, body
56
57 def delete_account(self, data=None, params=None):
58 """Delete an account."""
59 url = ''
60 if params:
Daisuke Morita499bba32013-11-28 18:44:49 +090061 url = '?%s%s' % (url, urllib.urlencode(params))
62
vponomaryov67b58fe2014-02-06 19:05:41 +020063 resp, body = self.delete(url, headers={}, body=data)
Daisuke Morita499bba32013-11-28 18:44:49 +090064 return resp, body
65
dwalleck5d734432012-10-04 01:11:47 -050066 def list_account_metadata(self):
67 """
68 HEAD on the storage URL
69 Returns all account metadata headers
70 """
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -080071 resp, body = self.head('')
dwalleck5d734432012-10-04 01:11:47 -050072 return resp, body
73
74 def create_account_metadata(self, metadata,
Daisuke Moritae3f6ed32014-08-25 11:34:21 +090075 metadata_prefix='X-Account-Meta-',
76 data=None, params=None):
Sean Daguef237ccb2013-01-04 15:19:14 -050077 """Creates an account metadata entry."""
dwalleck5d734432012-10-04 01:11:47 -050078 headers = {}
Daisuke Moritae3f6ed32014-08-25 11:34:21 +090079 if metadata:
80 for key in metadata:
81 headers[metadata_prefix + key] = metadata[key]
dwalleck5d734432012-10-04 01:11:47 -050082
Daisuke Moritae3f6ed32014-08-25 11:34:21 +090083 url = ''
84 if params:
85 url = '?%s%s' % (url, urllib.urlencode(params))
86
87 resp, body = self.post(url, headers=headers, body=data)
dwalleck5d734432012-10-04 01:11:47 -050088 return resp, body
89
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020090 def delete_account_metadata(self, metadata,
91 metadata_prefix='X-Remove-Account-Meta-'):
92 """
93 Deletes an account metadata entry.
94 """
95
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -080096 headers = {}
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020097 for item in metadata:
Daisuke Morita83441282014-01-14 18:56:17 +090098 headers[metadata_prefix + item] = metadata[item]
99 resp, body = self.post('', headers=headers, body=None)
100 return resp, body
101
102 def create_and_delete_account_metadata(
103 self,
104 create_metadata=None,
105 delete_metadata=None,
106 create_metadata_prefix='X-Account-Meta-',
107 delete_metadata_prefix='X-Remove-Account-Meta-'):
108 """
109 Creates and deletes an account metadata entry.
110 """
111 headers = {}
112 for key in create_metadata:
113 headers[create_metadata_prefix + key] = create_metadata[key]
114 for key in delete_metadata:
115 headers[delete_metadata_prefix + key] = delete_metadata[key]
116
Larisa Ustalov6c3c7802012-11-05 12:25:19 +0200117 resp, body = self.post('', headers=headers, body=None)
118 return resp, body
119
dwalleck5d734432012-10-04 01:11:47 -0500120 def list_account_containers(self, params=None):
121 """
122 GET on the (base) storage URL
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -0800123 Given valid X-Auth-Token, returns a list of all containers for the
124 account.
dwalleck5d734432012-10-04 01:11:47 -0500125
126 Optional Arguments:
127 limit=[integer value N]
128 Limits the number of results to at most N values
129 DEFAULT: 10,000
130
131 marker=[string value X]
132 Given string value X, return object names greater in value
133 than the specified marker.
134 DEFAULT: No Marker
135
136 format=[string value, either 'json' or 'xml']
137 Specify either json or xml to return the respective serialized
138 response.
139 DEFAULT: Python-List returned in response body
140 """
Daisuke Morita83441282014-01-14 18:56:17 +0900141 url = '?%s' % urllib.urlencode(params) if params else ''
dwalleck5d734432012-10-04 01:11:47 -0500142
Daisuke Morita83441282014-01-14 18:56:17 +0900143 resp, body = self.get(url, headers={})
Daisuke Morita499bba32013-11-28 18:44:49 +0900144 if params and params.get('format') == 'json':
145 body = json.loads(body)
Daisuke Morita83441282014-01-14 18:56:17 +0900146 elif params and params.get('format') == 'xml':
147 body = etree.fromstring(body)
148 else:
149 body = body.strip().splitlines()
dwalleck5d734432012-10-04 01:11:47 -0500150 return resp, body
harika-vakadi2daed0a2013-01-01 20:51:39 +0530151
Joe H. Rahme9e07bf02014-01-13 18:58:02 +0100152 def list_extensions(self):
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000153 self.skip_path()
Daisuke Morita83441282014-01-14 18:56:17 +0900154 try:
155 resp, body = self.get('info')
156 finally:
157 self.reset_path()
Joe H. Rahme9e07bf02014-01-13 18:58:02 +0100158 body = json.loads(body)
159 return resp, body
160
harika-vakadi2daed0a2013-01-01 20:51:39 +0530161
Eiichi Aikawaca3d9bd2014-03-06 15:06:21 +0900162class AccountClientCustomizedHeader(rest_client.RestClient):
harika-vakadi2daed0a2013-01-01 20:51:39 +0530163
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000164 # TODO(andreaf) This class is now redundant, to be removed in next patch
165
166 def __init__(self, auth_provider):
167 super(AccountClientCustomizedHeader, self).__init__(
168 auth_provider)
Eiichi Aikawaca3d9bd2014-03-06 15:06:21 +0900169 # Overwrites json-specific header encoding in rest_client.RestClient
Matthew Treinish684d8992014-01-30 16:27:40 +0000170 self.service = CONF.object_storage.catalog_type
harika-vakadi2daed0a2013-01-01 20:51:39 +0530171 self.format = 'json'
172
Sergey Murashov4fccd322014-03-22 09:58:52 +0400173 def request(self, method, url, extra_headers=False, headers=None,
174 body=None):
harika-vakadi2daed0a2013-01-01 20:51:39 +0530175 """A simple HTTP request interface."""
Mate Lakat23a58a32013-08-23 02:06:22 +0100176 self.http_obj = http.ClosingHttp()
harika-vakadi2daed0a2013-01-01 20:51:39 +0530177 if headers is None:
178 headers = {}
Sergey Murashov4fccd322014-03-22 09:58:52 +0400179 elif extra_headers:
180 try:
181 headers.update(self.get_headers())
182 except (ValueError, TypeError):
183 headers = {}
harika-vakadi2daed0a2013-01-01 20:51:39 +0530184
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000185 # Authorize the request
186 req_url, req_headers, req_body = self.auth_provider.auth_request(
187 method=method, url=url, headers=headers, body=body,
188 filters=self.filters
189 )
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000190 # use original body
harika-vakadi2daed0a2013-01-01 20:51:39 +0530191 resp, resp_body = self.http_obj.request(req_url, method,
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000192 headers=req_headers,
193 body=req_body)
Sean Dague89a85912014-03-19 16:37:29 -0400194 self._log_request(method, req_url, resp)
harika-vakadi2daed0a2013-01-01 20:51:39 +0530195
196 if resp.status == 401 or resp.status == 403:
harika-vakadi2daed0a2013-01-01 20:51:39 +0530197 raise exceptions.Unauthorized()
198
199 return resp, resp_body
200
201 def list_account_containers(self, params=None, metadata=None):
202 """
203 GET on the (base) storage URL
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -0800204 Given a valid X-Auth-Token, returns a list of all containers for the
205 account.
harika-vakadi2daed0a2013-01-01 20:51:39 +0530206
207 Optional Arguments:
208 limit=[integer value N]
209 Limits the number of results to at most N values
210 DEFAULT: 10,000
211
212 marker=[string value X]
213 Given string value X, return object names greater in value
214 than the specified marker.
215 DEFAULT: No Marker
216
217 format=[string value, either 'json' or 'xml']
218 Specify either json or xml to return the respective serialized
219 response.
220 DEFAULT: Python-List returned in response body
221 """
222
223 url = '?format=%s' % self.format
224 if params:
225 url += '&%s' + urllib.urlencode(params)
226
227 headers = {}
228 if metadata:
229 for key in metadata:
230 headers[str(key)] = metadata[key]
231
232 resp, body = self.get(url, headers=headers)
233 return resp, body