Swap puppet compiler ENC to the encapic Go binary (#277)

## Why

The puppet-on-k8s compilers classify nodes with a uv/python ENC script (`encapi-enc`). Each fresh compiler pod resolves the script's python dependencies on first invocation, and that resolution fails on cold pods (observed exits 135/2), breaking puppet agent catalog compilation. `encapic` (git.unkin.net/unkin/encapic) is a stdlib-only Go replacement with no runtime dependency resolution — a behavioural drop-in whose output matches the python script byte-for-byte.

## Changes

- Points the compiler `external_nodes` at `/opt/bin/encapic`.
- Reworks the `setup-shared-bins` init container to `curl` the encapic `v0.1.0` `encapic_linux_amd64` release binary (sha256-verified against the published `.sha256`, installed mode 0755) into the shared bins dir, instead of copying the python script and installing uv.
- Removes the `puppet-encapi-enc` configmap generator, its volume and mount, and the `resources/encapi-enc` script. uv was consumed solely by that script (grep of `apps/base/puppet` confirms no other consumer), so its installation is removed too.

`kubectl kustomize apps/overlays/au-syd1/puppet` builds clean.

## Merge gate

Do not merge until the encapic `v0.1.0` release assets exist:
`https://git.unkin.net/unkin/encapic/releases/download/v0.1.0/encapic_linux_amd64` (+ `.sha256`). The init container pulls them at pod start.

## Rollback

Revert this PR to restore the `encapi-enc` configmap script + uv install and repoint `external_nodes`.

---------

Co-authored-by: benvin <neotheo@gmail.com>
Reviewed-on: #277
Co-authored-by: Ben Vincent <ben@unkin.net>
Co-committed-by: Ben Vincent <ben@unkin.net>
This commit was merged in pull request #277.
This commit is contained in:
2026-07-25 12:40:42 +10:00
committed by BenVincent
parent 3af12180fd
commit 05318553d6
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]))