From: Dan Mick Date: Fri, 14 Feb 2014 03:44:36 +0000 (-0800) Subject: Review: switch to selecting remotes by roles in the 'normal' way X-Git-Tag: 1.1.0~1666^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=a6eee01fa087b85bab04e1ef60097e38a61a88f3;p=teuthology.git Review: switch to selecting remotes by roles in the 'normal' way This buys us, also, the ability to select remotes by rule, i.e. "any osd or mon gets calamari-agent installed" Signed-off-by: Dan Mick --- diff --git a/teuthology/misc.py b/teuthology/misc.py index 2f7495332b..1bc2fa65b2 100644 --- a/teuthology/misc.py +++ b/teuthology/misc.py @@ -872,21 +872,6 @@ def replace_all_with_clients(cluster, config): norm_config['client.{id}'.format(id=client)] = config['all'] return norm_config -def roles_to_remotes(cluster, config, attrname='roles', unique=True): - """ - Get a list of roles from attrname, and return a list of - remotes corresponding to those roles. If 'unique' is False, - allow duplicates in the returned remote list (if a remote serves - multiple roles). attrname may not exist, in which case the - returned list is empty. - """ - roles = config.get(attrname, list()) - remotes = [] - for role in roles: - rem = cluster.only(role).remotes.keys()[0] - if (not unique) or (rem not in remotes): - remotes.append(rem) - return remotes def deep_merge(a, b): if a is None: diff --git a/teuthology/task/calamari.py b/teuthology/task/calamari.py index 1e49c185d5..f3c1495f69 100644 --- a/teuthology/task/calamari.py +++ b/teuthology/task/calamari.py @@ -14,6 +14,30 @@ five tasks: calamari.test runs on the local machine, as it accesses the Calamari server across https using requests.py, which must be present. It uses several external modules in calamari_test/. + +Sample configuration: +roles: +- [osd.0, osd.1, mon.0, calamari.restapi] +- [osd.2, osd.3, calamari.server] + +tasks: +- install: + branch: dumpling +- ceph: +- calamari.reposetup: +- calamari.agent: +- calamari.restapi: +- calamari.server: +- calamari.test: + delay: 40 + +calamari.reposetup will happen on all osd/mon/calamari.* remotes +calamari.agent will run on all osd/mon +calamari.restapi must run on a remote with a monitor +calamari.server must be able to find calamari.restapi to talk to +calamari.test has an optional delay to allow the webapp to settle before + talking to it (we could make the test retry/timeout instead) + """ from cStringIO import StringIO @@ -83,6 +107,9 @@ def _setup_calamari_cluster(remote, restapi_remote): stdout=StringIO()) +def _remotes(ctx, selector): + return ctx.cluster.only(selector).remotes.keys() + """ Tasks """ @@ -92,32 +119,41 @@ Tasks def agent(ctx, config): """ task agent - calamari.agent: install stats collection (for each cluster host) + calamari.agent: install stats collection + (for each role of type 'mon.' or 'osd.') For example:: + roles: + - [osd.0, mon.a] + - [osd.1] tasks: - calamari.agent: - roles: - - mon.0 - - osd.0 - - osd.1 - server: server.0 """ log.info('calamari.agent starting') overrides = ctx.config.get('overrides', {}) teuthology.deep_merge(config, overrides.get('calamari.agent', {})) - remotes = teuthology.roles_to_remotes(ctx.cluster, config) + # agent gets installed on any remote with role mon or osd + def needs_agent(role): + for type in 'mon.', 'osd.': + if role.startswith(type): + return True + return False + + remotes = _remotes(ctx, needs_agent) + if remotes is None: + raise RuntimeError('No role configured') try: for rem in remotes: log.info('Installing calamari-agent on %s', rem) pkg.install_package('calamari-agent', rem) - server_role = config.get('server') - if not server_role: - raise RuntimeError('must supply \'server\' config key') - server_remote = ctx.cluster.only(server_role).remotes.keys()[0] + server_remote = _remotes(ctx, + lambda r: r.startswith('calamari.server')) + if not server_remote: + raise RuntimeError('No calamari.server role available') + server_remote = server_remote[0] # why isn't shortname available by default? serverhost = server_remote.name.split('@')[1] log.info('configuring Diamond for {}'.format(serverhost)) @@ -135,7 +171,8 @@ def agent(ctx, config): def reposetup(ctx, config): """ task reposetup - Sets up calamari repository on all remotes; cleans up when done + Sets up calamari repository on all 'osd', 'mon', and 'calamari.' remotes; + cleans up when done calamari.reposetup: pkgdir: @@ -163,7 +200,16 @@ def reposetup(ctx, config): except KeyError: raise RuntimeError('requires pkgdir, username, and password') - remotes = ctx.cluster.remotes.keys() + # repo gets installed on any remote with role mon, osd, or calamari + def needs_repo(role): + for type in 'mon.', 'osd.', 'calamari.': + if role.startswith(type): + return True + return False + + remotes = _remotes(ctx, needs_repo) + if remotes is None: + raise RuntimeError('No roles configured') try: for rem in remotes: @@ -188,23 +234,33 @@ def restapi(ctx, config): For example:: + roles: + - [mon.a, osd.0, osd.1, calamari.restapi] + - [osd.2, osd.3] tasks: - calamari.restapi: - roles: mon.0 """ overrides = ctx.config.get('overrides', {}) teuthology.deep_merge(config, overrides.get('calamari.restapi', {})) - remotes = teuthology.roles_to_remotes(ctx.cluster, config) + remotes_and_roles = \ + ctx.cluster.only(lambda r: r.startswith('calamari.restapi')).remotes + if remotes_and_roles is None: + raise RuntimeError('No role configured') + + # check that the role selected also has at least one mon role + for rem, roles in remotes_and_roles.iteritems(): + if not any([r for r in roles if r.startswith('mon.')]): + raise RuntimeError('no mon on remote with roles %s', roles) try: - for rem in remotes: + for rem in remotes_and_roles.iterkeys(): log.info(rem) pkg.install_package('calamari-restapi', rem) yield finally: - for rem in remotes: + for rem in remotes_and_roles.iterkeys(): pkg.remove_package('calamari-restapi', rem) @@ -213,27 +269,34 @@ def server(ctx, config): """ task server: - Calamari server setup. "roles" is a list of roles that should run - the webapp, and "restapi_server" is a list of roles that will - be running the calamari-restapi package. Both lists probably should - have only one entry (only the first is used). + Calamari server setup. Add role 'calamari.server' to the remote + that will run the webapp. 'calamari.restapi' role must be present + to serve as the cluster-api target for calamari-server. Only one + of calamari.server and calamari.restapi roles is supported currently. For example:: - roles: [[server.0], [mon.0], [osd.0, osd.1]] + roles: + - [calamari.server] + - [mon.0, calamari.restapi] + - [osd.0, osd.1] tasks: + - calamari.restapi: - calamari.server: - roles: [server.0] - restapi_server: [mon.0] """ overrides = ctx.config.get('overrides', {}) teuthology.deep_merge(config, overrides.get('calamari.server', {})) - remote = teuthology.roles_to_remotes(ctx.cluster, config)[0] - restapi_remote = teuthology.roles_to_remotes(ctx.cluster, config, - attrname='restapi_server')[0] + remote = _remotes(ctx, lambda r: r.startswith('calamari.server')) + if not remote: + raise RuntimeError('No role configured') + + restapi_remote = _remotes(ctx, lambda r: r.startswith('calamari.restapi')) if not restapi_remote: - raise RuntimeError('Must supply restapi_server') + raise RuntimeError('Must supply calamari.restapi role') + + remote = remote[0] + restapi_remote = restapi_remote[0] try: # sqlite3 command is required; on some platforms it's already @@ -260,7 +323,7 @@ def server(ctx, config): def test(ctx, config): """ task test - Run the calamari smoketest + Run the calamari smoketest on the teuthology host (no role required) Tests to run are in calamari_testdir. delay: wait this long before starting @@ -273,8 +336,8 @@ def test(ctx, config): if delay: log.info("delaying %d sec", delay) time.sleep(delay) - testhost = ctx.cluster.only(config['server']).remotes.keys()[0].name - testhost = testhost.split('@')[1] + testhost = _remotes(ctx, lambda r: r.startswith('calamari.server'))[0] + testhost = testhost.name.split('@')[1] mypath = os.path.dirname(__file__) cmd_list = [os.path.join(mypath, 'calamari', 'servertest_1_0.py')] os.environ['CALAMARI_BASE_URI'] = 'http://{0}/api/v1/'.format(testhost)