]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | """ |
2 | Run rgw roundtrip message 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.iteritems(): | |
35 | branch = cconf.get('force-branch', None) | |
36 | if not branch: | |
37 | branch = cconf.get('branch', 'master') | |
38 | ctx.cluster.only(client).run( | |
39 | args=[ | |
40 | 'git', 'clone', | |
41 | '-b', branch, | |
42 | teuth_config.ceph_git_base_url + 's3-tests.git', | |
43 | '{tdir}/s3-tests'.format(tdir=testdir), | |
44 | ], | |
45 | ) | |
46 | try: | |
47 | yield | |
48 | finally: | |
49 | log.info('Removing s3-tests...') | |
50 | for client in config: | |
51 | ctx.cluster.only(client).run( | |
52 | args=[ | |
53 | 'rm', | |
54 | '-rf', | |
55 | '{tdir}/s3-tests'.format(tdir=testdir), | |
56 | ], | |
57 | ) | |
58 | ||
59 | def _config_user(s3tests_conf, section, user): | |
60 | """ | |
61 | Configure users for this section by stashing away keys, ids, and | |
62 | email addresses. | |
63 | """ | |
64 | s3tests_conf[section].setdefault('user_id', user) | |
65 | s3tests_conf[section].setdefault('email', '{user}+test@test.test'.format(user=user)) | |
66 | s3tests_conf[section].setdefault('display_name', 'Mr. {user}'.format(user=user)) | |
67 | s3tests_conf[section].setdefault('access_key', ''.join(random.choice(string.uppercase) for i in xrange(20))) | |
68 | s3tests_conf[section].setdefault('secret_key', base64.b64encode(os.urandom(40))) | |
69 | ||
70 | @contextlib.contextmanager | |
71 | def create_users(ctx, config): | |
72 | """ | |
73 | Create a default s3 user. | |
74 | """ | |
75 | assert isinstance(config, dict) | |
76 | log.info('Creating rgw users...') | |
77 | testdir = teuthology.get_testdir(ctx) | |
78 | users = {'s3': 'foo'} | |
79 | for client in config['clients']: | |
80 | s3tests_conf = config['s3tests_conf'][client] | |
81 | s3tests_conf.setdefault('roundtrip', {}) | |
82 | s3tests_conf['roundtrip'].setdefault('bucket', 'rttest-' + client + '-{random}-') | |
83 | s3tests_conf['roundtrip'].setdefault('readers', 10) | |
84 | s3tests_conf['roundtrip'].setdefault('writers', 3) | |
85 | s3tests_conf['roundtrip'].setdefault('duration', 300) | |
86 | s3tests_conf['roundtrip'].setdefault('files', {}) | |
87 | rtconf = s3tests_conf['roundtrip'] | |
88 | rtconf['files'].setdefault('num', 10) | |
89 | rtconf['files'].setdefault('size', 2000) | |
90 | rtconf['files'].setdefault('stddev', 500) | |
91 | for section, user in [('s3', 'foo')]: | |
92 | _config_user(s3tests_conf, section, '{user}.{client}'.format(user=user, client=client)) | |
93 | ctx.cluster.only(client).run( | |
94 | args=[ | |
95 | 'adjust-ulimits', | |
96 | 'ceph-coverage', | |
97 | '{tdir}/archive/coverage'.format(tdir=testdir), | |
98 | 'radosgw-admin', | |
99 | '-n', client, | |
100 | 'user', 'create', | |
101 | '--uid', s3tests_conf[section]['user_id'], | |
102 | '--display-name', s3tests_conf[section]['display_name'], | |
103 | '--access-key', s3tests_conf[section]['access_key'], | |
104 | '--secret', s3tests_conf[section]['secret_key'], | |
105 | '--email', s3tests_conf[section]['email'], | |
106 | ], | |
107 | ) | |
108 | try: | |
109 | yield | |
110 | finally: | |
111 | for client in config['clients']: | |
112 | for user in users.itervalues(): | |
113 | uid = '{user}.{client}'.format(user=user, client=client) | |
114 | ctx.cluster.only(client).run( | |
115 | args=[ | |
116 | 'adjust-ulimits', | |
117 | 'ceph-coverage', | |
118 | '{tdir}/archive/coverage'.format(tdir=testdir), | |
119 | 'radosgw-admin', | |
120 | '-n', client, | |
121 | 'user', 'rm', | |
122 | '--uid', uid, | |
123 | '--purge-data', | |
124 | ], | |
125 | ) | |
126 | ||
127 | @contextlib.contextmanager | |
128 | def configure(ctx, config): | |
129 | """ | |
130 | Configure the s3-tests. This includes the running of the | |
131 | bootstrap code and the updating of local conf files. | |
132 | """ | |
133 | assert isinstance(config, dict) | |
134 | log.info('Configuring s3-roundtrip-tests...') | |
135 | testdir = teuthology.get_testdir(ctx) | |
136 | for client, properties in config['clients'].iteritems(): | |
137 | s3tests_conf = config['s3tests_conf'][client] | |
138 | if properties is not None and 'rgw_server' in properties: | |
139 | host = None | |
140 | for target, roles in zip(ctx.config['targets'].iterkeys(), ctx.config['roles']): | |
141 | log.info('roles: ' + str(roles)) | |
142 | log.info('target: ' + str(target)) | |
143 | if properties['rgw_server'] in roles: | |
144 | _, host = split_user(target) | |
145 | assert host is not None, "Invalid client specified as the rgw_server" | |
146 | s3tests_conf['s3']['host'] = host | |
147 | else: | |
148 | s3tests_conf['s3']['host'] = 'localhost' | |
149 | ||
150 | def_conf = s3tests_conf['DEFAULT'] | |
151 | s3tests_conf['s3'].setdefault('port', def_conf['port']) | |
152 | s3tests_conf['s3'].setdefault('is_secure', def_conf['is_secure']) | |
153 | ||
154 | (remote,) = ctx.cluster.only(client).remotes.keys() | |
155 | remote.run( | |
156 | args=[ | |
157 | 'cd', | |
158 | '{tdir}/s3-tests'.format(tdir=testdir), | |
159 | run.Raw('&&'), | |
160 | './bootstrap', | |
161 | ], | |
162 | ) | |
163 | conf_fp = StringIO() | |
164 | conf = dict( | |
165 | s3=s3tests_conf['s3'], | |
166 | roundtrip=s3tests_conf['roundtrip'], | |
167 | ) | |
168 | yaml.safe_dump(conf, conf_fp, default_flow_style=False) | |
169 | teuthology.write_file( | |
170 | remote=remote, | |
171 | path='{tdir}/archive/s3roundtrip.{client}.config.yaml'.format(tdir=testdir, client=client), | |
172 | data=conf_fp.getvalue(), | |
173 | ) | |
174 | yield | |
175 | ||
176 | ||
177 | @contextlib.contextmanager | |
178 | def run_tests(ctx, config): | |
179 | """ | |
180 | Run the s3 roundtrip after everything is set up. | |
181 | ||
182 | :param ctx: Context passed to task | |
183 | :param config: specific configuration information | |
184 | """ | |
185 | assert isinstance(config, dict) | |
186 | testdir = teuthology.get_testdir(ctx) | |
187 | for client, client_config in config.iteritems(): | |
188 | (remote,) = ctx.cluster.only(client).remotes.keys() | |
189 | conf = teuthology.get_file(remote, '{tdir}/archive/s3roundtrip.{client}.config.yaml'.format(tdir=testdir, client=client)) | |
190 | args = [ | |
191 | '{tdir}/s3-tests/virtualenv/bin/s3tests-test-roundtrip'.format(tdir=testdir), | |
192 | ] | |
193 | if client_config is not None and 'extra_args' in client_config: | |
194 | args.extend(client_config['extra_args']) | |
195 | ||
196 | ctx.cluster.only(client).run( | |
197 | args=args, | |
198 | stdin=conf, | |
199 | ) | |
200 | yield | |
201 | ||
202 | ||
203 | @contextlib.contextmanager | |
204 | def task(ctx, config): | |
205 | """ | |
206 | Run the s3tests-test-roundtrip suite against rgw. | |
207 | ||
208 | To run all tests on all clients:: | |
209 | ||
210 | tasks: | |
211 | - ceph: | |
212 | - rgw: | |
213 | - s3roundtrip: | |
214 | ||
215 | To restrict testing to particular clients:: | |
216 | ||
217 | tasks: | |
218 | - ceph: | |
219 | - rgw: [client.0] | |
220 | - s3roundtrip: [client.0] | |
221 | ||
222 | To run against a server on client.1:: | |
223 | ||
224 | tasks: | |
225 | - ceph: | |
226 | - rgw: [client.1] | |
227 | - s3roundtrip: | |
228 | client.0: | |
229 | rgw_server: client.1 | |
230 | ||
231 | To pass extra test arguments | |
232 | ||
233 | tasks: | |
234 | - ceph: | |
235 | - rgw: [client.0] | |
236 | - s3roundtrip: | |
237 | client.0: | |
238 | roundtrip: | |
239 | bucket: mybucket | |
240 | readers: 10 | |
241 | writers: 3 | |
242 | duration: 600 | |
243 | files: | |
244 | num: 10 | |
245 | size: 2000 | |
246 | stddev: 500 | |
247 | client.1: | |
248 | ... | |
249 | ||
250 | To override s3 configuration | |
251 | ||
252 | tasks: | |
253 | - ceph: | |
254 | - rgw: [client.0] | |
255 | - s3roundtrip: | |
256 | client.0: | |
257 | s3: | |
258 | user_id: myuserid | |
259 | display_name: myname | |
260 | email: my@email | |
261 | access_key: myaccesskey | |
262 | secret_key: mysecretkey | |
263 | ||
264 | """ | |
494da23a | 265 | assert hasattr(ctx, 'rgw'), 's3roundtrip must run after the rgw task' |
7c673cae FG |
266 | assert config is None or isinstance(config, list) \ |
267 | or isinstance(config, dict), \ | |
494da23a | 268 | "task s3roundtrip only supports a list or dictionary for configuration" |
7c673cae FG |
269 | all_clients = ['client.{id}'.format(id=id_) |
270 | for id_ in teuthology.all_roles_of_type(ctx.cluster, 'client')] | |
271 | if config is None: | |
272 | config = all_clients | |
273 | if isinstance(config, list): | |
274 | config = dict.fromkeys(config) | |
275 | clients = config.keys() | |
276 | ||
277 | s3tests_conf = {} | |
278 | for client in clients: | |
279 | if config[client] is None: | |
280 | config[client] = {} | |
281 | config[client].setdefault('s3', {}) | |
282 | config[client].setdefault('roundtrip', {}) | |
283 | ||
494da23a TL |
284 | endpoint = ctx.rgw.role_endpoints.get(client) |
285 | assert endpoint, 's3roundtrip: no rgw endpoint for {}'.format(client) | |
286 | ||
7c673cae FG |
287 | s3tests_conf[client] = ({ |
288 | 'DEFAULT': | |
289 | { | |
494da23a TL |
290 | 'port' : endpoint.port, |
291 | 'is_secure' : endpoint.cert is not None, | |
7c673cae FG |
292 | }, |
293 | 'roundtrip' : config[client]['roundtrip'], | |
294 | 's3' : config[client]['s3'], | |
295 | }) | |
296 | ||
297 | with contextutil.nested( | |
298 | lambda: download(ctx=ctx, config=config), | |
299 | lambda: create_users(ctx=ctx, config=dict( | |
300 | clients=clients, | |
301 | s3tests_conf=s3tests_conf, | |
302 | )), | |
303 | lambda: configure(ctx=ctx, config=dict( | |
304 | clients=config, | |
305 | s3tests_conf=s3tests_conf, | |
306 | )), | |
307 | lambda: run_tests(ctx=ctx, config=config), | |
308 | ): | |
309 | pass | |
310 | yield |