]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | """ |
2 | Run rgw roundtrip message tests | |
3 | """ | |
4 | from cStringIO import StringIO | |
5 | import base64 | |
6 | import contextlib | |
7 | import logging | |
8 | import os | |
9 | import random | |
10 | import string | |
11 | import yaml | |
12 | ||
13 | from teuthology import misc as teuthology | |
14 | from teuthology import contextutil | |
15 | from teuthology.config import config as teuth_config | |
16 | from teuthology.orchestra import run | |
17 | from teuthology.orchestra.connection import split_user | |
18 | ||
19 | log = logging.getLogger(__name__) | |
20 | ||
7c673cae FG |
21 | @contextlib.contextmanager |
22 | def download(ctx, config): | |
23 | """ | |
24 | Download the s3 tests from the git builder. | |
25 | Remove downloaded s3 file upon exit. | |
92f5a8d4 | 26 | |
7c673cae FG |
27 | The context passed in should be identical to the context |
28 | passed in to the main task. | |
29 | """ | |
30 | assert isinstance(config, dict) | |
31 | log.info('Downloading s3-tests...') | |
32 | testdir = teuthology.get_testdir(ctx) | |
92f5a8d4 TL |
33 | for (client, client_config) in config.items(): |
34 | s3tests_branch = client_config.get('force-branch', None) | |
35 | if not s3tests_branch: | |
36 | raise ValueError( | |
37 | "Could not determine what branch to use for s3-tests. Please add 'force-branch: {s3-tests branch name}' to the .yaml config for this s3roundtrip task.") | |
38 | ||
39 | log.info("Using branch '%s' for s3tests", s3tests_branch) | |
40 | sha1 = client_config.get('sha1') | |
41 | git_remote = client_config.get('git_remote', teuth_config.ceph_git_base_url) | |
7c673cae FG |
42 | ctx.cluster.only(client).run( |
43 | args=[ | |
44 | 'git', 'clone', | |
92f5a8d4 TL |
45 | '-b', s3tests_branch, |
46 | git_remote + 's3-tests.git', | |
7c673cae FG |
47 | '{tdir}/s3-tests'.format(tdir=testdir), |
48 | ], | |
49 | ) | |
92f5a8d4 TL |
50 | if sha1 is not None: |
51 | ctx.cluster.only(client).run( | |
52 | args=[ | |
53 | 'cd', '{tdir}/s3-tests'.format(tdir=testdir), | |
54 | run.Raw('&&'), | |
55 | 'git', 'reset', '--hard', sha1, | |
56 | ], | |
57 | ) | |
7c673cae FG |
58 | try: |
59 | yield | |
60 | finally: | |
61 | log.info('Removing s3-tests...') | |
92f5a8d4 | 62 | testdir = teuthology.get_testdir(ctx) |
7c673cae FG |
63 | for client in config: |
64 | ctx.cluster.only(client).run( | |
65 | args=[ | |
66 | 'rm', | |
67 | '-rf', | |
68 | '{tdir}/s3-tests'.format(tdir=testdir), | |
69 | ], | |
70 | ) | |
71 | ||
92f5a8d4 | 72 | |
7c673cae FG |
73 | def _config_user(s3tests_conf, section, user): |
74 | """ | |
75 | Configure users for this section by stashing away keys, ids, and | |
76 | email addresses. | |
77 | """ | |
78 | s3tests_conf[section].setdefault('user_id', user) | |
79 | s3tests_conf[section].setdefault('email', '{user}+test@test.test'.format(user=user)) | |
80 | s3tests_conf[section].setdefault('display_name', 'Mr. {user}'.format(user=user)) | |
81 | s3tests_conf[section].setdefault('access_key', ''.join(random.choice(string.uppercase) for i in xrange(20))) | |
82 | s3tests_conf[section].setdefault('secret_key', base64.b64encode(os.urandom(40))) | |
83 | ||
84 | @contextlib.contextmanager | |
85 | def create_users(ctx, config): | |
86 | """ | |
87 | Create a default s3 user. | |
88 | """ | |
89 | assert isinstance(config, dict) | |
90 | log.info('Creating rgw users...') | |
91 | testdir = teuthology.get_testdir(ctx) | |
92 | users = {'s3': 'foo'} | |
93 | for client in config['clients']: | |
94 | s3tests_conf = config['s3tests_conf'][client] | |
95 | s3tests_conf.setdefault('roundtrip', {}) | |
96 | s3tests_conf['roundtrip'].setdefault('bucket', 'rttest-' + client + '-{random}-') | |
97 | s3tests_conf['roundtrip'].setdefault('readers', 10) | |
98 | s3tests_conf['roundtrip'].setdefault('writers', 3) | |
99 | s3tests_conf['roundtrip'].setdefault('duration', 300) | |
100 | s3tests_conf['roundtrip'].setdefault('files', {}) | |
101 | rtconf = s3tests_conf['roundtrip'] | |
102 | rtconf['files'].setdefault('num', 10) | |
103 | rtconf['files'].setdefault('size', 2000) | |
104 | rtconf['files'].setdefault('stddev', 500) | |
105 | for section, user in [('s3', 'foo')]: | |
106 | _config_user(s3tests_conf, section, '{user}.{client}'.format(user=user, client=client)) | |
107 | ctx.cluster.only(client).run( | |
108 | args=[ | |
109 | 'adjust-ulimits', | |
110 | 'ceph-coverage', | |
111 | '{tdir}/archive/coverage'.format(tdir=testdir), | |
112 | 'radosgw-admin', | |
113 | '-n', client, | |
114 | 'user', 'create', | |
115 | '--uid', s3tests_conf[section]['user_id'], | |
116 | '--display-name', s3tests_conf[section]['display_name'], | |
117 | '--access-key', s3tests_conf[section]['access_key'], | |
118 | '--secret', s3tests_conf[section]['secret_key'], | |
119 | '--email', s3tests_conf[section]['email'], | |
120 | ], | |
121 | ) | |
122 | try: | |
123 | yield | |
124 | finally: | |
125 | for client in config['clients']: | |
126 | for user in users.itervalues(): | |
127 | uid = '{user}.{client}'.format(user=user, client=client) | |
128 | ctx.cluster.only(client).run( | |
129 | args=[ | |
130 | 'adjust-ulimits', | |
131 | 'ceph-coverage', | |
132 | '{tdir}/archive/coverage'.format(tdir=testdir), | |
133 | 'radosgw-admin', | |
134 | '-n', client, | |
135 | 'user', 'rm', | |
136 | '--uid', uid, | |
137 | '--purge-data', | |
138 | ], | |
139 | ) | |
140 | ||
141 | @contextlib.contextmanager | |
142 | def configure(ctx, config): | |
143 | """ | |
144 | Configure the s3-tests. This includes the running of the | |
145 | bootstrap code and the updating of local conf files. | |
146 | """ | |
147 | assert isinstance(config, dict) | |
148 | log.info('Configuring s3-roundtrip-tests...') | |
149 | testdir = teuthology.get_testdir(ctx) | |
150 | for client, properties in config['clients'].iteritems(): | |
151 | s3tests_conf = config['s3tests_conf'][client] | |
152 | if properties is not None and 'rgw_server' in properties: | |
153 | host = None | |
154 | for target, roles in zip(ctx.config['targets'].iterkeys(), ctx.config['roles']): | |
155 | log.info('roles: ' + str(roles)) | |
156 | log.info('target: ' + str(target)) | |
157 | if properties['rgw_server'] in roles: | |
158 | _, host = split_user(target) | |
159 | assert host is not None, "Invalid client specified as the rgw_server" | |
160 | s3tests_conf['s3']['host'] = host | |
161 | else: | |
162 | s3tests_conf['s3']['host'] = 'localhost' | |
163 | ||
164 | def_conf = s3tests_conf['DEFAULT'] | |
165 | s3tests_conf['s3'].setdefault('port', def_conf['port']) | |
166 | s3tests_conf['s3'].setdefault('is_secure', def_conf['is_secure']) | |
167 | ||
168 | (remote,) = ctx.cluster.only(client).remotes.keys() | |
169 | remote.run( | |
170 | args=[ | |
171 | 'cd', | |
172 | '{tdir}/s3-tests'.format(tdir=testdir), | |
173 | run.Raw('&&'), | |
174 | './bootstrap', | |
175 | ], | |
176 | ) | |
177 | conf_fp = StringIO() | |
178 | conf = dict( | |
179 | s3=s3tests_conf['s3'], | |
180 | roundtrip=s3tests_conf['roundtrip'], | |
181 | ) | |
182 | yaml.safe_dump(conf, conf_fp, default_flow_style=False) | |
183 | teuthology.write_file( | |
184 | remote=remote, | |
185 | path='{tdir}/archive/s3roundtrip.{client}.config.yaml'.format(tdir=testdir, client=client), | |
186 | data=conf_fp.getvalue(), | |
187 | ) | |
188 | yield | |
189 | ||
190 | ||
191 | @contextlib.contextmanager | |
192 | def run_tests(ctx, config): | |
193 | """ | |
194 | Run the s3 roundtrip after everything is set up. | |
195 | ||
196 | :param ctx: Context passed to task | |
197 | :param config: specific configuration information | |
198 | """ | |
199 | assert isinstance(config, dict) | |
200 | testdir = teuthology.get_testdir(ctx) | |
201 | for client, client_config in config.iteritems(): | |
202 | (remote,) = ctx.cluster.only(client).remotes.keys() | |
203 | conf = teuthology.get_file(remote, '{tdir}/archive/s3roundtrip.{client}.config.yaml'.format(tdir=testdir, client=client)) | |
204 | args = [ | |
205 | '{tdir}/s3-tests/virtualenv/bin/s3tests-test-roundtrip'.format(tdir=testdir), | |
206 | ] | |
207 | if client_config is not None and 'extra_args' in client_config: | |
208 | args.extend(client_config['extra_args']) | |
209 | ||
210 | ctx.cluster.only(client).run( | |
211 | args=args, | |
212 | stdin=conf, | |
213 | ) | |
214 | yield | |
215 | ||
216 | ||
217 | @contextlib.contextmanager | |
218 | def task(ctx, config): | |
219 | """ | |
220 | Run the s3tests-test-roundtrip suite against rgw. | |
221 | ||
222 | To run all tests on all clients:: | |
223 | ||
224 | tasks: | |
225 | - ceph: | |
226 | - rgw: | |
227 | - s3roundtrip: | |
92f5a8d4 | 228 | force-branch: ceph-nautilus |
7c673cae FG |
229 | |
230 | To restrict testing to particular clients:: | |
231 | ||
232 | tasks: | |
233 | - ceph: | |
234 | - rgw: [client.0] | |
92f5a8d4 TL |
235 | - s3roundtrip: |
236 | client.0: | |
237 | force-branch: ceph-nautilus | |
7c673cae FG |
238 | |
239 | To run against a server on client.1:: | |
240 | ||
241 | tasks: | |
242 | - ceph: | |
243 | - rgw: [client.1] | |
244 | - s3roundtrip: | |
245 | client.0: | |
92f5a8d4 | 246 | force-branch: ceph-nautilus |
7c673cae FG |
247 | rgw_server: client.1 |
248 | ||
249 | To pass extra test arguments | |
250 | ||
251 | tasks: | |
252 | - ceph: | |
253 | - rgw: [client.0] | |
254 | - s3roundtrip: | |
255 | client.0: | |
92f5a8d4 | 256 | force-branch: ceph-nautilus |
7c673cae FG |
257 | roundtrip: |
258 | bucket: mybucket | |
259 | readers: 10 | |
260 | writers: 3 | |
261 | duration: 600 | |
262 | files: | |
263 | num: 10 | |
264 | size: 2000 | |
265 | stddev: 500 | |
266 | client.1: | |
267 | ... | |
268 | ||
269 | To override s3 configuration | |
270 | ||
271 | tasks: | |
272 | - ceph: | |
273 | - rgw: [client.0] | |
274 | - s3roundtrip: | |
92f5a8d4 | 275 | force-branch: ceph-nautilus |
7c673cae FG |
276 | client.0: |
277 | s3: | |
278 | user_id: myuserid | |
279 | display_name: myname | |
280 | email: my@email | |
281 | access_key: myaccesskey | |
282 | secret_key: mysecretkey | |
283 | ||
284 | """ | |
494da23a | 285 | assert hasattr(ctx, 'rgw'), 's3roundtrip must run after the rgw task' |
7c673cae FG |
286 | assert config is None or isinstance(config, list) \ |
287 | or isinstance(config, dict), \ | |
494da23a | 288 | "task s3roundtrip only supports a list or dictionary for configuration" |
7c673cae FG |
289 | all_clients = ['client.{id}'.format(id=id_) |
290 | for id_ in teuthology.all_roles_of_type(ctx.cluster, 'client')] | |
291 | if config is None: | |
292 | config = all_clients | |
293 | if isinstance(config, list): | |
294 | config = dict.fromkeys(config) | |
295 | clients = config.keys() | |
296 | ||
297 | s3tests_conf = {} | |
298 | for client in clients: | |
299 | if config[client] is None: | |
300 | config[client] = {} | |
301 | config[client].setdefault('s3', {}) | |
302 | config[client].setdefault('roundtrip', {}) | |
303 | ||
494da23a TL |
304 | endpoint = ctx.rgw.role_endpoints.get(client) |
305 | assert endpoint, 's3roundtrip: no rgw endpoint for {}'.format(client) | |
306 | ||
7c673cae FG |
307 | s3tests_conf[client] = ({ |
308 | 'DEFAULT': | |
309 | { | |
494da23a TL |
310 | 'port' : endpoint.port, |
311 | 'is_secure' : endpoint.cert is not None, | |
7c673cae FG |
312 | }, |
313 | 'roundtrip' : config[client]['roundtrip'], | |
314 | 's3' : config[client]['s3'], | |
315 | }) | |
316 | ||
317 | with contextutil.nested( | |
318 | lambda: download(ctx=ctx, config=config), | |
319 | lambda: create_users(ctx=ctx, config=dict( | |
320 | clients=clients, | |
321 | s3tests_conf=s3tests_conf, | |
322 | )), | |
323 | lambda: configure(ctx=ctx, config=dict( | |
324 | clients=config, | |
325 | s3tests_conf=s3tests_conf, | |
326 | )), | |
327 | lambda: run_tests(ctx=ctx, config=config), | |
328 | ): | |
329 | pass | |
330 | yield |