profiles::puppet::server: restart puppetserver when its JVM binary is replaced
ci/woodpecker/pr/puppet-lint Pipeline was successful
ci/woodpecker/pr/ruby-validate Pipeline was successful
ci/woodpecker/pr/yamllint Pipeline was successful
ci/woodpecker/pr/erb-validate Pipeline was successful
ci/woodpecker/pr/bolt-validate Pipeline was successful
ci/woodpecker/pr/epp-validate Pipeline was successful
ci/woodpecker/pr/puppet-validate Pipeline was successful
ci/woodpecker/pr/ruby-check Pipeline was successful

An out-of-band OpenJDK upgrade (java-17-openjdk 17.0.18 -> 17.0.19, delivered
by the AlmaLinux repo migration in #496) removed the old versioned JAVA_HOME
while the puppetserver JVMs kept running against the now-deleted files. The
running JVM re-execs jspawnhelper from its original (deleted) JAVA_HOME on every
posix_spawn, so ProcessBuilder fails with "error=2, No such file or directory".
That broke the exec ENC (/opt/cobbler-enc/cobbler-enc) and 500'd every catalog
compile across all 6 masters, failing 136/143 nodes. The masters could not
self-heal because nothing restarts the JVM on a java upgrade.

Add a puppetserver-jvm-guard systemd timer (every 5 min) that detects a
puppetserver JVM executing from deleted binaries and restarts the service,
so any future JVM/library upgrade recovers automatically.

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
This commit is contained in:
2026-07-30 00:46:32 +10:00
parent 72bcbacddb
commit 85a5afda6b
+60
View File
@@ -134,4 +134,64 @@ class profiles::puppet::server (
enable => true,
require => File['/usr/local/bin/puppet_generate_types.sh'],
}
# Guard against an OpenJDK (or other JVM library) package upgrade landing
# underneath a long-running puppetserver. When the java package is replaced
# out-of-band (e.g. a yum repo/version bump), the old versioned JAVA_HOME is
# removed while the JVM keeps running against the now-deleted files. The JVM
# still execs jspawnhelper from its original (deleted) JAVA_HOME on every
# subprocess spawn, so ProcessBuilder fails with "error=2, No such file or
# directory" -- which breaks the exec ENC (/opt/cobbler-enc/cobbler-enc) and
# 500s every catalog compile fleet-wide. A restart re-binds to the new JVM.
# This timer detects the running JVM executing from deleted binaries and
# restarts the service to recover automatically.
file { '/usr/local/bin/puppetserver_jvm_guard.sh':
ensure => file,
mode => '0755',
content => @(EOF),
#!/bin/bash
# Restart puppetserver if its running JVM is executing deleted binaries
# (e.g. an OpenJDK package upgrade replaced the versioned JAVA_HOME),
# which breaks subprocess spawning and thus ENC / catalog compilation.
for pid in $(pgrep -f puppet-server-release.jar); do
exe=$(readlink "/proc/${pid}/exe" 2>/dev/null)
case "${exe}" in
*'(deleted)'*)
logger -t puppetserver-jvm-guard "puppetserver JVM (pid ${pid}) running on deleted binaries; restarting"
systemctl restart puppetserver
exit 0
;;
esac
done
exit 0
| EOF
}
$_guard_timer = @(EOT)
[Unit]
Description=puppetserver JVM guard timer
[Timer]
OnCalendar=*:0/5
RandomizedDelaySec=30s
[Install]
WantedBy=timers.target
EOT
$_guard_service = @(EOT)
[Unit]
Description=puppetserver JVM guard service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/puppetserver_jvm_guard.sh
User=root
Group=root
EOT
systemd::timer { 'puppetserver-jvm-guard.timer':
timer_content => $_guard_timer,
service_content => $_guard_service,
active => true,
enable => true,
require => File['/usr/local/bin/puppetserver_jvm_guard.sh'],
}
}