From 2a6971df039bdcf51669b69efa08025f28230d79 Mon Sep 17 00:00:00 2001 From: nholtware Date: Tue, 10 Nov 2026 13:15:00 -0600 Subject: [PATCH] feat(new-service): render __DOMAIN__ from INGRESS_DOMAIN; HTTPS URLs and health checks Plan 11 step 7. INGRESS_DOMAIN=lab.holtlabs.xyz; health checks pin the host to INGRESS_IP on 443 and verify the wildcard cert. Co-Authored-By: Claude Fable 5.1 --- README.md | 15 ++++++++++----- bin/new-service | 10 +++++----- lib/common.sh | 10 +++++----- platform.env.example | 4 ++-- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ccfbbf8..1129203 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,11 @@ new-service NAME --kind backend|frontend [--with postgres,redis] [--api BACKEND] | 2 | generate public repo from `service-template-express` / `service-template-react` | repo exists | | 3 | set Actions secrets `REGISTRY_USER`, `REGISTRY_TOKEN`, `GITOPS_TOKEN` | never (PUT is idempotent) | | 4 | create namespace + Secret `unleash-client-token` (copied from `unleash/unleash-init-tokens`) | they exist | -| 5 | render gitops `templates/` (+ `postgres`, `redis`) → `manifests/NAME`, `kustomize build` lint, commit, push | dir exists | +| 5 | render gitops `templates/` (+ `postgres`, `redis`; `__APP__`, `__API__`, `__DOMAIN__`) → `manifests/NAME`, `kustomize build` lint, commit, push | dir exists | | 6 | clone repo to `$CODE_DIR/NAME`, push empty commit `chore: kick ci` | CI already deployed, or a kick is running/succeeded | | 7 | wait for CI's `gitops-bump` to replace `newTag: latest` (fails fast if the CI run fails) | tag already bumped | | 8 | write `apps/NAME.yaml`, commit, push, refresh ArgoCD `root` | file exists | -| 9 | `--wait`: ArgoCD app `Synced/Healthy`, then `/readyz` (backend) or `/healthz` + `/api/readyz` (frontend) → 200 | no `--wait` | +| 9 | `--wait`: ArgoCD app `Synced/Healthy`, then `https://NAME.$INGRESS_DOMAIN/readyz` (backend) or `/healthz` + `/api/readyz` (frontend) → 200 | no `--wait` | Then it prints the service, ArgoCD, Kibana (pre-filtered on `service:"NAME"`) and Unleash URLs, and the elapsed time. @@ -91,6 +91,11 @@ call (secret values redacted), git push and kubectl change instead of doing it. registry push token (same user). - Git pushes use the admin token through an inline credential helper; it is never written into a remote URL or `argv`. -- Platform UIs: ArgoCD, Kibana and Unleash at `argocd.` / `kibana.` / - `unleash.192.168.1.83.nip.io`. Credentials and conventions: homelab - `PLATFORM.md`. +- Platform UIs: ArgoCD, Kibana and Unleash at `https://argocd.` / `kibana.` / + `unleash.lab.holtlabs.xyz` (`INGRESS_DOMAIN`). Credentials and conventions: + homelab `PLATFORM.md`. +- `INGRESS_DOMAIN` (`lab.holtlabs.xyz`) fills `__DOMAIN__` in the gitops + templates, so services get `https://NAME.$INGRESS_DOMAIN/`. The wildcard + DNS record and the wildcard certificate are cluster-level (Plan 11); a new + service creates no DNS record and requests no certificate. Health checks + pin the host to `INGRESS_IP` with `curl --resolve` but still verify TLS. diff --git a/bin/new-service b/bin/new-service index 2cdb0f4..7f30bde 100755 --- a/bin/new-service +++ b/bin/new-service @@ -171,13 +171,13 @@ render_manifests() { for f in "${extra[@]}"; do add+=" - $f\n"; done sed -i "s|^ # Added by the render recipe.*$|${add%\\n}|" "$out/kustomization.yaml" sed -i '/^$/d' "$out/kustomization.yaml" - sed -i "s/__APP__/$NAME/g" "$out"/*.yaml + sed -i "s/__APP__/$NAME/g; s/__DOMAIN__/$INGRESS_DOMAIN/g" "$out"/*.yaml else if [[ -z $API_APP ]]; then rm "$out/ingress-api.yaml" "$out/middleware.yaml" sed -i '/ingress-api.yaml$/d; /middleware.yaml$/d; /# \/api -> backend/d' "$out/kustomization.yaml" fi - sed -i "s/__APP__/$NAME/g; s/__API__/$API_APP/g" "$out"/*.yaml + sed -i "s/__APP__/$NAME/g; s/__API__/$API_APP/g; s/__DOMAIN__/$INGRESS_DOMAIN/g" "$out"/*.yaml fi ! grep -rn '__[A-Z]*__' "$out" || die "unrendered placeholder left in manifests" kustomize_build "$out" >/dev/null || die "kustomize build of rendered manifests failed" @@ -291,14 +291,14 @@ if ((WAIT)) && ! is_dry; then local p for p in "$@"; do [[ $(curl -s -o /dev/null -w '%{http_code}' --max-time 5 \ - --resolve "$HOST:80:$INGRESS_IP" "http://$HOST$p") == 200 ]] || return 1 + --resolve "$HOST:443:$INGRESS_IP" "https://$HOST$p") == 200 ]] || return 1 done } paths=("$HEALTH_PATH") [[ -n $API_APP ]] && paths+=(/api/readyz) - wait_until 180 5 "http://$HOST${paths[*]} -> 200" http_ok "${paths[@]}" + wait_until 180 5 "https://$HOST${paths[*]} -> 200" http_ok "${paths[@]}" for p in "${paths[@]}"; do - printf ' GET %s -> %s\n' "$p" "$(curl -s --max-time 5 --resolve "$HOST:80:$INGRESS_IP" "http://$HOST$p")" >&2 + printf ' GET %s -> %s\n' "$p" "$(curl -s --max-time 5 --resolve "$HOST:443:$INGRESS_IP" "https://$HOST$p")" >&2 done fi diff --git a/lib/common.sh b/lib/common.sh index 8be3057..e09c006 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -223,11 +223,11 @@ print_urls() { kql=$(jq -rn --arg s "$name" '"service:\"\($s)\"" | @uri') cat <.$INGRESS_DOMAIN -INGRESS_IP=192.168.1.83 # health checks use curl --resolve, no DNS needed +INGRESS_DOMAIN=lab.holtlabs.xyz # services at https://.$INGRESS_DOMAIN (renders __DOMAIN__) +INGRESS_IP=192.168.1.83 # health checks use curl --resolve, no DNS needed (TLS still verified)