From 00e2a488726a353b7183d5d3b4c2084b9bf5dbc2 Mon Sep 17 00:00:00 2001 From: François Cami Date: Apr 03 2020 09:45:28 +0000 Subject: ipatests: test ipa-backup with different role configurations. ipa-backup should refuse to execute if the local IPA server does not have all the roles used in the cluster. A --disable-role-check knob should also be provided to bypass the check. Add an integration test for the new behavior and the knob. Related: https://pagure.io/freeipa/issue/8217 Signed-off-by: François Cami Reviewed-By: Rob Crittenden Reviewed-By: Mohammad Rizwan Yusuf Reviewed-By: Rob Crittenden Reviewed-By: Mohammad Rizwan Yusuf Reviewed-By: Florence Blanc-Renaud Reviewed-By: Michal Polovka --- diff --git a/ipatests/prci_definitions/nightly_ipa-4-8_latest.yaml b/ipatests/prci_definitions/nightly_ipa-4-8_latest.yaml index 4eb0b8a..c5edc2a 100644 --- a/ipatests/prci_definitions/nightly_ipa-4-8_latest.yaml +++ b/ipatests/prci_definitions/nightly_ipa-4-8_latest.yaml @@ -788,6 +788,18 @@ jobs: timeout: 7200 topology: *master_2repl_1client + fedora-latest-ipa-4-8/test_backup_and_restore_TestBackupRoles: + requires: [fedora-latest-ipa-4-8/build] + priority: 50 + job: + class: RunPytest + args: + build_url: '{fedora-latest-ipa-4-8/build_url}' + test_suite: test_integration/test_backup_and_restore.py::TestBackupRoles + template: *ci-ipa-4-8-latest + timeout: 7200 + topology: *master_1repl + fedora-latest-ipa-4-8/test_dnssec: requires: [fedora-latest-ipa-4-8/build] priority: 50 diff --git a/ipatests/prci_definitions/nightly_ipa-4-8_previous.yaml b/ipatests/prci_definitions/nightly_ipa-4-8_previous.yaml index 705ee9a..a3b7544 100644 --- a/ipatests/prci_definitions/nightly_ipa-4-8_previous.yaml +++ b/ipatests/prci_definitions/nightly_ipa-4-8_previous.yaml @@ -788,6 +788,18 @@ jobs: timeout: 7200 topology: *master_2repl_1client + fedora-previous-ipa-4-8/test_backup_and_restore_TestBackupRoles: + requires: [fedora-previous-ipa-4-8/build] + priority: 50 + job: + class: RunPytest + args: + build_url: '{fedora-previous-ipa-4-8/build_url}' + test_suite: test_integration/test_backup_and_restore.py::TestBackupRoles + template: *ci-ipa-4-8-previous + timeout: 7200 + topology: *master_1repl + fedora-previous-ipa-4-8/test_dnssec: requires: [fedora-previous-ipa-4-8/build] priority: 50 diff --git a/ipatests/test_integration/test_backup_and_restore.py b/ipatests/test_integration/test_backup_and_restore.py index 9182ac9..a1e86a2 100644 --- a/ipatests/test_integration/test_backup_and_restore.py +++ b/ipatests/test_integration/test_backup_and_restore.py @@ -40,6 +40,7 @@ from ldap.dn import escape_dn_chars logger = logging.getLogger(__name__) + def assert_entries_equal(a, b): assert_deepequal(a.dn, b.dn) assert_deepequal(dict(a), dict(b)) @@ -161,9 +162,14 @@ def restore_checker(host): assert_func(expected, got) -def backup(host): - """Run backup on host, return the path to the backup directory""" - result = host.run_command(['ipa-backup', '-v']) +def backup(host, disable_role_check=False, raiseonerr=True): + """Run backup on host and return a tuple: + (path to the backup directory, run_command result) + """ + cmd = ['ipa-backup', '-v'] + if disable_role_check: + cmd.append('--disable-role-check') + result = host.run_command(cmd, raiseonerr=raiseonerr) # Test for ticket 7632: check that services are restarted # before the backup is compressed @@ -177,9 +183,12 @@ def backup(host): if line.startswith(prefix): backup_path = line[len(prefix):].strip() logger.info('Backup path for %s is %s', host.hostname, backup_path) - return backup_path + return backup_path, result else: - raise AssertionError('Backup directory not found in output') + if raiseonerr: + raise AssertionError('Backup directory not found in output') + else: + return None, result @pytest.yield_fixture(scope="function") @@ -206,7 +215,7 @@ class TestBackupAndRestore(IntegrationTest): def test_full_backup_and_restore(self): """backup, uninstall, restore""" with restore_checker(self.master): - backup_path = backup(self.master) + backup_path, unused = backup(self.master) self.master.run_command(['ipa-server-install', '--uninstall', @@ -232,7 +241,7 @@ class TestBackupAndRestore(IntegrationTest): def test_full_backup_and_restore_with_removed_users(self): """regression test for https://fedorahosted.org/freeipa/ticket/3866""" with restore_checker(self.master): - backup_path = backup(self.master) + backup_path, unused = backup(self.master) logger.info('Backup path for %s is %s', self.master, backup_path) @@ -258,7 +267,7 @@ class TestBackupAndRestore(IntegrationTest): def test_full_backup_and_restore_with_selinux_booleans_off(self): """regression test for https://fedorahosted.org/freeipa/ticket/4157""" with restore_checker(self.master): - backup_path = backup(self.master) + backup_path, unused = backup(self.master) logger.info('Backup path for %s is %s', self.master, backup_path) @@ -311,7 +320,7 @@ class BaseBackupAndRestoreWithDNS(IntegrationTest): tasks.resolve_record(self.master.ip, self.example_test_zone) - backup_path = backup(self.master) + backup_path, unused = backup(self.master) self.master.run_command(['ipa-server-install', '--uninstall', @@ -387,7 +396,7 @@ class BaseBackupAndRestoreWithDNSSEC(IntegrationTest): self.master.ip, self.example_test_zone) ), "Zone is not signed" - backup_path = backup(self.master) + backup_path, unused = backup(self.master) self.master.run_command(['ipa-server-install', '--uninstall', @@ -469,7 +478,7 @@ class BaseBackupAndRestoreWithKRA(IntegrationTest): "--password", self.vault_password, ]) - backup_path = backup(self.master) + backup_path, unused = backup(self.master) self.master.run_command(['ipa-server-install', '--uninstall', @@ -588,7 +597,7 @@ class TestBackupAndRestoreWithReplica(IntegrationTest): tasks.user_add(self.replica1, 'test1_replica') with restore_checker(self.master): - backup_path = backup(self.master) + backup_path, unused = backup(self.master) # change data after backup self.master.run_command(['ipa', 'user-del', 'test1_master']) @@ -712,7 +721,7 @@ class TestUserRootFilesOwnershipPermission(IntegrationTest): def test_userroot_ldif_files_ownership_and_permission(self): """backup, uninstall, restore, backup""" tasks.install_master(self.master) - backup_path = backup(self.master) + backup_path, unused = backup(self.master) self.master.run_command(['ipa-server-install', '--uninstall', @@ -778,7 +787,7 @@ class TestBackupAndRestoreDMPassword(IntegrationTest): def test_restore_bad_dm_password(self): """backup, uninstall, restore, wrong DM password (expect failure)""" with restore_checker(self.master): - backup_path = backup(self.master) + backup_path, unused = backup(self.master) # No uninstall, just pure restore, the only case where # prompting for the DM password matters. @@ -792,7 +801,7 @@ class TestBackupAndRestoreDMPassword(IntegrationTest): # Flying blind without the restore_checker so we can have # an error thrown when dirsrv is down. - backup_path = backup(self.master) + backup_path, unused = backup(self.master) self.master.run_command(['ipactl', 'stop']) @@ -827,7 +836,7 @@ class TestReplicaInstallAfterRestore(IntegrationTest): check_replication(master, replica1, "testuser1") # backup master. - backup_path = backup(master) + backup_path, unused = backup(master) suffix = ipautil.realm_to_suffix(master.domain.realm) suffix = escape_dn_chars(str(suffix)) @@ -891,7 +900,7 @@ class TestBackupAndRestoreTrust(IntegrationTest): '--add-sids']) with restore_checker(self.master): - backup_path = backup(self.master) + backup_path, unused = backup(self.master) self.master.run_command(['ipa-server-install', '--uninstall', @@ -909,3 +918,138 @@ class TestBackupAndRestoreTrust(IntegrationTest): tasks.install_packages(self.master, ['*ipa-server-trust-ad']) self.master.run_command(['ipa-restore', backup_path], stdin_text=dirman_password + '\nyes') + + +class TestBackupRoles(IntegrationTest): + """ipa-backup should only run on replicas with all the in-use roles + https://pagure.io/freeipa/issue/8217 + """ + + num_replicas = 1 + topology = 'star' + + @classmethod + def install(cls, mh): + tasks.install_master(cls.master, setup_dns=True) + + def _check_rolecheck_backup_failure(self, host): + unused, result = backup(host, raiseonerr=False) + assert result.returncode == 1 + assert "Error: Local roles" in result.stderr_text + assert "do not match globally used roles" in result.stderr_text + + unused, result = backup( + host, disable_role_check=True + ) + assert result.returncode == 0 + assert "Warning: Local roles" in result.stderr_text + assert "do not match globally used roles" in result.stderr_text + + def _check_rolecheck_backup_success(self, host): + unused, result = backup(host) + assert result.returncode == 0 + assert "Local roles match globally used roles, proceeding." \ + in result.stderr_text + + def test_rolecheck_DNS_CA(self): + """ipa-backup rolecheck: + start with a master with DNS and CA then + gradually upgrade a replica to the DNS and CA + roles. + """ + + # single master: check that backup works. + self._check_rolecheck_backup_success(self.master) + + # install CA-less, DNS-less replica + tasks.install_replica(self.master, self.replicas[0], setup_ca=False) + self._check_rolecheck_backup_success(self.master) + self._check_rolecheck_backup_failure(self.replicas[0]) + + # install DNS on replica + tasks.install_dns(self.replicas[0]) + self._check_rolecheck_backup_failure(self.replicas[0]) + + def test_rolecheck_KRA(self): + """ipa-backup rolecheck: add a KRA. + """ + + # install CA on replica. + tasks.install_ca(self.replicas[0]) + # master and replicas[0] have matching roles now. + self._check_rolecheck_backup_success(self.master) + self._check_rolecheck_backup_success(self.replicas[0]) + + # install KRA on replica + tasks.install_kra(self.replicas[0], first_instance=True) + self._check_rolecheck_backup_success(self.replicas[0]) + self._check_rolecheck_backup_failure(self.master) + + # install KRA on master + tasks.install_kra(self.master) + # master and replicas[0] have matching roles now. + self._check_rolecheck_backup_success(self.replicas[0]) + self._check_rolecheck_backup_success(self.master) + + def test_rolecheck_Trust(self): + """ipa-backup rolecheck: add Trust controllers/agents. + """ + + # install AD Trust packages on replica first + tasks.install_packages(self.replicas[0], ['*ipa-server-trust-ad']) + self._check_rolecheck_backup_success(self.replicas[0]) + self._check_rolecheck_backup_success(self.master) + tasks.install_packages(self.master, ['*ipa-server-trust-ad']) + + # make replicas[0] become Trust Controller + self.replicas[0].run_command([ + 'ipa-adtrust-install', '-U', '--netbios-name', 'IPA', + '-a', self.master.config.admin_password, + '--add-sids' + ]) + self._check_rolecheck_backup_success(self.replicas[0]) + self._check_rolecheck_backup_failure(self.master) + + # make master become Trust Agent + cmd_input = ( + # admin password: + self.master.config.admin_password + '\n' + + # WARNING: The smb.conf already exists. Running ipa-adtrust-install + # will break your existing samba configuration. + # Do you wish to continue? [no]: + 'yes\n' + # Enable trusted domains support in slapi-nis? [no]: + '\n' + + # WARNING: 1 IPA masters are not yet able to serve information + # about users from trusted forests. + # Installer can add them to the list of IPA masters allowed to + # access information about trusts. + # If you choose to do so, you also need to restart LDAP service on + # those masters. + # Refer to ipa-adtrust-install(1) man page for details. + # IPA master[replica1.testrelm.test]?[no]: + 'yes\n' + ) + self.replicas[0].run_command([ + 'ipa-adtrust-install', '--add-agents'], stdin_text=cmd_input + ) + self._check_rolecheck_backup_success(self.replicas[0]) + self._check_rolecheck_backup_failure(self.master) + + # make master become Trust Controller + self.master.run_command([ + 'ipa-adtrust-install', '-U', '--netbios-name', 'IPA', + '-a', self.master.config.admin_password, + '--add-sids' + ]) + # master and replicas[0] are both AD Trust Controllers now. + self._check_rolecheck_backup_success(self.master) + self._check_rolecheck_backup_success(self.replicas[0]) + + # switch replicas[0] to hidden + self.replicas[0].run_command([ + 'ipa', 'server-state', + self.replicas[0].hostname, '--state=hidden' + ]) + self._check_rolecheck_backup_success(self.master) + self._check_rolecheck_backup_success(self.replicas[0]) diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py index d11976a..c17a3d1 100644 --- a/ipatests/test_integration/test_replica_promotion.py +++ b/ipatests/test_integration/test_replica_promotion.py @@ -928,7 +928,7 @@ class TestHiddenReplicaPromotion(IntegrationTest): """ self._check_server_role(self.replicas[0], 'hidden') # backup - backup_path = backup(self.replicas[0]) + backup_path, unused = backup(self.replicas[0]) # uninstall tasks.uninstall_master(self.replicas[0]) # restore