#!/usr/bin/env bash set -euo pipefail # new-site.sh — Create a new static site: Gitea repo + Garage bucket. # # Usage: ./new-site.sh --name --domain [--type static|hugo|mkdocs] # # Requires: tea CLI configured; kubectl with sjc001 context (for bucket setup). usage() { echo "Usage: $0 --name --domain [--type static|hugo|mkdocs]" >&2 exit 1 } NAME="" DOMAIN="" TYPE="static" while [ $# -gt 0 ]; do case "$1" in --name) NAME="$2"; shift 2 ;; --domain) DOMAIN="$2"; shift 2 ;; --type) TYPE="$2"; shift 2 ;; *) usage ;; esac done [ -z "$NAME" ] || [ -z "$DOMAIN" ] && usage ORG="websites" WORK_DIR="$(mktemp -d)" trap 'rm -rf "$WORK_DIR"' EXIT # --- Garage bucket setup (one-off, via in-cluster Job) --- echo "Creating Garage bucket '${NAME}' and enabling web hosting..." cat </dev/null apiVersion: batch/v1 kind: Job metadata: name: bucket-setup-${NAME//./-} namespace: storage spec: ttlSecondsAfterFinished: 120 backoffLimit: 0 template: spec: restartPolicy: Never containers: - name: setup image: alpine:3.20 command: [/bin/sh, -euc] args: - | apk add --no-cache curl jq >/dev/null H=http://garage.storage.svc:3903 AUTH="Authorization: Bearer \$TOKEN" # ci-deploy-key id is fixed per cluster — update if re-keyed CI_KID=GKbe265a2b8ea53695ae734787 BUCKET=${NAME} # Create bucket (idempotent: 409 if exists) curl -s -X POST -H "\$AUTH" -H "Content-Type: application/json" \ -d "{\"globalAlias\":\"\$BUCKET\"}" "\$H/v2/CreateBucket" -o /dev/null BID=\$(curl -sf -H "\$AUTH" "\$H/v2/GetBucketInfo?globalAlias=\$BUCKET" | jq -r .id) echo "bucket id: \$BID" curl -s -X POST -H "\$AUTH" -H "Content-Type: application/json" \ -d "{\"bucketId\":\"\$BID\",\"accessKeyId\":\"\$CI_KID\",\"permissions\":{\"read\":true,\"write\":true,\"owner\":false}}" \ "\$H/v2/AllowBucketKey" -o /dev/null curl -s -X POST -H "\$AUTH" -H "Content-Type: application/json" \ -d '{"websiteAccess":{"enabled":true,"indexDocument":"index.html","errorDocument":"404.html"}}' \ "\$H/v2/UpdateBucket?id=\$BID" -o /dev/null curl -sf -H "\$AUTH" "\$H/v2/GetBucketInfo?globalAlias=\$BUCKET" | jq '{websiteAccess, keys: (.keys | map(.name))}' env: - name: TOKEN valueFrom: secretKeyRef: name: garage-rpc-secret key: admin-token EOF kubectl --context sjc001 -n storage wait --for=condition=complete --timeout=60s job/bucket-setup-${NAME//./-} kubectl --context sjc001 -n storage logs job/bucket-setup-${NAME//./-} kubectl --context sjc001 -n storage delete job bucket-setup-${NAME//./-} --ignore-not-found >/dev/null # --- Gitea repo --- echo "Creating Gitea repo ${ORG}/${NAME}..." tea repo create --owner "$ORG" --name "$NAME" --init echo "Cloning..." git clone "ssh://git@code.fritzlab.net/${ORG}/${NAME}.git" "$WORK_DIR" cd "$WORK_DIR" # --- Starter content + site.yaml --- case "$TYPE" in static) mkdir -p html cat > html/index.html <<'HTML' Welcome

Hello from fritzlab

Served from Garage S3.

HTML cat > site.yaml < site.yaml < mkdocs.yml < docs/index.md < site.yaml < .gitea/workflows/publish.yaml <<'WORKFLOW' name: Publish on: push: branches: [main] jobs: publish: runs-on: fritzlab steps: - uses: actions/checkout@v4 - uses: https://code.fritzlab.net/action/site-publish@v1 with: token: ${{ secrets.CI_BOT_TOKEN }} s3-access-key: ${{ secrets.GARAGE_S3_ACCESS_KEY }} s3-secret-key: ${{ secrets.GARAGE_S3_SECRET_KEY }} WORKFLOW git add -A git commit -m "Initial site scaffold" git push echo echo "Site created: ${ORG}/${NAME}" echo "First build will trigger on push." echo echo "DNS: ${DOMAIN} is covered by the *.vino.network wildcard (→ traefik.edge)." echo "For a domain outside vino.network, add an explicit CNAME:" echo " ${DOMAIN} 300 IN CNAME traefik.edge.svc.k8s.sjc001.fritzlab.net."