]> git.proxmox.com Git - ceph.git/blame - ceph/qa/tasks/ragweed.py
import 15.2.4
[ceph.git] / ceph / qa / tasks / ragweed.py
CommitLineData
11fdf7f2
TL
1"""
2Run a set of s3 tests on rgw.
3"""
e306af50 4from io import BytesIO
11fdf7f2
TL
5from configobj import ConfigObj
6import base64
7import contextlib
8import logging
9import os
10import random
e306af50 11import six
11fdf7f2
TL
12import string
13
11fdf7f2
TL
14from teuthology import misc as teuthology
15from teuthology import contextutil
16from teuthology.config import config as teuth_config
17from teuthology.orchestra import run
11fdf7f2
TL
18
19log = logging.getLogger(__name__)
20
21@contextlib.contextmanager
22def download(ctx, config):
23 """
24 Download the s3 tests from the git builder.
25 Remove downloaded s3 file upon exit.
26
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 ragweed...')
32 testdir = teuthology.get_testdir(ctx)
33 s3_branches = [ 'master', 'nautilus', 'mimic', 'luminous', 'kraken', 'jewel' ]
34 for (client, cconf) in config.items():
35 default_branch = ''
36 branch = cconf.get('force-branch', None)
37 if not branch:
38 default_branch = cconf.get('default-branch', None)
39 ceph_branch = ctx.config.get('branch')
40 suite_branch = ctx.config.get('suite_branch', ceph_branch)
41 ragweed_repo = ctx.config.get('ragweed_repo', teuth_config.ceph_git_base_url + 'ragweed.git')
42 if suite_branch in s3_branches:
43 branch = cconf.get('branch', 'ceph-' + suite_branch)
9f95a23c 44 else:
11fdf7f2
TL
45 branch = cconf.get('branch', suite_branch)
46 if not branch:
47 raise ValueError(
48 "Could not determine what branch to use for ragweed!")
49 else:
50 log.info("Using branch '%s' for ragweed", branch)
51 sha1 = cconf.get('sha1')
52 try:
53 ctx.cluster.only(client).run(
54 args=[
55 'git', 'clone',
56 '-b', branch,
57 ragweed_repo,
58 '{tdir}/ragweed'.format(tdir=testdir),
59 ],
60 )
61 except Exception as e:
62 if not default_branch:
63 raise e
64 ctx.cluster.only(client).run(
65 args=[
66 'git', 'clone',
67 '-b', default_branch,
68 ragweed_repo,
69 '{tdir}/ragweed'.format(tdir=testdir),
70 ],
71 )
72
73 if sha1 is not None:
74 ctx.cluster.only(client).run(
75 args=[
76 'cd', '{tdir}/ragweed'.format(tdir=testdir),
77 run.Raw('&&'),
78 'git', 'reset', '--hard', sha1,
79 ],
80 )
81 try:
82 yield
83 finally:
84 log.info('Removing ragweed...')
85 testdir = teuthology.get_testdir(ctx)
86 for client in config:
87 ctx.cluster.only(client).run(
88 args=[
89 'rm',
90 '-rf',
91 '{tdir}/ragweed'.format(tdir=testdir),
92 ],
93 )
94
95
96def _config_user(ragweed_conf, section, user):
97 """
98 Configure users for this section by stashing away keys, ids, and
99 email addresses.
100 """
101 ragweed_conf[section].setdefault('user_id', user)
102 ragweed_conf[section].setdefault('email', '{user}+test@test.test'.format(user=user))
103 ragweed_conf[section].setdefault('display_name', 'Mr. {user}'.format(user=user))
e306af50
TL
104 ragweed_conf[section].setdefault('access_key', ''.join(random.choice(string.ascii_uppercase) for i in range(20)))
105 ragweed_conf[section].setdefault('secret_key', base64.b64encode(os.urandom(40)).decode('ascii'))
11fdf7f2
TL
106
107
108@contextlib.contextmanager
109def create_users(ctx, config, run_stages):
110 """
111 Create a main and an alternate s3 user.
112 """
113 assert isinstance(config, dict)
114
9f95a23c 115 for client, properties in config['config'].items():
e306af50 116 run_stages[client] = properties.get('stages', 'prepare,check').split(',')
11fdf7f2
TL
117
118 log.info('Creating rgw users...')
119 testdir = teuthology.get_testdir(ctx)
81eedcae 120 users = {'user regular': 'ragweed', 'user system': 'sysuser'}
11fdf7f2
TL
121 for client in config['clients']:
122 if not 'prepare' in run_stages[client]:
123 # should have been prepared in a previous run
124 continue
125
126 ragweed_conf = config['ragweed_conf'][client]
127 ragweed_conf.setdefault('fixtures', {})
128 ragweed_conf['rgw'].setdefault('bucket_prefix', 'test-' + client)
9f95a23c 129 for section, user in users.items():
11fdf7f2
TL
130 _config_user(ragweed_conf, section, '{user}.{client}'.format(user=user, client=client))
131 log.debug('Creating user {user} on {host}'.format(user=ragweed_conf[section]['user_id'], host=client))
132 if user == 'sysuser':
133 sys_str = 'true'
134 else:
135 sys_str = 'false'
136 ctx.cluster.only(client).run(
137 args=[
138 'adjust-ulimits',
139 'ceph-coverage',
140 '{tdir}/archive/coverage'.format(tdir=testdir),
141 'radosgw-admin',
142 '-n', client,
143 'user', 'create',
144 '--uid', ragweed_conf[section]['user_id'],
145 '--display-name', ragweed_conf[section]['display_name'],
146 '--access-key', ragweed_conf[section]['access_key'],
147 '--secret', ragweed_conf[section]['secret_key'],
148 '--email', ragweed_conf[section]['email'],
149 '--system', sys_str,
150 ],
151 )
152 try:
153 yield
154 finally:
155 for client in config['clients']:
156 if not 'check' in run_stages[client]:
157 # only remove user if went through the check stage
158 continue
e306af50 159 for user in users.values():
11fdf7f2
TL
160 uid = '{user}.{client}'.format(user=user, client=client)
161 ctx.cluster.only(client).run(
162 args=[
163 'adjust-ulimits',
164 'ceph-coverage',
165 '{tdir}/archive/coverage'.format(tdir=testdir),
166 'radosgw-admin',
167 '-n', client,
168 'user', 'rm',
169 '--uid', uid,
170 '--purge-data',
171 ],
172 )
173
174
175@contextlib.contextmanager
176def configure(ctx, config, run_stages):
177 """
178 Configure the ragweed. This includes the running of the
179 bootstrap code and the updating of local conf files.
180 """
181 assert isinstance(config, dict)
182 log.info('Configuring ragweed...')
183 testdir = teuthology.get_testdir(ctx)
9f95a23c 184 for client, properties in config['clients'].items():
11fdf7f2
TL
185 (remote,) = ctx.cluster.only(client).remotes.keys()
186 remote.run(
187 args=[
188 'cd',
189 '{tdir}/ragweed'.format(tdir=testdir),
190 run.Raw('&&'),
191 './bootstrap',
192 ],
193 )
194
195 preparing = 'prepare' in run_stages[client]
196 if not preparing:
197 # should have been prepared in a previous run
198 continue
199
200 ragweed_conf = config['ragweed_conf'][client]
11fdf7f2 201 if properties is not None and 'slow_backend' in properties:
9f95a23c 202 ragweed_conf['fixtures']['slow backend'] = properties['slow_backend']
11fdf7f2 203
e306af50 204 conf_fp = BytesIO()
11fdf7f2
TL
205 ragweed_conf.write(conf_fp)
206 teuthology.write_file(
207 remote=remote,
208 path='{tdir}/archive/ragweed.{client}.conf'.format(tdir=testdir, client=client),
209 data=conf_fp.getvalue(),
210 )
211
212 log.info('Configuring boto...')
213 boto_src = os.path.join(os.path.dirname(__file__), 'boto.cfg.template')
9f95a23c 214 for client, properties in config['clients'].items():
e306af50 215 with open(boto_src, 'r') as f:
11fdf7f2
TL
216 (remote,) = ctx.cluster.only(client).remotes.keys()
217 conf = f.read().format(
218 idle_timeout=config.get('idle_timeout', 30)
219 )
220 teuthology.write_file(
221 remote=remote,
222 path='{tdir}/boto.cfg'.format(tdir=testdir),
223 data=conf,
224 )
225
226 try:
227 yield
228
229 finally:
230 log.info('Cleaning up boto...')
9f95a23c 231 for client, properties in config['clients'].items():
11fdf7f2
TL
232 (remote,) = ctx.cluster.only(client).remotes.keys()
233 remote.run(
234 args=[
235 'rm',
236 '{tdir}/boto.cfg'.format(tdir=testdir),
237 ],
238 )
239
240@contextlib.contextmanager
241def run_tests(ctx, config, run_stages):
242 """
243 Run the ragweed after everything is set up.
244
245 :param ctx: Context passed to task
246 :param config: specific configuration information
247 """
248 assert isinstance(config, dict)
249 testdir = teuthology.get_testdir(ctx)
250 attrs = ["!fails_on_rgw"]
9f95a23c 251 for client, client_config in config.items():
e306af50 252 stages = ','.join(run_stages[client])
11fdf7f2
TL
253 args = [
254 'RAGWEED_CONF={tdir}/archive/ragweed.{client}.conf'.format(tdir=testdir, client=client),
255 'RAGWEED_STAGES={stages}'.format(stages=stages),
256 'BOTO_CONFIG={tdir}/boto.cfg'.format(tdir=testdir),
9f95a23c
TL
257 '{tdir}/ragweed/virtualenv/bin/python'.format(tdir=testdir),
258 '-m', 'nose',
11fdf7f2
TL
259 '-w',
260 '{tdir}/ragweed'.format(tdir=testdir),
261 '-v',
262 '-a', ','.join(attrs),
263 ]
264 if client_config is not None and 'extra_args' in client_config:
265 args.extend(client_config['extra_args'])
266
267 ctx.cluster.only(client).run(
268 args=args,
269 label="ragweed tests against rgw"
270 )
271 yield
272
273@contextlib.contextmanager
274def task(ctx, config):
275 """
276 Run the ragweed suite against rgw.
277
278 To run all tests on all clients::
279
280 tasks:
281 - ceph:
282 - rgw:
283 - ragweed:
284
285 To restrict testing to particular clients::
286
287 tasks:
288 - ceph:
289 - rgw: [client.0]
290 - ragweed: [client.0]
291
292 To run against a server on client.1 and increase the boto timeout to 10m::
293
294 tasks:
295 - ceph:
296 - rgw: [client.1]
297 - ragweed:
298 client.0:
299 rgw_server: client.1
300 idle_timeout: 600
301 stages: prepare,check
302
303 To pass extra arguments to nose (e.g. to run a certain test)::
304
305 tasks:
306 - ceph:
307 - rgw: [client.0]
308 - ragweed:
309 client.0:
310 extra_args: ['test_s3:test_object_acl_grand_public_read']
311 client.1:
312 extra_args: ['--exclude', 'test_100_continue']
313 """
314 assert hasattr(ctx, 'rgw'), 'ragweed must run after the rgw task'
315 assert config is None or isinstance(config, list) \
316 or isinstance(config, dict), \
317 "task ragweed only supports a list or dictionary for configuration"
318 all_clients = ['client.{id}'.format(id=id_)
319 for id_ in teuthology.all_roles_of_type(ctx.cluster, 'client')]
320 if config is None:
321 config = all_clients
322 if isinstance(config, list):
323 config = dict.fromkeys(config)
324 clients = config.keys()
325
326 overrides = ctx.config.get('overrides', {})
327 # merge each client section, not the top level.
9f95a23c 328 for client in config.keys():
11fdf7f2
TL
329 if not config[client]:
330 config[client] = {}
331 teuthology.deep_merge(config[client], overrides.get('ragweed', {}))
332
333 log.debug('ragweed config is %s', config)
334
335 ragweed_conf = {}
336 for client in clients:
9f95a23c
TL
337 # use rgw_server endpoint if given, or default to same client
338 target = config[client].get('rgw_server', client)
339
340 endpoint = ctx.rgw.role_endpoints.get(target)
341 assert endpoint, 'ragweed: no rgw endpoint for {}'.format(target)
11fdf7f2
TL
342
343 ragweed_conf[client] = ConfigObj(
344 indent_type='',
345 infile={
346 'rgw':
347 {
9f95a23c 348 'host' : endpoint.dns_name,
11fdf7f2 349 'port' : endpoint.port,
494da23a 350 'is_secure' : endpoint.cert is not None,
11fdf7f2
TL
351 },
352 'fixtures' : {},
353 'user system' : {},
354 'user regular' : {},
355 'rados':
356 {
357 'ceph_conf' : '/etc/ceph/ceph.conf',
358 },
359 }
360 )
361
362 run_stages = {}
363
364 with contextutil.nested(
365 lambda: download(ctx=ctx, config=config),
366 lambda: create_users(ctx=ctx, config=dict(
367 clients=clients,
368 ragweed_conf=ragweed_conf,
369 config=config,
370 ),
371 run_stages=run_stages),
372 lambda: configure(ctx=ctx, config=dict(
373 clients=config,
374 ragweed_conf=ragweed_conf,
375 ),
376 run_stages=run_stages),
377 lambda: run_tests(ctx=ctx, config=config, run_stages=run_stages),
378 ):
379 pass
380 yield