""" Export/Unexport a ``nfs server`` client. """ import contextlib import logging import os from teuthology import misc as teuthology log = logging.getLogger(__name__) @contextlib.contextmanager def task(ctx, config): """ Export/Unexport a ``nfs server`` client. The config is optional and defaults to exporting on all clients. If a config is given, it is expected to be a list or dict of clients to do this operation on. You must have specified ``ceph-fuse`` or ``kclient`` on all clients specified for knfsd. Example that exports all clients:: tasks: - ceph: - kclient: - knfsd: - interactive: Example that uses both ``kclient` and ``ceph-fuse``:: tasks: - ceph: - ceph-fuse: [client.0] - kclient: [client.1] - knfsd: [client.0, client.1] - interactive: Example that specifies export options:: tasks: - ceph: - kclient: [client.0, client.1] - knfsd: client.0: options: [rw,root_squash] client.1: - interactive: Note that when options aren't specified, rw,no_root_squash is the default. When you specify options, the defaults are as specified by exports(5). So if empty options are specified, i.e. options: [] these are the defaults: ro,sync,wdelay,hide,nocrossmnt,secure,root_squash,no_all_squash, no_subtree_check,secure_locks,acl,anonuid=65534,anongid=65534 :param ctx: Context :param config: Configuration """ log.info('Exporting nfs server...') 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) clients = list(teuthology.get_clients(ctx=ctx, roles=config.keys())) for id_, remote in clients: mnt = os.path.join(teuthology.get_testdir(ctx), 'mnt.{id}'.format(id=id_)) client_config = config.get("client.%s" % id_) if client_config is None: client_config = {} log.debug("Client client.%s config is %s" % (id_, client_config)) if client_config.get('options') is not None: opts = ','.join(client_config.get('options')) else: opts = 'rw,no_root_squash' # Undocumented option to export to any client in case # testing in interactive mode from other unspecified clients. wildcard = False if client_config.get('wildcard') is not None: wildcard = True log.info('Exporting knfsd client.{id} at {remote} *:{mnt} ({opt})...'.format( id=id_, remote=remote, mnt=mnt, opt=opts)) """ Should the user want to run with root_squash enabled, there is no way to write anything to the initial ceph root dir which is set to rwxr-xr-x root root. This could possibly break test cases that make assumptions about the initial state of the root dir. """ remote.run( args=[ 'sudo', 'chmod', "777", '{MNT}'.format(MNT=mnt), ], ) args=[ 'sudo', "exportfs", '-o', 'fsid=123{id},{opt}'.format(id=id_,opt=opts), ] if wildcard: args += ['*:{MNT}'.format(MNT=mnt)] else: """ DEFAULT Prevent bogus clients from old runs from access our export. Specify all specify node addresses for this run. """ ips = [host for (host, _) in (remote.ssh.get_transport().getpeername() for (remote, roles) in ctx.cluster.remotes.items())] for ip in ips: args += [ '{ip}:{MNT}'.format(ip=ip, MNT=mnt) ] log.info('remote run {args}'.format(args=args)) remote.run( args=args ) try: yield finally: log.info('Unexporting nfs server...') for id_, remote in clients: log.debug('Unexporting client client.{id}...'.format(id=id_)) mnt = os.path.join(teuthology.get_testdir(ctx), 'mnt.{id}'.format(id=id_)) remote.run( args=[ 'sudo', 'exportfs', '-au', ], )