Label Sync / Label Sync (push) Failing after 1m7s
E2E / reject-invalid (bad-bgp-asn) (push) Skipped
E2E / reject-invalid (bad-mac-address) (push) Skipped
E2E / reject-invalid (bad-repo-url) (push) Skipped
E2E / reject-invalid (bad-vlan-tag) (push) Skipped
E2E / reject-invalid (duplicate-gateway-addrs) (push) Skipped
E2E / reject-invalid (duplicate-node-names) (push) Skipped
E2E / reject-invalid (gateway-node-collision) (push) Skipped
E2E / reject-invalid (missing-dns-token) (push) Skipped
E2E / reject-invalid (nested-cidr-overlap) (push) Skipped
E2E / reject-invalid (node-addr-outside-cidr) (push) Skipped
E2E / reject-invalid (tunnel-without-dns) (push) Skipped
E2E / accept-valid (selfhosted) (push) Skipped
E2E / reject-invalid (missing-known-hosts) (push) Skipped
E2E / reject-invalid (missing-schematic) (push) Skipped
E2E / reject-invalid (partial-bgp) (push) Skipped
E2E / accept-valid (internal) (push) Skipped
E2E / reject-invalid (missing-external-gateway) (push) Skipped
E2E / reject-invalid (node-uses-gateway-addr) (push) Skipped
E2E / reject-invalid (non-canonical-cidr) (push) Skipped
E2E / accept-valid (private) (push) Skipped
E2E / accept-valid (single-node) (push) Skipped
E2E / reject-invalid (overlapping-cidrs) (push) Skipped
E2E / reject-invalid (reserved-node-name) (push) Skipped
E2E / reject-invalid (tiny-svc-cidr) (push) Skipped
E2E / validator-tests (push) Skipped
E2E / accept-valid (direct) (push) Skipped
E2E / accept-valid (multi-controller) (push) Skipped
E2E / accept-valid (no-webhook) (push) Skipped
E2E / accept-valid (public) (push) Skipped
106 lines
4.0 KiB
Plaintext
106 lines
4.0 KiB
Plaintext
set no-exit-message
|
|
set quiet
|
|
set shell := ['bash', '-euo', 'pipefail', '-c']
|
|
set script-interpreter := ['bash', '-euo', 'pipefail']
|
|
set default-list
|
|
set default-script
|
|
|
|
kubernetes_dir := justfile_dir() + '/kubernetes'
|
|
|
|
[doc('Bootstrap the Talos cluster')]
|
|
[group('bootstrap')]
|
|
talos: talos-secret talos-apply talos-talosconfig talos-kubeconfig
|
|
|
|
[doc('Bootstrap apps into the Talos cluster')]
|
|
[group('bootstrap')]
|
|
apps: apps-ready apps-namespaces apps-secrets apps-crds apps-helm
|
|
just log info "Cluster is bootstrapped — Flux will start syncing the Git repository"
|
|
|
|
# No sops call or existence guard is needed: the bundle is stored already
|
|
# encrypted with the repo's age recipient, and existing bundles are left
|
|
# untouched.
|
|
[private]
|
|
[working-directory('../talos')]
|
|
talos-secret:
|
|
just log info "Generating secrets" stage "{{ recipe_name() }}"
|
|
topf secrets --confirm=false > /dev/null
|
|
|
|
[private]
|
|
[working-directory('../talos')]
|
|
talos-apply:
|
|
just log info "Applying talos config and bootstrapping" stage "{{ recipe_name() }}"
|
|
topf apply --auto-bootstrap --confirm=false
|
|
|
|
[private]
|
|
[working-directory('../talos')]
|
|
talos-talosconfig:
|
|
just log info "Generating talosconfig" stage "{{ recipe_name() }}"
|
|
topf talosconfig > talosconfig
|
|
|
|
# topf issues short-lived admin certs by default; 8760h keeps the
|
|
# kubeconfig usable long-term.
|
|
[private]
|
|
[working-directory('../talos')]
|
|
talos-kubeconfig:
|
|
just log info "Fetching kubeconfig" stage "{{ recipe_name() }}"
|
|
topf kubeconfig --validity 8760h > "{{ justfile_dir() }}/kubeconfig"
|
|
|
|
[private]
|
|
apps-crds:
|
|
just log info "Applying CRDs" stage "{{ recipe_name() }}"
|
|
if ! helmfile --file "{{ source_directory() }}/helmfile/crds.yaml" template --quiet | yq eval-all --exit-status 'select(.kind == "CustomResourceDefinition")' | kubectl apply --server-side --force-conflicts --filename -; then
|
|
just log fatal "Failed to apply crds"
|
|
fi
|
|
|
|
[private]
|
|
apps-helm:
|
|
just log info "Syncing helmfile" stage "{{ recipe_name() }}"
|
|
if ! helmfile --file "{{ source_directory() }}/helmfile/apps.yaml" sync --hide-notes; then
|
|
just log fatal "Failed to sync helmfile"
|
|
fi
|
|
|
|
[private]
|
|
apps-namespaces:
|
|
just log info "Applying namespaces for apps" stage "{{ recipe_name() }}"
|
|
for app in "{{ kubernetes_dir }}/apps"/*/; do
|
|
ns="$(basename "$app")"
|
|
if kubectl create namespace "$ns" --dry-run=client -o yaml \
|
|
| kubectl apply --server-side --filename - &>/dev/null; then
|
|
just log info "Namespace applied" namespace "$ns"
|
|
else
|
|
just log fatal "Failed to apply namespace" namespace "$ns"
|
|
fi
|
|
done
|
|
|
|
[private]
|
|
apps-secrets:
|
|
just log info "Applying secrets for apps" stage "{{ recipe_name() }}"
|
|
for secret in \
|
|
"{{ source_directory() }}/deploy-key.sops.yaml" \
|
|
"{{ source_directory() }}/sops-age.sops.yaml" \
|
|
"{{ kubernetes_dir }}/components/sops/cluster-secrets.sops.yaml"
|
|
do
|
|
name="$(basename "$secret" .sops.yaml)"
|
|
if sops decrypt "$secret" \
|
|
| kubectl --namespace flux-system apply --server-side --filename - &>/dev/null; then
|
|
just log info "Secret applied" resource "$name"
|
|
else
|
|
just log fatal "Failed to apply secret" resource "$name"
|
|
fi
|
|
done
|
|
|
|
# Wait until nodes register as Ready=False. They only become Ready=True once the CNI is healthy.
|
|
[private]
|
|
apps-ready:
|
|
just log info "Waiting for nodes to register as Ready=False" stage "{{ recipe_name() }}"
|
|
if ! kubectl wait nodes --for=condition=Ready=True --all --timeout=10s &>/dev/null; then
|
|
deadline=$((SECONDS + 600))
|
|
until kubectl wait nodes --for=condition=Ready=False --all --timeout=10s &>/dev/null; do
|
|
if (( SECONDS >= deadline )); then
|
|
just log fatal "Timed out waiting for nodes to register"
|
|
fi
|
|
just log info "Nodes not available, waiting for nodes to be available. Retrying in 5 seconds..."
|
|
sleep 5
|
|
done
|
|
fi
|