blob: eca57c001ae3f5e57376ffafd05fe36d59ba2be5 [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:
61 if 'bulk-delete' in params:
62 url += 'bulk-delete&'
63 url = '?%s%s' % (url, urllib.urlencode(params))
64
vponomaryov67b58fe2014-02-06 19:05:41 +020065 resp, body = self.delete(url, headers={}, body=data)
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('')
dwalleck5d734432012-10-04 01:11:47 -050074 return resp, body
75
76 def create_account_metadata(self, metadata,
77 metadata_prefix='X-Account-Meta-'):
Sean Daguef237ccb2013-01-04 15:19:14 -050078 """Creates an account metadata entry."""
dwalleck5d734432012-10-04 01:11:47 -050079 headers = {}
80 for key in metadata:
81 headers[metadata_prefix + key] = metadata[key]
82
83 resp, body = self.post('', headers=headers, body=None)
84 return resp, body
85
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020086 def delete_account_metadata(self, metadata,
87 metadata_prefix='X-Remove-Account-Meta-'):
88 """
89 Deletes an account metadata entry.
90 """
91
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -080092 headers = {}
Larisa Ustalov6c3c7802012-11-05 12:25:19 +020093 for item in metadata:
Daisuke Morita83441282014-01-14 18:56:17 +090094 headers[metadata_prefix + item] = metadata[item]
95 resp, body = self.post('', headers=headers, body=None)
96 return resp, body
97
98 def create_and_delete_account_metadata(
99 self,
100 create_metadata=None,
101 delete_metadata=None,
102 create_metadata_prefix='X-Account-Meta-',
103 delete_metadata_prefix='X-Remove-Account-Meta-'):
104 """
105 Creates and deletes an account metadata entry.
106 """
107 headers = {}
108 for key in create_metadata:
109 headers[create_metadata_prefix + key] = create_metadata[key]
110 for key in delete_metadata:
111 headers[delete_metadata_prefix + key] = delete_metadata[key]
112
Larisa Ustalov6c3c7802012-11-05 12:25:19 +0200113 resp, body = self.post('', headers=headers, body=None)
114 return resp, body
115
dwalleck5d734432012-10-04 01:11:47 -0500116 def list_account_containers(self, params=None):
117 """
118 GET on the (base) storage URL
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -0800119 Given valid X-Auth-Token, returns a list of all containers for the
120 account.
dwalleck5d734432012-10-04 01:11:47 -0500121
122 Optional Arguments:
123 limit=[integer value N]
124 Limits the number of results to at most N values
125 DEFAULT: 10,000
126
127 marker=[string value X]
128 Given string value X, return object names greater in value
129 than the specified marker.
130 DEFAULT: No Marker
131
132 format=[string value, either 'json' or 'xml']
133 Specify either json or xml to return the respective serialized
134 response.
135 DEFAULT: Python-List returned in response body
136 """
Daisuke Morita83441282014-01-14 18:56:17 +0900137 url = '?%s' % urllib.urlencode(params) if params else ''
dwalleck5d734432012-10-04 01:11:47 -0500138
Daisuke Morita83441282014-01-14 18:56:17 +0900139 resp, body = self.get(url, headers={})
Daisuke Morita499bba32013-11-28 18:44:49 +0900140 if params and params.get('format') == 'json':
141 body = json.loads(body)
Daisuke Morita83441282014-01-14 18:56:17 +0900142 elif params and params.get('format') == 'xml':
143 body = etree.fromstring(body)
144 else:
145 body = body.strip().splitlines()
dwalleck5d734432012-10-04 01:11:47 -0500146 return resp, body
harika-vakadi2daed0a2013-01-01 20:51:39 +0530147
Joe H. Rahme9e07bf02014-01-13 18:58:02 +0100148 def list_extensions(self):
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000149 self.skip_path()
Daisuke Morita83441282014-01-14 18:56:17 +0900150 try:
151 resp, body = self.get('info')
152 finally:
153 self.reset_path()
Joe H. Rahme9e07bf02014-01-13 18:58:02 +0100154 body = json.loads(body)
155 return resp, body
156
harika-vakadi2daed0a2013-01-01 20:51:39 +0530157
Eiichi Aikawaca3d9bd2014-03-06 15:06:21 +0900158class AccountClientCustomizedHeader(rest_client.RestClient):
harika-vakadi2daed0a2013-01-01 20:51:39 +0530159
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000160 # TODO(andreaf) This class is now redundant, to be removed in next patch
161
162 def __init__(self, auth_provider):
163 super(AccountClientCustomizedHeader, self).__init__(
164 auth_provider)
Eiichi Aikawaca3d9bd2014-03-06 15:06:21 +0900165 # Overwrites json-specific header encoding in rest_client.RestClient
Matthew Treinish684d8992014-01-30 16:27:40 +0000166 self.service = CONF.object_storage.catalog_type
harika-vakadi2daed0a2013-01-01 20:51:39 +0530167 self.format = 'json'
168
Sergey Murashov4fccd322014-03-22 09:58:52 +0400169 def request(self, method, url, extra_headers=False, headers=None,
170 body=None):
harika-vakadi2daed0a2013-01-01 20:51:39 +0530171 """A simple HTTP request interface."""
Mate Lakat23a58a32013-08-23 02:06:22 +0100172 self.http_obj = http.ClosingHttp()
harika-vakadi2daed0a2013-01-01 20:51:39 +0530173 if headers is None:
174 headers = {}
Sergey Murashov4fccd322014-03-22 09:58:52 +0400175 elif extra_headers:
176 try:
177 headers.update(self.get_headers())
178 except (ValueError, TypeError):
179 headers = {}
harika-vakadi2daed0a2013-01-01 20:51:39 +0530180
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000181 # Authorize the request
182 req_url, req_headers, req_body = self.auth_provider.auth_request(
183 method=method, url=url, headers=headers, body=body,
184 filters=self.filters
185 )
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000186 # use original body
harika-vakadi2daed0a2013-01-01 20:51:39 +0530187 resp, resp_body = self.http_obj.request(req_url, method,
Andrea Frittoli8bbdb162014-01-06 11:06:13 +0000188 headers=req_headers,
189 body=req_body)
Sean Dague89a85912014-03-19 16:37:29 -0400190 self._log_request(method, req_url, resp)
harika-vakadi2daed0a2013-01-01 20:51:39 +0530191
192 if resp.status == 401 or resp.status == 403:
harika-vakadi2daed0a2013-01-01 20:51:39 +0530193 raise exceptions.Unauthorized()
194
195 return resp, resp_body
196
197 def list_account_containers(self, params=None, metadata=None):
198 """
199 GET on the (base) storage URL
Chmouel Boudjnahdcf40ea2014-01-06 18:35:34 -0800200 Given a valid X-Auth-Token, returns a list of all containers for the
201 account.
harika-vakadi2daed0a2013-01-01 20:51:39 +0530202
203 Optional Arguments:
204 limit=[integer value N]
205 Limits the number of results to at most N values
206 DEFAULT: 10,000
207
208 marker=[string value X]
209 Given string value X, return object names greater in value
210 than the specified marker.
211 DEFAULT: No Marker
212
213 format=[string value, either 'json' or 'xml']
214 Specify either json or xml to return the respective serialized
215 response.
216 DEFAULT: Python-List returned in response body
217 """
218
219 url = '?format=%s' % self.format
220 if params:
221 url += '&%s' + urllib.urlencode(params)
222
223 headers = {}
224 if metadata:
225 for key in metadata:
226 headers[str(key)] = metadata[key]
227
228 resp, body = self.get(url, headers=headers)
229 return resp, body