From 27d583ad22758d45451b95310732bae73d99f997 Mon Sep 17 00:00:00 2001 From: Chris Selzo Date: Fri, 19 Jun 2026 14:17:23 -0700 Subject: [PATCH] Restore non-essential systemd unit cleanup for jammy warden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bosh-docker-cpi-release#60 moved the cleanup of non-essential systemd units out of the Docker CPI and into the stemcell, on the basis that the stemcell would mask anything that can't run in a container (resolving bosh-docker-cpi-release#58 and #504). On the jammy line, only the systemd-binfmt mask landed (#500); the rest of the CPI's allow-list was never reproduced here. As a result, warden stemcells started with exec /sbin/init now boot the full stock systemd unit set. In a BOSH director the stock units contend with the monit-managed bpm jobs and the director fails to converge (e.g. the postgres role is never created). This regresses any consumer running a Docker-CPI director on a jammy warden stemcell ≥ the build that pairs with Docker CPI ≥ 0.2.9. This restores the CPI's historical allow-list in base_warden, removing the non-essential .wants entries at build time. It uses -delete (≡ systemctl disable) rather than mask, matching the CPI's original semantics: units are dropped from the boot sequence but can still start as dependencies of a kept unit. runit, ssh, dbus, journald, logrotate, systemd-tmpfiles, systemd-user-sessions, and the bosh-agent are preserved. Deriving the set at build time keeps it correct as the package set changes. Verified against ubuntu-jammy-stemcell:1.1250: 13 essential .wants entries kept, ~75 non-essential removed. This is the same prune Docker CPI 0.2.3 applied, which is green on cgroups-v1 workers. Adds a warden_spec assertion that non-essential units are removed and essential ones remain. Related: bosh-docker-cpi-release#60, bosh-docker-cpi-release#58, #500, ai-assisted=yes [TNZ-88995] --- bosh-stemcell/spec/stemcells/warden_spec.rb | 30 ++++++++++++++++++++ stemcell_builder/stages/base_warden/apply.sh | 30 ++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/bosh-stemcell/spec/stemcells/warden_spec.rb b/bosh-stemcell/spec/stemcells/warden_spec.rb index df2d074f2a..897d5644ad 100644 --- a/bosh-stemcell/spec/stemcells/warden_spec.rb +++ b/bosh-stemcell/spec/stemcells/warden_spec.rb @@ -58,4 +58,34 @@ its(:content) { should include('"UseMonitIptablesFirewall": true') } end end + + context "systemd unit cleanup for warden containers" do + # The Docker CPI runs warden stemcells with `exec /sbin/init`. base_warden + # strips non-essential stock systemd units from the boot sequence so they + # don't contend with the monit-managed bpm jobs in the BOSH director + # container (symptom: postgres role never created, bosh/0 never converges). + # Keep-list mirrors the historical Docker CPI allow-list. See + # base_warden/apply.sh and cloudfoundry/bosh-docker-cpi-release#60. + keep_patterns = %w[ + *bosh-agent* *dbus* *journald* *logrotate* *runit* *ssh* + *systemd-user-sessions* *systemd-tmpfiles* + ] + not_name = keep_patterns.map { |g| "-not -name '#{g}'" }.join(" ") + wants = "find /etc/systemd/system /lib/systemd/system -type l -path '*.wants/*'" + + describe "non-essential units are removed from the boot sequence" do + describe command("#{wants} #{not_name}") do + its(:exit_status) { should eq 0 } + its(:stdout) { should eq "" } + end + end + + describe "essential units are preserved (guards against an over-broad prune)" do + describe command(wants) do + its(:exit_status) { should eq 0 } + its(:stdout) { should include("runit.service") } + its(:stdout) { should include("ssh.service") } + end + end + end end diff --git a/stemcell_builder/stages/base_warden/apply.sh b/stemcell_builder/stages/base_warden/apply.sh index 7d1844495a..b19949d5fd 100755 --- a/stemcell_builder/stages/base_warden/apply.sh +++ b/stemcell_builder/stages/base_warden/apply.sh @@ -85,3 +85,33 @@ JSON # Mask systemd-binfmt.service which fails under Rosetta emulation run_in_chroot "$chroot" "systemctl mask systemd-binfmt.service" + +# Trim non-essential systemd units from the boot sequence. +# +# When the Docker CPI runs a warden stemcell with `exec /sbin/init`, full stock +# systemd comes up and its units contend with the monit-managed bpm jobs in the +# BOSH director container (symptom: the postgres role is never created and +# bosh/0 never converges). The Docker CPI used to strip these units at +# container-create time, but that allow-list prune was removed in +# cloudfoundry/bosh-docker-cpi-release#60 on the assumption the stemcell would +# take it over. The jammy stemcell only ever picked up the systemd-binfmt mask +# above, so we reproduce the CPI's full allow-list here. +# +# This removes the `.wants` symlinks (equivalent to `systemctl disable`): units +# are dropped from the boot sequence but can still start as dependencies of a +# kept unit. The keep patterns mirror the historical CPI list exactly. Deriving +# the set at build time keeps it correct as the stemcell's package set changes. +run_in_chroot "$chroot" " +find /etc/systemd/system /lib/systemd/system \ + -type l \ + -path '*.wants/*' \ + -not -name '*bosh-agent*' \ + -not -name '*dbus*' \ + -not -name '*journald*' \ + -not -name '*logrotate*' \ + -not -name '*runit*' \ + -not -name '*ssh*' \ + -not -name '*systemd-user-sessions*' \ + -not -name '*systemd-tmpfiles*' \ + -delete +"