]> git.proxmox.com Git - ceph.git/blame - ceph/qa/tasks/rgw.py
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / qa / tasks / rgw.py
CommitLineData
7c673cae
FG
1"""
2rgw routines
3"""
4import argparse
5import contextlib
6import json
7import logging
8import os
9import errno
10import util.rgw as rgw_utils
11
7c673cae
FG
12from teuthology.orchestra import run
13from teuthology import misc as teuthology
14from teuthology import contextutil
11fdf7f2
TL
15from teuthology.exceptions import ConfigError
16from util import get_remote_for_role
31f18b77 17from util.rgw import rgwadmin, wait_for_radosgw
7c673cae
FG
18from util.rados import (rados, create_ec_pool,
19 create_replicated_pool,
20 create_cache_pool)
21
22log = logging.getLogger(__name__)
23
11fdf7f2
TL
24class RGWEndpoint:
25 def __init__(self, hostname=None, port=None, cert=None):
26 self.hostname = hostname
27 self.port = port
28 self.cert = cert
29
30 def url(self):
31 proto = 'https' if self.cert else 'http'
32 return '{proto}://{hostname}:{port}/'.format(proto=proto, hostname=self.hostname, port=self.port)
33
7c673cae 34@contextlib.contextmanager
224ce89b 35def start_rgw(ctx, config, clients):
7c673cae
FG
36 """
37 Start rgw on remote sites.
38 """
39 log.info('Starting rgw...')
7c673cae 40 testdir = teuthology.get_testdir(ctx)
224ce89b 41 for client in clients:
7c673cae
FG
42 (remote,) = ctx.cluster.only(client).remotes.iterkeys()
43 cluster_name, daemon_type, client_id = teuthology.split_role(client)
44 client_with_id = daemon_type + '.' + client_id
45 client_with_cluster = cluster_name + '.' + client_with_id
7c673cae
FG
46
47 client_config = config.get(client)
48 if client_config is None:
49 client_config = {}
50 log.info("rgw %s config is %s", client, client_config)
7c673cae
FG
51 cmd_prefix = [
52 'sudo',
53 'adjust-ulimits',
54 'ceph-coverage',
55 '{tdir}/archive/coverage'.format(tdir=testdir),
56 'daemon-helper',
57 'term',
58 ]
59
60 rgw_cmd = ['radosgw']
61
31f18b77 62 log.info("Using %s as radosgw frontend", ctx.rgw.frontend)
7c673cae 63
11fdf7f2
TL
64 endpoint = ctx.rgw.role_endpoints[client]
65 frontends = ctx.rgw.frontend
66 frontend_prefix = client_config.get('frontend_prefix', None)
67 if frontend_prefix:
68 frontends += ' prefix={pfx}'.format(pfx=frontend_prefix)
69
70 if endpoint.cert:
71 # add the ssl certificate path
72 frontends += ' ssl_certificate={}'.format(endpoint.cert.certificate)
73 if ctx.rgw.frontend == 'civetweb':
74 frontends += ' port={}s'.format(endpoint.port)
75 else:
76 frontends += ' ssl_port={}'.format(endpoint.port)
77 else:
78 frontends += ' port={}'.format(endpoint.port)
79
7c673cae 80 rgw_cmd.extend([
11fdf7f2 81 '--rgw-frontends', frontends,
7c673cae
FG
82 '-n', client_with_id,
83 '--cluster', cluster_name,
84 '-k', '/etc/ceph/{client_with_cluster}.keyring'.format(client_with_cluster=client_with_cluster),
85 '--log-file',
86 '/var/log/ceph/rgw.{client_with_cluster}.log'.format(client_with_cluster=client_with_cluster),
87 '--rgw_ops_log_socket_path',
88 '{tdir}/rgw.opslog.{client_with_cluster}.sock'.format(tdir=testdir,
11fdf7f2
TL
89 client_with_cluster=client_with_cluster)
90 ])
91
92 keystone_role = client_config.get('use-keystone-role', None)
93 if keystone_role is not None:
94 if not ctx.keystone:
95 raise ConfigError('rgw must run after the keystone task')
96 url = 'http://{host}:{port}/v1/KEY_$(tenant_id)s'.format(host=endpoint.hostname,
97 port=endpoint.port)
98 ctx.keystone.create_endpoint(ctx, keystone_role, 'swift', url)
99
100 keystone_host, keystone_port = \
101 ctx.keystone.public_endpoints[keystone_role]
102 rgw_cmd.extend([
103 '--rgw_keystone_url',
104 'http://{khost}:{kport}'.format(khost=keystone_host,
105 kport=keystone_port),
106 ])
107
108 rgw_cmd.extend([
7c673cae
FG
109 '--foreground',
110 run.Raw('|'),
111 'sudo',
112 'tee',
113 '/var/log/ceph/rgw.{client_with_cluster}.stdout'.format(tdir=testdir,
114 client_with_cluster=client_with_cluster),
115 run.Raw('2>&1'),
116 ])
117
118 if client_config.get('valgrind'):
119 cmd_prefix = teuthology.get_valgrind_args(
120 testdir,
31f18b77 121 client_with_cluster,
7c673cae
FG
122 cmd_prefix,
123 client_config.get('valgrind')
124 )
125
126 run_cmd = list(cmd_prefix)
127 run_cmd.extend(rgw_cmd)
128
129 ctx.daemons.add_daemon(
31f18b77 130 remote, 'rgw', client_with_id,
7c673cae
FG
131 cluster=cluster_name,
132 args=run_cmd,
133 logger=log.getChild(client),
134 stdin=run.PIPE,
135 wait=False,
136 )
137
138 # XXX: add_daemon() doesn't let us wait until radosgw finishes startup
11fdf7f2
TL
139 for client in clients:
140 endpoint = ctx.rgw.role_endpoints[client]
141 url = endpoint.url()
142 log.info('Polling {client} until it starts accepting connections on {url}'.format(client=client, url=url))
143 wait_for_radosgw(url)
7c673cae
FG
144
145 try:
146 yield
147 finally:
11fdf7f2 148 for client in clients:
31f18b77
FG
149 cluster_name, daemon_type, client_id = teuthology.split_role(client)
150 client_with_id = daemon_type + '.' + client_id
151 client_with_cluster = cluster_name + '.' + client_with_id
152 ctx.daemons.get_daemon('rgw', client_with_id, cluster_name).stop()
7c673cae
FG
153 ctx.cluster.only(client).run(
154 args=[
155 'rm',
156 '-f',
31f18b77
FG
157 '{tdir}/rgw.opslog.{client}.sock'.format(tdir=testdir,
158 client=client_with_cluster),
7c673cae
FG
159 ],
160 )
161
11fdf7f2 162def assign_endpoints(ctx, config, default_cert):
7c673cae 163 """
11fdf7f2 164 Assign port numbers starting with port 7280.
7c673cae
FG
165 """
166 port = 7280
167 role_endpoints = {}
11fdf7f2
TL
168
169 for role, client_config in config.iteritems():
170 client_config = client_config or {}
171 remote = get_remote_for_role(ctx, role)
172
173 cert = client_config.get('ssl certificate', default_cert)
174 if cert:
175 # find the certificate created by the ssl task
176 if not hasattr(ctx, 'ssl_certificates'):
177 raise ConfigError('rgw: no ssl task found for option "ssl certificate"')
178 ssl_certificate = ctx.ssl_certificates.get(cert, None)
179 if not ssl_certificate:
180 raise ConfigError('rgw: missing ssl certificate "{}"'.format(cert))
181 else:
182 ssl_certificate = None
183
184 role_endpoints[role] = RGWEndpoint(remote.hostname, port, ssl_certificate)
185 port += 1
7c673cae
FG
186
187 return role_endpoints
188
7c673cae 189@contextlib.contextmanager
224ce89b 190def create_pools(ctx, clients):
7c673cae 191 """Create replicated or erasure coded data pools for rgw."""
7c673cae 192
31f18b77 193 log.info('Creating data pools')
224ce89b
WB
194 for client in clients:
195 log.debug("Obtaining remote for client {}".format(client))
7c673cae 196 (remote,) = ctx.cluster.only(client).remotes.iterkeys()
11fdf7f2 197 data_pool = 'default.rgw.buckets.data'
7c673cae
FG
198 cluster_name, daemon_type, client_id = teuthology.split_role(client)
199
200 if ctx.rgw.ec_data_pool:
11fdf7f2 201 create_ec_pool(remote, data_pool, client, ctx.rgw.data_pool_pg_size,
b5b8bbf5 202 ctx.rgw.erasure_code_profile, cluster_name, 'rgw')
7c673cae 203 else:
11fdf7f2
TL
204 create_replicated_pool(remote, data_pool, ctx.rgw.data_pool_pg_size, cluster_name, 'rgw')
205
206 index_pool = 'default.rgw.buckets.index'
207 create_replicated_pool(remote, index_pool, ctx.rgw.index_pool_pg_size, cluster_name, 'rgw')
208
7c673cae
FG
209 if ctx.rgw.cache_pools:
210 create_cache_pool(remote, data_pool, data_pool + '.cache', 64,
181888fb 211 64*1024*1024, cluster_name)
31f18b77 212 log.debug('Pools created')
7c673cae
FG
213 yield
214
215@contextlib.contextmanager
224ce89b 216def configure_compression(ctx, clients, compression):
31f18b77
FG
217 """ set a compression type in the default zone placement """
218 log.info('Configuring compression type = %s', compression)
224ce89b 219 for client in clients:
7c673cae
FG
220 # XXX: the 'default' zone and zonegroup aren't created until we run RGWRados::init_complete().
221 # issue a 'radosgw-admin user list' command to trigger this
222 rgwadmin(ctx, client, cmd=['user', 'list'], check_status=True)
223
224 rgwadmin(ctx, client,
225 cmd=['zone', 'placement', 'modify', '--rgw-zone', 'default',
31f18b77
FG
226 '--placement-id', 'default-placement',
227 '--compression', compression],
7c673cae 228 check_status=True)
7c673cae
FG
229 yield
230
11fdf7f2
TL
231@contextlib.contextmanager
232def configure_storage_classes(ctx, clients, storage_classes):
233 """ set a compression type in the default zone placement """
234
235 sc = [s.strip() for s in storage_classes.split(',')]
236
237 for client in clients:
238 # XXX: the 'default' zone and zonegroup aren't created until we run RGWRados::init_complete().
239 # issue a 'radosgw-admin user list' command to trigger this
240 rgwadmin(ctx, client, cmd=['user', 'list'], check_status=True)
241
242 for storage_class in sc:
243 log.info('Configuring storage class type = %s', storage_class)
244 rgwadmin(ctx, client,
245 cmd=['zonegroup', 'placement', 'add',
246 '--rgw-zone', 'default',
247 '--placement-id', 'default-placement',
248 '--storage-class', storage_class],
249 check_status=True)
250 rgwadmin(ctx, client,
251 cmd=['zone', 'placement', 'add',
252 '--rgw-zone', 'default',
253 '--placement-id', 'default-placement',
254 '--storage-class', storage_class,
255 '--data-pool', 'default.rgw.buckets.data.' + storage_class.lower()],
256 check_status=True)
257 yield
258
7c673cae
FG
259@contextlib.contextmanager
260def task(ctx, config):
261 """
7c673cae
FG
262 For example, to run rgw on all clients::
263
264 tasks:
265 - ceph:
266 - rgw:
267
268 To only run on certain clients::
269
270 tasks:
271 - ceph:
272 - rgw: [client.0, client.3]
273
274 or
275
276 tasks:
277 - ceph:
278 - rgw:
279 client.0:
280 client.3:
281
7c673cae
FG
282 To run radosgw through valgrind:
283
284 tasks:
285 - ceph:
286 - rgw:
287 client.0:
288 valgrind: [--tool=memcheck]
289 client.3:
290 valgrind: [--tool=memcheck]
11fdf7f2
TL
291
292 To configure data or index pool pg_size:
293
294 overrides:
295 rgw:
296 data_pool_pg_size: 256
297 index_pool_pg_size: 128
7c673cae
FG
298 """
299 if config is None:
300 config = dict(('client.{id}'.format(id=id_), None)
301 for id_ in teuthology.all_roles_of_type(
302 ctx.cluster, 'client'))
303 elif isinstance(config, list):
304 config = dict((name, None) for name in config)
305
224ce89b
WB
306 clients = config.keys() # http://tracker.ceph.com/issues/20417
307
7c673cae
FG
308 overrides = ctx.config.get('overrides', {})
309 teuthology.deep_merge(config, overrides.get('rgw', {}))
310
7c673cae 311 ctx.rgw = argparse.Namespace()
7c673cae 312
31f18b77
FG
313 ctx.rgw.ec_data_pool = bool(config.pop('ec-data-pool', False))
314 ctx.rgw.erasure_code_profile = config.pop('erasure_code_profile', {})
315 ctx.rgw.cache_pools = bool(config.pop('cache-pools', False))
316 ctx.rgw.frontend = config.pop('frontend', 'civetweb')
317 ctx.rgw.compression_type = config.pop('compression type', None)
11fdf7f2
TL
318 ctx.rgw.storage_classes = config.pop('storage classes', None)
319 default_cert = config.pop('ssl certificate', None)
320 ctx.rgw.data_pool_pg_size = config.pop('data_pool_pg_size', 64)
321 ctx.rgw.index_pool_pg_size = config.pop('index_pool_pg_size', 64)
7c673cae 322 ctx.rgw.config = config
7c673cae 323
224ce89b
WB
324 log.debug("config is {}".format(config))
325 log.debug("client list is {}".format(clients))
11fdf7f2
TL
326
327 ctx.rgw.role_endpoints = assign_endpoints(ctx, config, default_cert)
328
31f18b77 329 subtasks = [
224ce89b 330 lambda: create_pools(ctx=ctx, clients=clients),
31f18b77
FG
331 ]
332 if ctx.rgw.compression_type:
7c673cae 333 subtasks.extend([
224ce89b 334 lambda: configure_compression(ctx=ctx, clients=clients,
31f18b77 335 compression=ctx.rgw.compression_type),
7c673cae 336 ])
11fdf7f2
TL
337 if ctx.rgw.storage_classes:
338 subtasks.extend([
339 lambda: configure_storage_classes(ctx=ctx, clients=clients,
340 storage_classes=ctx.rgw.storage_classes),
341 ])
31f18b77 342 subtasks.extend([
224ce89b 343 lambda: start_rgw(ctx=ctx, config=config, clients=clients),
31f18b77 344 ])
7c673cae 345
7c673cae
FG
346 with contextutil.nested(*subtasks):
347 yield