mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-27 09:21:59 -06:00
313ae46b57
https://pagure.io/freeipa/issue/6798 Signed-off-by: Christian Heimes <cheimes@redhat.com> Reviewed-By: Milan Kubik <mkubik@redhat.com>
303 lines
9.7 KiB
Python
303 lines
9.7 KiB
Python
#
|
|
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
|
|
#
|
|
|
|
from itertools import permutations
|
|
|
|
from ipatests.test_integration.base import IntegrationTest
|
|
from ipatests.pytest_plugins.integration import tasks
|
|
from ipalib.constants import DOMAIN_LEVEL_1, DOMAIN_SUFFIX_NAME, CA_SUFFIX_NAME
|
|
|
|
REMOVAL_ERR_TEMPLATE = ("Removal of '{hostname}' leads to disconnected "
|
|
"topology in suffix '{suffix}'")
|
|
|
|
|
|
def check_master_removal(host, hostname_to_remove,
|
|
force=False,
|
|
ignore_topology_disconnect=False,
|
|
ignore_last_of_role=False):
|
|
result = tasks.run_server_del(
|
|
host,
|
|
hostname_to_remove,
|
|
force=force,
|
|
ignore_topology_disconnect=ignore_topology_disconnect,
|
|
ignore_last_of_role=ignore_last_of_role)
|
|
|
|
assert result.returncode == 0
|
|
if force:
|
|
assert ("Forcing removal of {hostname}".format(
|
|
hostname=hostname_to_remove) in result.stderr_text)
|
|
|
|
if ignore_topology_disconnect:
|
|
assert "Ignoring topology connectivity errors." in result.stderr_text
|
|
|
|
if ignore_last_of_role:
|
|
assert ("Ignoring these warnings and proceeding with removal" in
|
|
result.stderr_text)
|
|
|
|
tasks.assert_error(
|
|
host.run_command(
|
|
['ipa', 'server-show', hostname_to_remove], raiseonerr=False
|
|
),
|
|
"{}: server not found".format(hostname_to_remove),
|
|
returncode=2
|
|
)
|
|
|
|
|
|
def check_removal_disconnects_topology(
|
|
host, hostname_to_remove,
|
|
affected_suffixes=(DOMAIN_SUFFIX_NAME,)):
|
|
result = tasks.run_server_del(host, hostname_to_remove)
|
|
assert len(affected_suffixes) <= 2
|
|
|
|
err_messages_by_suffix = {
|
|
CA_SUFFIX_NAME: REMOVAL_ERR_TEMPLATE.format(
|
|
hostname=hostname_to_remove,
|
|
suffix=CA_SUFFIX_NAME
|
|
),
|
|
DOMAIN_SUFFIX_NAME: REMOVAL_ERR_TEMPLATE.format(
|
|
hostname=hostname_to_remove,
|
|
suffix=DOMAIN_SUFFIX_NAME
|
|
)
|
|
}
|
|
|
|
for suffix in err_messages_by_suffix:
|
|
if suffix in affected_suffixes:
|
|
tasks.assert_error(
|
|
result, err_messages_by_suffix[suffix], returncode=1)
|
|
else:
|
|
assert err_messages_by_suffix[suffix] not in result.stderr_text
|
|
|
|
|
|
class ServerDelBase(IntegrationTest):
|
|
num_replicas = 2
|
|
num_clients = 1
|
|
domain_level = DOMAIN_LEVEL_1
|
|
topology = 'star'
|
|
|
|
@classmethod
|
|
def install(cls, mh):
|
|
super(ServerDelBase, cls).install(mh)
|
|
|
|
cls.client = cls.clients[0]
|
|
cls.replica1 = cls.replicas[0]
|
|
cls.replica2 = cls.replicas[1]
|
|
|
|
|
|
class TestServerDel(ServerDelBase):
|
|
|
|
@classmethod
|
|
def install(cls, mh):
|
|
super(TestServerDel, cls).install(mh)
|
|
# prepare topologysegments for negative test cases
|
|
# it should look like this for DOMAIN_SUFFIX_NAME:
|
|
# master
|
|
# /
|
|
# /
|
|
# /
|
|
# replica1------- replica2
|
|
# and like this for CA_SUFFIX_NAME
|
|
# master
|
|
# \
|
|
# \
|
|
# \
|
|
# replica1------- replica2
|
|
|
|
tasks.create_segment(cls.client, cls.replica1, cls.replica2)
|
|
tasks.create_segment(cls.client, cls.replica1, cls.replica2,
|
|
suffix=CA_SUFFIX_NAME)
|
|
|
|
# try to delete all relevant segment connecting master and replica1/2
|
|
segment_name_fmt = '{p[0].hostname}-to-{p[1].hostname}'
|
|
for domain_pair in permutations((cls.master, cls.replica2)):
|
|
tasks.destroy_segment(
|
|
cls.client, segment_name_fmt.format(p=domain_pair))
|
|
|
|
for ca_pair in permutations((cls.master, cls.replica1)):
|
|
tasks.destroy_segment(
|
|
cls.client, segment_name_fmt.format(p=ca_pair),
|
|
suffix=CA_SUFFIX_NAME)
|
|
|
|
def test_removal_of_nonexistent_master_raises_error(self):
|
|
"""
|
|
tests that removal of non-existent master raises an error
|
|
"""
|
|
hostname = u'bogus-master.bogus.domain'
|
|
err_message = "{}: server not found".format(hostname)
|
|
tasks.assert_error(
|
|
tasks.run_server_del(self.client, hostname),
|
|
err_message,
|
|
returncode=2
|
|
)
|
|
|
|
def test_forced_removal_of_nonexistent_master(self):
|
|
"""
|
|
tests that removal of non-existent master with '--force' does not raise
|
|
an error
|
|
"""
|
|
hostname = u'bogus-master.bogus.domain'
|
|
result = tasks.run_server_del(self.client, hostname, force=True)
|
|
assert result.returncode == 0
|
|
assert ('Deleted IPA server "{}"'.format(hostname) in
|
|
result.stdout_text)
|
|
|
|
assert ("Server has already been deleted" in result.stderr_text)
|
|
|
|
def test_removal_of_replica1_disconnects_domain_topology(self):
|
|
"""
|
|
tests that given the used topology, attempted removal of replica1 fails
|
|
with disconnected DOMAIN topology but not CA
|
|
"""
|
|
|
|
check_removal_disconnects_topology(
|
|
self.client,
|
|
self.replica1.hostname,
|
|
affected_suffixes=(DOMAIN_SUFFIX_NAME,)
|
|
)
|
|
|
|
def test_removal_of_replica2_disconnects_ca_topology(self):
|
|
"""
|
|
tests that given the used topology, attempted removal of replica2 fails
|
|
with disconnected CA topology but not DOMAIN
|
|
"""
|
|
|
|
check_removal_disconnects_topology(
|
|
self.client,
|
|
self.replica2.hostname,
|
|
affected_suffixes=(CA_SUFFIX_NAME,)
|
|
)
|
|
|
|
def test_ignore_topology_disconnect_replica1(self):
|
|
"""
|
|
tests that removal of replica1 with '--ignore-topology-disconnect'
|
|
destroys master for good
|
|
"""
|
|
check_master_removal(
|
|
self.client,
|
|
self.replica1.hostname,
|
|
ignore_topology_disconnect=True
|
|
)
|
|
|
|
# reinstall the replica
|
|
tasks.uninstall_master(self.replica1)
|
|
tasks.install_replica(self.master, self.replica1, setup_ca=True)
|
|
|
|
def test_ignore_topology_disconnect_replica2(self):
|
|
"""
|
|
tests that removal of replica2 with '--ignore-topology-disconnect'
|
|
destroys master for good
|
|
"""
|
|
check_master_removal(
|
|
self.client,
|
|
self.replica2.hostname,
|
|
ignore_topology_disconnect=True
|
|
)
|
|
|
|
# reinstall the replica
|
|
tasks.uninstall_master(self.replica2)
|
|
tasks.install_replica(self.master, self.replica2, setup_ca=True)
|
|
|
|
def test_removal_of_master_disconnects_both_topologies(self):
|
|
"""
|
|
tests that master removal will now raise errors in both suffixes.
|
|
"""
|
|
check_removal_disconnects_topology(
|
|
self.client,
|
|
self.master.hostname,
|
|
affected_suffixes=(CA_SUFFIX_NAME, DOMAIN_SUFFIX_NAME)
|
|
)
|
|
|
|
def test_removal_of_replica1(self):
|
|
"""
|
|
tests the removal of replica1 which should now pass without errors
|
|
"""
|
|
check_master_removal(
|
|
self.client,
|
|
self.replica1.hostname
|
|
)
|
|
|
|
def test_removal_of_replica2(self):
|
|
"""
|
|
tests the removal of replica2 which should now pass without errors
|
|
"""
|
|
check_master_removal(
|
|
self.client,
|
|
self.replica2.hostname
|
|
)
|
|
|
|
|
|
class TestLastServices(ServerDelBase):
|
|
"""
|
|
Test the checks for last services during server-del and their bypassing
|
|
using when forcing the removal
|
|
"""
|
|
num_replicas = 1
|
|
domain_level = DOMAIN_LEVEL_1
|
|
topology = 'line'
|
|
|
|
@classmethod
|
|
def install(cls, mh):
|
|
tasks.install_topo(
|
|
cls.topology, cls.master, cls.replicas, [],
|
|
domain_level=cls.domain_level, setup_replica_cas=False)
|
|
|
|
def test_removal_of_master_raises_error_about_last_ca(self):
|
|
"""
|
|
test that removal of master fails on the last
|
|
"""
|
|
tasks.assert_error(
|
|
tasks.run_server_del(self.replicas[0], self.master.hostname),
|
|
"Deleting this server is not allowed as it would leave your "
|
|
"installation without a CA.",
|
|
1
|
|
)
|
|
|
|
def test_install_ca_on_replica1(self):
|
|
"""
|
|
Install CA on replica so that we can test DNS-related checks
|
|
"""
|
|
tasks.install_ca(self.replicas[0], domain_level=self.domain_level)
|
|
|
|
def test_removal_of_master_raises_error_about_last_dns(self):
|
|
"""
|
|
Now server-del should complain about the removal of last DNS server
|
|
"""
|
|
tasks.assert_error(
|
|
tasks.run_server_del(self.replicas[0], self.master.hostname),
|
|
"Deleting this server will leave your installation "
|
|
"without a DNS.",
|
|
1
|
|
)
|
|
|
|
def test_install_dns_on_replica1_and_dnssec_on_master(self):
|
|
"""
|
|
install DNS server on replica and DNSSec on master
|
|
"""
|
|
tasks.install_dns(self.replicas[0])
|
|
args = [
|
|
"ipa-dns-install",
|
|
"--dnssec-master",
|
|
"--forwarder", self.master.config.dns_forwarder,
|
|
"-U",
|
|
]
|
|
self.master.run_command(args)
|
|
|
|
def test_removal_of_master_raises_error_about_dnssec(self):
|
|
tasks.assert_error(
|
|
tasks.run_server_del(self.replicas[0], self.master.hostname),
|
|
"Replica is active DNSSEC key master. Uninstall "
|
|
"could break your DNS system. Please disable or replace "
|
|
"DNSSEC key master first.",
|
|
1
|
|
)
|
|
|
|
def test_forced_removal_of_master(self):
|
|
"""
|
|
Tests that we can still force remove the master using
|
|
'--ignore-last-of-role'
|
|
"""
|
|
check_master_removal(
|
|
self.replicas[0], self.master.hostname,
|
|
ignore_last_of_role=True
|
|
)
|