def _delete_dir(ctx, role, created_mountpoint): """ Delete file used by this role, and delete the directory that this role appeared in. :param ctx: Context :param role: "role.#" where # is used for the role id. """ cluster, _, id_ = misc.split_role(role) remote = get_remote_for_role(ctx, role) mnt = _client_mountpoint(ctx, cluster, id_) client = os.path.join(mnt, 'client.{id}'.format(id=id_)) # Remove the directory inside the mount where the workunit ran remote.run(args=[ 'sudo', 'rm', '-rf', '--', client, ], ) log.info("Deleted dir {dir}".format(dir=client)) # If the mount was an artificially created dir, delete that too if created_mountpoint: remote.run(args=[ 'rmdir', '--', mnt, ], ) log.info("Deleted artificial mount point {dir}".format(dir=client))
def assign_endpoints(ctx, config, default_cert): role_endpoints = {} for role, client_config in config.items(): client_config = client_config or {} remote = get_remote_for_role(ctx, role) cert = client_config.get('ssl certificate', default_cert) if cert: # find the certificate created by the ssl task if not hasattr(ctx, 'ssl_certificates'): raise ConfigError('rgw: no ssl task found for option "ssl certificate"') ssl_certificate = ctx.ssl_certificates.get(cert, None) if not ssl_certificate: raise ConfigError('rgw: missing ssl certificate "{}"'.format(cert)) else: ssl_certificate = None port = client_config.get('port', 443 if ssl_certificate else 80) # if dns-name is given, use it as the hostname (or as a prefix) dns_name = client_config.get('dns-name', '') if len(dns_name) == 0 or dns_name.endswith('.'): dns_name += remote.hostname website_dns_name = client_config.get('dns-s3website-name') if website_dns_name: if len(website_dns_name) == 0 or website_dns_name.endswith('.'): website_dns_name += remote.hostname role_endpoints[role] = RGWEndpoint(remote.hostname, port, ssl_certificate, dns_name, website_dns_name) return role_endpoints
def setup(self): super(CephFSMirror, self).setup() try: self.client = self.config['client'] except KeyError: raise ConfigError('cephfs-mirror requires a client to connect') self.cluster_name, type_, self.client_id = misc.split_role(self.client) if not type_ == 'client': raise ConfigError(f'client role {self.client} must be a client') self.remote = get_remote_for_role(self.ctx, self.client)
def assign_ports(ctx, config, initial_port): """ Assign port numbers starting from @initial_port """ port = initial_port role_endpoints = {} for remote, roles_for_host in ctx.cluster.remotes.items(): for role in roles_for_host: if role in config: r = get_remote_for_role(ctx, role) role_endpoints[role] = r.ip_address, port, r.hostname port += 1 return role_endpoints
def setup(self): super(RBDMirror, self).setup() try: self.client = self.config['client'] except KeyError: raise ConfigError('rbd-mirror requires a client to connect with') self.cluster_name, type_, self.client_id = misc.split_role(self.client) if type_ != 'client': msg = 'client role ({0}) must be a client'.format(self.client) raise ConfigError(msg) self.remote = get_remote_for_role(self.ctx, self.client)
def _run_tests(ctx, refspec, role, tests, env, basedir, subdir=None, timeout=None, cleanup=True, coverage_and_limits=True): """ Run the individual test. Create a scratch directory and then extract the workunits from git. Make the executables, and then run the tests. Clean up (remove files created) after the tests are finished. :param ctx: Context :param refspec: branch, sha1, or version tag used to identify this build :param tests: specific tests specified. :param env: environment set in yaml file. Could be None. :param subdir: subdirectory set in yaml file. Could be None :param timeout: If present, use the 'timeout' command on the remote host to limit execution time. Must be specified by a number followed by 's' for seconds, 'm' for minutes, 'h' for hours, or 'd' for days. If '0' or anything that evaluates to False is passed, the 'timeout' command is not used. """ testdir = misc.get_testdir(ctx) assert isinstance(role, str) cluster, type_, id_ = misc.split_role(role) assert type_ == 'client' remote = get_remote_for_role(ctx, role) mnt = _client_mountpoint(ctx, cluster, id_) # subdir so we can remove and recreate this a lot without sudo if subdir is None: scratch_tmp = os.path.join(mnt, 'client.{id}'.format(id=id_), 'tmp') else: scratch_tmp = os.path.join(mnt, subdir) clonedir = '{tdir}/clone.{role}'.format(tdir=testdir, role=role) srcdir = '{cdir}/{basedir}'.format(cdir=clonedir, basedir=basedir) git_url = teuth_config.get_ceph_qa_suite_git_url() # if we are running an upgrade test, and ceph-ci does not have branches like # `jewel`, so should use ceph.git as an alternative. try: remote.run(logger=log.getChild(role), args=refspec.clone(git_url, clonedir)) except CommandFailedError: if git_url.endswith('/ceph-ci.git'): alt_git_url = git_url.replace('/ceph-ci.git', '/ceph.git') elif git_url.endswith('/ceph-ci'): alt_git_url = re.sub(r'/ceph-ci$', '/ceph.git', git_url) else: raise log.info( "failed to check out '%s' from %s; will also try in %s", refspec, git_url, alt_git_url, ) remote.run(logger=log.getChild(role), args=refspec.clone(alt_git_url, clonedir)) remote.run( logger=log.getChild(role), args=[ 'cd', '--', srcdir, run.Raw('&&'), 'if', 'test', '-e', 'Makefile', run.Raw(';'), 'then', 'make', run.Raw(';'), 'fi', run.Raw('&&'), 'find', '-executable', '-type', 'f', '-printf', r'%P\0', run.Raw('>{tdir}/workunits.list.{role}'.format(tdir=testdir, role=role)), ], ) workunits_file = '{tdir}/workunits.list.{role}'.format(tdir=testdir, role=role) workunits = sorted( misc.get_file(remote, workunits_file).decode().split('\0')) assert workunits try: assert isinstance(tests, list) for spec in tests: dir_or_fname, *optional_args = shlex.split(spec) log.info('Running workunits matching %s on %s...', dir_or_fname, role) # match executables named "foo" or "foo/*" with workunit named # "foo" to_run = [ w for w in workunits if os.path.commonpath([w, dir_or_fname]) == dir_or_fname ] if not to_run: raise RuntimeError( 'Spec did not match any workunits: {spec!r}'.format( spec=spec)) for workunit in to_run: log.info('Running workunit %s...', workunit) args = [ 'mkdir', '-p', '--', scratch_tmp, run.Raw('&&'), 'cd', '--', scratch_tmp, run.Raw('&&'), run.Raw('CEPH_CLI_TEST_DUP_COMMAND=1'), run.Raw('CEPH_REF={ref}'.format(ref=refspec)), run.Raw('TESTDIR="{tdir}"'.format(tdir=testdir)), run.Raw('CEPH_ARGS="--cluster {0}"'.format(cluster)), run.Raw('CEPH_ID="{id}"'.format(id=id_)), run.Raw('PATH=$PATH:/usr/sbin'), run.Raw('CEPH_BASE={dir}'.format(dir=clonedir)), run.Raw('CEPH_ROOT={dir}'.format(dir=clonedir)), ] if env is not None: for var, val in env.items(): quoted_val = pipes.quote(val) env_arg = '{var}={val}'.format(var=var, val=quoted_val) args.append(run.Raw(env_arg)) if coverage_and_limits: args.extend([ 'adjust-ulimits', 'ceph-coverage', '{tdir}/archive/coverage'.format(tdir=testdir) ]) if timeout and timeout != '0': args.extend(['timeout', timeout]) args.extend([ '{srcdir}/{workunit}'.format( srcdir=srcdir, workunit=workunit, ), ]) remote.run( logger=log.getChild(role), args=args + optional_args, label="workunit test {workunit}".format(workunit=workunit)) if cleanup: args = ['sudo', 'rm', '-rf', '--', scratch_tmp] remote.run(logger=log.getChild(role), args=args, timeout=(60 * 60)) finally: log.info('Stopping %s on %s...', tests, role) args = ['sudo', 'rm', '-rf', '--', workunits_file, clonedir] # N.B. don't cleanup scratch_tmp! If the mount is broken then rm will hang. remote.run( logger=log.getChild(role), args=args, )
def _make_scratch_dir(ctx, role, subdir): """ Make scratch directories for this role. This also makes the mount point if that directory does not exist. :param ctx: Context :param role: "role.#" where # is used for the role id. :param subdir: use this subdir (False if not used) """ created_mountpoint = False cluster, _, id_ = misc.split_role(role) remote = get_remote_for_role(ctx, role) dir_owner = remote.user mnt = _client_mountpoint(ctx, cluster, id_) # if neither kclient nor ceph-fuse are required for a workunit, # mnt may not exist. Stat and create the directory if it doesn't. try: remote.run(args=[ 'stat', '--', mnt, ], ) log.info('Did not need to create dir {dir}'.format(dir=mnt)) except CommandFailedError: remote.run(args=[ 'mkdir', '--', mnt, ], ) log.info('Created dir {dir}'.format(dir=mnt)) created_mountpoint = True if not subdir: subdir = 'client.{id}'.format(id=id_) if created_mountpoint: remote.run(args=[ 'cd', '--', mnt, run.Raw('&&'), 'mkdir', '--', subdir, ], ) else: remote.run( args=[ # cd first so this will fail if the mount point does # not exist; pure install -d will silently do the # wrong thing 'cd', '--', mnt, run.Raw('&&'), 'sudo', 'install', '-d', '-m', '0755', '--owner={user}'.format(user=dir_owner), '--', subdir, ], ) return created_mountpoint
def task(ctx, config): """ Configures dnsmasq to add cnames for teuthology remotes. The task expects a dictionary, where each key is a role. If all cnames for that role use the same address as that role, the cnames can be given as a list. For example, this entry configures dnsmasq on the remote associated with client.0, adding two cnames for the ip address associated with client.0: - dnsmasq: client.0: - client0.example.com - c0.example.com If the addresses do not all match the given role, a dictionary can be given to specify the ip address by its target role. For example: - dnsmasq: client.0: client.0.example.com: client.0 client.1.example.com: client.1 Cnames that end with a . are treated as prefix for the existing hostname. For example, if the remote for client.0 has a hostname of 'example.com', this task will add cnames for dev.example.com and test.example.com: - dnsmasq: client.0: [dev., test.] """ # apply overrides overrides = config.get('overrides', {}) misc.deep_merge(config, overrides.get('dnsmasq', {})) # multiple roles may map to the same remote, so collect names by remote remote_names = {} for role, cnames in config.items(): remote = get_remote_for_role(ctx, role) if remote is None: raise ConfigError('no remote for role %s' % role) names = remote_names.get(remote, {}) if isinstance(cnames, list): # when given a list of cnames, point to local ip for cname in cnames: if cname.endswith('.'): cname += remote.hostname names[cname] = remote.ip_address elif isinstance(cnames, dict): # when given a dict, look up the remote ip for each for cname, client in cnames.items(): r = get_remote_for_role(ctx, client) if r is None: raise ConfigError('no remote for role %s' % client) if cname.endswith('.'): cname += r.hostname names[cname] = r.ip_address remote_names[remote] = names testdir = misc.get_testdir(ctx) resolv_bak = '/'.join((testdir, 'resolv.bak')) resolv_tmp = '/'.join((testdir, 'resolv.tmp')) # run subtasks for each unique remote subtasks = [] for remote, cnames in remote_names.items(): subtasks.extend([lambda r=remote: install_dnsmasq(r)]) subtasks.extend([lambda r=remote: backup_resolv(r, resolv_bak)]) subtasks.extend([lambda r=remote: replace_resolv(r, resolv_tmp)]) subtasks.extend( [lambda r=remote, cn=cnames: setup_dnsmasq(r, testdir, cn)]) with contextutil.nested(*subtasks): yield