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