--- /dev/null
+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
+
+ """
+ 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('/tmp/cephtest', '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, port) 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('/tmp/cephtest', 'mnt.{id}'.format(id=id_))
+ remote.run(
+ args=[
+ 'sudo',
+ 'exportfs',
+ '-au',
+ ],
+ )