diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b652dd4..eae183e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,11 @@ jobs: run: ./venv/bin/ceph-devstack -v start - name: Check Status run: podman ps -a + - name: Check ssh access to testnode container + run: sleep 10 && podman exec teuthology ssh -oBatchMode=yes -v "cm@$(podman inspect --format '{{ slice .ID 0 12 }}' testnode_0)" whoami + - name: Dump testnode journal + if: failure() + run: podman exec testnode_0 journalctl - name: Wait run: ./venv/bin/ceph-devstack wait teuthology - name: Dump logs diff --git a/ceph_devstack/host.py b/ceph_devstack/host.py index 1fcca5f4..6f50f8fd 100644 --- a/ceph_devstack/host.py +++ b/ceph_devstack/host.py @@ -1,3 +1,4 @@ +import asyncio import logging import os import pathlib @@ -44,7 +45,7 @@ async def arun( cwd: Optional[pathlib.Path] = None, env: Optional[Dict] = None, stream_output: bool = False, - ): + ) -> asyncio.subprocess.Process: return await self.cmd( args, cwd=cwd, env=env, stream_output=stream_output ).arun() @@ -107,6 +108,10 @@ async def get_sysctl_value(self, name: str) -> int: out = await proc.stdout.read() return int(out.decode().strip()) + async def apparmor_enabled(self) -> bool: + proc = await host.arun(["aa-enabled", "-q"]) + return await proc.wait() == 0 + class LocalHost(Host): pass diff --git a/ceph_devstack/requirements.py b/ceph_devstack/requirements.py index 090dc804..2d71ba0e 100644 --- a/ceph_devstack/requirements.py +++ b/ceph_devstack/requirements.py @@ -1,3 +1,4 @@ +import shlex import sys from pathlib import Path @@ -35,7 +36,7 @@ async def evaluate(self) -> bool: async def suggest(self): if hasattr(self, "suggest_msg"): - logger.error(f"{self.suggest_msg}. Try: {' '.join(self.fix_cmd)}") + logger.error(f"{self.suggest_msg}. Try: {shlex.join(self.fix_cmd)}") async def fix(self) -> bool: assert self.fix_cmd, "Attempted to fix without a fix command" @@ -217,6 +218,19 @@ class FuseOverlayfsPresence(FixableRequirement): fix_cmd = ["sudo", "dnf", "install", "-y", "fuse-overlayfs"] +class AppArmorProfile(FixableRequirement): + _profile_path = "/etc/apparmor.d/local/unix-chkpwd" + _profile_content = '"capability dac_override,"' + check_cmd = ["test", "-f", _profile_path] + suggest_msg = "Did not find required apparmor profile" + fix_cmd = [ + "sudo", + "bash", + "-c", + f"echo -e {_profile_content} > {_profile_path} && systemctl reload apparmor", + ] + + async def check_requirements(): if not await PodmanPlatform().evaluate(): return False @@ -248,6 +262,10 @@ async def check_requirements(): result = result and await SELinuxBoolean("container_manage_cgroup").evaluate() result = result and await SELinuxBoolean("container_use_devices").evaluate() + # AppArmor + if await host.apparmor_enabled(): + result = result and await AppArmorProfile().evaluate() + # podman DNS plugin if not await PodmanVersion("5.0").evaluate(): result = result and await PodmanDNSPlugin().evaluate()