diff --git a/podman-image/00-podman-machine.preset b/podman-image/00-podman-machine.preset index baadf427..5bb4a919 100644 --- a/podman-image/00-podman-machine.preset +++ b/podman-image/00-podman-machine.preset @@ -10,3 +10,6 @@ disable coreos-container-signing-migration-motd.service # Disable coreos chrony config, we do provide our own. disable coreos-platform-chrony-config.service + +# qemu-guest-agent (vsock) for macOS (vfkit, libkrun) and Linux (qemu); gated by systemd conditions. +enable qemu-guest-agent.service diff --git a/podman-image/Containerfile.COREOS b/podman-image/Containerfile.COREOS index a9e14afb..93a753af 100644 --- a/podman-image/Containerfile.COREOS +++ b/podman-image/Containerfile.COREOS @@ -1,4 +1,13 @@ ARG FCOS_BASE_IMAGE=${FCOS_BASE_IMAGE} + +# Compile SELinux in a throwaway stage using the same base as the final image so policy module +# format matches (fedora:latest can emit a newer policydb than FCOS semodule accepts). +FROM ${FCOS_BASE_IMAGE} AS qemu_guest_agent_vsock_selinux +COPY qemu_guest_agent_vsock.te /qemu_guest_agent_vsock.te +RUN dnf install -y checkpolicy policycoreutils && dnf clean all && \ + checkmodule -M -m -o /qemu_guest_agent_vsock.mod /qemu_guest_agent_vsock.te && \ + semodule_package -o /qemu_guest_agent_vsock.pp -m /qemu_guest_agent_vsock.mod + FROM ${FCOS_BASE_IMAGE} ARG PODMAN_PR_NUM=${PODMAN_PR_NUM} @@ -45,3 +54,8 @@ RUN --network=none rm -vf /etc/resolv.conf && rpm -e systemd-resolved # https://github.com/containers/podman/pull/21670#discussion_r1585790802 COPY rosetta-activation.service /etc/systemd/system/rosetta-activation.service COPY rosetta-activation.sh /usr/local/bin/rosetta-activation.sh + +# qemu-guest-agent over vsock +COPY --from=qemu_guest_agent_vsock_selinux /qemu_guest_agent_vsock.pp /tmp/qemu_guest_agent_vsock.pp +RUN semodule -i /tmp/qemu_guest_agent_vsock.pp && rm -f /tmp/qemu_guest_agent_vsock.pp +COPY qemu-guest-agent.service /etc/systemd/system/qemu-guest-agent.service diff --git a/podman-image/build_common.sh b/podman-image/build_common.sh index ff6869f1..a380458f 100755 --- a/podman-image/build_common.sh +++ b/podman-image/build_common.sh @@ -107,6 +107,9 @@ PACKAGES=( # git-core for Containerfile `ADD ` clone feature git-core + + # Guest agent (vsock) for time sync and host-guest features (macOS vfkit/libkrun, Linux qemu) + qemu-guest-agent ) dnf install -y "${PACKAGES[@]}" diff --git a/podman-image/qemu-guest-agent.service b/podman-image/qemu-guest-agent.service new file mode 100644 index 00000000..0bad0d5e --- /dev/null +++ b/podman-image/qemu-guest-agent.service @@ -0,0 +1,15 @@ +[Unit] +Description=QEMU Guest Agent +IgnoreOnIsolate=true +ConditionVirtualization=|kvm +ConditionVirtualization=|apple +ConditionFirmware=|smbios-field(sys_vendor = Libkrun) + +[Service] +UMask=0077 +ExecStart=/usr/bin/qemu-ga --method=vsock-listen --path=3:1234 +Restart=on-failure +RestartSec=5s + +[Install] +WantedBy=default.target diff --git a/podman-image/qemu_guest_agent_vsock.te b/podman-image/qemu_guest_agent_vsock.te new file mode 100644 index 00000000..f46cf07a --- /dev/null +++ b/podman-image/qemu_guest_agent_vsock.te @@ -0,0 +1,9 @@ +module qemu_guest_agent_vsock 1.0; + +require { + type virt_qemu_ga_t; + class vsock_socket { bind create getattr listen accept read write }; +} + +#============= virt_qemu_ga_t ============== +allow virt_qemu_ga_t self:vsock_socket { bind create getattr listen accept read write }; diff --git a/verify/image_test.go b/verify/image_test.go index 7ca833d3..80d32c20 100644 --- a/verify/image_test.go +++ b/verify/image_test.go @@ -118,6 +118,34 @@ var _ = Describe("run image tests", Ordered, ContinueOnFailure, func() { Expect(rosettaSession).To(Exit(0)) Expect(rosettaSession.outputToString()).To(Equal("active")) }) + It("should ship qemu-guest-agent for vsock (FCOS images)", func() { + skipIfVmtype(WSLVirt, "WSL image does not use the CoreOS Containerfile customizations") + rpmCmd := []string{"machine", "ssh", machineName, "rpm", "-q", "qemu-guest-agent"} + rpmSession, err := mb.setCmd(rpmCmd).run() + Expect(err).ToNot(HaveOccurred()) + Expect(rpmSession).To(Exit(0)) + Expect(rpmSession.outputToString()).To(ContainSubstring("qemu-guest-agent")) + + catCmd := []string{"machine", "ssh", machineName, "systemctl", "cat", "qemu-guest-agent.service"} + catSession, err := mb.setCmd(catCmd).run() + Expect(err).ToNot(HaveOccurred()) + Expect(catSession).To(Exit(0)) + out := catSession.outputToString() + Expect(out).To(ContainSubstring("vsock-listen")) + Expect(out).To(ContainSubstring("--path=3:1234")) + }) + It("should have qemu-guest-agent active on Linux and macOS providers", func() { + skipIfVmtype(WSLVirt, "WSL image does not include qemu-guest-agent") + skipIfVmtype(HyperVVirt, "HyperV does not expose a vsock channel for qemu-guest-agent") + cmd := []string{"machine", "ssh", machineName, "systemctl", "-P", "ActiveState", "show", "qemu-guest-agent.service"} + session, err := mb.setCmd(cmd).run() + Expect(err).ToNot(HaveOccurred()) + Expect(session).To(Exit(0)) + // "active" when the host exposes the vsock channel, "activating" when + // qemu-ga is in a restart loop because the host side is not yet wired up. + // Both confirm that the systemd conditions matched and the service was started. + Expect(session.outputToString()).To(Or(Equal("active"), Equal("activating"))) + }) It("should have zero critical error messages journalctl", func() { skipIfVmtype(LibKrun, "TODO: analyze the error messages in journalctl when using libkrun") skipIfVmtype(AppleHvVirt, "TODO: analyze the error messages in journalctl when using applehv")