# # Copyright (C) 2018 FreeIPA Contributors see COPYING for license # """This module provides tests for NFS-related features like krb5 NFS and automount locations. Wishlist * add automount direct and indirect maps * add automount /home for the "seattle" location only * validate it is not available in another location * krb5 /home for IdM users in test_automount * store nfs configuration in a single place """ from __future__ import absolute_import import time import re from ipatests.test_integration.base import IntegrationTest from ipatests.pytest_ipa.integration import tasks from ipaplatform.paths import paths import os # give some time for units to stabilize # otherwise we get transient errors WAIT_AFTER_INSTALL = 5 WAIT_AFTER_UNINSTALL = WAIT_AFTER_INSTALL class TestInit(IntegrationTest): @classmethod def fix_resolv_conf(cls, client, server): contents = client.get_file_contents(paths.RESOLV_CONF, encoding='utf-8') nameserver = 'nameserver %s\n' % server.ip if not contents.startswith(nameserver): contents = nameserver + contents.replace(nameserver, '') client.run_command([ '/usr/bin/cp', paths.RESOLV_CONF, '%s.sav' % paths.RESOLV_CONF ]) client.put_file_contents(paths.RESOLV_CONF, contents) @classmethod def restore_resolv_conf(cls, client): client.run_command([ '/usr/bin/cp', '%s.sav' % paths.RESOLV_CONF, paths.RESOLV_CONF ]) class TestNFS(TestInit): num_replicas = 2 num_clients = 1 topology = 'star' @classmethod def install(cls, mh): tasks.install_master(cls.master, setup_dns=True) clients = (cls.clients[0], cls.replicas[0], cls.replicas[1]) for client in clients: cls.fix_resolv_conf(client, cls.master) tasks.install_client(cls.master, client) client.run_command(["cat", "/etc/resolv.conf"]) def cleanup(self): nfssrv = self.clients[0] nfsclt = self.replicas[0] automntclt = self.replicas[1] nfsclt.run_command(["umount", "-a", "-t", "nfs4"]) nfsclt.run_command(["systemctl", "stop", "rpc-gssd"]) nfssrv.run_command(["systemctl", "stop", "nfs-server"]) nfssrv.run_command(["systemctl", "disable", "nfs-server"]) nfssrv.run_command([ "rm", "-f", "/etc/exports.d/krbnfs.exports", "/etc/exports.d/stdnfs.exports" ]) nfssrv.run_command(["rm", "-rf", "/exports"]) tasks.uninstall_client(nfsclt) tasks.uninstall_client(nfssrv) self.master.run_command([ "ipa", "host-mod", automntclt.hostname, "--location", "''" ]) # not strictly necessary, but this exercises automountlocation-del self.master.run_command([ "ipa", "automountlocation-del", "seattle" ]) nfsclt.run_command(["systemctl", "restart", "nfs-utils"]) nfssrv.run_command(["systemctl", "restart", "nfs-utils"]) for client in (nfssrv, nfsclt, automntclt): self.restore_resolv_conf(client) tasks.uninstall_master(self.master) def test_prepare_users(self): users = { "athena": "p", "euripides": "s" } temp_pass = 'temppass' for user in users: self.master.run_command([ "ipa", "user-add", "%s" % user, "--first", "%s" % user, "--last", "%s" % users[user], '--password'], stdin_text="%s\n%s\n" % (temp_pass, temp_pass) ) self.master.run_command(["kdestroy", "-A"]) password = "Secret123" user_kinit = "%s\n%s\n%s\n" % (temp_pass, password, password) self.master.run_command( ['kinit', user], stdin_text=user_kinit ) self.master.run_command(["kdestroy", "-A"]) tasks.kinit_admin(self.master) def test_krb5_nfsd(self): nfssrv = self.clients[0] # NFS keytab management self.master.run_command([ "ipa", "service-add", "nfs/%s" % nfssrv.hostname ]) nfssrv.run_command([ "ipa-getkeytab", "-p", "nfs/%s" % nfssrv.hostname, "-k", "/etc/krb5.keytab" ]) nfssrv.run_command(["systemctl", "restart", "nfs-server"]) nfssrv.run_command(["systemctl", "enable", "nfs-server"]) time.sleep(WAIT_AFTER_INSTALL) basedir = "exports" exports = { "krbnfs": "*(sec=krb5p,rw)", "stdnfs": "*(ro)", "home": "*(sec=krb5p,rw)" } for export in exports: exportpath = os.sep.join(('', basedir, export)) exportfile = os.sep.join(( '', 'etc', 'exports.d', "%s.exports" % export )) exportline = " ".join((exportpath, exports[export])) nfssrv.run_command(["mkdir", "-p", exportpath]) nfssrv.run_command(["chmod", "770", exportpath]) nfssrv.put_file_contents(exportfile, exportline) nfssrv.run_command(["cat", exportfile]) nfssrv.run_command(["exportfs", "-r"]) nfssrv.run_command(["exportfs", "-s"]) def test_krb5_nfs_manual_configuration(self): nfssrv = self.clients[0] nfsclt = self.replicas[0] nfsclt.run_command(["systemctl", "restart", "rpc-gssd"]) time.sleep(WAIT_AFTER_INSTALL) mountpoints = ("/mnt/krb", "/mnt/std", "/home") for mountpoint in mountpoints: nfsclt.run_command(["mkdir", "-p", mountpoint]) nfsclt.run_command([ "systemctl", "status", "gssproxy" ]) nfsclt.run_command([ "systemctl", "status", "rpc-gssd" ]) nfsclt.run_command([ "mount", "-t", "nfs4", "-o", "sec=krb5p,vers=4.0", "%s:/exports/krbnfs" % nfssrv.hostname, "/mnt/krb", "-v" ]) nfsclt.run_command([ "mount", "-t", "nfs4", "-o", "sec=krb5p,vers=4.0", "%s:/exports/home" % nfssrv.hostname, "/home", "-v" ]) def test_automount(self): """ Test if ipa-client-automount behaves as expected """ nfssrv = self.clients[0] automntclt = self.replicas[1] self.master.run_command([ "ipa", "automountlocation-add", "seattle" ]) self.master.run_command([ "ipa", "automountmap-add", "seattle", "auto.home" ]) self.master.run_command([ "ipa", "automountkey-add", "seattle", "auto.home", "--key='*'", "--info=sec=krb5p,vers=4" " 'rhel8-nfsserver0.laptop.example.org:/export/home/&'" ]) self.master.run_command([ "ipa", "automountkey-add", "seattle", "auto.master", "--key=/home", "--info=auto.home" ]) self.master.run_command([ "ipa", "host-mod", automntclt.hostname, "--location", "seattle" ]) # systemctl non-fatal errors will only be displayed # if ipa-client-automount is launched with --debug result1 = automntclt.run_command([ 'ipa-client-automount', '--location', 'seattle', '-U', '--debug' ]) time.sleep(WAIT_AFTER_INSTALL) # systemctl non-fatal errors will show up like this: # stderr=Failed to restart nfs-secure.service: \ # Unit nfs-secure.service not found. # normal output: # stderr= m1 = re.search(r'(?<=stderr\=Failed).+', result1.stderr_text) # maybe re-use m1.group(0) if it exists. assert m1 is None # https://pagure.io/freeipa/issue/7918 # check whether idmapd.conf was setup using the IPA domain automntclt.run_command([ "grep", "Domain = %s" % self.master.domain.name, "/etc/idmapd.conf" ]) automntclt.run_command([ "mount", "-t", "nfs4", "-o", "sec=krb5p,vers=4.0", "%s:/exports/home" % nfssrv.hostname, "/home", "-v" ]) # TODO leverage users automntclt.run_command(["umount", "-a", "-t", "nfs4"]) result2 = automntclt.run_command([ 'ipa-client-automount', '--uninstall', '-U', '--debug' ]) m2 = re.search(r'(?<=stderr\=Failed).+', result2.stderr_text) assert m2 is None time.sleep(WAIT_AFTER_UNINSTALL) # https://pagure.io/freeipa/issue/7918 # test for --idmap-domain DNS automntclt.run_command([ 'ipa-client-automount', '--location', 'default', '-U', '--debug', "--idmap-domain", "DNS" ]) time.sleep(WAIT_AFTER_INSTALL) # check whether idmapd.conf was setup properly: # grep must not find any configured Domain. result = automntclt.run_command( ["grep", "^Domain =", "/etc/idmapd.conf"], raiseonerr=False ) assert result.returncode == 1 automntclt.run_command([ 'ipa-client-automount', '--uninstall', '-U', '--debug' ]) time.sleep(WAIT_AFTER_UNINSTALL) # https://pagure.io/freeipa/issue/7918 # test for --idmap-domain exampledomain.net nfs_domain = "exampledomain.net" automntclt.run_command([ 'ipa-client-automount', '--location', 'default', '-U', '--debug', "--idmap-domain", nfs_domain ]) # check whether idmapd.conf was setup using nfs_domain automntclt.run_command([ "grep", "Domain = %s" % nfs_domain, "/etc/idmapd.conf" ]) time.sleep(WAIT_AFTER_INSTALL) automntclt.run_command([ 'ipa-client-automount', '--uninstall', '-U', '--debug' ]) time.sleep(WAIT_AFTER_UNINSTALL) self.cleanup()