Swap puppet compiler ENC to the encapic Go binary
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful

The uv/python encapi-enc ENC script resolves its dependencies on first
invocation inside each fresh compiler pod; that resolution fails on cold pods
(exits 135/2), breaking puppet agent catalog compilation. encapic is a
stdlib-only Go replacement with no runtime dependency resolution.

- Point the compiler external_nodes at /opt/bin/encapic.
- Rework the setup-shared-bins init container to curl the encapic v0.1.0
  linux/amd64 release binary (sha256-verified, installed 0755) instead of
  copying the python script and installing uv.
- Remove the puppet-encapi-enc configmap generator, volume, mount, and the
  resources/encapi-enc script; uv was used solely by that script, so its
  installation is removed too.
This commit is contained in:
benvin
2026-07-25 09:58:02 +10:00
parent 3af12180fd
commit a4ab25778a
4 changed files with 14 additions and 77 deletions
@@ -187,28 +187,28 @@ spec:
- -c
args:
- |
set -e
echo "Setting up shared binaries..."
mkdir -p /opt/bin
mkdir -p /opt/bin/.cache/uv
# Copy encapi ENC script to shared bin volume
cp /configmaps/encapi-enc /opt/bin/encapi-enc
chmod +x /opt/bin/encapi-enc
# Install uv to shared bin volume
# Install the encapic ENC client (stdlib-only Go binary) to the shared
# bin volume. It replaces the uv/python ENC script, whose
# first-invocation dependency resolution failed on fresh compiler pods.
ENCAPIC_VERSION=v0.1.0
BASE=https://git.unkin.net/unkin/encapic/releases/download/$ENCAPIC_VERSION
cd /tmp
wget -O uv-x86_64-unknown-linux-gnu.tar.gz https://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/github/astral-sh/uv/releases/download/0.9.20/uv-x86_64-unknown-linux-gnu.tar.gz
tar xf uv-x86_64-unknown-linux-gnu.tar.gz
cp uv-x86_64-unknown-linux-gnu/uv /opt/bin/uv
chmod +x /opt/bin/uv
curl -fsSL -o encapic "$BASE/encapic_linux_amd64"
curl -fsSL -o encapic.sha256 "$BASE/encapic_linux_amd64.sha256"
# The published checksum names the release asset; verify against the
# file we downloaded regardless of the recorded filename.
EXPECTED=$(awk '{print $1}' encapic.sha256)
echo "$EXPECTED encapic" | sha256sum -c -
install -m 0755 encapic /opt/bin/encapic
echo "Shared binaries setup completed"
volumeMounts:
- mountPath: /opt/bin/
name: puppet-shared-bins
- mountPath: /configmaps/encapi-enc
name: puppet-encapi-enc
subPath: encapi-enc
securityContext:
fsGroup: 999
volumes:
@@ -231,9 +231,6 @@ spec:
- name: compiler-autosign-conf
configMap:
name: compiler-autosign.conf
- name: puppet-encapi-enc
configMap:
name: puppet-encapi-enc
- name: puppet-shared-bins
persistentVolumeClaim:
claimName: puppet-shared-bins
-5
View File
@@ -53,11 +53,6 @@ configMapGenerator:
- resources/compiler/puppetdb.conf
options:
disableNameSuffixHash: true
- name: puppet-encapi-enc
files:
- resources/encapi-enc
options:
disableNameSuffixHash: true
- name: additional-ruby-gems
files:
- resources/additional-ruby-gems.sh
@@ -11,7 +11,7 @@ logdir = /var/log/puppetlabs/puppetserver
rundir = /var/run/puppetlabs/puppetserver
pidfile = /var/run/puppetlabs/puppetserver/puppetserver.pid
node_terminus = exec
external_nodes = /opt/bin/encapi-enc
external_nodes = /opt/bin/encapic
autosign = /etc/puppetlabs/puppet/autosign.conf
storeconfigs = true
storeconfigs_backend = puppetdb
-55
View File
@@ -1,55 +0,0 @@
#!/usr/bin/env -S /opt/bin/uv run --quiet --cache-dir /opt/bin/.cache/uv --script
# /// script
# requires-python = ">=3.11"
# dependencies = ['pyyaml','requests']
# ///
"""
External Node Classifier (ENC) for Puppet.
If the environment specified in the YAML file is 'testing',
the environment is not included in the output.
"""
import os
import sys
import yaml
import requests
# In-cluster encapi service (cobbler-wire-compatible endpoint). Plain HTTP,
# so no CA bundle is needed. Overridable via ENCAPI_URL.
ENCAPI_URL = os.environ.get("ENCAPI_URL", "http://encapi.encapi.svc.cluster.local")
def fetch_enc_data(base_url: str, hostname: str) -> str:
"""
Fetches and modifies ENC data from a given URL to ensure classes are in list format.
"""
url = f"{base_url}/cblr/svc/op/puppet/hostname/{hostname}"
try:
response = requests.get(url)
response.raise_for_status()
except requests.RequestException as e:
sys.exit(f"Request failed: {e}")
data = yaml.safe_load(response.text)
data["parameters"] = data.get("parameters", {})
# Ensure 'classes' is in the desired list format
if "classes" in data:
if isinstance(data["classes"], dict):
data["parameters"]["enc_role"] = list(data["classes"].keys())
data["classes"] = list(data["classes"].keys())
else:
data["parameters"]["enc_role"] = list(data["classes"])
data["classes"] = list(data["classes"])
if "environment" in data:
data["parameters"]["enc_env"] = data["environment"]
if data["environment"] == "testing":
del data["environment"]
return yaml.dump(data)
if __name__ == "__main__":
if len(sys.argv) != 2:
sys.exit(f"Usage: {sys.argv[0]} <hostname>")
print(fetch_enc_data(ENCAPI_URL, sys.argv[1]))