From 9f584502c94e030e39351bfedabe74c7892791b1 Mon Sep 17 00:00:00 2001 From: Anuja More Date: Fri, 23 Aug 2024 15:08:57 +0530 Subject: [PATCH] ipatests: Update ipatests to test topology with multiple domain. Added changes in ipatests so that ipa server-replica-client can be installed with two domain - ipa.test and trustedipa.test Related: https://pagure.io/freeipa/issue/9657 Signed-off-by: Anuja More --- ipatests/pytest_ipa/integration/__init__.py | 34 ++++++++- ipatests/pytest_ipa/integration/config.py | 30 +++++++- ipatests/test_integration/base.py | 71 +++++++++++++++++++ .../test_integration/test_multidomain_ipa.py | 54 ++++++++++++++ pylint_plugins.py | 12 ++++ 5 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 ipatests/test_integration/test_multidomain_ipa.py diff --git a/ipatests/pytest_ipa/integration/__init__.py b/ipatests/pytest_ipa/integration/__init__.py index 34b6ef0fb1e..7b66afb6eeb 100644 --- a/ipatests/pytest_ipa/integration/__init__.py +++ b/ipatests/pytest_ipa/integration/__init__.py @@ -413,6 +413,16 @@ def mh(request, class_integration_logs): 'type': 'AD_TREEDOMAIN', 'hosts': {'ad_treedomain': 1} }) + for _i in range(cls.num_trusted_domains): + domain_descriptions.append({ + 'type': 'TRUSTED_IPA', + 'hosts': + { + 'master': 1, + 'replica': cls.num_trusted_replicas, + 'client': cls.num_trusted_clients, + } + }) mh = make_multihost_fixture( request, @@ -421,10 +431,20 @@ def mh(request, class_integration_logs): _config=get_global_config(), ) - mh.domain = mh.config.domains[0] + for domain in mh.config.domains: + if domain.type == 'IPA': + mh.domain = domain + elif domain.type == 'TRUSTED_IPA': + mh.trusted_domain = domain + [mh.master] = mh.domain.hosts_by_role('master') mh.replicas = mh.domain.hosts_by_role('replica') mh.clients = mh.domain.hosts_by_role('client') + if mh.config.trusted_domains: + [mh.trusted_master] = mh.trusted_domain.hosts_by_role('master') + mh.trusted_replicas = mh.trusted_domain.hosts_by_role('replica') + mh.trusted_clients = mh.trusted_domain.hosts_by_role('client') + ad_domains = mh.config.ad_domains if ad_domains: mh.ads = [] @@ -487,6 +507,12 @@ def add_compat_attrs(cls, mh): cls.ad_subdomains = mh.ad_subdomains cls.ad_treedomains = mh.ad_treedomains + cls.trusted_domains = mh.config.trusted_domains + if cls.trusted_domains: + cls.trusted_master = mh.trusted_master + cls.trusted_replicas = mh.trusted_replicas + cls.trusted_clients = mh.trusted_clients + def del_compat_attrs(cls): """Remove convenience attributes from the test class @@ -504,6 +530,12 @@ def del_compat_attrs(cls): del cls.ad_treedomains del cls.ad_domains + if cls.trusted_domains: + del cls.trusted_master + del cls.trusted_replicas + del cls.trusted_clients + del cls.trusted_domains + def skip_if_fips(reason='Not supported in FIPS mode', host='master'): if callable(reason): diff --git a/ipatests/pytest_ipa/integration/config.py b/ipatests/pytest_ipa/integration/config.py index 1f4dff7f652..0fb2313db0a 100644 --- a/ipatests/pytest_ipa/integration/config.py +++ b/ipatests/pytest_ipa/integration/config.py @@ -88,13 +88,19 @@ def get_logger(self, name): def ad_domains(self): return [d for d in self.domains if d.is_ad_type] + @property + def trusted_domains(self): + return [d for d in self.domains if d.is_trusted_ipa_type] + def get_all_hosts(self): for domain in self.domains: for host in domain.hosts: yield host def get_all_ipa_hosts(self): - for ipa_domain in (d for d in self.domains if d.is_ipa_type): + for ipa_domain in (d for d in self.domains + if d.is_ipa_type or d.is_trusted_ipa_type + ): for ipa_host in ipa_domain.hosts: yield ipa_host @@ -135,7 +141,7 @@ def __init__(self, config, name, domain_type): self.name = str(name) self.hosts = [] - assert self.is_ipa_type or self.is_ad_type + assert self.is_ipa_type or self.is_ad_type or self.is_trusted_ipa_type self.realm = self.name.upper() self.basedn = DN(*(('dc', p) for p in name.split('.'))) @@ -143,6 +149,10 @@ def __init__(self, config, name, domain_type): def is_ipa_type(self): return self.type == 'IPA' + @property + def is_trusted_ipa_type(self): + return self.type == 'TRUSTED_IPA' + @property def is_ad_type(self): return self.type == 'AD' or self.type.startswith('AD_') @@ -158,6 +168,8 @@ def static_roles(self): return ('ad_subdomain',) elif self.type == 'AD_TREEDOMAIN': return ('ad_treedomain',) + elif self.type == 'TRUSTED_IPA': + return ('trusted_master', 'trusted_replica', 'trusted_client') else: raise LookupError(self.type) @@ -168,6 +180,8 @@ def get_host_class(self, host_dict): return Host elif self.is_ad_type: return WinHost + elif self.is_trusted_ipa_type: + return Host else: raise LookupError(self.type) @@ -175,6 +189,10 @@ def get_host_class(self, host_dict): def master(self): return self.host_by_role('master') + @property + def trusted_master(self): + return self.host_by_role('trusted_master') + @property def masters(self): return self.hosts_by_role('master') @@ -183,10 +201,18 @@ def masters(self): def replicas(self): return self.hosts_by_role('replica') + @property + def trusted_replicas(self): + return self.hosts_by_role('replica') + @property def clients(self): return self.hosts_by_role('client') + @property + def trusted_clients(self): + return self.hosts_by_role('client') + @property def ads(self): return self.hosts_by_role('ad') diff --git a/ipatests/test_integration/base.py b/ipatests/test_integration/base.py index 4717667cb0c..cb34067d4d3 100644 --- a/ipatests/test_integration/base.py +++ b/ipatests/test_integration/base.py @@ -33,6 +33,7 @@ class IntegrationTest: num_replicas = 0 num_clients = 0 num_ad_domains = 0 + num_trusted_domains = 0 num_ad_subdomains = 0 num_ad_treedomains = 0 required_extra_roles = [] @@ -95,6 +96,7 @@ def install(cls, mh): cls.clients, domain_level, random_serial=cls.random_serial, extra_args=extra_args,) + @classmethod def uninstall(cls, mh): for replica in cls.replicas: @@ -112,3 +114,72 @@ def uninstall(cls, mh): tasks.uninstall_client(client) if cls.fips_mode: cls.disable_fips_mode() + + +@ordered +@pytest.mark.usefixtures('mh') +@pytest.mark.usefixtures('integration_logs') +class MultiDomainIntegrationTest(IntegrationTest): + num_trusted_domains = 1 + num_trusted_replicas = 0 + num_trusted_clients = 0 + + @classmethod + def get_domains(cls): + return super(MultiDomainIntegrationTest, cls + ).get_domains() + cls.trusted_domains + + @classmethod + def install(cls, mh): + super(MultiDomainIntegrationTest, cls).install(mh) + extra_args = [] + if cls.topology is None: + return + else: + if cls.token_password: + extra_args.extend(('--token-password', cls.token_password,)) + tasks.install_topo(cls.topology, + cls.trusted_master, cls.trusted_replicas, + cls.trusted_clients, 1, + random_serial=cls.random_serial, + extra_args=extra_args,) + tasks.kinit_admin(cls.master) + tasks.kinit_admin(cls.trusted_master) + # Now enable dnssec on the zones + cls.master.run_command([ + "ipa-dns-install", + "--dnssec-master", + "--forwarder", cls.master.config.dns_forwarder, + "-U", + ]) + cls.master.run_command([ + "ipa", "dnszone-mod", cls.master.domain.name, + "--dnssec=True" + ]) + cls.trusted_master.run_command([ + "ipa-dns-install", + "--dnssec-master", + "--forwarder", cls.trusted_master.config.dns_forwarder, + "-U", + ]) + cls.trusted_master.run_command([ + "ipa", "dnszone-mod", cls.trusted_master.domain.name, + "--dnssec=True" + ]) + + @classmethod + def uninstall(cls, mh): + super(MultiDomainIntegrationTest, cls).uninstall(mh) + for trustedreplica in cls.trusted_replicas: + try: + tasks.run_server_del( + cls.trusted_master, trustedreplica.hostname, force=True, + ignore_topology_disconnect=True, ignore_last_of_role=True) + except subprocess.CalledProcessError: + # If the master has already been uninstalled, + # this call may fail + pass + tasks.uninstall_master(trustedreplica) + tasks.uninstall_master(cls.trusted_master) + for client in cls.trusted_clients: + tasks.uninstall_client(client) diff --git a/ipatests/test_integration/test_multidomain_ipa.py b/ipatests/test_integration/test_multidomain_ipa.py new file mode 100644 index 00000000000..678dbe00a91 --- /dev/null +++ b/ipatests/test_integration/test_multidomain_ipa.py @@ -0,0 +1,54 @@ +from ipatests.pytest_ipa.integration import tasks +from ipatests.test_integration.base import MultiDomainIntegrationTest + + +class TestMultidomain(MultiDomainIntegrationTest): + num_clients = 1 + num_replicas = 1 + num_trusted_clients = 1 + num_trusted_replicas = 1 + topology = 'line' + + def test_multidomain_trust(self): + """ + Test services on multidomain topology. + """ + + for host in (self.master, self.replicas[0], + self.trusted_master, self.trusted_replicas[0] + ): + tasks.start_ipa_server(host) + + for host in (self.master, self.trusted_master): + tasks.disable_dnssec_validation(host) + tasks.restart_named(host) + + for host in (self.master, self.replicas[0], + self.trusted_master, self.trusted_replicas[0], + self.clients[0], self.trusted_clients[0] + ): + tasks.kinit_admin(host) + + # Add DNS forwarder to trusted domain on ipa domain + self.master.run_command([ + "ipa", "dnsforwardzone-add", self.trusted_master.domain.name, + "--forwarder", self.trusted_master.ip, + "--forward-policy=only" + ]) + self.trusted_master.run_command([ + "ipa", "dnsforwardzone-add", self.master.domain.name, + "--forwarder", self.master.ip, + "--forward-policy=only" + ]) + + tasks.install_adtrust(self.master) + tasks.install_adtrust(self.trusted_master) + + # Establish trust + self.master.run_command([ + "ipa", "trust-add", "--type=ipa", + "--admin", "admin@{}".format(self.trusted_master.domain.realm), + "--range-type=ipa-ad-trust-posix", + "--password", "--two-way=true", + self.trusted_master.domain.name + ], stdin_text=self.trusted_master.config.admin_password) diff --git a/pylint_plugins.py b/pylint_plugins.py index d75da3f4aae..75d65f016fd 100644 --- a/pylint_plugins.py +++ b/pylint_plugins.py @@ -566,6 +566,7 @@ def wildcard(*args, **kwargs): textwrap.dedent( """\ from ipatests.test_integration.base import IntegrationTest + from ipatests.test_integration.base import MultiDomainIntegrationTest from ipatests.pytest_ipa.integration.host import Host, WinHost from ipatests.pytest_ipa.integration.config import Config, Domain @@ -584,6 +585,9 @@ class PylintADDomains: def __getitem__(self, key): return Domain() + class PylintTrustedDomains: + def __getitem__(self, key): + return Domain() Host.config = Config() Host.domain = Domain() @@ -596,6 +600,14 @@ def __getitem__(self, key): IntegrationTest.ad_treedomains = PylintWinHosts() IntegrationTest.ad_subdomains = PylintWinHosts() IntegrationTest.ad_domains = PylintADDomains() + MultiDomainIntegrationTest.domain = Domain() + MultiDomainIntegrationTest.master = Host() + MultiDomainIntegrationTest.replicas = PylintIPAHosts() + MultiDomainIntegrationTest.clients = PylintIPAHosts() + MultiDomainIntegrationTest.trusted_master = Host() + MultiDomainIntegrationTest.trusted_replicas = PylintIPAHosts() + MultiDomainIntegrationTest.trusted_clients = PylintIPAHosts() + MultiDomainIntegrationTest.trusted_domains = PylintTrustedDomains() """ ) )