summaryrefslogtreecommitdiffstats
path: root/src/ceph/qa/tasks/rgw_multisite.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/ceph/qa/tasks/rgw_multisite.py')
-rw-r--r--src/ceph/qa/tasks/rgw_multisite.py427
1 files changed, 0 insertions, 427 deletions
diff --git a/src/ceph/qa/tasks/rgw_multisite.py b/src/ceph/qa/tasks/rgw_multisite.py
deleted file mode 100644
index 74c1f3f..0000000
--- a/src/ceph/qa/tasks/rgw_multisite.py
+++ /dev/null
@@ -1,427 +0,0 @@
-"""
-rgw multisite configuration routines
-"""
-import argparse
-import contextlib
-import logging
-import random
-import string
-from copy import deepcopy
-from util.rgw import rgwadmin, wait_for_radosgw
-from util.rados import create_ec_pool, create_replicated_pool
-from rgw_multi import multisite
-from rgw_multi.zone_rados import RadosZone as RadosZone
-
-from teuthology.orchestra import run
-from teuthology import misc
-from teuthology.exceptions import ConfigError
-from teuthology.task import Task
-
-log = logging.getLogger(__name__)
-
-class RGWMultisite(Task):
- """
- Performs rgw multisite configuration to match the given realm definition.
-
- - rgw-multisite:
- realm:
- name: test-realm
- is_default: true
-
- List one or more zonegroup definitions. These are provided as json
- input to `radosgw-admin zonegroup set`, with the exception of these keys:
-
- * 'is_master' is passed on the command line as --master
- * 'is_default' is passed on the command line as --default
- * 'endpoints' given as client names are replaced with actual endpoints
-
- zonegroups:
- - name: test-zonegroup
- api_name: test-api
- is_master: true
- is_default: true
- endpoints: [c1.client.0]
-
- List each of the zones to be created in this zonegroup.
-
- zones:
- - name: test-zone1
- is_master: true
- is_default: true
- endpoints: [c1.client.0]
- - name: test-zone2
- is_default: true
- endpoints: [c2.client.0]
-
- A complete example:
-
- tasks:
- - install:
- - ceph: {cluster: c1}
- - ceph: {cluster: c2}
- - rgw:
- c1.client.0:
- c2.client.0:
- - rgw-multisite:
- realm:
- name: test-realm
- is_default: true
- zonegroups:
- - name: test-zonegroup
- is_master: true
- is_default: true
- zones:
- - name: test-zone1
- is_master: true
- is_default: true
- endpoints: [c1.client.0]
- - name: test-zone2
- is_default: true
- endpoints: [c2.client.0]
-
- """
- def __init__(self, ctx, config):
- super(RGWMultisite, self).__init__(ctx, config)
-
- def setup(self):
- super(RGWMultisite, self).setup()
-
- overrides = self.ctx.config.get('overrides', {})
- misc.deep_merge(self.config, overrides.get('rgw-multisite', {}))
-
- if not self.ctx.rgw:
- raise ConfigError('rgw-multisite must run after the rgw task')
- role_endpoints = self.ctx.rgw.role_endpoints
-
- # construct Clusters and Gateways for each client in the rgw task
- clusters, gateways = extract_clusters_and_gateways(self.ctx,
- role_endpoints)
-
- # get the master zone and zonegroup configuration
- mz, mzg = extract_master_zone_zonegroup(self.config['zonegroups'])
- cluster1 = cluster_for_zone(clusters, mz)
-
- # create the realm and period on the master zone's cluster
- log.info('creating realm..')
- realm = create_realm(cluster1, self.config['realm'])
- period = realm.current_period
-
- creds = gen_credentials()
-
- # create the master zonegroup and its master zone
- log.info('creating master zonegroup..')
- master_zonegroup = create_zonegroup(cluster1, gateways, period,
- deepcopy(mzg))
- period.master_zonegroup = master_zonegroup
-
- log.info('creating master zone..')
- master_zone = create_zone(self.ctx, cluster1, gateways, creds,
- master_zonegroup, deepcopy(mz))
- master_zonegroup.master_zone = master_zone
-
- period.update(master_zone, commit=True)
- restart_zone_gateways(master_zone) # restart with --rgw-zone
-
- # create the admin user on the master zone
- log.info('creating admin user..')
- user_args = ['--display-name', 'Realm Admin', '--system']
- user_args += creds.credential_args()
- admin_user = multisite.User('realm-admin')
- admin_user.create(master_zone, user_args)
-
- # process 'zonegroups'
- for zg_config in self.config['zonegroups']:
- zones_config = zg_config.pop('zones')
-
- zonegroup = None
- for zone_config in zones_config:
- # get the cluster for this zone
- cluster = cluster_for_zone(clusters, zone_config)
-
- if cluster != cluster1: # already created on master cluster
- log.info('pulling realm configuration to %s', cluster.name)
- realm.pull(cluster, master_zone.gateways[0], creds)
-
- # use the first zone's cluster to create the zonegroup
- if not zonegroup:
- if zg_config['name'] == master_zonegroup.name:
- zonegroup = master_zonegroup
- else:
- log.info('creating zonegroup..')
- zonegroup = create_zonegroup(cluster, gateways,
- period, zg_config)
-
- if zone_config['name'] == master_zone.name:
- # master zone was already created
- zone = master_zone
- else:
- # create the zone and commit the period
- log.info('creating zone..')
- zone = create_zone(self.ctx, cluster, gateways, creds,
- zonegroup, zone_config)
- period.update(zone, commit=True)
-
- restart_zone_gateways(zone) # restart with --rgw-zone
-
- # attach configuration to the ctx for other tasks
- self.ctx.rgw_multisite = argparse.Namespace()
- self.ctx.rgw_multisite.clusters = clusters
- self.ctx.rgw_multisite.gateways = gateways
- self.ctx.rgw_multisite.realm = realm
- self.ctx.rgw_multisite.admin_user = admin_user
-
- log.info('rgw multisite configuration completed')
-
- def end(self):
- del self.ctx.rgw_multisite
-
-class Cluster(multisite.Cluster):
- """ Issues 'radosgw-admin' commands with the rgwadmin() helper """
- def __init__(self, ctx, name, client):
- super(Cluster, self).__init__()
- self.ctx = ctx
- self.name = name
- self.client = client
-
- def admin(self, args = None, **kwargs):
- """ radosgw-admin command """
- args = args or []
- args += ['--cluster', self.name]
- args += ['--debug-rgw', '0']
- if kwargs.pop('read_only', False):
- args += ['--rgw-cache-enabled', 'false']
- kwargs['decode'] = False
- check_retcode = kwargs.pop('check_retcode', True)
- r, s = rgwadmin(self.ctx, self.client, args, **kwargs)
- if check_retcode:
- assert r == 0
- return s, r
-
-class Gateway(multisite.Gateway):
- """ Controls a radosgw instance using its daemon """
- def __init__(self, role, remote, daemon, *args, **kwargs):
- super(Gateway, self).__init__(*args, **kwargs)
- self.role = role
- self.remote = remote
- self.daemon = daemon
-
- def set_zone(self, zone):
- """ set the zone and add its args to the daemon's command line """
- assert self.zone is None, 'zone can only be set once'
- self.zone = zone
- # daemon.restart_with_args() would be perfect for this, except that
- # radosgw args likely include a pipe and redirect. zone arguments at
- # the end won't actually apply to radosgw
- args = self.daemon.command_kwargs.get('args', [])
- try:
- # insert zone args before the first |
- pipe = args.index(run.Raw('|'))
- args = args[0:pipe] + zone.zone_args() + args[pipe:]
- except ValueError, e:
- args += zone.zone_args()
- self.daemon.command_kwargs['args'] = args
-
- def start(self, args = None):
- """ (re)start the daemon """
- self.daemon.restart()
- # wait until startup completes
- wait_for_radosgw(self.endpoint())
-
- def stop(self):
- """ stop the daemon """
- self.daemon.stop()
-
-def extract_clusters_and_gateways(ctx, role_endpoints):
- """ create cluster and gateway instances for all of the radosgw roles """
- clusters = {}
- gateways = {}
- for role, (host, port) in role_endpoints.iteritems():
- cluster_name, daemon_type, client_id = misc.split_role(role)
- # find or create the cluster by name
- cluster = clusters.get(cluster_name)
- if not cluster:
- clusters[cluster_name] = cluster = Cluster(ctx, cluster_name, role)
- # create a gateway for this daemon
- client_with_id = daemon_type + '.' + client_id # match format from rgw.py
- daemon = ctx.daemons.get_daemon('rgw', client_with_id, cluster_name)
- if not daemon:
- raise ConfigError('no daemon for role=%s cluster=%s type=rgw id=%s' % \
- (role, cluster_name, client_id))
- (remote,) = ctx.cluster.only(role).remotes.keys()
- gateways[role] = Gateway(role, remote, daemon, host, port, cluster)
- return clusters, gateways
-
-def create_realm(cluster, config):
- """ create a realm from configuration and initialize its first period """
- realm = multisite.Realm(config['name'])
- args = []
- if config.get('is_default', False):
- args += ['--default']
- realm.create(cluster, args)
- realm.current_period = multisite.Period(realm)
- return realm
-
-def extract_user_credentials(config):
- """ extract keys from configuration """
- return multisite.Credentials(config['access_key'], config['secret_key'])
-
-def extract_master_zone(zonegroup_config):
- """ find and return the master zone definition """
- master = None
- for zone in zonegroup_config['zones']:
- if not zone.get('is_master', False):
- continue
- if master:
- raise ConfigError('zones %s and %s cannot both set \'is_master\'' % \
- (master['name'], zone['name']))
- master = zone
- # continue the loop so we can detect duplicates
- if not master:
- raise ConfigError('one zone must set \'is_master\' in zonegroup %s' % \
- zonegroup_config['name'])
- return master
-
-def extract_master_zone_zonegroup(zonegroups_config):
- """ find and return the master zone and zonegroup definitions """
- master_zone, master_zonegroup = (None, None)
- for zonegroup in zonegroups_config:
- # verify that all zonegroups have a master zone set, even if they
- # aren't in the master zonegroup
- zone = extract_master_zone(zonegroup)
- if not zonegroup.get('is_master', False):
- continue
- if master_zonegroup:
- raise ConfigError('zonegroups %s and %s cannot both set \'is_master\'' % \
- (master_zonegroup['name'], zonegroup['name']))
- master_zonegroup = zonegroup
- master_zone = zone
- # continue the loop so we can detect duplicates
- if not master_zonegroup:
- raise ConfigError('one zonegroup must set \'is_master\'')
- return master_zone, master_zonegroup
-
-def extract_zone_cluster_name(zone_config):
- """ return the cluster (must be common to all zone endpoints) """
- cluster_name = None
- endpoints = zone_config.get('endpoints')
- if not endpoints:
- raise ConfigError('zone %s missing \'endpoints\' list' % \
- zone_config['name'])
- for role in endpoints:
- name, _, _ = misc.split_role(role)
- if not cluster_name:
- cluster_name = name
- elif cluster_name != name:
- raise ConfigError('all zone %s endpoints must be in the same cluster' % \
- zone_config['name'])
- return cluster_name
-
-def cluster_for_zone(clusters, zone_config):
- """ return the cluster entry for the given zone """
- name = extract_zone_cluster_name(zone_config)
- try:
- return clusters[name]
- except KeyError:
- raise ConfigError('no cluster %s found' % name)
-
-def gen_access_key():
- return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(16))
-
-def gen_secret():
- return ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(32))
-
-def gen_credentials():
- return multisite.Credentials(gen_access_key(), gen_secret())
-
-def extract_gateway_endpoints(gateways, endpoints_config):
- """ return a list of gateway endpoints associated with the given roles """
- endpoints = []
- for role in endpoints_config:
- try:
- # replace role names with their gateway's endpoint
- endpoints.append(gateways[role].endpoint())
- except KeyError:
- raise ConfigError('no radosgw endpoint found for role %s' % role)
- return endpoints
-
-def is_default_arg(config):
- return ['--default'] if config.pop('is_default', False) else []
-
-def is_master_arg(config):
- return ['--master'] if config.pop('is_master', False) else []
-
-def create_zonegroup(cluster, gateways, period, config):
- """ pass the zonegroup configuration to `zonegroup set` """
- config.pop('zones', None) # remove 'zones' from input to `zonegroup set`
- endpoints = config.get('endpoints')
- if endpoints:
- # replace client names with their gateway endpoints
- config['endpoints'] = extract_gateway_endpoints(gateways, endpoints)
- zonegroup = multisite.ZoneGroup(config['name'], period)
- # `zonegroup set` needs --default on command line, and 'is_master' in json
- args = is_default_arg(config)
- zonegroup.set(cluster, config, args)
- period.zonegroups.append(zonegroup)
- return zonegroup
-
-def create_zone(ctx, cluster, gateways, creds, zonegroup, config):
- """ create a zone with the given configuration """
- zone = multisite.Zone(config['name'], zonegroup, cluster)
- zone = RadosZone(config['name'], zonegroup, cluster)
-
- # collect Gateways for the zone's endpoints
- endpoints = config.get('endpoints')
- if not endpoints:
- raise ConfigError('no \'endpoints\' for zone %s' % config['name'])
- zone.gateways = [gateways[role] for role in endpoints]
- for gateway in zone.gateways:
- gateway.set_zone(zone)
-
- # format the gateway endpoints
- endpoints = [g.endpoint() for g in zone.gateways]
-
- args = is_default_arg(config)
- args += is_master_arg(config)
- args += creds.credential_args()
- if len(endpoints):
- args += ['--endpoints', ','.join(endpoints)]
- zone.create(cluster, args)
- zonegroup.zones.append(zone)
-
- create_zone_pools(ctx, zone)
- if ctx.rgw.compression_type:
- configure_zone_compression(zone, ctx.rgw.compression_type)
-
- zonegroup.zones_by_type.setdefault(zone.tier_type(), []).append(zone)
-
- if zone.is_read_only():
- zonegroup.ro_zones.append(zone)
- else:
- zonegroup.rw_zones.append(zone)
-
- return zone
-
-def create_zone_pools(ctx, zone):
- """ Create the data_pool for each placement type """
- gateway = zone.gateways[0]
- cluster = zone.cluster
- for pool_config in zone.data.get('placement_pools', []):
- pool_name = pool_config['val']['data_pool']
- if ctx.rgw.ec_data_pool:
- create_ec_pool(gateway.remote, pool_name, zone.name, 64,
- ctx.rgw.erasure_code_profile, cluster.name, 'rgw')
- else:
- create_replicated_pool(gateway.remote, pool_name, 64, cluster.name, 'rgw')
-
-def configure_zone_compression(zone, compression):
- """ Set compression type in the zone's default-placement """
- zone.json_command(zone.cluster, 'placement', ['modify',
- '--placement-id', 'default-placement',
- '--compression', compression
- ])
-
-def restart_zone_gateways(zone):
- zone.stop()
- zone.start()
-
-task = RGWMultisite