ceph/qa/tasks/rgw.py
Casey Bodley 76e147614f qa/rgw: fixes for cluster name on cleanup
Signed-off-by: Casey Bodley <cbodley@redhat.com>
2017-05-17 14:48:55 -04:00

1309 lines
48 KiB
Python

"""
rgw routines
"""
import argparse
import contextlib
import json
import logging
import os
import errno
import util.rgw as rgw_utils
from requests.packages.urllib3 import PoolManager
from requests.packages.urllib3.util import Retry
from cStringIO import StringIO
from teuthology.orchestra import run
from teuthology import misc as teuthology
from teuthology import contextutil
from teuthology.orchestra.run import CommandFailedError
from util.rgw import rgwadmin, get_config_master_client, extract_zone_info, extract_region_info
from util.rados import (rados, create_ec_pool,
create_replicated_pool,
create_cache_pool)
log = logging.getLogger(__name__)
@contextlib.contextmanager
def create_apache_dirs(ctx, config, on_client = None, except_client = None):
"""
Remotely create apache directories. Delete when finished.
"""
log.info('Creating apache directories...')
log.debug('client is %r', on_client)
testdir = teuthology.get_testdir(ctx)
clients_to_create_as = [on_client]
if on_client is None:
clients_to_create_as = config.keys()
for client in clients_to_create_as:
if client == except_client:
continue
cluster_name, daemon_type, client_id = teuthology.split_role(client)
client_with_cluster = cluster_name + '.' + daemon_type + '.' + client_id
ctx.cluster.only(client).run(
args=[
'mkdir',
'-p',
'{tdir}/apache/htdocs.{client_with_cluster}'.format(tdir=testdir,
client_with_cluster=client_with_cluster),
'{tdir}/apache/tmp.{client_with_cluster}/fastcgi_sock'.format(
tdir=testdir,
client_with_cluster=client_with_cluster),
run.Raw('&&'),
'mkdir',
'{tdir}/archive/apache.{client_with_cluster}'.format(tdir=testdir,
client_with_cluster=client_with_cluster),
],
)
try:
yield
finally:
log.info('Cleaning up apache directories...')
for client in clients_to_create_as:
ctx.cluster.only(client).run(
args=[
'rm',
'-rf',
'{tdir}/apache/tmp.{client_with_cluster}'.format(tdir=testdir,
client_with_cluster=client_with_cluster),
run.Raw('&&'),
'rmdir',
'{tdir}/apache/htdocs.{client_with_cluster}'.format(tdir=testdir,
client_with_cluster=client_with_cluster),
],
)
for client in clients_to_create_as:
ctx.cluster.only(client).run(
args=[
'rmdir',
'{tdir}/apache'.format(tdir=testdir),
],
check_status=False, # only need to remove once per host
)
def _use_uds_with_fcgi(remote):
"""
Returns true if this node supports the usage of
unix domain sockets with mod_proxy_fcgi.
FIXME: returns False always for now until we know for
sure what distros will support UDS. RHEL 7.0 is the only one
currently I know of, but we can't install that version of apache
yet in the labs.
"""
return False
@contextlib.contextmanager
def ship_apache_configs(ctx, config, role_endpoints, on_client = None,
except_client = None):
"""
Ship apache config and rgw.fgci to all clients. Clean up on termination
"""
assert isinstance(config, dict)
assert isinstance(role_endpoints, dict)
testdir = teuthology.get_testdir(ctx)
log.info('Shipping apache config and rgw.fcgi...')
src = os.path.join(os.path.dirname(__file__), 'apache.conf.template')
clients_to_create_as = [on_client]
if on_client is None:
clients_to_create_as = config.keys()
for client in clients_to_create_as:
if client == except_client:
continue
cluster_name, daemon_type, client_id = teuthology.split_role(client)
client_with_id = daemon_type + '.' + client_id
client_with_cluster = cluster_name + '.' + client_with_id
(remote,) = ctx.cluster.only(client).remotes.keys()
system_type = teuthology.get_system_type(remote)
conf = config.get(client)
if not conf:
conf = {}
idle_timeout = conf.get('idle_timeout', ctx.rgw.default_idle_timeout)
if system_type == 'deb':
mod_path = '/usr/lib/apache2/modules'
print_continue = 'on'
user = 'www-data'
group = 'www-data'
apache24_modconfig = '''
IncludeOptional /etc/apache2/mods-available/mpm_event.conf
IncludeOptional /etc/apache2/mods-available/mpm_event.load
'''
else:
mod_path = '/usr/lib64/httpd/modules'
print_continue = 'off'
user = 'apache'
group = 'apache'
apache24_modconfig = \
'IncludeOptional /etc/httpd/conf.modules.d/00-mpm.conf'
host, port = role_endpoints[client]
# decide if we want to use mod_fastcgi or mod_proxy_fcgi
template_dir = os.path.dirname(__file__)
fcgi_config = os.path.join(template_dir,
'mod_proxy_fcgi.tcp.conf.template')
if ctx.rgw.use_fastcgi:
log.info("Apache is configured to use mod_fastcgi")
fcgi_config = os.path.join(template_dir,
'mod_fastcgi.conf.template')
elif _use_uds_with_fcgi(remote):
log.info("Apache is configured to use mod_proxy_fcgi with UDS")
fcgi_config = os.path.join(template_dir,
'mod_proxy_fcgi.uds.conf.template')
else:
log.info("Apache is configured to use mod_proxy_fcgi with TCP")
with file(fcgi_config, 'rb') as f:
fcgi_config = f.read()
with file(src, 'rb') as f:
conf = f.read() + fcgi_config
conf = conf.format(
testdir=testdir,
mod_path=mod_path,
print_continue=print_continue,
host=host,
port=port,
client=client_with_cluster,
idle_timeout=idle_timeout,
user=user,
group=group,
apache24_modconfig=apache24_modconfig,
)
teuthology.write_file(
remote=remote,
path='{tdir}/apache/apache.{client_with_cluster}.conf'.format(
tdir=testdir,
client_with_cluster=client_with_cluster),
data=conf,
)
rgw_options = []
if ctx.rgw.use_fastcgi or _use_uds_with_fcgi(remote):
rgw_options = [
'--rgw-socket-path',
'{tdir}/apache/tmp.{client_with_cluster}/fastcgi_sock/rgw_sock'.format(
tdir=testdir,
client_with_cluster=client_with_cluster
),
'--rgw-frontends',
'fastcgi',
]
else:
rgw_options = [
'--rgw-socket-path', '""',
'--rgw-print-continue', 'false',
'--rgw-frontends',
'fastcgi socket_port=9000 socket_host=0.0.0.0',
]
teuthology.write_file(
remote=remote,
path='{tdir}/apache/htdocs.{client_with_cluster}/rgw.fcgi'.format(
tdir=testdir,
client_with_cluster=client_with_cluster),
data="""#!/bin/sh
ulimit -c unlimited
exec radosgw -f -n {client_with_id} --cluster {cluster_name} -k /etc/ceph/{client_with_cluster}.keyring {rgw_options}
""".format(tdir=testdir, client_with_id=client_with_id, client_with_cluster=client_with_cluster, cluster_name=cluster_name, rgw_options=" ".join(rgw_options))
)
remote.run(
args=[
'chmod',
'a=rx',
'{tdir}/apache/htdocs.{client_with_cluster}/rgw.fcgi'.format(tdir=testdir,
client_with_cluster=client_with_cluster),
],
)
try:
yield
finally:
log.info('Removing apache config...')
for client in clients_to_create_as:
cluster_name, daemon_type, client_id = teuthology.split_role(client)
client_with_cluster = '.'.join((cluster_name, daemon_type, client_id))
ctx.cluster.only(client).run(
args=[
'rm',
'-f',
'{tdir}/apache/apache.{client_with_cluster}.conf'.format(tdir=testdir,
client_with_cluster=client_with_cluster),
run.Raw('&&'),
'rm',
'-f',
'{tdir}/apache/htdocs.{client_with_cluster}/rgw.fcgi'.format(
tdir=testdir,
client_with_cluster=client_with_cluster),
],
)
@contextlib.contextmanager
def start_rgw(ctx, config, on_client = None, except_client = None):
"""
Start rgw on remote sites.
"""
log.info('Starting rgw...')
log.debug('client %r', on_client)
clients_to_run = [on_client]
if on_client is None:
clients_to_run = config.keys()
log.debug('client %r', clients_to_run)
testdir = teuthology.get_testdir(ctx)
for client in clients_to_run:
if client == except_client:
continue
(remote,) = ctx.cluster.only(client).remotes.iterkeys()
cluster_name, daemon_type, client_id = teuthology.split_role(client)
client_with_id = daemon_type + '.' + client_id
client_with_cluster = cluster_name + '.' + client_with_id
zone = rgw_utils.zone_for_client(ctx, client)
log.debug('zone %s', zone)
client_config = config.get(client)
if client_config is None:
client_config = {}
log.info("rgw %s config is %s", client, client_config)
cmd_prefix = [
'sudo',
'adjust-ulimits',
'ceph-coverage',
'{tdir}/archive/coverage'.format(tdir=testdir),
'daemon-helper',
'term',
]
rgw_cmd = ['radosgw']
if ctx.rgw.frontend == 'apache':
if ctx.rgw.use_fastcgi or _use_uds_with_fcgi(remote):
rgw_cmd.extend([
'--rgw-socket-path',
'{tdir}/apache/tmp.{client_with_cluster}/fastcgi_sock/rgw_sock'.format(
tdir=testdir,
client_with_cluster=client_with_cluster,
),
'--rgw-frontends',
'fastcgi',
])
else:
# for mod_proxy_fcgi, using tcp
rgw_cmd.extend([
'--rgw-socket-path', '',
'--rgw-print-continue', 'false',
'--rgw-frontends',
'fastcgi socket_port=9000 socket_host=0.0.0.0',
])
elif ctx.rgw.frontend == 'civetweb':
host, port = ctx.rgw.role_endpoints[client]
rgw_cmd.extend([
'--rgw-frontends',
'civetweb port={port}'.format(port=port),
])
if zone is not None:
rgw_cmd.extend(['--rgw-zone', zone])
rgw_cmd.extend([
'-n', client_with_id,
'--cluster', cluster_name,
'-k', '/etc/ceph/{client_with_cluster}.keyring'.format(client_with_cluster=client_with_cluster),
'--log-file',
'/var/log/ceph/rgw.{client_with_cluster}.log'.format(client_with_cluster=client_with_cluster),
'--rgw_ops_log_socket_path',
'{tdir}/rgw.opslog.{client_with_cluster}.sock'.format(tdir=testdir,
client_with_cluster=client_with_cluster),
'--foreground',
run.Raw('|'),
'sudo',
'tee',
'/var/log/ceph/rgw.{client_with_cluster}.stdout'.format(tdir=testdir,
client_with_cluster=client_with_cluster),
run.Raw('2>&1'),
])
if client_config.get('valgrind'):
cmd_prefix = teuthology.get_valgrind_args(
testdir,
client_with_cluster,
cmd_prefix,
client_config.get('valgrind')
)
run_cmd = list(cmd_prefix)
run_cmd.extend(rgw_cmd)
ctx.daemons.add_daemon(
remote, 'rgw', client_with_id,
cluster=cluster_name,
args=run_cmd,
logger=log.getChild(client),
stdin=run.PIPE,
wait=False,
)
# XXX: add_daemon() doesn't let us wait until radosgw finishes startup
# use a connection pool with retry/backoff to poll each gateway until it starts listening
http = PoolManager(retries=Retry(connect=8, backoff_factor=1))
for client in clients_to_run:
if client == except_client:
continue
host, port = ctx.rgw.role_endpoints[client]
endpoint = 'http://{host}:{port}/'.format(host=host, port=port)
log.info('Polling {client} until it starts accepting connections on {endpoint}'.format(client=client, endpoint=endpoint))
http.request('GET', endpoint)
try:
yield
finally:
for client in config.iterkeys():
cluster_name, daemon_type, client_id = teuthology.split_role(client)
client_with_id = daemon_type + '.' + client_id
client_with_cluster = cluster_name + '.' + client_with_id
ctx.daemons.get_daemon('rgw', client_with_id, cluster_name).stop()
ctx.cluster.only(client).run(
args=[
'rm',
'-f',
'{tdir}/rgw.opslog.{client}.sock'.format(tdir=testdir,
client=client_with_cluster),
],
)
@contextlib.contextmanager
def start_apache(ctx, config, on_client = None, except_client = None):
"""
Start apache on remote sites.
"""
log.info('Starting apache...')
testdir = teuthology.get_testdir(ctx)
apaches = {}
clients_to_run = [on_client]
if on_client is None:
clients_to_run = config.keys()
for client in clients_to_run:
cluster_name, daemon_type, client_id = teuthology.split_role(client)
client_with_cluster = cluster_name + '.' + daemon_type + '.' + client_id
if client == except_client:
continue
(remote,) = ctx.cluster.only(client).remotes.keys()
system_type = teuthology.get_system_type(remote)
if system_type == 'deb':
apache_name = 'apache2'
else:
try:
remote.run(
args=[
'stat',
'/usr/sbin/httpd.worker',
],
)
apache_name = '/usr/sbin/httpd.worker'
except CommandFailedError:
apache_name = '/usr/sbin/httpd'
proc = remote.run(
args=[
'adjust-ulimits',
'daemon-helper',
'kill',
apache_name,
'-X',
'-f',
'{tdir}/apache/apache.{client_with_cluster}.conf'.format(tdir=testdir,
client_with_cluster=client_with_cluster),
],
logger=log.getChild(client),
stdin=run.PIPE,
wait=False,
)
apaches[client_with_cluster] = proc
try:
yield
finally:
log.info('Stopping apache...')
for client, proc in apaches.iteritems():
proc.stdin.close()
run.wait(apaches.itervalues())
def extract_user_info(client_config):
"""
Extract user info from the client config specified. Returns a dict
that includes system key information.
"""
# test if there isn't a system user or if there isn't a name for that
# user, return None
if ('system user' not in client_config or
'name' not in client_config['system user']):
return None
user_info = dict()
user_info['system_key'] = dict(
user=client_config['system user']['name'],
access_key=client_config['system user']['access key'],
secret_key=client_config['system user']['secret key'],
)
return user_info
def assign_ports(ctx, config):
"""
Assign port numberst starting with port 7280.
"""
port = 7280
role_endpoints = {}
for remote, roles_for_host in ctx.cluster.remotes.iteritems():
for role in roles_for_host:
if role in config:
role_endpoints[role] = (remote.name.split('@')[1], port)
port += 1
return role_endpoints
def fill_in_endpoints(region_info, role_zones, role_endpoints):
"""
Iterate through the list of role_endpoints, filling in zone information
:param region_info: region data
:param role_zones: region and zone information.
:param role_endpoints: endpoints being used
"""
for role, (host, port) in role_endpoints.iteritems():
region, zone, zone_info, _ = role_zones[role]
host, port = role_endpoints[role]
endpoint = 'http://{host}:{port}/'.format(host=host, port=port)
# check if the region specified under client actually exists
# in region_info (it should, if properly configured).
# If not, throw a reasonable error
if region not in region_info:
raise Exception(
'Region: {region} was specified but no corresponding'
' entry was found under \'regions\''.format(region=region))
region_conf = region_info[region]
region_conf.setdefault('endpoints', [])
region_conf['endpoints'].append(endpoint)
# this is the payload for the 'zones' field in the region field
zone_payload = dict()
zone_payload['endpoints'] = [endpoint]
zone_payload['name'] = zone
# Pull the log meta and log data settings out of zone_info, if they
# exist, then pop them as they don't actually belong in the zone info
for key in ['rgw log meta', 'rgw log data']:
new_key = key.split(' ', 1)[1]
new_key = new_key.replace(' ', '_')
if key in zone_info:
value = zone_info.pop(key)
else:
value = 'false'
zone_payload[new_key] = value
region_conf.setdefault('zones', [])
region_conf['zones'].append(zone_payload)
@contextlib.contextmanager
def configure_users_for_client(ctx, config, client, everywhere=False):
"""
Create users by remotely running rgwadmin commands using extracted
user information.
"""
log.info('Configuring users...')
log.info('for client %s', client)
log.info('everywhere %s', everywhere)
# For data sync the master zones and regions must have the
# system users of the secondary zones. To keep this simple,
# just create the system users on every client if regions are
# configured.
clients_to_create_as = [client]
if everywhere:
clients_to_create_as = config.keys()
# extract the user info and append it to the payload tuple for the given
# client
for client, c_config in config.iteritems():
if not c_config:
continue
user_info = extract_user_info(c_config)
if not user_info:
continue
for client_name in clients_to_create_as:
log.debug('Creating user {user} on {client}'.format(
user=user_info['system_key']['user'], client=client_name))
rgwadmin(ctx, client_name,
cmd=[
'user', 'create',
'--uid', user_info['system_key']['user'],
'--access-key', user_info['system_key']['access_key'],
'--secret', user_info['system_key']['secret_key'],
'--display-name', user_info['system_key']['user'],
'--system',
],
check_status=True,
)
yield
@contextlib.contextmanager
def configure_users(ctx, config, everywhere=False):
"""
Create users by remotely running rgwadmin commands using extracted
user information.
"""
log.info('Configuring users...')
# extract the user info and append it to the payload tuple for the given
# client
for client, c_config in config.iteritems():
if not c_config:
continue
user_info = extract_user_info(c_config)
if not user_info:
continue
# For data sync the master zones and regions must have the
# system users of the secondary zones. To keep this simple,
# just create the system users on every client if regions are
# configured.
clients_to_create_as = [client]
if everywhere:
clients_to_create_as = config.keys()
for client_name in clients_to_create_as:
log.debug('Creating user {user} on {client}'.format(
user=user_info['system_key']['user'], client=client))
rgwadmin(ctx, client_name,
cmd=[
'user', 'create',
'--uid', user_info['system_key']['user'],
'--access-key', user_info['system_key']['access_key'],
'--secret', user_info['system_key']['secret_key'],
'--display-name', user_info['system_key']['user'],
'--system',
],
check_status=True,
)
yield
@contextlib.contextmanager
def create_nonregion_pools(ctx, config, regions):
"""Create replicated or erasure coded data pools for rgw."""
if regions:
yield
return
log.info('creating data pools')
for client in config.keys():
(remote,) = ctx.cluster.only(client).remotes.iterkeys()
data_pool = '.rgw.buckets'
cluster_name, daemon_type, client_id = teuthology.split_role(client)
if ctx.rgw.ec_data_pool:
create_ec_pool(remote, data_pool, client, 64,
ctx.rgw.erasure_code_profile, cluster_name)
else:
create_replicated_pool(remote, data_pool, 64, cluster_name)
if ctx.rgw.cache_pools:
create_cache_pool(remote, data_pool, data_pool + '.cache', 64,
64*1024*1024, cluster_name)
yield
@contextlib.contextmanager
def configure_multisite_regions_and_zones(ctx, config, regions, role_endpoints, realm, master_client):
"""
Configure multisite regions and zones from rados and rgw.
"""
if not regions:
log.debug(
'In rgw.configure_multisite_regions_and_zones() and regions is None. '
'Bailing')
yield
return
if not realm:
log.debug(
'In rgw.configure_multisite_regions_and_zones() and realm is None. '
'Bailing')
yield
return
log.info('Configuring multisite regions and zones...')
log.debug('config is %r', config)
log.debug('regions are %r', regions)
log.debug('role_endpoints = %r', role_endpoints)
log.debug('realm is %r', realm)
# extract the zone info
role_zones = dict([(client, extract_zone_info(ctx, client, c_config))
for client, c_config in config.iteritems()])
log.debug('role_zones = %r', role_zones)
# extract the user info and append it to the payload tuple for the given
# client
for client, c_config in config.iteritems():
if not c_config:
user_info = None
else:
user_info = extract_user_info(c_config)
(region, zone, zone_info) = role_zones[client]
role_zones[client] = (region, zone, zone_info, user_info)
region_info = dict([
(region_name, extract_region_info(region_name, r_config))
for region_name, r_config in regions.iteritems()])
fill_in_endpoints(region_info, role_zones, role_endpoints)
# clear out the old defaults
cluster_name, daemon_type, client_id = teuthology.split_role(master_client)
first_mon = teuthology.get_first_mon(ctx, config, cluster_name)
(mon,) = ctx.cluster.only(first_mon).remotes.iterkeys()
# read master zonegroup and master_zone
for zonegroup, zg_info in region_info.iteritems():
if zg_info['is_master']:
master_zonegroup = zonegroup
master_zone = zg_info['master_zone']
break
log.debug('master zonegroup =%r', master_zonegroup)
log.debug('master zone = %r', master_zone)
log.debug('master client = %r', master_client)
rgwadmin(ctx, master_client,
cmd=['realm', 'create', '--rgw-realm', realm, '--default'],
check_status=True)
for region, info in region_info.iteritems():
region_json = json.dumps(info)
log.debug('region info is: %s', region_json)
rgwadmin(ctx, master_client,
cmd=['zonegroup', 'set'],
stdin=StringIO(region_json),
check_status=True)
rgwadmin(ctx, master_client,
cmd=['zonegroup', 'default', '--rgw-zonegroup', master_zonegroup],
check_status=True)
for role, (zonegroup, zone, zone_info, user_info) in role_zones.iteritems():
(remote,) = ctx.cluster.only(role).remotes.keys()
for pool_info in zone_info['placement_pools']:
remote.run(args=['sudo', 'ceph', 'osd', 'pool', 'create',
pool_info['val']['index_pool'], '64', '64', '--cluster', cluster_name])
if ctx.rgw.ec_data_pool:
create_ec_pool(remote, pool_info['val']['data_pool'],
zone, 64, ctx.rgw.erasure_code_profile, cluster_name)
else:
create_replicated_pool(remote, pool_info['val']['data_pool'], 64, cluster_name)
(zonegroup, zone, zone_info, user_info) = role_zones[master_client]
zone_json = json.dumps(dict(zone_info.items() + user_info.items()))
log.debug("zone info is: %r", zone_json)
rgwadmin(ctx, master_client,
cmd=['zone', 'set', '--rgw-zonegroup', zonegroup,
'--rgw-zone', zone],
stdin=StringIO(zone_json),
check_status=True)
rgwadmin(ctx, master_client,
cmd=['zone', 'default', '--rgw-zone', zone],
check_status=True)
rgwadmin(ctx, master_client,
cmd=['period', 'update', '--commit'],
check_status=True)
yield
def configure_compression_in_default_zone(ctx, config):
compression = ctx.rgw.compression_type
if not compression:
return
log.debug('Configuring compression type = %s', compression)
for client, c_config in config.iteritems():
# XXX: the 'default' zone and zonegroup aren't created until we run RGWRados::init_complete().
# issue a 'radosgw-admin user list' command to trigger this
rgwadmin(ctx, client, cmd=['user', 'list'], check_status=True)
rgwadmin(ctx, client,
cmd=['zone', 'placement', 'modify', '--rgw-zone', 'default',
'--placement-id', 'default-placement',
'--compression', compression],
check_status=True)
@contextlib.contextmanager
def configure_regions_and_zones(ctx, config, regions, role_endpoints, realm):
"""
Configure regions and zones from rados and rgw.
"""
if not regions:
log.debug(
'In rgw.configure_regions_and_zones() and regions is None. '
'Bailing')
configure_compression_in_default_zone(ctx, config)
yield
return
if not realm:
log.debug(
'In rgw.configure_regions_and_zones() and realm is None. '
'Bailing')
configure_compression_in_default_zone(ctx, config)
yield
return
log.info('Configuring regions and zones...')
log.debug('config is %r', config)
log.debug('regions are %r', regions)
log.debug('role_endpoints = %r', role_endpoints)
log.debug('realm is %r', realm)
# extract the zone info
role_zones = dict([(client, extract_zone_info(ctx, client, c_config))
for client, c_config in config.iteritems()])
log.debug('roles_zones = %r', role_zones)
# extract the user info and append it to the payload tuple for the given
# client
for client, c_config in config.iteritems():
if not c_config:
user_info = None
else:
user_info = extract_user_info(c_config)
(region, zone, zone_info) = role_zones[client]
role_zones[client] = (region, zone, zone_info, user_info)
region_info = dict([
(region_name, extract_region_info(region_name, r_config))
for region_name, r_config in regions.iteritems()])
fill_in_endpoints(region_info, role_zones, role_endpoints)
# clear out the old defaults
cluster_name, daemon_type, client_id = teuthology.split_role(client)
first_mon = teuthology.get_first_mon(ctx, config, cluster_name)
(mon,) = ctx.cluster.only(first_mon).remotes.iterkeys()
# removing these objects from .rgw.root and the per-zone root pools
# may or may not matter
rados(ctx, mon,
cmd=['-p', '.rgw.root', 'rm', 'region_info.default', '--cluster', cluster_name])
rados(ctx, mon,
cmd=['-p', '.rgw.root', 'rm', 'zone_info.default', '--cluster', cluster_name])
# read master zonegroup and master_zone
for zonegroup, zg_info in region_info.iteritems():
if zg_info['is_master']:
master_zonegroup = zonegroup
master_zone = zg_info['master_zone']
break
for client in config.iterkeys():
(zonegroup, zone, zone_info, user_info) = role_zones[client]
if zonegroup == master_zonegroup and zone == master_zone:
master_client = client
break
log.debug('master zonegroup =%r', master_zonegroup)
log.debug('master zone = %r', master_zone)
log.debug('master client = %r', master_client)
log.debug('config %r ', config)
(ret, out)=rgwadmin(ctx, client,
cmd=['realm', 'create', '--rgw-realm', realm, '--default'])
log.debug('realm create ret %r exists %r', -ret, errno.EEXIST)
assert ret == 0 or ret != -errno.EEXIST
if ret is -errno.EEXIST:
log.debug('realm %r exists', realm)
for client in config.iterkeys():
for role, (zonegroup, zone, zone_info, user_info) in role_zones.iteritems():
rados(ctx, mon,
cmd=['-p', zone_info['domain_root'],
'rm', 'region_info.default', '--cluster', cluster_name])
rados(ctx, mon,
cmd=['-p', zone_info['domain_root'],
'rm', 'zone_info.default', '--cluster', cluster_name])
(remote,) = ctx.cluster.only(role).remotes.keys()
for pool_info in zone_info['placement_pools']:
remote.run(args=['sudo', 'ceph', 'osd', 'pool', 'create',
pool_info['val']['index_pool'], '64', '64', '--cluster', cluster_name])
if ctx.rgw.ec_data_pool:
create_ec_pool(remote, pool_info['val']['data_pool'],
zone, 64, ctx.rgw.erasure_code_profile, cluster_name)
else:
create_replicated_pool(
remote, pool_info['val']['data_pool'],
64, cluster_name)
zone_json = json.dumps(dict(zone_info.items() + user_info.items()))
log.debug('zone info is: %r', zone_json)
rgwadmin(ctx, client,
cmd=['zone', 'set', '--rgw-zonegroup', zonegroup,
'--rgw-zone', zone],
stdin=StringIO(zone_json),
check_status=True)
for region, info in region_info.iteritems():
region_json = json.dumps(info)
log.debug('region info is: %s', region_json)
rgwadmin(ctx, client,
cmd=['zonegroup', 'set'],
stdin=StringIO(region_json),
check_status=True)
if info['is_master']:
rgwadmin(ctx, client,
cmd=['zonegroup', 'default', '--rgw-zonegroup', master_zonegroup],
check_status=True)
(zonegroup, zone, zone_info, user_info) = role_zones[client]
rgwadmin(ctx, client,
cmd=['zone', 'default', '--rgw-zone', zone],
check_status=True)
#this used to take master_client, need to edit that accordingly
rgwadmin(ctx, client,
cmd=['period', 'update', '--commit'],
check_status=True)
yield
@contextlib.contextmanager
def pull_configuration(ctx, config, regions, role_endpoints, realm, master_client):
"""
Configure regions and zones from rados and rgw.
"""
if not regions:
log.debug(
'In rgw.pull_confguration() and regions is None. '
'Bailing')
yield
return
if not realm:
log.debug(
'In rgw.pull_configuration() and realm is None. '
'Bailing')
yield
return
log.info('Pulling configuration...')
log.debug('config is %r', config)
log.debug('regions are %r', regions)
log.debug('role_endpoints = %r', role_endpoints)
log.debug('realm is %r', realm)
log.debug('master client = %r', master_client)
# extract the zone info
role_zones = dict([(client, extract_zone_info(ctx, client, c_config))
for client, c_config in config.iteritems()])
log.debug('roles_zones = %r', role_zones)
# extract the user info and append it to the payload tuple for the given
# client
for client, c_config in config.iteritems():
if not c_config:
user_info = None
else:
user_info = extract_user_info(c_config)
(region, zone, zone_info) = role_zones[client]
role_zones[client] = (region, zone, zone_info, user_info)
region_info = dict([
(region_name, extract_region_info(region_name, r_config))
for region_name, r_config in regions.iteritems()])
fill_in_endpoints(region_info, role_zones, role_endpoints)
for client in config.iterkeys():
if client != master_client:
cluster_name, daemon_type, client_id = teuthology.split_role(client)
host, port = role_endpoints[master_client]
endpoint = 'http://{host}:{port}/'.format(host=host, port=port)
log.debug("endpoint: %s", endpoint)
rgwadmin(ctx, client,
cmd=['realm', 'pull', '--rgw-realm', realm, '--default', '--url',
endpoint, '--access_key',
user_info['system_key']['access_key'], '--secret',
user_info['system_key']['secret_key']],
check_status=True)
(zonegroup, zone, zone_info, zone_user_info) = role_zones[client]
zone_json = json.dumps(dict(zone_info.items() + zone_user_info.items()))
log.debug("zone info is: %r", zone_json)
rgwadmin(ctx, client,
cmd=['zone', 'set', '--default',
'--rgw-zone', zone],
stdin=StringIO(zone_json),
check_status=True)
rgwadmin(ctx, client,
cmd=['zonegroup', 'add', '--rgw-zonegroup', zonegroup, '--rgw-zone', zone],
check_status=True)
rgwadmin(ctx, client,
cmd=['zonegroup', 'default', '--rgw-zonegroup', zonegroup],
check_status=True)
rgwadmin(ctx, client,
cmd=['period', 'update', '--commit', '--url',
endpoint, '--access_key',
user_info['system_key']['access_key'], '--secret',
user_info['system_key']['secret_key']],
check_status=True)
yield
@contextlib.contextmanager
def task(ctx, config):
"""
Either use configure apache to run a rados gateway, or use the built-in
civetweb server.
Only one should be run per machine, since it uses a hard-coded port for
now.
For example, to run rgw on all clients::
tasks:
- ceph:
- rgw:
To only run on certain clients::
tasks:
- ceph:
- rgw: [client.0, client.3]
or
tasks:
- ceph:
- rgw:
client.0:
client.3:
You can adjust the idle timeout for fastcgi (default is 30 seconds):
tasks:
- ceph:
- rgw:
client.0:
idle_timeout: 90
To run radosgw through valgrind:
tasks:
- ceph:
- rgw:
client.0:
valgrind: [--tool=memcheck]
client.3:
valgrind: [--tool=memcheck]
To use civetweb instead of apache:
tasks:
- ceph:
- rgw:
- client.0
overrides:
rgw:
frontend: civetweb
Note that without a modified fastcgi module e.g. with the default
one on CentOS, you must have rgw print continue = false in ceph.conf::
tasks:
- ceph:
conf:
global:
rgw print continue: false
- rgw: [client.0]
To use mod_proxy_fcgi instead of mod_fastcgi:
overrides:
rgw:
use_fcgi: true
To run rgws for multiple regions or zones, describe the regions
and their zones in a regions section. The endpoints will be
generated by this task. Each client must have a region, zone,
and pools assigned in ceph.conf::
tasks:
- install:
- ceph:
conf:
client.0:
rgw region: foo
rgw zone: foo-1
rgw region root pool: .rgw.rroot.foo
rgw zone root pool: .rgw.zroot.foo
rgw log meta: true
rgw log data: true
client.1:
rgw region: bar
rgw zone: bar-master
rgw region root pool: .rgw.rroot.bar
rgw zone root pool: .rgw.zroot.bar
rgw log meta: true
rgw log data: true
client.2:
rgw region: bar
rgw zone: bar-secondary
rgw region root pool: .rgw.rroot.bar
rgw zone root pool: .rgw.zroot.bar-secondary
- rgw:
default_idle_timeout: 30
ec-data-pool: true
erasure_code_profile:
k: 2
m: 1
ruleset-failure-domain: osd
realm: foo
regions:
foo:
api name: api_name # default: region name
is master: true # default: false
master zone: foo-1 # default: first zone
zones: [foo-1]
log meta: true
log data: true
placement targets: [target1, target2] # default: []
default placement: target2 # default: ''
bar:
api name: bar-api
zones: [bar-master, bar-secondary]
client.0:
system user:
name: foo-system
access key: X2IYPSTY1072DDY1SJMC
secret key: YIMHICpPvT+MhLTbSsiBJ1jQF15IFvJA8tgwJEcm
client.1:
system user:
name: bar1
access key: Y2IYPSTY1072DDY1SJMC
secret key: XIMHICpPvT+MhLTbSsiBJ1jQF15IFvJA8tgwJEcm
client.2:
system user:
name: bar2
access key: Z2IYPSTY1072DDY1SJMC
secret key: ZIMHICpPvT+MhLTbSsiBJ1jQF15IFvJA8tgwJEcm
"""
if config is None:
config = dict(('client.{id}'.format(id=id_), None)
for id_ in teuthology.all_roles_of_type(
ctx.cluster, 'client'))
elif isinstance(config, list):
config = dict((name, None) for name in config)
overrides = ctx.config.get('overrides', {})
teuthology.deep_merge(config, overrides.get('rgw', {}))
regions = config.pop('regions', {})
realm = config.pop('realm', None)
role_endpoints = assign_ports(ctx, config)
ctx.rgw = argparse.Namespace()
ctx.rgw.role_endpoints = role_endpoints
ctx.rgw.regions = regions
ctx.rgw.realm = realm
ctx.rgw.ec_data_pool = bool(config.pop('ec-data-pool', False))
ctx.rgw.erasure_code_profile = config.pop('erasure_code_profile', {})
ctx.rgw.default_idle_timeout = int(config.pop('default_idle_timeout', 30))
ctx.rgw.cache_pools = bool(config.pop('cache-pools', False))
ctx.rgw.frontend = config.pop('frontend', 'civetweb')
ctx.rgw.use_fastcgi = not config.pop('use_fcgi', True)
if not ctx.rgw.use_fastcgi:
log.info("Using mod_proxy_fcgi instead of mod_fastcgi...")
ctx.rgw.compression_type = config.pop('compression type', None)
subtasks = [
lambda: create_nonregion_pools(
ctx=ctx, config=config, regions=regions),
]
log.debug('Nonregion pools created')
multisite = len(regions) > 1
if not multisite:
for zonegroup, zonegroup_info in regions.iteritems():
log.debug("zonegroup_info =%r", zonegroup_info)
if len(zonegroup_info['zones']) > 1:
multisite = True
break
log.debug('multisite %s', multisite)
multi_cluster = False
if multisite:
prev_cluster_name = None
roles = ctx.config['roles']
#check if any roles have a different cluster_name from eachother
for lst in roles:
for role in lst:
cluster_name, daemon_type, client_id = teuthology.split_role(role)
if cluster_name != prev_cluster_name and prev_cluster_name != None:
multi_cluster = True
break
prev_cluster_name = cluster_name
if multi_cluster:
break
log.debug('multi_cluster %s', multi_cluster)
ctx.rgw.config = config
master_client = None
if multi_cluster:
log.debug('multi cluster run')
master_client = get_config_master_client(ctx=ctx,
config=config,
regions=regions)
log.debug('master_client %r', master_client)
subtasks.extend([
lambda: configure_multisite_regions_and_zones(
ctx=ctx,
config=config,
regions=regions,
role_endpoints=role_endpoints,
realm=realm,
master_client = master_client,
)
])
subtasks.extend([
lambda: configure_users_for_client(
ctx=ctx,
config=config,
client=master_client,
everywhere=False,
),
])
if ctx.rgw.frontend == 'apache':
subtasks.insert(0,
lambda: create_apache_dirs(ctx=ctx, config=config,
on_client=master_client))
subtasks.extend([
lambda: ship_apache_configs(ctx=ctx, config=config,
role_endpoints=role_endpoints, on_client=master_client),
lambda: start_apache(ctx=ctx, config=config, on_client=master_client),
lambda: start_rgw(ctx=ctx, config=config, on_client=master_client),
])
elif ctx.rgw.frontend == 'civetweb':
subtasks.extend([
lambda: start_rgw(ctx=ctx, config=config, on_client=master_client),
])
else:
raise ValueError("frontend must be 'apache' or 'civetweb'")
subtasks.extend([
lambda: pull_configuration(ctx=ctx,
config=config,
regions=regions,
role_endpoints=role_endpoints,
realm=realm,
master_client=master_client
),
])
subtasks.extend([
lambda: configure_users_for_client(
ctx=ctx,
config=config,
client=master_client,
everywhere=True
),
])
if ctx.rgw.frontend == 'apache':
subtasks.insert(0,
lambda: create_apache_dirs(ctx=ctx, config=config,
on_client=None,
except_client = master_client))
subtasks.extend([
lambda: ship_apache_configs(ctx=ctx, config=config,
role_endpoints=role_endpoints,
on_client=None,
except_client = master_client,
),
lambda: start_apache(ctx=ctx,
config = config,
on_client=None,
except_client = master_client,
),
lambda: start_rgw(ctx=ctx,
config=config,
on_client=None,
except_client = master_client),
])
elif ctx.rgw.frontend == 'civetweb':
subtasks.extend([
lambda: start_rgw(ctx=ctx,
config=config,
on_client=None,
except_client = master_client),
])
else:
raise ValueError("frontend must be 'apache' or 'civetweb'")
else:
log.debug('single cluster run')
subtasks.extend([
lambda: configure_regions_and_zones(
ctx=ctx,
config=config,
regions=regions,
role_endpoints=role_endpoints,
realm=realm,
),
lambda: configure_users(
ctx=ctx,
config=config,
everywhere=True,
),
])
if ctx.rgw.frontend == 'apache':
subtasks.insert(0, lambda: create_apache_dirs(ctx=ctx, config=config))
subtasks.extend([
lambda: ship_apache_configs(ctx=ctx, config=config,
role_endpoints=role_endpoints),
lambda: start_apache(ctx=ctx, config=config),
lambda: start_rgw(ctx=ctx,
config=config),
])
elif ctx.rgw.frontend == 'civetweb':
subtasks.extend([
lambda: start_rgw(ctx=ctx,
config=config),
])
else:
raise ValueError("frontend must be 'apache' or 'civetweb'")
log.info("Using %s as radosgw frontend", ctx.rgw.frontend)
with contextutil.nested(*subtasks):
yield