]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
qa/tasks: move smb related task funcs out of cephadm.py to smb.py 65757/head
authorJohn Mulligan <jmulligan@redhat.com>
Mon, 29 Sep 2025 19:47:30 +0000 (15:47 -0400)
committerJohn Mulligan <jmulligan@redhat.com>
Thu, 2 Oct 2025 17:11:18 +0000 (13:11 -0400)
Move a bunch of functionality specific to smb out of cephadm.py and
in to a new qa/tasks/smb.py file. The cephadm.py file had contained
a bunch of smb specific stuff because it was easy to add it that
way initially. Now that I am planning on expanding to add some more
smb tasks, it makes sense to move these smb specific functions first.

Update the needed yaml files with the new module.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
17 files changed:
qa/suites/orch/cephadm/smb/tasks/deploy_smb_basic.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_ctdb_node_gone_state.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_domain.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_mgr_basic.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_mgr_clustering_ips.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_mgr_ctdb_res_basic.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_mgr_ctdb_res_dom.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_mgr_ctdb_res_ips.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_mgr_ctdb_res_ports2c.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_mgr_domain.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_mgr_res_basic.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_mgr_res_dom.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_mgr_res_ports.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_proxy_disabled.yaml
qa/suites/orch/cephadm/smb/tasks/deploy_smb_proxy_enabled.yaml
qa/tasks/cephadm.py
qa/tasks/smb.py [new file with mode: 0644]

index eba5025cf35ad0e8b790d1eabc4d1f910259fcfb..aed5723e9c0e25efa10fc71cde8f5550c0eb58e4 100644 (file)
@@ -17,7 +17,7 @@ overrides:
 tasks:
   # TODO: (jjm) I don't think `install` is necessary for this file. Remove?
   - install:
-  - cephadm.configure_samba_client_container:
+  - smb.configure_samba_client_container:
       role: host.b
   - cephadm:
   - cephadm.shell:
index 2a1257e5c95b6a95daaba3fcc125983aabdce4bc..92f84d7df80eeb2522bf83253987e7640eb98eab 100644 (file)
@@ -22,7 +22,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.configure_samba_client_container:
+- smb.configure_samba_client_container:
     role: host.d
 - pexec:
     all:
index 86220108c23690aa3131d98c9ec744eb10ccbb22..82a21253f7b4d4d7232eb4b1bf80f0e620a12dc2 100644 (file)
@@ -14,7 +14,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.deploy_samba_ad_dc:
+- smb.deploy_samba_ad_dc:
     role: host.b
 - cephadm:
 
index 957977c0b6b127acc4a232419413a6334b69ebe7..94033e59fb57cc6903c58339b28341e45450d766 100644 (file)
@@ -14,7 +14,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.configure_samba_client_container:
+- smb.configure_samba_client_container:
     role: host.b
 - cephadm:
     single_host_defaults: true
index 14e28c89f4e8ec3c43cc445a16938f92e8eba12f..6db409638a56469876ddee59b363c2fcbd769e43 100644 (file)
@@ -22,7 +22,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.configure_samba_client_container:
+- smb.configure_samba_client_container:
     role: host.d
 - vip:
     count: 1
index d3a979be5f1915ef843bc9691a1d3a1c9e9143b4..cb2535202973b718529b2e26029be3ff7cf67463 100644 (file)
@@ -22,7 +22,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.configure_samba_client_container:
+- smb.configure_samba_client_container:
     role: host.d
 - pexec:
     all:
index bf96de81f2fdc59311cd29ac3588aded6ef39d54..ce5d2b49000d0e7f09c7054ce9e1494b838e07ad 100644 (file)
@@ -22,7 +22,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.deploy_samba_ad_dc:
+- smb.deploy_samba_ad_dc:
     role: host.d
 - pexec:
     all:
index f0405e4d14dc709dbaeb6828699fdf53383b06ec..63efb232d080984c36833b59924da6723b4aca49 100644 (file)
@@ -22,7 +22,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.deploy_samba_ad_dc:
+- smb.deploy_samba_ad_dc:
     role: host.d
 - vip:
     count: 2
index bbac4357f6fbafd6bf2c39b1a8cfeb6e224d4649..77b98882827ce407d27c481682f778a5bc5ccde7 100644 (file)
@@ -22,7 +22,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.deploy_samba_ad_dc:
+- smb.deploy_samba_ad_dc:
     role: host.d
 - vip:
     count: 3
index ac7ad45c03697097ea8f75035f2666d3634d0f41..985eb4cf4f8aa8b482462867a2034494ec41cd1b 100644 (file)
@@ -14,7 +14,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.deploy_samba_ad_dc:
+- smb.deploy_samba_ad_dc:
     role: host.b
 - cephadm:
     single_host_defaults: true
index 735966e876eb16201388e65cff5657ff1486500f..99f145f9d9860e82744b30aa05ac76494e5c6a36 100644 (file)
@@ -14,7 +14,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.configure_samba_client_container:
+- smb.configure_samba_client_container:
     role: host.b
 - cephadm:
     single_host_defaults: true
index 64fd109f66af79566ab616048b3ee2fc53fdaec8..36f15575ee9b4558e4de2844dcb3683e0df6fe6f 100644 (file)
@@ -14,7 +14,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.deploy_samba_ad_dc:
+- smb.deploy_samba_ad_dc:
     role: host.b
 - cephadm:
     single_host_defaults: true
index 542ff0650794c5be992625d763049564e682a885..65402886c2a74c1b00a78da59079b72c2c21d064 100644 (file)
@@ -14,7 +14,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.deploy_samba_ad_dc:
+- smb.deploy_samba_ad_dc:
     role: host.b
 - cephadm:
     single_host_defaults: true
index a1fd177cf5c3d752f0b13eb2d89aaea1b156c976..a7253328c29b872cf024c3aa0649da0dce302455 100644 (file)
@@ -14,7 +14,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.deploy_samba_ad_dc:
+- smb.deploy_samba_ad_dc:
     role: host.b
 - cephadm:
     single_host_defaults: true
index 2f281366a57e5608f7b663bc2935814fa502ea2a..05001b67f684b0738d417e2d5d8a5d7a10e66745 100644 (file)
@@ -14,7 +14,7 @@ overrides:
     log-only-match:
       - CEPHADM_
 tasks:
-- cephadm.deploy_samba_ad_dc:
+- smb.deploy_samba_ad_dc:
     role: host.b
 - cephadm:
     single_host_defaults: true
index a312f7fe7bc06bc724dfb925af87256d739ca483..5d48c904e619c64c314c3b82037999acc6bebfef 100644 (file)
@@ -8,7 +8,6 @@ import json
 import logging
 import os
 import re
-import time
 import uuid
 import yaml
 
@@ -1885,292 +1884,6 @@ def initialize_config(ctx, config):
     yield
 
 
-def _disable_systemd_resolved(ctx, remote):
-    r = remote.run(args=['ss', '-lunH'], stdout=StringIO())
-    # this heuristic tries to detect if systemd-resolved is running
-    if '%lo:53' not in r.stdout.getvalue():
-        return
-    log.info('Disabling systemd-resolved on %s', remote.shortname)
-    # Samba AD DC container DNS support conflicts with resolved stub
-    # resolver when using host networking. And we want host networking
-    # because it is the simplest thing to set up.  We therefore will turn
-    # off the stub resolver.
-    r = remote.run(
-        args=['sudo', 'cat', '/etc/systemd/resolved.conf'],
-        stdout=StringIO(),
-    )
-    resolved_conf = r.stdout.getvalue()
-    setattr(ctx, 'orig_resolved_conf', resolved_conf)
-    new_resolved_conf = (
-        resolved_conf + '\n# EDITED BY TEUTHOLOGY: deploy_samba_ad_dc\n'
-    )
-    if '[Resolve]' not in new_resolved_conf.splitlines():
-        new_resolved_conf += '[Resolve]\n'
-    new_resolved_conf += 'DNSStubListener=no\n'
-    remote.write_file(
-        path='/etc/systemd/resolved.conf',
-        data=new_resolved_conf,
-        sudo=True,
-    )
-    remote.run(args=['sudo', 'systemctl', 'restart', 'systemd-resolved'])
-    r = remote.run(args=['ss', '-lunH'], stdout=StringIO())
-    assert '%lo:53' not in r.stdout.getvalue()
-    # because docker is a big fat persistent deamon, we need to bounce it
-    # after resolved is restarted
-    remote.run(args=['sudo', 'systemctl', 'restart', 'docker'])
-
-
-def _reset_systemd_resolved(ctx, remote):
-    orig_resolved_conf = getattr(ctx, 'orig_resolved_conf', None)
-    if not orig_resolved_conf:
-        return  # no orig_resolved_conf means nothing to reset
-    log.info('Resetting systemd-resolved state on %s', remote.shortname)
-    remote.write_file(
-        path='/etc/systemd/resolved.conf',
-        data=orig_resolved_conf,
-        sudo=True,
-    )
-    remote.run(args=['sudo', 'systemctl', 'restart', 'systemd-resolved'])
-    setattr(ctx, 'orig_resolved_conf', None)
-
-
-def _samba_ad_dc_conf(ctx, remote, cengine):
-    # this config has not been tested outside of smithi nodes. it's possible
-    # that this will break when used elsewhere because we have to list
-    # interfaces explicitly. Later I may add a feature to sambacc to exclude
-    # known-unwanted interfaces that having to specify known good interfaces.
-    cf = {
-        "samba-container-config": "v0",
-        "configs": {
-            "demo": {
-                "instance_features": ["addc"],
-                "domain_settings": "sink",
-                "instance_name": "dc1",
-            }
-        },
-        "domain_settings": {
-            "sink": {
-                "realm": "DOMAIN1.SINK.TEST",
-                "short_domain": "DOMAIN1",
-                "admin_password": "Passw0rd",
-                "interfaces": {
-                    "exclude_pattern": "^docker[0-9]+$",
-                },
-            }
-        },
-        "domain_groups": {
-            "sink": [
-                {"name": "supervisors"},
-                {"name": "employees"},
-                {"name": "characters"},
-                {"name": "bulk"},
-            ]
-        },
-        "domain_users": {
-            "sink": [
-                {
-                    "name": "bwayne",
-                    "password": "1115Rose.",
-                    "given_name": "Bruce",
-                    "surname": "Wayne",
-                    "member_of": ["supervisors", "characters", "employees"],
-                },
-                {
-                    "name": "ckent",
-                    "password": "1115Rose.",
-                    "given_name": "Clark",
-                    "surname": "Kent",
-                    "member_of": ["characters", "employees"],
-                },
-                {
-                    "name": "user0",
-                    "password": "1115Rose.",
-                    "given_name": "George0",
-                    "surname": "Hue-Sir",
-                    "member_of": ["bulk"],
-                },
-                {
-                    "name": "user1",
-                    "password": "1115Rose.",
-                    "given_name": "George1",
-                    "surname": "Hue-Sir",
-                    "member_of": ["bulk"],
-                },
-                {
-                    "name": "user2",
-                    "password": "1115Rose.",
-                    "given_name": "George2",
-                    "surname": "Hue-Sir",
-                    "member_of": ["bulk"],
-                },
-                {
-                    "name": "user3",
-                    "password": "1115Rose.",
-                    "given_name": "George3",
-                    "surname": "Hue-Sir",
-                    "member_of": ["bulk"],
-                },
-            ]
-        },
-    }
-    cf_json = json.dumps(cf)
-    remote.run(args=['sudo', 'mkdir', '-p', '/var/tmp/samba'])
-    remote.write_file(
-        path='/var/tmp/samba/container.json', data=cf_json, sudo=True
-    )
-    return [
-        '--volume=/var/tmp/samba:/etc/samba-container:ro',
-        '-eSAMBACC_CONFIG=/etc/samba-container/container.json',
-    ]
-
-
-@contextlib.contextmanager
-def configure_samba_client_container(ctx, config):
-    # TODO: deduplicate logic between this task and deploy_samba_ad_dc
-    role = config.get('role')
-    samba_client_image = config.get(
-        'samba_client_image', 'quay.io/samba.org/samba-client:latest'
-    )
-    if not role:
-        raise ConfigError(
-            "you must specify a role to discover container engine / pull image"
-        )
-    (remote,) = ctx.cluster.only(role).remotes.keys()
-    cengine = 'podman'
-    try:
-        log.info("Testing if podman is available")
-        remote.run(args=['sudo', cengine, '--help'])
-    except CommandFailedError:
-        log.info("Failed to find podman. Using docker")
-        cengine = 'docker'
-
-    remote.run(args=['sudo', cengine, 'pull', samba_client_image])
-    samba_client_container_cmd = [
-        'sudo',
-        cengine,
-        'run',
-        '--rm',
-        '--net=host',
-        '-eKRB5_CONFIG=/dev/null',
-        samba_client_image,
-    ]
-
-    setattr(ctx, 'samba_client_container_cmd', samba_client_container_cmd)
-    try:
-        yield
-    finally:
-        setattr(ctx, 'samba_client_container_cmd', None)
-
-
-@contextlib.contextmanager
-def deploy_samba_ad_dc(ctx, config):
-    role = config.get('role')
-    ad_dc_image = config.get(
-        'ad_dc_image', 'quay.io/samba.org/samba-ad-server:latest'
-    )
-    samba_client_image = config.get(
-        'samba_client_image', 'quay.io/samba.org/samba-client:latest'
-    )
-    test_user_pass = config.get('test_user_pass', 'DOMAIN1\\ckent%1115Rose.')
-    if not role:
-        raise ConfigError(
-            "you must specify a role to allocate a host for the AD DC"
-        )
-    (remote,) = ctx.cluster.only(role).remotes.keys()
-    ip = remote.ssh.get_transport().getpeername()[0]
-    cengine = 'podman'
-    try:
-        log.info("Testing if podman is available")
-        remote.run(args=['sudo', cengine, '--help'])
-    except CommandFailedError:
-        log.info("Failed to find podman. Using docker")
-        cengine = 'docker'
-    remote.run(args=['sudo', cengine, 'pull', ad_dc_image])
-    remote.run(args=['sudo', cengine, 'pull', samba_client_image])
-    _disable_systemd_resolved(ctx, remote)
-    remote.run(
-        args=[
-            'sudo',
-            'mkdir',
-            '-p',
-            '/var/lib/samba/container/logs',
-            '/var/lib/samba/container/data',
-        ]
-    )
-    remote.run(
-        args=[
-            'sudo',
-            cengine,
-            'run',
-            '-d',
-            '--name=samba-ad',
-            '--network=host',
-            '--privileged',
-        ]
-        + _samba_ad_dc_conf(ctx, remote, cengine)
-        + [ad_dc_image]
-    )
-
-    # test that the ad dc is running and basically works
-    connected = False
-    samba_client_container_cmd = [
-        'sudo',
-        cengine,
-        'run',
-        '--rm',
-        '--net=host',
-        f'--dns={ip}',
-        '-eKRB5_CONFIG=/dev/null',
-        samba_client_image,
-    ]
-    for idx in range(10):
-        time.sleep((2 ** (1 + idx)) / 8)
-        log.info("Probing SMB status of DC %s, idx=%s", ip, idx)
-        cmd = samba_client_container_cmd + [
-            'smbclient',
-            '-U',
-            test_user_pass,
-            '//domain1.sink.test/sysvol',
-            '-c',
-            'ls',
-        ]
-        try:
-            remote.run(args=cmd)
-            connected = True
-            log.info("SMB status probe succeeded")
-            break
-        except CommandFailedError:
-            pass
-    if not connected:
-        raise RuntimeError('failed to connect to AD DC SMB share')
-
-    setattr(ctx, 'samba_ad_dc_ip', ip)
-    setattr(ctx, 'samba_client_container_cmd', samba_client_container_cmd)
-    try:
-        yield
-    finally:
-        try:
-            remote.run(args=['sudo', cengine, 'stop', 'samba-ad'])
-        except CommandFailedError:
-            log.error("Failed to stop samba-ad container")
-        try:
-            remote.run(args=['sudo', cengine, 'rm', 'samba-ad'])
-        except CommandFailedError:
-            log.error("Failed to remove samba-ad container")
-        remote.run(
-            args=[
-                'sudo',
-                'rm',
-                '-rf',
-                '/var/lib/samba/container/logs',
-                '/var/lib/samba/container/data',
-            ]
-        )
-        _reset_systemd_resolved(ctx, remote)
-        setattr(ctx, 'samba_ad_dc_ip', None)
-        setattr(ctx, 'samba_client_container_cmd', None)
-
-
 @contextlib.contextmanager
 def task(ctx, config):
     """
diff --git a/qa/tasks/smb.py b/qa/tasks/smb.py
new file mode 100644 (file)
index 0000000..23f49dc
--- /dev/null
@@ -0,0 +1,299 @@
+"""
+Ceph teuthology task for managed smb features.
+"""
+from io import StringIO
+import contextlib
+import logging
+import json
+import time
+
+from teuthology.exceptions import ConfigError, CommandFailedError
+
+
+log = logging.getLogger(__name__)
+
+
+def _disable_systemd_resolved(ctx, remote):
+    r = remote.run(args=['ss', '-lunH'], stdout=StringIO())
+    # this heuristic tries to detect if systemd-resolved is running
+    if '%lo:53' not in r.stdout.getvalue():
+        return
+    log.info('Disabling systemd-resolved on %s', remote.shortname)
+    # Samba AD DC container DNS support conflicts with resolved stub
+    # resolver when using host networking. And we want host networking
+    # because it is the simplest thing to set up.  We therefore will turn
+    # off the stub resolver.
+    r = remote.run(
+        args=['sudo', 'cat', '/etc/systemd/resolved.conf'],
+        stdout=StringIO(),
+    )
+    resolved_conf = r.stdout.getvalue()
+    setattr(ctx, 'orig_resolved_conf', resolved_conf)
+    new_resolved_conf = (
+        resolved_conf + '\n# EDITED BY TEUTHOLOGY: deploy_samba_ad_dc\n'
+    )
+    if '[Resolve]' not in new_resolved_conf.splitlines():
+        new_resolved_conf += '[Resolve]\n'
+    new_resolved_conf += 'DNSStubListener=no\n'
+    remote.write_file(
+        path='/etc/systemd/resolved.conf',
+        data=new_resolved_conf,
+        sudo=True,
+    )
+    remote.run(args=['sudo', 'systemctl', 'restart', 'systemd-resolved'])
+    r = remote.run(args=['ss', '-lunH'], stdout=StringIO())
+    assert '%lo:53' not in r.stdout.getvalue()
+    # because docker is a big fat persistent deamon, we need to bounce it
+    # after resolved is restarted
+    remote.run(args=['sudo', 'systemctl', 'restart', 'docker'])
+
+
+def _reset_systemd_resolved(ctx, remote):
+    orig_resolved_conf = getattr(ctx, 'orig_resolved_conf', None)
+    if not orig_resolved_conf:
+        return  # no orig_resolved_conf means nothing to reset
+    log.info('Resetting systemd-resolved state on %s', remote.shortname)
+    remote.write_file(
+        path='/etc/systemd/resolved.conf',
+        data=orig_resolved_conf,
+        sudo=True,
+    )
+    remote.run(args=['sudo', 'systemctl', 'restart', 'systemd-resolved'])
+    setattr(ctx, 'orig_resolved_conf', None)
+
+
+def _samba_ad_dc_conf(ctx, remote, cengine):
+    # this config has not been tested outside of smithi nodes. it's possible
+    # that this will break when used elsewhere because we have to list
+    # interfaces explicitly. Later I may add a feature to sambacc to exclude
+    # known-unwanted interfaces that having to specify known good interfaces.
+    cf = {
+        "samba-container-config": "v0",
+        "configs": {
+            "demo": {
+                "instance_features": ["addc"],
+                "domain_settings": "sink",
+                "instance_name": "dc1",
+            }
+        },
+        "domain_settings": {
+            "sink": {
+                "realm": "DOMAIN1.SINK.TEST",
+                "short_domain": "DOMAIN1",
+                "admin_password": "Passw0rd",
+                "interfaces": {
+                    "exclude_pattern": "^docker[0-9]+$",
+                },
+            }
+        },
+        "domain_groups": {
+            "sink": [
+                {"name": "supervisors"},
+                {"name": "employees"},
+                {"name": "characters"},
+                {"name": "bulk"},
+            ]
+        },
+        "domain_users": {
+            "sink": [
+                {
+                    "name": "bwayne",
+                    "password": "1115Rose.",
+                    "given_name": "Bruce",
+                    "surname": "Wayne",
+                    "member_of": ["supervisors", "characters", "employees"],
+                },
+                {
+                    "name": "ckent",
+                    "password": "1115Rose.",
+                    "given_name": "Clark",
+                    "surname": "Kent",
+                    "member_of": ["characters", "employees"],
+                },
+                {
+                    "name": "user0",
+                    "password": "1115Rose.",
+                    "given_name": "George0",
+                    "surname": "Hue-Sir",
+                    "member_of": ["bulk"],
+                },
+                {
+                    "name": "user1",
+                    "password": "1115Rose.",
+                    "given_name": "George1",
+                    "surname": "Hue-Sir",
+                    "member_of": ["bulk"],
+                },
+                {
+                    "name": "user2",
+                    "password": "1115Rose.",
+                    "given_name": "George2",
+                    "surname": "Hue-Sir",
+                    "member_of": ["bulk"],
+                },
+                {
+                    "name": "user3",
+                    "password": "1115Rose.",
+                    "given_name": "George3",
+                    "surname": "Hue-Sir",
+                    "member_of": ["bulk"],
+                },
+            ]
+        },
+    }
+    cf_json = json.dumps(cf)
+    remote.run(args=['sudo', 'mkdir', '-p', '/var/tmp/samba'])
+    remote.write_file(
+        path='/var/tmp/samba/container.json', data=cf_json, sudo=True
+    )
+    return [
+        '--volume=/var/tmp/samba:/etc/samba-container:ro',
+        '-eSAMBACC_CONFIG=/etc/samba-container/container.json',
+    ]
+
+
+@contextlib.contextmanager
+def configure_samba_client_container(ctx, config):
+    # TODO: deduplicate logic between this task and deploy_samba_ad_dc
+    role = config.get('role')
+    samba_client_image = config.get(
+        'samba_client_image', 'quay.io/samba.org/samba-client:latest'
+    )
+    if not role:
+        raise ConfigError(
+            "you must specify a role to discover container engine / pull image"
+        )
+    (remote,) = ctx.cluster.only(role).remotes.keys()
+    cengine = 'podman'
+    try:
+        log.info("Testing if podman is available")
+        remote.run(args=['sudo', cengine, '--help'])
+    except CommandFailedError:
+        log.info("Failed to find podman. Using docker")
+        cengine = 'docker'
+
+    remote.run(args=['sudo', cengine, 'pull', samba_client_image])
+    samba_client_container_cmd = [
+        'sudo',
+        cengine,
+        'run',
+        '--rm',
+        '--net=host',
+        '-eKRB5_CONFIG=/dev/null',
+        samba_client_image,
+    ]
+
+    setattr(ctx, 'samba_client_container_cmd', samba_client_container_cmd)
+    try:
+        yield
+    finally:
+        setattr(ctx, 'samba_client_container_cmd', None)
+
+
+@contextlib.contextmanager
+def deploy_samba_ad_dc(ctx, config):
+    role = config.get('role')
+    ad_dc_image = config.get(
+        'ad_dc_image', 'quay.io/samba.org/samba-ad-server:latest'
+    )
+    samba_client_image = config.get(
+        'samba_client_image', 'quay.io/samba.org/samba-client:latest'
+    )
+    test_user_pass = config.get('test_user_pass', 'DOMAIN1\\ckent%1115Rose.')
+    if not role:
+        raise ConfigError(
+            "you must specify a role to allocate a host for the AD DC"
+        )
+    (remote,) = ctx.cluster.only(role).remotes.keys()
+    ip = remote.ssh.get_transport().getpeername()[0]
+    cengine = 'podman'
+    try:
+        log.info("Testing if podman is available")
+        remote.run(args=['sudo', cengine, '--help'])
+    except CommandFailedError:
+        log.info("Failed to find podman. Using docker")
+        cengine = 'docker'
+    remote.run(args=['sudo', cengine, 'pull', ad_dc_image])
+    remote.run(args=['sudo', cengine, 'pull', samba_client_image])
+    _disable_systemd_resolved(ctx, remote)
+    remote.run(
+        args=[
+            'sudo',
+            'mkdir',
+            '-p',
+            '/var/lib/samba/container/logs',
+            '/var/lib/samba/container/data',
+        ]
+    )
+    remote.run(
+        args=[
+            'sudo',
+            cengine,
+            'run',
+            '-d',
+            '--name=samba-ad',
+            '--network=host',
+            '--privileged',
+        ]
+        + _samba_ad_dc_conf(ctx, remote, cengine)
+        + [ad_dc_image]
+    )
+
+    # test that the ad dc is running and basically works
+    connected = False
+    samba_client_container_cmd = [
+        'sudo',
+        cengine,
+        'run',
+        '--rm',
+        '--net=host',
+        f'--dns={ip}',
+        '-eKRB5_CONFIG=/dev/null',
+        samba_client_image,
+    ]
+    for idx in range(10):
+        time.sleep((2 ** (1 + idx)) / 8)
+        log.info("Probing SMB status of DC %s, idx=%s", ip, idx)
+        cmd = samba_client_container_cmd + [
+            'smbclient',
+            '-U',
+            test_user_pass,
+            '//domain1.sink.test/sysvol',
+            '-c',
+            'ls',
+        ]
+        try:
+            remote.run(args=cmd)
+            connected = True
+            log.info("SMB status probe succeeded")
+            break
+        except CommandFailedError:
+            pass
+    if not connected:
+        raise RuntimeError('failed to connect to AD DC SMB share')
+
+    setattr(ctx, 'samba_ad_dc_ip', ip)
+    setattr(ctx, 'samba_client_container_cmd', samba_client_container_cmd)
+    try:
+        yield
+    finally:
+        try:
+            remote.run(args=['sudo', cengine, 'stop', 'samba-ad'])
+        except CommandFailedError:
+            log.error("Failed to stop samba-ad container")
+        try:
+            remote.run(args=['sudo', cengine, 'rm', 'samba-ad'])
+        except CommandFailedError:
+            log.error("Failed to remove samba-ad container")
+        remote.run(
+            args=[
+                'sudo',
+                'rm',
+                '-rf',
+                '/var/lib/samba/container/logs',
+                '/var/lib/samba/container/data',
+            ]
+        )
+        _reset_systemd_resolved(ctx, remote)
+        setattr(ctx, 'samba_ad_dc_ip', None)
+        setattr(ctx, 'samba_client_container_cmd', None)