]>
git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/ragweed.py
2 Run a set of s3 tests on rgw.
5 from configobj
import ConfigObj
14 from teuthology
import misc
as teuthology
15 from teuthology
import contextutil
16 from teuthology
.config
import config
as teuth_config
17 from teuthology
.orchestra
import run
19 log
= logging
.getLogger(__name__
)
22 def get_ragweed_branches(config
, client_conf
):
24 figure out the ragweed branch according to the per-client settings
26 use force-branch is specified, and fall back to the ones deduced using ceph
29 force_branch
= client_conf
.get('force-branch', None)
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
)
40 branch
= client_conf
.get('branch', suite_branch
)
41 default_branch
= client_conf
.get('default-branch', None)
43 return [branch
, default_branch
]
48 @contextlib.contextmanager
49 def download(ctx
, config
):
51 Download the s3 tests from the git builder.
52 Remove downloaded s3 file upon exit.
54 The context passed in should be identical to the context
55 passed in to the main task.
57 assert isinstance(config
, dict)
58 log
.info('Downloading ragweed...')
59 testdir
= teuthology
.get_testdir(ctx
)
60 for (client
, cconf
) in config
.items():
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
):
64 log
.info("Using branch '%s' for ragweed", branch
)
66 ctx
.cluster
.only(client
).sh(
67 script
=f
'git clone -b {branch} {ragweed_repo} {testdir}/ragweed')
69 except Exception as e
:
74 sha1
= cconf
.get('sha1')
76 ctx
.cluster
.only(client
).run(
78 'cd', '{tdir}/ragweed'.format(tdir
=testdir
),
80 'git', 'reset', '--hard', sha1
,
86 log
.info('Removing ragweed...')
87 testdir
= teuthology
.get_testdir(ctx
)
89 ctx
.cluster
.only(client
).run(
93 '{tdir}/ragweed'.format(tdir
=testdir
),
98 def _config_user(ragweed_conf
, section
, user
):
100 Configure users for this section by stashing away keys, ids, and
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
))
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'))
110 @contextlib.contextmanager
111 def create_users(ctx
, config
, run_stages
):
113 Create a main and an alternate s3 user.
115 assert isinstance(config
, dict)
117 for client
, properties
in config
['config'].items():
118 run_stages
[client
] = properties
.get('stages', 'prepare,check').split(',')
120 log
.info('Creating rgw users...')
121 testdir
= teuthology
.get_testdir(ctx
)
122 users
= {'user regular': 'ragweed', 'user system': 'sysuser'}
123 for client
in config
['clients']:
124 if not 'prepare' in run_stages
[client
]:
125 # should have been prepared in a previous run
128 ragweed_conf
= config
['ragweed_conf'][client
]
129 ragweed_conf
.setdefault('fixtures', {})
130 ragweed_conf
['rgw'].setdefault('bucket_prefix', 'test-' + client
)
131 for section
, user
in users
.items():
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':
138 ctx
.cluster
.only(client
).run(
142 '{tdir}/archive/coverage'.format(tdir
=testdir
),
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'],
157 for client
in config
['clients']:
158 if not 'check' in run_stages
[client
]:
159 # only remove user if went through the check stage
161 for user
in users
.values():
162 uid
= '{user}.{client}'.format(user
=user
, client
=client
)
163 ctx
.cluster
.only(client
).run(
167 '{tdir}/archive/coverage'.format(tdir
=testdir
),
177 @contextlib.contextmanager
178 def configure(ctx
, config
, run_stages
):
180 Configure the ragweed. This includes the running of the
181 bootstrap code and the updating of local conf files.
183 assert isinstance(config
, dict)
184 log
.info('Configuring ragweed...')
185 testdir
= teuthology
.get_testdir(ctx
)
186 for client
, properties
in config
['clients'].items():
187 (remote
,) = ctx
.cluster
.only(client
).remotes
.keys()
191 '{tdir}/ragweed'.format(tdir
=testdir
),
197 preparing
= 'prepare' in run_stages
[client
]
199 # should have been prepared in a previous run
202 ragweed_conf
= config
['ragweed_conf'][client
]
203 if properties
is not None and 'slow_backend' in properties
:
204 ragweed_conf
['fixtures']['slow backend'] = properties
['slow_backend']
207 ragweed_conf
.write(conf_fp
)
208 teuthology
.write_file(
210 path
='{tdir}/archive/ragweed.{client}.conf'.format(tdir
=testdir
, client
=client
),
211 data
=conf_fp
.getvalue(),
214 log
.info('Configuring boto...')
215 boto_src
= os
.path
.join(os
.path
.dirname(__file__
), 'boto.cfg.template')
216 for client
, properties
in config
['clients'].items():
217 with
open(boto_src
, 'r') as f
:
218 (remote
,) = ctx
.cluster
.only(client
).remotes
.keys()
219 conf
= f
.read().format(
220 idle_timeout
=config
.get('idle_timeout', 30)
222 teuthology
.write_file(
224 path
='{tdir}/boto.cfg'.format(tdir
=testdir
),
232 log
.info('Cleaning up boto...')
233 for client
, properties
in config
['clients'].items():
234 (remote
,) = ctx
.cluster
.only(client
).remotes
.keys()
238 '{tdir}/boto.cfg'.format(tdir
=testdir
),
242 @contextlib.contextmanager
243 def run_tests(ctx
, config
, run_stages
):
245 Run the ragweed after everything is set up.
247 :param ctx: Context passed to task
248 :param config: specific configuration information
250 assert isinstance(config
, dict)
251 testdir
= teuthology
.get_testdir(ctx
)
252 attrs
= ["!fails_on_rgw"]
253 for client
, client_config
in config
.items():
254 stages
= ','.join(run_stages
[client
])
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
),
259 '{tdir}/ragweed/virtualenv/bin/python'.format(tdir
=testdir
),
262 '{tdir}/ragweed'.format(tdir
=testdir
),
264 '-a', ','.join(attrs
),
266 if client_config
is not None and 'extra_args' in client_config
:
267 args
.extend(client_config
['extra_args'])
269 ctx
.cluster
.only(client
).run(
271 label
="ragweed tests against rgw"
275 @contextlib.contextmanager
276 def task(ctx
, config
):
278 Run the ragweed suite against rgw.
280 To run all tests on all clients::
287 To restrict testing to particular clients::
292 - ragweed: [client.0]
294 To run against a server on client.1 and increase the boto timeout to 10m::
303 stages: prepare,check
305 To pass extra arguments to nose (e.g. to run a certain test)::
312 extra_args: ['test_s3:test_object_acl_grand_public_read']
314 extra_args: ['--exclude', 'test_100_continue']
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')]
324 if isinstance(config
, list):
325 config
= dict.fromkeys(config
)
326 clients
= config
.keys()
328 overrides
= ctx
.config
.get('overrides', {})
329 # merge each client section, not the top level.
330 for client
in config
.keys():
331 if not config
[client
]:
333 teuthology
.deep_merge(config
[client
], overrides
.get('ragweed', {}))
335 log
.debug('ragweed config is %s', config
)
338 for client
in clients
:
339 # use rgw_server endpoint if given, or default to same client
340 target
= config
[client
].get('rgw_server', client
)
342 endpoint
= ctx
.rgw
.role_endpoints
.get(target
)
343 assert endpoint
, 'ragweed: no rgw endpoint for {}'.format(target
)
345 ragweed_conf
[client
] = ConfigObj(
350 'host' : endpoint
.dns_name
,
351 'port' : endpoint
.port
,
352 'is_secure' : endpoint
.cert
is not None,
359 'ceph_conf' : '/etc/ceph/ceph.conf',
366 with contextutil
.nested(
367 lambda: download(ctx
=ctx
, config
=config
),
368 lambda: create_users(ctx
=ctx
, config
=dict(
370 ragweed_conf
=ragweed_conf
,
373 run_stages
=run_stages
),
374 lambda: configure(ctx
=ctx
, config
=dict(
376 ragweed_conf
=ragweed_conf
,
378 run_stages
=run_stages
),
379 lambda: run_tests(ctx
=ctx
, config
=config
, run_stages
=run_stages
),