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