Initial commit
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
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
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
---
|
||||
- name: type/digest
|
||||
color: ffeC19
|
||||
- name: type/patch
|
||||
color: ffeC19
|
||||
- name: type/minor
|
||||
color: ff9800
|
||||
- name: type/major
|
||||
color: f6412d
|
||||
@@ -0,0 +1,5 @@
|
||||
changelog:
|
||||
exclude:
|
||||
authors:
|
||||
- github-actions
|
||||
- renovate
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: e2e-deny-server
|
||||
namespace: default
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app: e2e-network-server
|
||||
ingress:
|
||||
- {}
|
||||
Executable
+291
@@ -0,0 +1,291 @@
|
||||
#!/usr/bin/env bash
|
||||
# Full-fidelity bootstrap e2e: takes maintenance-mode Talos VMs, discovers
|
||||
# their hardware the same way the README instructs users to, writes a
|
||||
# cluster.toml from the discovered facts, and runs the template's real
|
||||
# bootstrap flow against them.
|
||||
#
|
||||
# Two provisioning paths share this test body:
|
||||
# - CI: talosctl-cluster-action boots the nodes (talos-cluster.yaml) and
|
||||
# passes E2E_CONTROLPLANE_IPS / E2E_WORKER_IPS / E2E_CIDR; the action's
|
||||
# post step destroys them.
|
||||
# - Local: run with no env set; the script boots and destroys the cluster
|
||||
# itself. Requires Docker, /dev/kvm, passwordless sudo, qemu-system-x86,
|
||||
# and the repo's mise toolchain on PATH.
|
||||
#
|
||||
# Renders into the working tree like any configure run.
|
||||
set -euo pipefail
|
||||
|
||||
NAME="${E2E_NAME:-template-e2e}"
|
||||
MODE="${1:-all}"
|
||||
E2E_DIR=".github/template-tests/e2e"
|
||||
CIDR="${E2E_CIDR:-10.9.0.0/24}"
|
||||
PREFIX="${CIDR%/*}"
|
||||
PREFIX="${PREFIX%.*}"
|
||||
TALOSCTL="$(command -v talosctl)"
|
||||
# The Image Factory vanilla schematic, matching the ISO the nodes boot from.
|
||||
SCHEMATIC="376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
|
||||
if [ -n "${E2E_CONTROLPLANE_IPS:-}" ]; then
|
||||
PROVISIONED=true
|
||||
IFS=',' read -r -a CONTROLPLANES <<< "$E2E_CONTROLPLANE_IPS"
|
||||
IFS=',' read -r -a WORKERS <<< "${E2E_WORKER_IPS:-}"
|
||||
else
|
||||
PROVISIONED=false
|
||||
CONTROLPLANES=("$PREFIX.2")
|
||||
WORKERS=("$PREFIX.3")
|
||||
fi
|
||||
NODES=("${CONTROLPLANES[@]}" "${WORKERS[@]}")
|
||||
# The VMs reach the host at the gateway address; the rendered workspace is
|
||||
# served from there over git smart HTTP so Flux can sync it.
|
||||
GIT_HOST="${E2E_GATEWAY:-$PREFIX.1}"
|
||||
GIT_PORT=8418
|
||||
GIT_SERVER_CONTAINER=""
|
||||
|
||||
# The provisioner runs under sudo and writes state relative to its cwd and
|
||||
# TALOSCONFIG, so both are pointed at a scratch dir to keep root-owned files
|
||||
# out of the repo.
|
||||
if [ -n "${E2E_STATE:-}" ]; then
|
||||
STATE="$E2E_STATE"
|
||||
STATE_OWNED=false
|
||||
else
|
||||
STATE="$(mktemp -d)"
|
||||
STATE_OWNED=true
|
||||
fi
|
||||
mkdir -p "$STATE"
|
||||
GIT_PUSH_URL="http://127.0.0.1:$GIT_PORT/repo.git"
|
||||
|
||||
cleanup() {
|
||||
rc=$?
|
||||
if [ "$rc" -ne 0 ]; then
|
||||
echo "==> e2e failed (rc=$rc), collecting diagnostics"
|
||||
kubectl get pods --all-namespaces 2>/dev/null || true
|
||||
kubectl get gitrepositories,kustomizations,helmreleases --all-namespaces 2>/dev/null || true
|
||||
kubectl get events --all-namespaces --sort-by=.lastTimestamp 2>/dev/null | tail -30 || true
|
||||
[ -n "$GIT_SERVER_CONTAINER" ] && docker logs --tail 5 "$GIT_SERVER_CONTAINER" 2>/dev/null || true
|
||||
for ip in "${NODES[@]}"; do
|
||||
talosctl -n "$ip" dmesg 2>/dev/null | tail -20 || true
|
||||
done
|
||||
fi
|
||||
if [ "$MODE" = all ]; then
|
||||
[ -n "$GIT_SERVER_CONTAINER" ] && docker stop "$GIT_SERVER_CONTAINER" >/dev/null 2>&1 || true
|
||||
fi
|
||||
if [ "$MODE" = all ] && [ "$PROVISIONED" = false ]; then
|
||||
(cd "$STATE" && sudo -E env TALOSCONFIG="$STATE/talosconfig" \
|
||||
"$TALOSCTL" cluster destroy --name "$NAME" --provisioner qemu >/dev/null 2>&1) || true
|
||||
fi
|
||||
if [ "$MODE" = all ] && [ "$STATE_OWNED" = true ]; then
|
||||
sudo rm -rf "$STATE" || true
|
||||
fi
|
||||
exit "$rc"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
start_local_git_server() {
|
||||
GIT_SERVER_CONTAINER="$NAME-git"
|
||||
docker run --detach --rm --name "$GIT_SERVER_CONTAINER" \
|
||||
--publish "$GIT_PORT:23232" \
|
||||
--env SOFT_SERVE_GIT_ENABLED=false \
|
||||
--env SOFT_SERVE_LFS_ENABLED=false \
|
||||
--env SOFT_SERVE_SSH_LISTEN_ADDR=127.0.0.1:23231 \
|
||||
--env SOFT_SERVE_STATS_ENABLED=false \
|
||||
--entrypoint /bin/sh \
|
||||
ghcr.io/charmbracelet/soft-serve:v0.11.6 \
|
||||
-c 'set -eu; ssh-keygen -q -t ed25519 -N "" -f /tmp/admin; export SOFT_SERVE_INITIAL_ADMIN_KEYS="$(cat /tmp/admin.pub)"; /usr/local/bin/soft serve & pid=$!; until ssh -q -i /tmp/admin -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -p 23231 localhost settings anon-access read-write; do sleep 1; done; ssh -q -i /tmp/admin -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -p 23231 localhost repo create repo; wait "$pid"' \
|
||||
>/dev/null
|
||||
deadline=$((SECONDS + 60))
|
||||
until git ls-remote "$GIT_PUSH_URL" >/dev/null 2>&1; do
|
||||
if (( SECONDS >= deadline )); then
|
||||
just log fatal "Soft Serve is not reachable"
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
prepare() {
|
||||
# In CI the action itself waits for every node's maintenance API before
|
||||
# returning, so the poll here covers only the local path, where cluster
|
||||
# create returns as soon as the VMs launch.
|
||||
if [ "$PROVISIONED" = false ]; then
|
||||
echo "==> booting maintenance-mode nodes"
|
||||
(cd "$STATE" && sudo -E env TALOSCONFIG="$STATE/talosconfig" \
|
||||
"$TALOSCTL" cluster create qemu --name "$NAME" --presets iso,maintenance \
|
||||
--controlplanes 1 --workers 1 --cidr "$CIDR" \
|
||||
--memory-controlplanes 4GiB --memory-workers 3GiB)
|
||||
|
||||
echo "==> waiting for the maintenance API"
|
||||
for ip in "${NODES[@]}"; do
|
||||
until talosctl -n "$ip" get links --insecure >/dev/null 2>&1; do sleep 5; done
|
||||
done
|
||||
fi
|
||||
|
||||
echo "==> discovering node hardware"
|
||||
declare -A MACS DISKS
|
||||
for ip in "${NODES[@]}"; do
|
||||
MACS[$ip]="$(talosctl -n "$ip" get links --insecure -o json \
|
||||
| jq -r 'select(.spec.type == "ether" and .spec.operationalState == "up" and (.metadata.id | startswith("bond") | not)) | .spec.hardwareAddr' | head -1)"
|
||||
DISKS[$ip]="/dev/$(talosctl -n "$ip" get disks --insecure -o json \
|
||||
| jq -r 'select(.spec.readonly == false and (.metadata.id | startswith("loop") | not)) | .metadata.id' | head -1)"
|
||||
echo " $ip mac=${MACS[$ip]} disk=${DISKS[$ip]}"
|
||||
done
|
||||
|
||||
echo "==> generating cluster.toml"
|
||||
export E2E_CIDR="$CIDR"
|
||||
export E2E_GATEWAY="${E2E_GATEWAY:-$PREFIX.1}"
|
||||
export E2E_GIT_HOST="$GIT_HOST"
|
||||
export E2E_GIT_PORT="$GIT_PORT"
|
||||
export E2E_PREFIX="$PREFIX"
|
||||
export E2E_SCHEMATIC="$SCHEMATIC"
|
||||
envsubst '${E2E_CIDR} ${E2E_GATEWAY} ${E2E_GIT_HOST} ${E2E_GIT_PORT} ${E2E_PREFIX} ${E2E_SCHEMATIC}' \
|
||||
< "$E2E_DIR/cluster.toml.tmpl" > cluster.toml
|
||||
index=0
|
||||
for ip in "${NODES[@]}"; do
|
||||
controller=false
|
||||
for cp in "${CONTROLPLANES[@]}"; do [ "$ip" = "$cp" ] && controller=true; done
|
||||
export E2E_NODE_NAME="e2e-$index"
|
||||
export E2E_NODE_ADDRESS="$ip"
|
||||
export E2E_NODE_CONTROLLER="$controller"
|
||||
export E2E_NODE_DISK="${DISKS[$ip]}"
|
||||
export E2E_NODE_MAC="${MACS[$ip]}"
|
||||
envsubst '${E2E_NODE_ADDRESS} ${E2E_NODE_CONTROLLER} ${E2E_NODE_DISK} ${E2E_NODE_MAC} ${E2E_NODE_NAME}' \
|
||||
< "$E2E_DIR/node.toml.tmpl" >> cluster.toml
|
||||
index=$((index + 1))
|
||||
done
|
||||
|
||||
echo "==> configure"
|
||||
just init
|
||||
just configure
|
||||
|
||||
# Flux's FluxInstance only reports Ready once its Git sync succeeds, so the
|
||||
# rendered kubernetes/ tree is committed to a bare repo and served to the
|
||||
# cluster — the same push-then-bootstrap flow the README walks users through.
|
||||
echo "==> publishing rendered repo"
|
||||
mkdir -p "$STATE/gitwork"
|
||||
cp -r kubernetes "$STATE/gitwork/"
|
||||
git -C "$STATE/gitwork" init --quiet --initial-branch main
|
||||
git -C "$STATE/gitwork" add --all
|
||||
git -C "$STATE/gitwork" -c user.name=e2e -c user.email=e2e@cluster.local \
|
||||
commit --quiet --message "rendered workspace"
|
||||
git -C "$STATE/gitwork" push --quiet "$GIT_PUSH_URL" main
|
||||
}
|
||||
|
||||
assert_cluster_health() {
|
||||
echo "==> asserting cluster health"
|
||||
kubectl wait nodes --all --for=condition=Ready --timeout=10m
|
||||
for ns in kube-system cert-manager flux-system; do
|
||||
kubectl wait pods --namespace "$ns" --all --for=condition=Ready --timeout=10m
|
||||
done
|
||||
|
||||
echo "==> asserting flux reconciliation"
|
||||
kubectl wait fluxinstance/flux --namespace flux-system --for=condition=Ready --timeout=10m
|
||||
kubectl wait gitrepositories --all --all-namespaces --for=condition=Ready --timeout=5m
|
||||
kubectl wait kustomizations --all --all-namespaces --for=condition=Ready --timeout=10m
|
||||
kubectl wait helmreleases --all --all-namespaces --for=condition=Ready --timeout=10m
|
||||
}
|
||||
|
||||
foundation() {
|
||||
deadline=$((SECONDS + 60))
|
||||
until git ls-remote "http://$GIT_HOST:$GIT_PORT/repo.git" >/dev/null 2>&1; do
|
||||
if (( SECONDS >= deadline )); then
|
||||
just log fatal "Rendered repository server is not reachable"
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
echo "==> bootstrap talos"
|
||||
just bootstrap talos
|
||||
|
||||
echo "==> bootstrap apps"
|
||||
just bootstrap apps
|
||||
assert_cluster_health
|
||||
|
||||
echo "==> asserting bootstrap idempotency"
|
||||
just configure
|
||||
just bootstrap talos
|
||||
just bootstrap apps
|
||||
assert_cluster_health
|
||||
}
|
||||
|
||||
flux_sops() {
|
||||
echo "==> asserting Flux SOPS decryption"
|
||||
SOPS_SECRET="$STATE/gitwork/kubernetes/apps/default/e2e-sops.sops.yaml"
|
||||
export E2E_SOPS_VALUE=flux-decrypted
|
||||
envsubst '${E2E_SOPS_VALUE}' < "$E2E_DIR/sops-secret.yaml.tmpl" > "$SOPS_SECRET"
|
||||
sops encrypt --filename-override kubernetes/apps/default/e2e-sops.sops.yaml \
|
||||
--in-place "$SOPS_SECRET"
|
||||
yq --inplace '.resources += ["./e2e-sops.sops.yaml"]' \
|
||||
"$STATE/gitwork/kubernetes/apps/default/kustomization.yaml"
|
||||
git -C "$STATE/gitwork" add --all
|
||||
git -C "$STATE/gitwork" -c user.name=e2e -c user.email=e2e@cluster.local \
|
||||
commit --quiet --message "test Flux SOPS decryption"
|
||||
git -C "$STATE/gitwork" push --quiet "$GIT_PUSH_URL" main
|
||||
flux reconcile kustomization cluster-apps --with-source --timeout=10m
|
||||
test "$(kubectl get secret e2e-sops --namespace default \
|
||||
--output jsonpath='{.data.value}' | base64 --decode)" = "flux-decrypted"
|
||||
}
|
||||
|
||||
networking() {
|
||||
echo "==> asserting pod networking and DNS"
|
||||
export E2E_CONTROLPLANE_NODE="$(kubectl get nodes \
|
||||
--selector=node-role.kubernetes.io/control-plane \
|
||||
--output jsonpath='{.items[0].metadata.name}')"
|
||||
export E2E_WORKER_NODE="$(kubectl get nodes \
|
||||
--selector='!node-role.kubernetes.io/control-plane' \
|
||||
--output jsonpath='{.items[0].metadata.name}')"
|
||||
NETWORK_CONFIG="$STATE/network.yaml"
|
||||
envsubst '${E2E_CONTROLPLANE_NODE} ${E2E_WORKER_NODE}' \
|
||||
< "$E2E_DIR/network.yaml.tmpl" > "$NETWORK_CONFIG"
|
||||
kubectl apply --filename "$NETWORK_CONFIG"
|
||||
kubectl wait pods/e2e-network-server pods/e2e-network-client \
|
||||
--namespace default --for=condition=Ready --timeout=5m
|
||||
SERVER_IP="$(kubectl get pod e2e-network-server --namespace default \
|
||||
--output jsonpath='{.status.podIP}')"
|
||||
kubectl exec --namespace default e2e-network-client -- \
|
||||
/agnhost connect --timeout=10s "$SERVER_IP:8080"
|
||||
kubectl exec --namespace default e2e-network-client -- \
|
||||
/agnhost connect --timeout=10s e2e-network-server.default.svc.cluster.local:8080
|
||||
kubectl exec --namespace default e2e-network-client -- \
|
||||
/agnhost connect --timeout=10s github.com:443
|
||||
kubectl apply --filename "$E2E_DIR/cilium-network-policy.yaml"
|
||||
deadline=$((SECONDS + 60))
|
||||
while kubectl exec --namespace default e2e-network-client -- \
|
||||
/agnhost connect --timeout=2s "$SERVER_IP:8080" &>/dev/null; do
|
||||
if (( SECONDS >= deadline )); then
|
||||
just log fatal "CiliumNetworkPolicy did not block pod traffic"
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
kubectl delete ciliumnetworkpolicy e2e-deny-server --namespace default
|
||||
deadline=$((SECONDS + 60))
|
||||
until kubectl exec --namespace default e2e-network-client -- \
|
||||
/agnhost connect --timeout=2s "$SERVER_IP:8080" &>/dev/null; do
|
||||
if (( SECONDS >= deadline )); then
|
||||
just log fatal "Pod traffic did not recover after removing CiliumNetworkPolicy"
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
}
|
||||
|
||||
summary() {
|
||||
kubectl get nodes --output wide
|
||||
kubectl get kustomizations,helmreleases --all-namespaces
|
||||
echo "==> e2e bootstrap succeeded"
|
||||
}
|
||||
|
||||
case "$MODE" in
|
||||
prepare) prepare ;;
|
||||
foundation) foundation ;;
|
||||
flux-sops) flux_sops ;;
|
||||
networking) networking ;;
|
||||
summary) summary ;;
|
||||
all)
|
||||
start_local_git_server
|
||||
prepare
|
||||
foundation
|
||||
flux_sops
|
||||
networking
|
||||
summary
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 {prepare|foundation|flux-sops|networking|summary|all}" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,22 @@
|
||||
[network]
|
||||
node_cidr = "${E2E_CIDR}"
|
||||
default_gateway = "${E2E_GATEWAY}"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "${E2E_PREFIX}.100"
|
||||
|
||||
[gateways]
|
||||
internal = "${E2E_PREFIX}.101"
|
||||
dns = "${E2E_PREFIX}.102"
|
||||
|
||||
[domain]
|
||||
name = "e2e.example.com"
|
||||
|
||||
[dns]
|
||||
provider = "none"
|
||||
|
||||
[repository]
|
||||
url = "http://${E2E_GIT_HOST}:${E2E_GIT_PORT}/repo.git"
|
||||
|
||||
[talos]
|
||||
schematic_id = "${E2E_SCHEMATIC}"
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: e2e-network-server
|
||||
namespace: default
|
||||
labels:
|
||||
app: e2e-network-server
|
||||
spec:
|
||||
nodeName: "${E2E_WORKER_NODE}"
|
||||
containers:
|
||||
- name: server
|
||||
image: registry.k8s.io/e2e-test-images/agnhost:2.66.0
|
||||
args: ["netexec", "--http-port=8080"]
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: e2e-network-server
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
app: e2e-network-server
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: http
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: e2e-network-client
|
||||
namespace: default
|
||||
spec:
|
||||
nodeName: "${E2E_CONTROLPLANE_NODE}"
|
||||
containers:
|
||||
- name: client
|
||||
image: registry.k8s.io/e2e-test-images/agnhost:2.66.0
|
||||
args: ["pause"]
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
[[nodes]]
|
||||
name = "${E2E_NODE_NAME}"
|
||||
address = "${E2E_NODE_ADDRESS}"
|
||||
controller = ${E2E_NODE_CONTROLLER}
|
||||
disk = "${E2E_NODE_DISK}"
|
||||
mac_addr = "${E2E_NODE_MAC}"
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: e2e-sops
|
||||
namespace: default
|
||||
stringData:
|
||||
value: "${E2E_SOPS_VALUE}"
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
# yaml-language-server: $schema=https://raw.githubusercontent.com/home-operations/talosctl-cluster-action/main/schema/talos-cluster.json
|
||||
# Maintenance-mode nodes for the bootstrap e2e: the action boots and destroys
|
||||
# them, and cluster.sh exercises the template's real bootstrap flow against
|
||||
# the unconfigured nodes.
|
||||
apiVersion: v1alpha1
|
||||
kind: TalosCluster
|
||||
metadata:
|
||||
name: template-e2e
|
||||
spec:
|
||||
controlplanes:
|
||||
count: 1
|
||||
memory: 4GiB
|
||||
workers:
|
||||
count: 1
|
||||
memory: 3GiB
|
||||
network:
|
||||
cidr: 10.9.0.0/24
|
||||
qemu:
|
||||
presets: [iso, maintenance]
|
||||
disks: [virtio:10GiB]
|
||||
@@ -0,0 +1,34 @@
|
||||
# Negative fixture: BGP router ASN above the 32-bit ASN range.
|
||||
# Expected to be rejected by _router_asn_in_range.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[cilium.bgp]
|
||||
router_addr = "10.10.1.1"
|
||||
router_asn = "4294967296"
|
||||
node_asn = "64514"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,29 @@
|
||||
# Negative fixture: malformed MAC address (uppercase + missing colons).
|
||||
# Expected to be rejected by the #Node.mac_addr regex constraint.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "AABBCCDDEEFF"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,30 @@
|
||||
# Negative fixture: scp-style git URL ("git@host:owner/repo.git") instead of
|
||||
# the canonical https:// or ssh://git@ form.
|
||||
# Expected to be rejected by the repository.url pattern.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "git@github.com:onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,30 @@
|
||||
# Negative fixture: vlan_tag outside the valid 1-4094 range.
|
||||
# Expected to be rejected by _vlan_tag_in_range.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
vlan_tag = "5000"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,29 @@
|
||||
# Negative fixture: gateways.internal == gateways.dns.
|
||||
# Expected to be rejected by `_addrs_check` (list.UniqueItems).
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.252"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,37 @@
|
||||
# Negative fixture: two nodes with the same name.
|
||||
# Expected to be rejected by `_node_name_check` (list.UniqueItems).
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.101"
|
||||
controller = false
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:01"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,29 @@
|
||||
# Negative fixture: a node reuses the internal gateway VIP.
|
||||
# Expected to be rejected by _addr_uniqueness_check.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.252"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,29 @@
|
||||
# Negative fixture: dns.provider "cloudflare" (the default) without a token.
|
||||
# Expected to be rejected by the Dns validator.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
provider = "cloudflare"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,28 @@
|
||||
# Negative fixture: cloudflare-tunnel ingress without gateways.external.
|
||||
# Expected to be rejected by the Config cross-check.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,30 @@
|
||||
# Negative fixture: ssh:// URL to a host without bundled SSH host keys
|
||||
# (github.com/gitlab.com/codeberg.org) and no repository.known_hosts set.
|
||||
# Expected to be rejected by the conditional known_hosts constraint.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "ssh://git@git.example.com/k8s/home-ops.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,28 @@
|
||||
# Negative fixture: a node without schematic_id and no [talos] default.
|
||||
# Expected to be rejected by the schematic resolution in Config.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
@@ -0,0 +1,30 @@
|
||||
# Negative fixture: node_cidr is nested inside the default pod_cidr
|
||||
# (10.42.0.0/16) without being string-equal to it.
|
||||
# Expected to be rejected by _cidr_overlap_check.
|
||||
[network]
|
||||
node_cidr = "10.42.128.0/17"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.42.128.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.42.128.252"
|
||||
dns = "10.42.128.253"
|
||||
external = "10.42.128.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.42.128.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,29 @@
|
||||
# Negative fixture: node address is not inside network.node_cidr.
|
||||
# Expected to be rejected by _node_addrs_in_node_cidr.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "192.168.1.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,30 @@
|
||||
# Negative fixture: a node claims the default gateway address (defaults to
|
||||
# the first IP in node_cidr).
|
||||
# Expected to be rejected by _addr_uniqueness_check.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.1"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,30 @@
|
||||
# Negative fixture: node_cidr written with host bits set instead of the
|
||||
# network address.
|
||||
# Expected to be rejected by _cidr_canonical_check.
|
||||
[network]
|
||||
node_cidr = "10.10.10.5/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,29 @@
|
||||
# Negative fixture: network.node_cidr overlaps the default kubernetes.pod_cidr (10.42.0.0/16).
|
||||
# Expected to be rejected by `_cidrs_check` (list.UniqueItems).
|
||||
[network]
|
||||
node_cidr = "10.42.0.0/16"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.42.0.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.42.0.252"
|
||||
dns = "10.42.0.253"
|
||||
external = "10.42.0.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.42.0.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,34 @@
|
||||
# Negative fixture: two of the three BGP fields set; previously this
|
||||
# silently left BGP disabled.
|
||||
# Expected to be rejected by the Bgp all-or-nothing check.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[cilium.bgp]
|
||||
router_addr = "10.10.1.1"
|
||||
router_asn = "64513"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,29 @@
|
||||
# Negative fixture: a node name uses the reserved word "controller".
|
||||
# Expected to be rejected by the #Node.name regex constraint.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "controller"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,33 @@
|
||||
# Negative fixture: svc_cidr too small to contain the derived CoreDNS
|
||||
# address (10th IP).
|
||||
# Expected to be rejected by _coredns_addr_in_svc_cidr.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes]
|
||||
svc_cidr = "10.43.0.0/29"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,32 @@
|
||||
# Negative fixture: cloudflare-tunnel ingress with dns.provider "none".
|
||||
# Expected to be rejected by the Config cross-check.
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
provider = "none"
|
||||
|
||||
[ingress]
|
||||
mode = "cloudflare-tunnel"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,38 @@
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[ingress]
|
||||
mode = "direct"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-1"
|
||||
address = "10.10.10.101"
|
||||
controller = false
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:01"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,34 @@
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
provider = "none"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-1"
|
||||
address = "10.10.10.101"
|
||||
controller = false
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:01"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,42 @@
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
|
||||
[repository]
|
||||
url = "ssh://git@github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
provider = "none"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-1"
|
||||
address = "10.10.10.101"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:01"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-2"
|
||||
address = "10.10.10.102"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:02"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,36 @@
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
webhook_provider = "none"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-1"
|
||||
address = "10.10.10.101"
|
||||
controller = false
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:01"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,39 @@
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "ssh://git@github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-1"
|
||||
address = "10.10.10.101"
|
||||
controller = false
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:01"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
mtu = 1500
|
||||
secureboot = true
|
||||
encrypt_disk = true
|
||||
kernel_modules = ["nvidia", "nvidia_uvm"]
|
||||
@@ -0,0 +1,59 @@
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
default_gateway = "10.10.10.1"
|
||||
vlan_tag = "100"
|
||||
dns_servers = ["1.1.1.1"]
|
||||
ntp_servers = ["162.159.200.123"]
|
||||
|
||||
[kubernetes]
|
||||
pod_cidr = "10.42.0.0/16"
|
||||
svc_cidr = "10.43.0.0/16"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
tls_sans = ["example.com"]
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
branch = "main"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[cilium]
|
||||
loadbalancer_mode = "dsr"
|
||||
|
||||
[cilium.bgp]
|
||||
router_addr = "10.10.1.1"
|
||||
router_asn = "64513"
|
||||
node_asn = "64514"
|
||||
|
||||
[talos]
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-1"
|
||||
address = "10.10.10.101"
|
||||
controller = false
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:01"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
mtu = 1500
|
||||
secureboot = true
|
||||
encrypt_disk = true
|
||||
kernel_modules = ["nvidia", "nvidia_uvm"]
|
||||
@@ -0,0 +1,39 @@
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
external = "10.10.10.251"
|
||||
|
||||
[repository]
|
||||
url = "ssh://git@git.example.com/k8s/home-ops.git"
|
||||
webhook_provider = "generic-hmac"
|
||||
known_hosts = """
|
||||
git.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
"""
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
token = "fake"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-1"
|
||||
address = "10.10.10.101"
|
||||
controller = false
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:01"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,26 @@
|
||||
[network]
|
||||
node_cidr = "10.10.10.0/24"
|
||||
|
||||
[kubernetes.api]
|
||||
addr = "10.10.10.254"
|
||||
|
||||
[gateways]
|
||||
internal = "10.10.10.252"
|
||||
dns = "10.10.10.253"
|
||||
|
||||
[domain]
|
||||
name = "example.com"
|
||||
|
||||
[dns]
|
||||
provider = "none"
|
||||
|
||||
[repository]
|
||||
url = "https://github.com/onedr0p/cluster-template.git"
|
||||
|
||||
[[nodes]]
|
||||
name = "k8s-0"
|
||||
address = "10.10.10.100"
|
||||
controller = true
|
||||
disk = "/dev/sdfake"
|
||||
mac_addr = "00:00:00:00:00:00"
|
||||
schematic_id = "376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba"
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
||||
name: "Flate"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
filter:
|
||||
name: Flate - Filter
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
changed-files: ${{ steps.changed-files.outputs.changed_files }}
|
||||
steps:
|
||||
- name: Get Changed Files
|
||||
id: changed-files
|
||||
uses: bjw-s-labs/action-changed-files@a9a36fb08ce06db9b02fbd8026cc2c0945eb9841 # v0.6.0
|
||||
with:
|
||||
patterns: kubernetes/**/*
|
||||
|
||||
flate:
|
||||
if: ${{ needs.filter.outputs.changed-files != '[]' }}
|
||||
needs: filter
|
||||
name: Flate
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Flate
|
||||
uses: home-operations/flate/action@631b76b69c4e58c6f4d1cb01e23616fa61aebafa # v0.6.5
|
||||
|
||||
- name: Run Flate
|
||||
id: flate
|
||||
run: flate test all -p ./kubernetes/flux/cluster
|
||||
|
||||
success:
|
||||
if: ${{ !cancelled() }}
|
||||
needs: flate
|
||||
name: Flate - Success
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Any jobs failed?
|
||||
if: ${{ contains(needs.*.result, 'failure') }}
|
||||
run: exit 1
|
||||
|
||||
- name: All jobs passed or skipped?
|
||||
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
||||
run: echo "All jobs passed or skipped" && echo "${{ toJSON(needs.*.result) }}"
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
||||
name: "Label Sync"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- .github/labels.yaml
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
label-sync:
|
||||
name: Label Sync
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Sync Labels
|
||||
uses: EndBug/label-sync@52074158190acb45f3077f9099fea818aa43f97a # v2.3.3
|
||||
with:
|
||||
config-file: .github/labels.yaml
|
||||
delete-other-labels: true
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
||||
name: "E2E Cluster"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
schedule:
|
||||
- cron: "30 5 * * *"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
bootstrap:
|
||||
if: ${{ github.repository == 'onedr0p/cluster-template' }}
|
||||
name: bootstrap (qemu)
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
services:
|
||||
git:
|
||||
image: ghcr.io/charmbracelet/soft-serve:v0.12.2
|
||||
env:
|
||||
SOFT_SERVE_GIT_ENABLED: "false"
|
||||
SOFT_SERVE_LFS_ENABLED: "false"
|
||||
SOFT_SERVE_SSH_LISTEN_ADDR: "127.0.0.1:23231"
|
||||
SOFT_SERVE_STATS_ENABLED: "false"
|
||||
ports:
|
||||
- 8418:23232
|
||||
entrypoint: /bin/sh
|
||||
command: >-
|
||||
-c "set -eu; ssh-keygen -q -t ed25519 -N '' -f /tmp/admin;
|
||||
export SOFT_SERVE_INITIAL_ADMIN_KEYS=$(cat /tmp/admin.pub);
|
||||
/usr/local/bin/soft serve & pid=$!;
|
||||
until ssh -q -i /tmp/admin -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -p 23231 localhost settings anon-access read-write; do sleep 1; done;
|
||||
ssh -q -i /tmp/admin -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -p 23231 localhost repo create repo;
|
||||
wait $pid"
|
||||
options: >-
|
||||
--health-cmd "git ls-remote http://localhost:23232/repo.git"
|
||||
--health-interval 2s
|
||||
--health-timeout 2s
|
||||
--health-retries 30
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install QEMU
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes --no-install-recommends gettext-base qemu-system-x86 qemu-utils ovmf
|
||||
|
||||
- name: Setup mise
|
||||
uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4.3.0
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
- name: Boot maintenance-mode nodes
|
||||
id: cluster
|
||||
uses: home-operations/talosctl-cluster-action@fb6a31bf5de43218acc80d2e23958a16eee7380c # v0.2.2
|
||||
with:
|
||||
config: ./.github/template-tests/e2e/talos-cluster.yaml
|
||||
cache: true
|
||||
|
||||
- name: Export cluster environment
|
||||
env:
|
||||
CONTROLPLANE_IPS: "${{ steps.cluster.outputs.controlplane-ips }}"
|
||||
GATEWAY: "${{ steps.cluster.outputs.gateway }}"
|
||||
WORKER_IPS: "${{ steps.cluster.outputs.worker-ips }}"
|
||||
run: |
|
||||
echo "E2E_CONTROLPLANE_IPS=$CONTROLPLANE_IPS" >> "$GITHUB_ENV"
|
||||
echo "E2E_WORKER_IPS=$WORKER_IPS" >> "$GITHUB_ENV"
|
||||
echo "E2E_GATEWAY=$GATEWAY" >> "$GITHUB_ENV"
|
||||
echo "E2E_CIDR=10.9.0.0/24" >> "$GITHUB_ENV"
|
||||
echo "E2E_STATE=$RUNNER_TEMP/template-e2e" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Prepare cluster
|
||||
run: bash ./.github/template-tests/e2e/cluster.sh prepare
|
||||
|
||||
- name: Build healthy cluster foundation
|
||||
run: bash ./.github/template-tests/e2e/cluster.sh foundation
|
||||
|
||||
- name: Test Flux SOPS
|
||||
id: flux-sops
|
||||
run: bash ./.github/template-tests/e2e/cluster.sh flux-sops
|
||||
background: true
|
||||
|
||||
- name: Test networking
|
||||
id: networking
|
||||
run: bash ./.github/template-tests/e2e/cluster.sh networking
|
||||
background: true
|
||||
|
||||
- name: Wait for E2E tests
|
||||
wait: [flux-sops, networking]
|
||||
|
||||
- name: Summarize cluster
|
||||
run: bash ./.github/template-tests/e2e/cluster.sh summary
|
||||
@@ -0,0 +1,176 @@
|
||||
---
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
||||
name: "E2E"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
validate-invalid:
|
||||
if: ${{ github.repository == 'onedr0p/cluster-template' }}
|
||||
name: reject-invalid (${{ matrix.fixture }})
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
fixture:
|
||||
- overlapping-cidrs
|
||||
- nested-cidr-overlap
|
||||
- non-canonical-cidr
|
||||
- tiny-svc-cidr
|
||||
- duplicate-gateway-addrs
|
||||
- duplicate-node-names
|
||||
- reserved-node-name
|
||||
- bad-mac-address
|
||||
- bad-repo-url
|
||||
- missing-known-hosts
|
||||
- node-addr-outside-cidr
|
||||
- node-uses-gateway-addr
|
||||
- gateway-node-collision
|
||||
- bad-vlan-tag
|
||||
- bad-bgp-asn
|
||||
- missing-dns-token
|
||||
- tunnel-without-dns
|
||||
- missing-external-gateway
|
||||
- missing-schematic
|
||||
- partial-bgp
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup mise
|
||||
uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4.3.0
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
- name: Assert schema rejects ${{ matrix.fixture }}.toml
|
||||
run: |
|
||||
fixture=./.github/template-tests/invalid/${{ matrix.fixture }}.toml
|
||||
if uv run --quiet --locked --no-dev ./template/scripts/validate.py "$fixture" >/dev/null 2>&1; then
|
||||
echo "::error::schema accepted invalid fixture ${{ matrix.fixture }} (expected rejection)"
|
||||
exit 1
|
||||
fi
|
||||
echo "schema correctly rejected ${{ matrix.fixture }}"
|
||||
# Also surface the actual error message in the log for debuggability.
|
||||
uv run --quiet --locked --no-dev ./template/scripts/validate.py "$fixture" || true
|
||||
|
||||
validator-tests:
|
||||
if: ${{ github.repository == 'onedr0p/cluster-template' }}
|
||||
name: validator-tests
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup mise
|
||||
uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4.3.0
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
- name: Run validator tests
|
||||
run: uv run --quiet --locked pytest ./template/scripts/test_validate.py
|
||||
|
||||
validate-valid:
|
||||
if: ${{ github.repository == 'onedr0p/cluster-template' }}
|
||||
name: accept-valid (${{ matrix.fixture }})
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
fixture:
|
||||
- public
|
||||
- private
|
||||
- selfhosted
|
||||
- no-webhook
|
||||
- internal
|
||||
- direct
|
||||
- single-node
|
||||
- multi-controller
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup mise
|
||||
uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4.3.0
|
||||
with:
|
||||
experimental: true
|
||||
install_args: --locked
|
||||
|
||||
- name: Run init recipe
|
||||
run: just init
|
||||
|
||||
- name: Prepare files
|
||||
run: |
|
||||
cp ./.github/template-tests/valid/${{ matrix.fixture }}.toml cluster.toml
|
||||
echo '{"AccountTag":"fake","TunnelSecret":"fake","TunnelID":"fake"}' > cloudflare-tunnel.json
|
||||
touch kubeconfig
|
||||
|
||||
- name: Assert cluster.toml passes the JSON Schema
|
||||
run: taplo check --schema "file://$PWD/cluster.schema.json" ./cluster.toml
|
||||
|
||||
- name: Run configure recipe
|
||||
run: just configure
|
||||
|
||||
# Rendered output must already match the format-yaml pre-commit hook,
|
||||
# otherwise every `just configure` shows up as formatting churn.
|
||||
- name: Assert rendered output is formatted
|
||||
run: oxfmt --check ./.sops.yaml ./bootstrap ./kubernetes ./talos
|
||||
|
||||
- name: Install flate
|
||||
uses: home-operations/flate/action@631b76b69c4e58c6f4d1cb01e23616fa61aebafa # v0.6.5
|
||||
with:
|
||||
base: ""
|
||||
|
||||
- name: Run flate test
|
||||
run: flate test all -p ./kubernetes/flux/cluster
|
||||
|
||||
- name: Render bootstrap helmfile charts
|
||||
run: just template test-helmfile
|
||||
|
||||
- name: Dry run bootstrap talos recipe
|
||||
run: just --dry-run bootstrap talos
|
||||
|
||||
- name: Create talos secret
|
||||
run: just bootstrap talos-secret
|
||||
|
||||
- name: Render talos configs
|
||||
run: just talos render
|
||||
|
||||
- name: Validate talos configs
|
||||
run: |
|
||||
for config in ./talos/rendered/*.yaml; do
|
||||
talosctl validate --config "$config" --mode metal
|
||||
done
|
||||
|
||||
- name: Dry run bootstrap apps recipe
|
||||
run: just --dry-run bootstrap apps
|
||||
|
||||
- name: Run reset recipe
|
||||
run: yes | just template reset
|
||||
|
||||
- name: Run tidy recipe
|
||||
run: yes | just template tidy
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
||||
name: "Release"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: 0 0 1 * *
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Get Previous Release Tag and Determine Next Tag
|
||||
id: determine-next-tag
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
result-encoding: string
|
||||
script: |
|
||||
const { data: releases } = await github.rest.repos.listReleases({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
per_page: 1,
|
||||
});
|
||||
|
||||
let previousTag = "0.0.0"; // Default if no previous release exists
|
||||
if (releases.length > 0) {
|
||||
previousTag = releases[0].tag_name;
|
||||
}
|
||||
|
||||
const [previousMajor, previousMinor, previousPatch] = previousTag.split('.').map(Number);
|
||||
const currentYear = new Date().getFullYear();
|
||||
const currentMonth = new Date().getMonth() + 1; // Months are 0-indexed in JavaScript
|
||||
|
||||
const nextMajorMinor = `${currentYear}.${currentMonth}`;
|
||||
let nextPatch;
|
||||
|
||||
if (`${previousMajor}.${previousMinor}` === nextMajorMinor) {
|
||||
console.log("Month release already exists for the year. Incrementing patch number by 1.");
|
||||
nextPatch = previousPatch + 1;
|
||||
} else {
|
||||
console.log("Month release does not exist for the year. Starting with patch number 0.");
|
||||
nextPatch = 0;
|
||||
}
|
||||
|
||||
return `${nextMajorMinor}.${nextPatch}`;
|
||||
|
||||
- name: Create Release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ steps.determine-next-tag.outputs.result }}
|
||||
run: gh release create "$TAG" --repo "$GITHUB_REPOSITORY" --generate-notes
|
||||
Reference in New Issue
Block a user