Skip to content

Commit cc58cad

Browse files
committed
GDM topology and util fixes
With additional changes for the Passwordless GDM tests, the changes allow for better integration with default MHC configs with out pre-provisioning environments. GDM topology controller now joins IPA domain during setup. Additional check in GDMTopologyController for gdm feature so that we skip topology_setup is gdm is not available on the client. Consolidate realm join steps into a join_domain helper method in ProvisionedBackupTopologyController and call it from topology_setup in relevant topologies. Check in join_domain if already joined and leave before attempting a join. Add realmd.conf to join_domain to prevent realm from clobbering krb5.conf. This is seen when joining AD domains.
1 parent 5be9c41 commit cc58cad

File tree

3 files changed

+78
-38
lines changed

3 files changed

+78
-38
lines changed

sssd_test_framework/topology.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def test_ldap(client: Client, ldap: LDAP):
6666
name="gdm",
6767
topology=Topology(TopologyDomain("sssd", client=1, ipa=1, keycloak=1)),
6868
controller=GDMTopologyController(),
69+
domains=dict(test="sssd.ipa[0]"),
6970
fixtures=dict(client="sssd.client[0]", ipa="sssd.ipa[0]", provider="sssd.ipa[0]", keycloak="sssd.keycloak[0]"),
7071
)
7172
"""

sssd_test_framework/topology_controllers.py

Lines changed: 68 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import re
34
import socket
45

56
from pytest_mh import BackupTopologyController
@@ -58,6 +59,54 @@ def teardown(self) -> None:
5859

5960
super().teardown()
6061

62+
def join_domain(self, client: ClientHost, provider: IPAHost | ADHost | SambaHost):
63+
"""
64+
Helper method for joining domains
65+
"""
66+
self.logger.info(f"Enrolling {client.hostname} into {provider.domain}")
67+
68+
# Remove any existing Kerberos configuration and keytab
69+
client.fs.rm("/etc/krb5.conf")
70+
client.fs.rm("/etc/krb5.keytab")
71+
72+
# First check if joined. If so, leave.
73+
result = client.conn.exec(["realm", "list"])
74+
self.logger.info(f"REALM_LIST STDOUT: \n{result.stdout}")
75+
self.logger.info(f"REALM_LIST STDERR: \n{result.stderr}")
76+
pattern = rf"^{re.escape(provider.domain)}$"
77+
if re.search(pattern, result.stdout, re.MULTILINE):
78+
self.logger.info(f"Found {provider.domain} in realm list. Leaving.")
79+
result = client.conn.exec(
80+
["realm", "leave", provider.domain], input=provider.adminpw, raise_on_error=False
81+
)
82+
self.logger.info(f"Optional realm leave failed...continuing to join {provider.domain}.")
83+
84+
if isinstance(provider, (IPAHost)):
85+
# Backup ipa-client-install files
86+
client.fs.backup("/etc/ipa")
87+
client.fs.backup("/var/lib/ipa-client")
88+
89+
# Configure realm to keep kerberos intact
90+
client.fs.backup("/etc/realmd.conf")
91+
client.fs.write(
92+
"/etc/realmd.conf",
93+
"""
94+
[service]
95+
manage-krb5-conf = no
96+
""",
97+
)
98+
99+
# Join provider domain
100+
result = client.conn.exec(["realm", "join", provider.domain], input=provider.adminpw, raise_on_error=False)
101+
if result.rc != 0:
102+
self.logger.info(f"Running realm join failed with:\n{result.stdout}\n{result.stderr}")
103+
self.logger.info("Trying uninstall and join again.")
104+
if isinstance(provider, (IPAHost)):
105+
client.conn.exec(["ipa-client-install", "--uninstall", "-U"])
106+
else:
107+
client.conn.exec(["realm", "leave", "--unattended", provider.domain], input=provider.adminpw)
108+
client.conn.exec(["realm", "join", provider.domain], input=provider.adminpw)
109+
61110

62111
class ClientTopologyController(ProvisionedBackupTopologyController):
63112
"""
@@ -86,18 +135,8 @@ def topology_setup(self, client: ClientHost, ipa: IPAHost) -> None:
86135
self.logger.info(f"Topology '{self.name}' is already provisioned")
87136
return
88137

89-
self.logger.info(f"Enrolling {client.hostname} into {ipa.domain}")
90-
91-
# Remove any existing Kerberos configuration and keytab
92-
client.fs.rm("/etc/krb5.conf")
93-
client.fs.rm("/etc/krb5.keytab")
94-
95-
# Backup ipa-client-install files
96-
client.fs.backup("/etc/ipa")
97-
client.fs.backup("/var/lib/ipa-client")
98-
99-
# Join ipa domain
100-
client.conn.exec(["realm", "join", ipa.domain], input=ipa.adminpw)
138+
# Join IPA domain
139+
self.join_domain(client, ipa)
101140

102141
# Backup so we can restore to this state after each test
103142
super().topology_setup()
@@ -114,14 +153,8 @@ def topology_setup(self, client: ClientHost, provider: ADHost | SambaHost) -> No
114153
self.logger.info(f"Topology '{self.name}' is already provisioned")
115154
return
116155

117-
self.logger.info(f"Enrolling {client.hostname} into {provider.domain}")
118-
119-
# Remove any existing Kerberos configuration and keytab
120-
client.fs.rm("/etc/krb5.conf")
121-
client.fs.rm("/etc/krb5.keytab")
122-
123-
# Join AD domain
124-
client.conn.exec(["realm", "join", provider.domain], input=provider.adminpw)
156+
# Join AD/Samba domain
157+
self.join_domain(client, provider)
125158

126159
# Backup so we can restore to this state after each test
127160
super().topology_setup()
@@ -156,18 +189,8 @@ def topology_setup(self, client: ClientHost, ipa: IPAHost, trusted: ADHost | Sam
156189

157190
# Do not enroll client into IPA domain if it is already joined
158191
if "ipa" not in self.multihost.provisioned_topologies:
159-
self.logger.info(f"Enrolling {client.hostname} into {ipa.domain}")
160-
161-
# Remove any existing Kerberos configuration and keytab
162-
client.fs.rm("/etc/krb5.conf")
163-
client.fs.rm("/etc/krb5.keytab")
164-
165-
# Backup ipa-client-install files
166-
client.fs.backup("/etc/ipa")
167-
client.fs.backup("/var/lib/ipa-client")
168-
169-
# Join IPA domain)
170-
client.conn.exec(["realm", "join", ipa.domain], input=ipa.adminpw)
192+
# Join IPA domain
193+
self.join_domain(client, ipa)
171194

172195
# Backup so we can restore to this state after each test
173196
super().topology_setup()
@@ -284,12 +307,19 @@ class GDMTopologyController(ProvisionedBackupTopologyController):
284307

285308
@BackupTopologyController.restore_vanilla_on_error
286309
def topology_setup(self, client: ClientHost, ipa: IPAHost, keycloak: KeycloakHost) -> None:
310+
if "gdm" not in client.features or not client.features["gdm"]:
311+
self.logger.info(f"Topology '{self.name}' setup skipped because gdm feature not found on client")
312+
return
313+
287314
if self.provisioned:
288315
self.logger.info(f"Topology '{self.name}' is already provisioned")
289316
return
290317

291318
self.logger.info(f"Enrolling IPA server {ipa.hostname} into {keycloak.hostname} by creating an IdP client")
292319

320+
# Join IPA domain
321+
self.join_domain(client, ipa)
322+
293323
# Create an IdP client
294324
keycloak.kclogin()
295325
keycloak.conn.run(
@@ -311,13 +341,18 @@ def topology_setup(self, client: ClientHost, ipa: IPAHost, keycloak: KeycloakHos
311341
# Backup so we can restore to this state after each test
312342
super().topology_setup()
313343

314-
def topology_teardown(self, ipa: IPAHost, keycloak: KeycloakHost) -> None:
344+
def topology_teardown(self, client: ClientHost, ipa: IPAHost, keycloak: KeycloakHost) -> None:
345+
if "gdm" not in client.features or not client.features["gdm"]:
346+
self.logger.info(f"Topology '{self.name}' teardown skipped because gdm feature not found on client")
347+
return
348+
315349
self.logger.info(f"Un-enrolling IPA server {ipa.hostname} from {keycloak.hostname} by deleting the IdP client")
316350
keycloak.kclogin()
317351
keycloak.conn.run(
318352
"ID=$(/opt/keycloak/bin/kcadm.sh get clients -q clientId=ipa_oidc_client --fields=id|jq -r '.[0].id'); "
319353
"/opt/keycloak/bin/kcadm.sh delete clients/$ID"
320354
)
355+
321356
ipa.kinit()
322357
ipa.conn.run("ipa idp-del keycloak")
323358
super().topology_teardown()

sssd_test_framework/utils/gdm.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def __init__(self, host):
3030
super().__init__(host)
3131
self.init_completed = False
3232

33-
self.cmd = [scauto_path, "gui", "--wait-time", "1", "--no-screenshot"]
33+
self.cmd = [scauto_path, "--verbose", "debug", "gui", "--wait-time", "1", "--no-screenshot"]
3434

3535
def teardown(self):
3636
if self.init_completed:
@@ -56,10 +56,13 @@ def assert_text(self, word: str) -> bool:
5656
if not self.init_completed:
5757
self.init()
5858

59-
result = self.host.conn.exec([*self.cmd, "assert-text", word])
59+
result = self.host.conn.exec([*self.cmd, "assert-text", word], raise_on_error=False)
60+
if result.rc != 0:
61+
self.logger.warn(f"Unable to find text ({word}) on screen")
6062
return result.rc == 0
6163

62-
def click_on(self, word: str) -> bool:
64+
@retry(max_retries=3, delay=1, on=AssertionError)
65+
def click_on(self, word: str) -> None:
6366
"""
6467
Run scauto gui click-on
6568
@@ -71,8 +74,9 @@ def click_on(self, word: str) -> bool:
7174
if not self.init_completed:
7275
self.init()
7376

74-
result = self.host.conn.exec([*self.cmd, "click-on", word])
75-
return result.rc == 0
77+
result = self.host.conn.exec([*self.cmd, "click-on", word], raise_on_error=False)
78+
if result.rc != 0:
79+
raise AssertionError(f"Unable to click-on target {word}")
7680

7781
def kb_write(self, word: str) -> bool:
7882
"""

0 commit comments

Comments
 (0)