diff --git a/README.md b/README.md index 0a99c69..8184d29 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ delete-service orders-web --yes && delete-service orders --yes ## Setup ```sh -git clone https://git.lab.holtlabs.xyz/nholtware/platform.git ~/Code/forgejo.local/nholtware/platform +git clone https://git.holtlabs.xyz/nholtware/platform.git ~/Code/forgejo.local/nholtware/platform cd ~/Code/forgejo.local/nholtware/platform cp platform.env.example platform.env # gitignored; defaults match the homelab export PATH="$PWD/bin:$PATH" # not installed globally @@ -40,13 +40,13 @@ new-service NAME --kind backend|frontend [--with postgres,redis] [--api BACKEND] | 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 | +| 8 | write `$APPS_DIR/NAME.yaml` (`apps-homelab` by default), commit, push, refresh ArgoCD `root` | file exists | | 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. -**Why `apps/NAME.yaml` comes last:** ArgoCD only sees the service once CI has +**Why `$APPS_DIR/NAME.yaml` (`apps-homelab` by default) comes last:** ArgoCD only sees the service once CI has pushed a real image. Registering it earlier made the backend's migrate Job sit in `ImagePullBackOff` on `:latest` and hold the sync forever (Plan 04 caveat). @@ -70,7 +70,7 @@ re-kicked automatically. delete-service NAME [--yes] [--dry-run] [--timeout SECONDS] ``` -Removes `apps/NAME.yaml` + `manifests/NAME` from gitops (the Application's +Removes `$APPS_DIR/NAME.yaml` (`apps-homelab` by default) + `manifests/NAME` from gitops (the Application's `resources-finalizer` makes ArgoCD delete its workloads when `root` prunes it), waits for the Application to go, deletes the namespace if it is the service's own (CNPG PVCs go with it), deletes every version of the container package and diff --git a/bin/delete-service b/bin/delete-service index 1dddacd..bd67cf9 100755 --- a/bin/delete-service +++ b/bin/delete-service @@ -45,7 +45,7 @@ OWN_NS=0 # Refuse to pull a namespace out from under a frontend co-located with us. dependents=() -for f in "$GITOPS_DIR"/apps/*.yaml; do +for f in "$GITOPS_DIR/$APPS_DIR"/*.yaml; do other=$(basename "$f" .yaml) [[ $other != "$NAME" && $(app_namespace "$other") == "$NAME" ]] && dependents+=("$other") done @@ -54,7 +54,7 @@ done APP_DIR=$CODE_DIR/$NAME cat >&2 </dev/null 2>&1; then -p '{"metadata":{"finalizers":["resources-finalizer.argocd.argoproj.io"]}}' >/dev/null fi paths=() -[[ -f $GITOPS_DIR/apps/$NAME.yaml ]] && paths+=("apps/$NAME.yaml") +[[ -f $GITOPS_DIR/$APPS_DIR/$NAME.yaml ]] && paths+=("$APPS_DIR/$NAME.yaml") [[ -d $GITOPS_DIR/manifests/$NAME ]] && paths+=("manifests/$NAME") if ((${#paths[@]})); then if is_dry; then diff --git a/bin/new-service b/bin/new-service index e99ac7b..0c0758e 100755 --- a/bin/new-service +++ b/bin/new-service @@ -88,13 +88,13 @@ gitops_sync ((!PUBLIC)) || cf_require if [[ -n $API_APP ]]; then - [[ -f $GITOPS_DIR/apps/$API_APP.yaml && -d $GITOPS_DIR/manifests/$API_APP ]] || + [[ -f $GITOPS_DIR/$APPS_DIR/$API_APP.yaml && -d $GITOPS_DIR/manifests/$API_APP ]] || die "--api $API_APP: no such service in gitops (create it first)" [[ $(app_namespace "$API_APP") == "$API_APP" ]] || die "--api $API_APP: not a backend (its namespace is '$(app_namespace "$API_APP")')" fi -if [[ -f $GITOPS_DIR/apps/$NAME.yaml && $(app_namespace "$NAME") != "$NS" ]]; then - die "gitops apps/$NAME.yaml exists with namespace '$(app_namespace "$NAME")', expected '$NS'" +if [[ -f $GITOPS_DIR/$APPS_DIR/$NAME.yaml && $(app_namespace "$NAME") != "$NS" ]]; then + die "gitops $APPS_DIR/$NAME.yaml exists with namespace '$(app_namespace "$NAME")', expected '$NS'" fi ok "validated $NAME (kind=$KIND ns=$NS postgres=$WITH_PG redis=$WITH_REDIS api=${API_APP:--})" @@ -148,7 +148,7 @@ else fi # ------------------------------------------------------------ 5. gitops manifests -# apps/.yaml is written only after CI's first image exists (step 7), so +# $APPS_DIR/.yaml is written only after CI's first image exists (step 7), so # ArgoCD never syncs `newTag: latest` before there is an image to pull (the # migrate-Job ImagePullBackOff caveat from Plan 04). # public_block DIR: keep (markers only) or strip the `# __PUBLIC_BEGIN__..END__` host rule. @@ -281,17 +281,17 @@ else fi # ------------------------------------------------------------ 8. register with ArgoCD -if [[ -f $GITOPS_DIR/apps/$NAME.yaml ]]; then - ok "gitops apps/$NAME.yaml exists" +if [[ -f $GITOPS_DIR/$APPS_DIR/$NAME.yaml ]]; then + ok "gitops $APPS_DIR/$NAME.yaml exists" else is_dry || git_auth -C "$GITOPS_DIR" pull -q --ff-only origin main if is_dry; then - dry "write $GITOPS_DIR/apps/$NAME.yaml (namespace $NS)" + dry "write $GITOPS_DIR/$APPS_DIR/$NAME.yaml (namespace $NS)" else sed "s/__APP__/$NAME/g; s/__NS__/$NS/g" "$GITOPS_DIR/templates/$KIND/application.yaml.tmpl" \ - >"$GITOPS_DIR/apps/$NAME.yaml" + >"$GITOPS_DIR/$APPS_DIR/$NAME.yaml" fi - gitops_commit_push "feat($NAME): register ArgoCD application" "apps/$NAME.yaml" + gitops_commit_push "feat($NAME): register ArgoCD application" "$APPS_DIR/$NAME.yaml" fi # Don't wait for ArgoCD's 3-min poll. argocd_refresh root diff --git a/lib/common.sh b/lib/common.sh index f720845..9e91de7 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -80,6 +80,9 @@ load_config() { for v in curl jq git kubectl; do need_cmd "$v"; done export KUBECONFIG + # Environment layer (Plan 14): the gitops dir this service's Application goes in. + APPS_DIR=${APPS_DIR:-apps-homelab} + [[ -d $GITOPS_DIR/$APPS_DIR ]] || die "platform.env: APPS_DIR=$APPS_DIR does not exist in $GITOPS_DIR" # Public access is optional config; only --public / delete-service use it. PUBLIC_DOMAIN=${PUBLIC_DOMAIN:-} CF_ZONE_ID=${CF_ZONE_ID:-} CF_TUNNEL_ID=${CF_TUNNEL_ID:-} CLOUDFLARE_TOKEN_FILE=${CLOUDFLARE_TOKEN_FILE:-} @@ -249,9 +252,9 @@ gitops_commit_push() { die "gitops push failed after 5 attempts" } -# app_namespace NAME: destination namespace from gitops apps/NAME.yaml (empty if absent). +# app_namespace NAME: destination namespace from gitops $APPS_DIR/NAME.yaml (empty if absent). app_namespace() { - local f=$GITOPS_DIR/apps/$1.yaml + local f=$GITOPS_DIR/$APPS_DIR/$1.yaml [[ -f $f ]] || return 0 awk '/^ destination:/{d=1; next} d && /^ namespace:/{print $2; exit}' "$f" } diff --git a/platform.env.example b/platform.env.example index bb0f2fc..9711675 100644 --- a/platform.env.example +++ b/platform.env.example @@ -2,7 +2,7 @@ # Every file below must exist or the scripts refuse to run. HOMELAB_SECRETS=$HOME/Code/github.com/nholtware/homelab/.secrets -FORGEJO_URL=https://git.lab.holtlabs.xyz +FORGEJO_URL=https://git.holtlabs.xyz FORGEJO_OWNER=nholtware FORGEJO_ADMIN_TOKEN_FILE=$HOMELAB_SECRETS/forgejo-admin-token # repo create/delete, Actions secrets, git push REGISTRY_PUSH_TOKEN_FILE=$HOMELAB_SECRETS/registry-push-token # becomes REGISTRY_TOKEN; also lists/deletes packages @@ -11,6 +11,7 @@ GITOPS_TOKEN_FILE=$HOMELAB_SECRETS/ci-bot-gitops-token # becomes GITOPS GITOPS_DIR=$HOME/Code/forgejo.local/nholtware/gitops # clean clone of nholtware/gitops on main CODE_DIR=$HOME/Code/forgejo.local/nholtware # new service repos are cloned here KUBECONFIG=$HOME/.kube/homelab.yaml +APPS_DIR=apps-homelab # gitops dir for this environment's Applications (Plan 14; apps-cloud for the cloud env) 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)