]>
git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/rgw.py
bde82de41756c97691f5fdfae8dd3233c21fe302
8 from teuthology
.orchestra
import run
9 from teuthology
import misc
as teuthology
10 from teuthology
import contextutil
11 from teuthology
.exceptions
import ConfigError
12 from tasks
.ceph_manager
import get_valgrind_args
13 from tasks
.util
import get_remote_for_role
14 from tasks
.util
.rgw
import rgwadmin
, wait_for_radosgw
15 from tasks
.util
.rados
import (create_ec_pool
,
16 create_replicated_pool
,
19 log
= logging
.getLogger(__name__
)
22 def __init__(self
, hostname
=None, port
=None, cert
=None, dns_name
=None, website_dns_name
=None):
23 self
.hostname
= hostname
26 self
.dns_name
= dns_name
27 self
.website_dns_name
= website_dns_name
30 proto
= 'https' if self
.cert
else 'http'
31 return '{proto}://{hostname}:{port}/'.format(proto
=proto
, hostname
=self
.hostname
, port
=self
.port
)
33 @contextlib.contextmanager
34 def start_rgw(ctx
, config
, clients
):
36 Start rgw on remote sites.
38 log
.info('Starting rgw...')
39 testdir
= teuthology
.get_testdir(ctx
)
40 for client
in clients
:
41 (remote
,) = ctx
.cluster
.only(client
).remotes
.keys()
42 cluster_name
, daemon_type
, client_id
= teuthology
.split_role(client
)
43 client_with_id
= daemon_type
+ '.' + client_id
44 client_with_cluster
= cluster_name
+ '.' + client_with_id
46 client_config
= config
.get(client
)
47 if client_config
is None:
49 log
.info("rgw %s config is %s", client
, client_config
)
54 '{tdir}/archive/coverage'.format(tdir
=testdir
),
61 log
.info("Using %s as radosgw frontend", ctx
.rgw
.frontend
)
63 endpoint
= ctx
.rgw
.role_endpoints
[client
]
64 frontends
= ctx
.rgw
.frontend
65 frontend_prefix
= client_config
.get('frontend_prefix', None)
67 frontends
+= ' prefix={pfx}'.format(pfx
=frontend_prefix
)
70 # add the ssl certificate path
71 frontends
+= ' ssl_certificate={}'.format(endpoint
.cert
.certificate
)
72 frontends
+= ' ssl_port={}'.format(endpoint
.port
)
74 frontends
+= ' port={}'.format(endpoint
.port
)
77 '--rgw-frontends', frontends
,
79 '--cluster', cluster_name
,
80 '-k', '/etc/ceph/{client_with_cluster}.keyring'.format(client_with_cluster
=client_with_cluster
),
82 '/var/log/ceph/rgw.{client_with_cluster}.log'.format(client_with_cluster
=client_with_cluster
),
83 '--rgw_ops_log_socket_path',
84 '{tdir}/rgw.opslog.{client_with_cluster}.sock'.format(tdir
=testdir
,
85 client_with_cluster
=client_with_cluster
),
88 keystone_role
= client_config
.get('use-keystone-role', None)
89 if keystone_role
is not None:
91 raise ConfigError('rgw must run after the keystone task')
92 url
= 'http://{host}:{port}/v1/KEY_$(tenant_id)s'.format(host
=endpoint
.hostname
,
94 ctx
.keystone
.create_endpoint(ctx
, keystone_role
, 'swift', url
)
96 keystone_host
, keystone_port
= \
97 ctx
.keystone
.public_endpoints
[keystone_role
]
100 'http://{khost}:{kport}'.format(khost
=keystone_host
,
101 kport
=keystone_port
),
105 if client_config
.get('dns-name') is not None:
106 rgw_cmd
.extend(['--rgw-dns-name', endpoint
.dns_name
])
107 if client_config
.get('dns-s3website-name') is not None:
108 rgw_cmd
.extend(['--rgw-dns-s3website-name', endpoint
.website_dns_name
])
111 vault_role
= client_config
.get('use-vault-role', None)
112 barbican_role
= client_config
.get('use-barbican-role', None)
113 pykmip_role
= client_config
.get('use-pykmip-role', None)
115 token_path
= '/etc/ceph/vault-root-token'
116 if barbican_role
is not None:
117 if not hasattr(ctx
, 'barbican'):
118 raise ConfigError('rgw must run after the barbican task')
120 barbican_host
, barbican_port
= \
121 ctx
.barbican
.endpoints
[barbican_role
]
122 log
.info("Use barbican url=%s:%s", barbican_host
, barbican_port
)
125 '--rgw_barbican_url',
126 'http://{bhost}:{bport}'.format(bhost
=barbican_host
,
127 bport
=barbican_port
),
129 elif vault_role
is not None:
130 if not ctx
.vault
.root_token
:
131 raise ConfigError('vault: no "root_token" specified')
132 # create token on file
133 ctx
.rgw
.vault_role
= vault_role
134 ctx
.cluster
.only(client
).run(args
=['sudo', 'echo', '-n', ctx
.vault
.root_token
, run
.Raw('|'), 'sudo', 'tee', token_path
])
135 log
.info("Token file content")
136 ctx
.cluster
.only(client
).run(args
=['cat', token_path
])
137 log
.info("Restrict access to token file")
138 ctx
.cluster
.only(client
).run(args
=['sudo', 'chmod', '600', token_path
])
139 ctx
.cluster
.only(client
).run(args
=['sudo', 'chown', 'ceph', token_path
])
141 vault_addr
= "{}:{}".format(*ctx
.vault
.endpoints
[vault_role
])
143 '--rgw_crypt_vault_addr', vault_addr
,
144 '--rgw_crypt_vault_token_file', token_path
,
145 '--rgw_crypt_sse_s3_vault_addr', vault_addr
,
146 '--rgw_crypt_sse_s3_vault_token_file', token_path
,
148 elif pykmip_role
is not None:
149 if not hasattr(ctx
, 'pykmip'):
150 raise ConfigError('rgw must run after the pykmip task')
151 ctx
.rgw
.pykmip_role
= pykmip_role
153 '--rgw_crypt_kmip_addr', "{}:{}".format(*ctx
.pykmip
.endpoints
[pykmip_role
]),
156 clientcert
= ctx
.ssl_certificates
.get('kmip-client')
157 servercert
= ctx
.ssl_certificates
.get('kmip-server')
158 clientca
= ctx
.ssl_certificates
.get('kmiproot')
160 clientkey
= clientcert
.key
161 clientcert
= clientcert
.certificate
162 serverkey
= servercert
.key
163 servercert
= servercert
.certificate
164 rootkey
= clientca
.key
165 rootcert
= clientca
.certificate
167 cert_path
= '/etc/ceph/'
168 ctx
.cluster
.only(client
).run(args
=['sudo', 'cp', clientcert
, cert_path
])
169 ctx
.cluster
.only(client
).run(args
=['sudo', 'cp', clientkey
, cert_path
])
170 ctx
.cluster
.only(client
).run(args
=['sudo', 'cp', servercert
, cert_path
])
171 ctx
.cluster
.only(client
).run(args
=['sudo', 'cp', serverkey
, cert_path
])
172 ctx
.cluster
.only(client
).run(args
=['sudo', 'cp', rootkey
, cert_path
])
173 ctx
.cluster
.only(client
).run(args
=['sudo', 'cp', rootcert
, cert_path
])
175 clientcert
= cert_path
+ 'kmip-client.crt'
176 clientkey
= cert_path
+ 'kmip-client.key'
177 servercert
= cert_path
+ 'kmip-server.crt'
178 serverkey
= cert_path
+ 'kmip-server.key'
179 rootkey
= cert_path
+ 'kmiproot.key'
180 rootcert
= cert_path
+ 'kmiproot.crt'
182 ctx
.cluster
.only(client
).run(args
=['sudo', 'chmod', '600', clientcert
, clientkey
, servercert
, serverkey
, rootkey
, rootcert
])
183 ctx
.cluster
.only(client
).run(args
=['sudo', 'chown', 'ceph', clientcert
, clientkey
, servercert
, serverkey
, rootkey
, rootcert
])
190 '/var/log/ceph/rgw.{client_with_cluster}.stdout'.format(client_with_cluster
=client_with_cluster
),
194 if client_config
.get('valgrind'):
195 cmd_prefix
= get_valgrind_args(
199 client_config
.get('valgrind'),
200 # see https://github.com/ceph/teuthology/pull/1600
201 exit_on_first_error
=False
204 run_cmd
= list(cmd_prefix
)
205 run_cmd
.extend(rgw_cmd
)
207 ctx
.daemons
.add_daemon(
208 remote
, 'rgw', client_with_id
,
209 cluster
=cluster_name
,
210 fsid
=ctx
.ceph
[cluster_name
].fsid
,
212 logger
=log
.getChild(client
),
217 # XXX: add_daemon() doesn't let us wait until radosgw finishes startup
218 for client
in clients
:
219 endpoint
= ctx
.rgw
.role_endpoints
[client
]
221 log
.info('Polling {client} until it starts accepting connections on {url}'.format(client
=client
, url
=url
))
222 (remote
,) = ctx
.cluster
.only(client
).remotes
.keys()
223 wait_for_radosgw(url
, remote
)
228 for client
in clients
:
229 cluster_name
, daemon_type
, client_id
= teuthology
.split_role(client
)
230 client_with_id
= daemon_type
+ '.' + client_id
231 client_with_cluster
= cluster_name
+ '.' + client_with_id
232 ctx
.daemons
.get_daemon('rgw', client_with_id
, cluster_name
).stop()
233 ctx
.cluster
.only(client
).run(
237 '{tdir}/rgw.opslog.{client}.sock'.format(tdir
=testdir
,
238 client
=client_with_cluster
),
241 ctx
.cluster
.only(client
).run(args
=['sudo', 'rm', '-f', token_path
])
243 def assign_endpoints(ctx
, config
, default_cert
):
245 for role
, client_config
in config
.items():
246 client_config
= client_config
or {}
247 remote
= get_remote_for_role(ctx
, role
)
249 cert
= client_config
.get('ssl certificate', default_cert
)
251 # find the certificate created by the ssl task
252 if not hasattr(ctx
, 'ssl_certificates'):
253 raise ConfigError('rgw: no ssl task found for option "ssl certificate"')
254 ssl_certificate
= ctx
.ssl_certificates
.get(cert
, None)
255 if not ssl_certificate
:
256 raise ConfigError('rgw: missing ssl certificate "{}"'.format(cert
))
258 ssl_certificate
= None
260 port
= client_config
.get('port', 443 if ssl_certificate
else 80)
262 # if dns-name is given, use it as the hostname (or as a prefix)
263 dns_name
= client_config
.get('dns-name', '')
264 if len(dns_name
) == 0 or dns_name
.endswith('.'):
265 dns_name
+= remote
.hostname
267 website_dns_name
= client_config
.get('dns-s3website-name')
268 if website_dns_name
is not None and (len(website_dns_name
) == 0 or website_dns_name
.endswith('.')):
269 website_dns_name
+= remote
.hostname
271 role_endpoints
[role
] = RGWEndpoint(remote
.hostname
, port
, ssl_certificate
, dns_name
, website_dns_name
)
273 return role_endpoints
275 @contextlib.contextmanager
276 def create_pools(ctx
, clients
):
277 """Create replicated or erasure coded data pools for rgw."""
279 log
.info('Creating data pools')
280 for client
in clients
:
281 log
.debug("Obtaining remote for client {}".format(client
))
282 (remote
,) = ctx
.cluster
.only(client
).remotes
.keys()
283 data_pool
= 'default.rgw.buckets.data'
284 cluster_name
, daemon_type
, client_id
= teuthology
.split_role(client
)
286 if ctx
.rgw
.ec_data_pool
:
287 create_ec_pool(remote
, data_pool
, client
, ctx
.rgw
.data_pool_pg_size
,
288 ctx
.rgw
.erasure_code_profile
, cluster_name
, 'rgw')
290 create_replicated_pool(remote
, data_pool
, ctx
.rgw
.data_pool_pg_size
, cluster_name
, 'rgw')
292 index_pool
= 'default.rgw.buckets.index'
293 create_replicated_pool(remote
, index_pool
, ctx
.rgw
.index_pool_pg_size
, cluster_name
, 'rgw')
295 if ctx
.rgw
.cache_pools
:
296 create_cache_pool(remote
, data_pool
, data_pool
+ '.cache', 64,
297 64*1024*1024, cluster_name
)
298 log
.debug('Pools created')
301 @contextlib.contextmanager
302 def configure_compression(ctx
, clients
, compression
):
303 """ set a compression type in the default zone placement """
304 log
.info('Configuring compression type = %s', compression
)
305 for client
in clients
:
306 # XXX: the 'default' zone and zonegroup aren't created until we run RGWRados::init_complete().
307 # issue a 'radosgw-admin user list' command to trigger this
308 rgwadmin(ctx
, client
, cmd
=['user', 'list'], check_status
=True)
310 rgwadmin(ctx
, client
,
311 cmd
=['zone', 'placement', 'modify', '--rgw-zone', 'default',
312 '--placement-id', 'default-placement',
313 '--compression', compression
],
317 @contextlib.contextmanager
318 def configure_datacache(ctx
, clients
, datacache_path
):
319 """ create directory for rgw datacache """
320 log
.info('Preparing directory for rgw datacache at %s', datacache_path
)
321 for client
in clients
:
322 if(datacache_path
!= None):
323 ctx
.cluster
.only(client
).run(args
=['mkdir', '-p', datacache_path
])
324 ctx
.cluster
.only(client
).run(args
=['sudo', 'chmod', 'a+rwx', datacache_path
])
326 log
.info('path for datacache was not provided')
329 @contextlib.contextmanager
330 def configure_storage_classes(ctx
, clients
, storage_classes
):
331 """ set a compression type in the default zone placement """
333 sc
= [s
.strip() for s
in storage_classes
.split(',')]
335 for client
in clients
:
336 # XXX: the 'default' zone and zonegroup aren't created until we run RGWRados::init_complete().
337 # issue a 'radosgw-admin user list' command to trigger this
338 rgwadmin(ctx
, client
, cmd
=['user', 'list'], check_status
=True)
340 for storage_class
in sc
:
341 log
.info('Configuring storage class type = %s', storage_class
)
342 rgwadmin(ctx
, client
,
343 cmd
=['zonegroup', 'placement', 'add',
344 '--rgw-zone', 'default',
345 '--placement-id', 'default-placement',
346 '--storage-class', storage_class
],
348 rgwadmin(ctx
, client
,
349 cmd
=['zone', 'placement', 'add',
350 '--rgw-zone', 'default',
351 '--placement-id', 'default-placement',
352 '--storage-class', storage_class
,
353 '--data-pool', 'default.rgw.buckets.data.' + storage_class
.lower()],
357 @contextlib.contextmanager
358 def task(ctx
, config
):
360 For example, to run rgw on all clients::
366 To only run on certain clients::
370 - rgw: [client.0, client.3]
380 To run radosgw through valgrind:
386 valgrind: [--tool=memcheck]
388 valgrind: [--tool=memcheck]
390 To configure data or index pool pg_size:
394 data_pool_pg_size: 256
395 index_pool_pg_size: 128
398 config
= dict(('client.{id}'.format(id=id_
), None)
399 for id_
in teuthology
.all_roles_of_type(
400 ctx
.cluster
, 'client'))
401 elif isinstance(config
, list):
402 config
= dict((name
, None) for name
in config
)
404 clients
= config
.keys() # http://tracker.ceph.com/issues/20417
406 overrides
= ctx
.config
.get('overrides', {})
407 teuthology
.deep_merge(config
, overrides
.get('rgw', {}))
409 ctx
.rgw
= argparse
.Namespace()
411 ctx
.rgw
.ec_data_pool
= bool(config
.pop('ec-data-pool', False))
412 ctx
.rgw
.erasure_code_profile
= config
.pop('erasure_code_profile', {})
413 ctx
.rgw
.cache_pools
= bool(config
.pop('cache-pools', False))
414 ctx
.rgw
.frontend
= config
.pop('frontend', 'beast')
415 ctx
.rgw
.compression_type
= config
.pop('compression type', None)
416 ctx
.rgw
.storage_classes
= config
.pop('storage classes', None)
417 default_cert
= config
.pop('ssl certificate', None)
418 ctx
.rgw
.data_pool_pg_size
= config
.pop('data_pool_pg_size', 64)
419 ctx
.rgw
.index_pool_pg_size
= config
.pop('index_pool_pg_size', 64)
420 ctx
.rgw
.datacache
= bool(config
.pop('datacache', False))
421 ctx
.rgw
.datacache_path
= config
.pop('datacache_path', None)
422 ctx
.rgw
.config
= config
424 log
.debug("config is {}".format(config
))
425 log
.debug("client list is {}".format(clients
))
427 ctx
.rgw
.role_endpoints
= assign_endpoints(ctx
, config
, default_cert
)
430 lambda: create_pools(ctx
=ctx
, clients
=clients
),
432 if ctx
.rgw
.compression_type
:
434 lambda: configure_compression(ctx
=ctx
, clients
=clients
,
435 compression
=ctx
.rgw
.compression_type
),
437 if ctx
.rgw
.datacache
:
439 lambda: configure_datacache(ctx
=ctx
, clients
=clients
,
440 datacache_path
=ctx
.rgw
.datacache_path
),
442 if ctx
.rgw
.storage_classes
:
444 lambda: configure_storage_classes(ctx
=ctx
, clients
=clients
,
445 storage_classes
=ctx
.rgw
.storage_classes
),
448 lambda: start_rgw(ctx
=ctx
, config
=config
, clients
=clients
),
451 with contextutil
.nested(*subtasks
):