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