provisioning-catalog/components/cert_manager/cluster/cert_manager-lib.sh

150 lines
5.1 KiB
Bash

#!/bin/bash
# Methods library for cert_manager — sourced by run-*.sh and install-cert_manager.sh.
# SCRIPT_DIR must be set by the caller before sourcing.
_kubectl() {
if command -v kubectl >/dev/null 2>&1; then
command kubectl "$@"
elif command -v k0s >/dev/null 2>&1; then
k0s kubectl "$@"
else
echo "ERROR: no kubectl or k0s binary found" >&2; exit 127
fi
}
_resolve_kubeconfig() {
if [ -n "${KUBECONFIG:-}" ] && [ -f "$KUBECONFIG" ]; then
return
fi
for candidate in \
/var/lib/k0s/pki/admin.conf \
/etc/kubernetes/admin.conf \
/root/.kube/config; do
if [ -f "$candidate" ]; then
export KUBECONFIG="$candidate"
return
fi
done
if command -v k0s >/dev/null 2>&1; then
local tmp
tmp="$(mktemp)"
k0s kubeconfig admin > "$tmp" 2>/dev/null && export KUBECONFIG="$tmp" && return
rm -f "$tmp"
fi
echo "ERROR: kubeconfig not found — set KUBECONFIG explicitly" >&2; exit 1
}
_require_env() {
local var="$1"
if [ -z "${!var:-}" ]; then
echo "ERROR: required variable $var is not set" >&2; exit 1
fi
}
_plan_apply() {
local file="$1"
local path="$SCRIPT_DIR/manifests/${file}.yaml"
[ -f "$path" ] || { echo " [skip] ${file}.yaml not in manifests/"; return 0; }
local content
content=$(sed '/^\s*#/d; /^\s*$/d' "$path" | tr -d '[:space:]')
[ -n "$content" ] || { echo " [skip] ${file}.yaml has no content"; return 0; }
_kubectl apply -f "$path"
}
_plan_apply_skip() {
local file="$1"
local path="$SCRIPT_DIR/manifests/${file}.yaml"
[ -f "$path" ] || { echo " [skip] ${file}.yaml not in manifests/"; return 0; }
[ -s "$path" ] || { echo " [skip] ${file}.yaml is empty"; return 0; }
if _kubectl get -f "$path" >/dev/null 2>&1; then
echo " [skip] $file already exists in cluster"
return 0
fi
_kubectl apply -f "$path"
}
_plan_delete() {
local file="$1"
local path="$SCRIPT_DIR/manifests/${file}.yaml"
[ -f "$path" ] || { echo " [skip] ${file}.yaml not in manifests/"; return 0; }
[ -s "$path" ] || { echo " [skip] ${file}.yaml is empty"; return 0; }
_kubectl delete -f "$path" --ignore-not-found
}
_method_apply_bundle() {
local version="${CERT_MANAGER_VERSION:-v1.19.5}"
local url="https://github.com/cert-manager/cert-manager/releases/download/${version}/cert-manager.yaml"
local bundle="${SCRIPT_DIR}/cert-manager.yaml"
if [ ! -f "$bundle" ]; then
echo " [apply_bundle] downloading cert-manager ${version}"
curl -fsSL "$url" -o "$bundle"
else
echo " [apply_bundle] bundle already present, skipping download"
fi
_kubectl apply --server-side -f "$bundle"
}
# Patch the cert-manager controller deployment to bypass cluster CoreDNS during
# DNS-01 challenge verification. Without this, _acme-challenge.* lookups can hit
# split-horizon zone blocks that lack `fallthrough`, returning SERVFAIL and
# stalling the challenge indefinitely.
_method_patch_recursive_dns() {
local ns="${CERT_MANAGER_NAMESPACE:-cert-manager}"
local ns_csv="${CERT_MANAGER_DNS01_RECURSIVE_NS:-1.1.1.1:53,8.8.8.8:53}"
local only="${CERT_MANAGER_DNS01_RECURSIVE_ONLY:-true}"
[ -n "$ns_csv" ] || { echo " [patch_recursive_dns] no nameservers configured, skipping"; return 0; }
local args="[\"--dns01-recursive-nameservers=${ns_csv}\""
if [ "$only" = "true" ] || [ "$only" = "1" ]; then
args="${args},\"--dns01-recursive-nameservers-only\""
fi
args="${args}]"
echo " [patch_recursive_dns] dns01 recursive nameservers: ${ns_csv} (only=${only})"
local current
current=$(_kubectl get deployment cert-manager -n "$ns" -o jsonpath='{.spec.template.spec.containers[0].args}' 2>/dev/null || true)
local needs_ns_arg=true needs_only_arg=false patched=false
[[ "$current" == *"--dns01-recursive-nameservers=${ns_csv}"* ]] && needs_ns_arg=false
if [ "$only" = "true" ] || [ "$only" = "1" ]; then
[[ "$current" != *"--dns01-recursive-nameservers-only"* ]] && needs_only_arg=true
fi
if $needs_ns_arg; then
_kubectl patch deployment cert-manager \
--namespace "$ns" \
--type=json \
-p "[{\"op\":\"add\",\"path\":\"/spec/template/spec/containers/0/args/-\",\"value\":\"--dns01-recursive-nameservers=${ns_csv}\"}]" \
>/dev/null 2>&1 || true
patched=true
fi
if $needs_only_arg; then
_kubectl patch deployment cert-manager \
--namespace "$ns" \
--type=json \
-p '[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--dns01-recursive-nameservers-only"}]' \
>/dev/null 2>&1 || true
patched=true
fi
if $patched; then
echo " [patch_recursive_dns] args added to deployment"
else
echo " [patch_recursive_dns] args already present — no change"
fi
_kubectl rollout status deployment cert-manager -n "$ns" --timeout=120s
}
_method_wait-ready() {
local kind="${PLAN_PARAM_KIND:-deployment}"
local ns="${PLAN_PARAM_NAMESPACE:-cert-manager}"
local name="${PLAN_PARAM_NAME:-}"
local timeout="${PLAN_PARAM_TIMEOUT:-120s}"
[ -n "$name" ] || { echo "ERROR: PLAN_PARAM_NAME not set for wait-ready" >&2; exit 1; }
_kubectl wait --for=condition=Available \
"${kind}/${name}" \
--namespace "$ns" \
--timeout="$timeout"
}