From 7f6f269f0dc2e13b9e7d8368075ccf3866f914d7 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Mon, 4 Mar 2024 07:33:32 +0100 Subject: [PATCH] tasks: Bind the host's podman API socket This paves the way for spawning per-job tasks containers from the container (via `job-runner`). Getting the permissions right is unfortunately annoyingly complicated, as the host's socket has 660 permissions, but the tasks container runs as uid 1111. Ideally we could use something like -v "${XDG_RUNTIME_DIR:-/run}/podman/podman.sock:/podman.sock:idmap=gids=$(id -g)-1111-1" but that fails with "invalid mappings", and is generally not well documented. `--mount=type=bind,[...],idmap --uidmap [...]` does not work either. So resort to file permissions for the host's `podman.sock`: - For local developers in `run-local.sh`, make the socket world writable. This does not actually hurt for a human developer: Its directory (/run/user/uid) is not accessible for any other user. - For production, set the socket group to `1111`. That doesn't matter much, the secrets are all already chmod'ed to the container user, and these machines don't do anything else. `setfacl` would be more targeted, but it isn't installed in Fedora IoT/CoreOS. --- .github/workflows/tests.yml | 8 ++++++++ tasks/install-service | 6 ++++++ tasks/run-local.sh | 23 ++++++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1200de01..d3e725be 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,6 +35,14 @@ jobs: git config user.email github-actions@github.com git rebase origin/main + # HACK: Ubuntu 22.04 has podman 3.4, which isn't compatible with podman-remote 4 in our tasks container + # This PPA is a backport of podman 4.3 from Debian 12; drop this when moving `runs-on:` to ubuntu-24.04 + - name: Update to newer podman + run: | + sudo add-apt-repository -y ppa:quarckster/containers + sudo apt install -y podman + systemctl --user daemon-reload + - name: Check which containers changed id: containers_changed run: | diff --git a/tasks/install-service b/tasks/install-service index cdf27f97..62c3c225 100755 --- a/tasks/install-service +++ b/tasks/install-service @@ -36,6 +36,8 @@ touch "$IMAGE_STORES" cat < /etc/systemd/system/cockpit-tasks@.service [Unit] Description=Cockpit Tasks %i +Requires=podman.socket +After=podman.socket [Service] Environment="TEST_JOBS=${TEST_JOBS:-8}" @@ -53,6 +55,8 @@ ExecStartPre=-/usr/bin/podman network rm cockpit-tasks-%i ExecStartPre=/usr/bin/chcon -R -l s0 \${TEST_CACHE}/images/ ExecStartPre=/usr/bin/flock /tmp/cockpit-image-pull podman pull quay.io/cockpit/tasks ExecStartPre=/usr/bin/podman network create cockpit-tasks-%i +# idmapped mount would be better, but did not figure out how +ExecStartPre=/usr/bin/chgrp 1111 %t/podman/podman.sock ExecStart=/usr/bin/podman run --name=cockpit-tasks-%i --hostname=${CONTAINER_HOSTNAME} \ --device=/dev/kvm --network=cockpit-tasks-%i \ --memory=24g --pids-limit=16384 --shm-size=1024m ${TMPVOL:-} \ @@ -61,8 +65,10 @@ ExecStart=/usr/bin/podman run --name=cockpit-tasks-%i --hostname=${CONTAINER_HOS --volume=\${TEST_SECRETS}/webhook:/run/secrets/webhook:ro \ --volume=${IMAGE_STORES}:/work/.config/cockpit-dev/image-stores:ro \ --volume=/etc/npmrc:/etc/npmrc:ro \ + --volume=%t/podman/podman.sock:/podman.sock:rw \ --env=COCKPIT_GITHUB_TOKEN_FILE=/run/secrets/webhook/.config--github-token \ --env=COCKPIT_S3_KEY_DIR=/run/secrets/tasks/s3-keys \ + --env=CONTAINER_HOST=unix:///podman.sock \ --env=TEST_JOBS=\${TEST_JOBS} \ --env=TEST_NOTIFICATION_MX=\${TEST_NOTIFICATION_MX} \ --env=TEST_NOTIFICATION_TO=\${TEST_NOTIFICATION_TO} \ diff --git a/tasks/run-local.sh b/tasks/run-local.sh index 2cb56a5d..934abb6a 100755 --- a/tasks/run-local.sh +++ b/tasks/run-local.sh @@ -99,8 +99,14 @@ EOF echo 'cockpituous foobarfoo' > tasks/s3-keys/localhost.localdomain ) - # need to make files world-readable, as containers run as different user + # start podman API + systemctl $([ $(id -u) -eq 0 ] || echo "--user") start podman.socket + + # need to make files world-readable, as containers run as different user 1111 chmod -R go+rX "$SECRETS" + # for the same reason, make podman socket accessible to that container user + # the directory is only accessible for the user, so 666 permissions don't hurt + chmod o+rw ${XDG_RUNTIME_DIR:-/run}/podman/podman.sock fi } @@ -173,6 +179,8 @@ EOF podman run -d -it --name cockpituous-tasks --pod=cockpituous \ -v "$SECRETS"/tasks:/run/secrets/tasks:ro,z \ -v "$SECRETS"/webhook:/run/secrets/webhook:ro,z \ + -v "${XDG_RUNTIME_DIR:-/run}/podman/podman.sock:/podman.sock" \ + --env=CONTAINER_HOST=unix:///podman.sock \ --env=COCKPIT_GITHUB_TOKEN_FILE=/run/secrets/webhook/.config--github-token \ --env=COCKPIT_CA_PEM=/run/secrets/webhook/ca.pem \ --env=COCKPIT_BOTS_REPO=${COCKPIT_BOTS_REPO:-} \ @@ -195,6 +203,9 @@ cleanup_containers() { # clean up dummy token, so that image-prune does not try to use it rm "$SECRETS"/webhook/.config--github-token + # revert podman socket permission change + chmod o-rw ${XDG_RUNTIME_DIR:-run}/podman/podman.sock + podman stop --time=0 cockpituous-tasks } @@ -334,6 +345,15 @@ test_queue() { echo "$OUT" | grep -q 'queue public does not exist' } +test_podman() { + # tasks can connect to host's podman service + # this will be covered implicitly by job-runner, but as a more basal plumbing test this is easier to debug + out="$(podman exec -i cockpituous-tasks podman-remote ps)" + assert_in 'cockpituous-tasks' "$out" + out="$(podman exec -i cockpituous-tasks podman-remote run -it --rm quay.io/cockpit/tasks:latest whoami)" + assert_in '^user' "$out" +} + # # main # @@ -352,6 +372,7 @@ else # tests which don't need GitHub interaction test_image test_queue + test_podman # "almost" end-to-end, starting with GitHub webhook JSON payload injection; fully localy, no privs test_mock_pr # if we have a PR number, run a unit test inside local deployment, and update PR status