@@ -60,110 +60,14 @@ jobs:
6060 - name : Checkout
6161 uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
6262
63- - name : Enable KVM
64- run : |
65- echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
66- sudo udevadm control --reload-rules
67- sudo udevadm trigger --name-match=kvm
68-
69- - name : Set up Go
70- uses : actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
63+ - name : Set up test control plane
64+ uses : ./.github/actions/agent-e2e-kind-control-plane
7165 with :
72- go-version-file : go.mod
66+ cluster-name : ${{ env.KIND_CLUSTER_NAME }}
67+ vm-subnet : ${{ env.VM_SUBNET }}
7368
74- - name : Install system dependencies
75- run : |
76- sudo apt-get update
77- sudo apt-get install -y --no-install-recommends \
78- qemu-system-x86 qemu-utils genisoimage \
79- iptables
80-
81- - name : Create Kind cluster
82- uses : helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0
83- with :
84- cluster_name : ${{ env.KIND_CLUSTER_NAME }}
85- version : v0.29.0
86-
87- - name : Configure Kind cluster networking for VM
88- run : |
89- set -euo pipefail
90- KIND_CONTAINER="${KIND_CLUSTER_NAME}-control-plane"
91- KIND_IP=$(docker inspect "${KIND_CONTAINER}" \
92- --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}')
93- if [[ -z "${KIND_IP}" ]]; then
94- echo "::error::Could not determine Kind control-plane container IP"
95- exit 1
96- fi
97- echo "[INFO] Kind control-plane IP: ${KIND_IP}"
98- BRIDGE="virbr-e2e"
99-
100- # Allow forwarding between the VM bridge and Docker bridge.
101- sudo iptables -I FORWARD -i "${BRIDGE}" -j ACCEPT
102- sudo iptables -I FORWARD -o "${BRIDGE}" -j ACCEPT
103-
104- # Docker may insert raw PREROUTING DROP rules that block non-Docker
105- # traffic to container IPs. Insert an ACCEPT so the VM can reach the
106- # Kind API server.
107- sudo iptables -t raw -I PREROUTING -i "${BRIDGE}" -j ACCEPT
108-
109- # Patch kindnet so CONTROL_PLANE_ENDPOINT uses the container IP instead
110- # of the hostname (which is unresolvable from the VM).
111- echo "[INFO] Patching kindnet DaemonSet for VM-reachable control plane endpoint..."
112- PATCH=$(cat <<EOF
113- {
114- "spec": {
115- "template": {
116- "spec": {
117- "containers": [{
118- "name": "kindnet-cni",
119- "env": [
120- {"name": "CONTROL_PLANE_ENDPOINT", "value": "${KIND_IP}:6443"}
121- ]
122- }]
123- }
124- }
125- }
126- }
127- EOF
128- )
129- kubectl -n kube-system patch daemonset kindnet \
130- --type=strategic -p "${PATCH}"
131-
132- echo "[INFO] Waiting for kindnet rollout..."
133- kubectl -n kube-system rollout status daemonset/kindnet --timeout=60s
134-
135- - name : Create QEMU VM
136- run : python3 ./hack/agent/e2e-kind/e2e.py --verbose create-vm
137-
138- - name : Attach Kind container to VM bridge
139- run : |
140- set -euo pipefail
141- KIND_CONTAINER="${KIND_CLUSTER_NAME}-control-plane"
142- BRIDGE="virbr-e2e"
143-
144- # Connect the Kind container directly to the VM bridge via a veth
145- # pair so that the VM subnet is directly reachable at L2. This is
146- # required because kindnet adds routes of the form
147- # "10.244.x.0/24 via <nodeIP>" and the kernel rejects these when
148- # the gateway is only reachable via an indirect route.
149- echo "[INFO] Attaching Kind container to ${BRIDGE} bridge..."
150- KIND_PID=$(docker inspect "${KIND_CONTAINER}" --format '{{.State.Pid}}')
151- sudo ip link delete veth-kind-e2e 2>/dev/null || true
152- sudo ip link add veth-kind-e2e type veth peer name eth-e2e
153- sudo ip link set veth-kind-e2e master "${BRIDGE}"
154- sudo ip link set veth-kind-e2e up
155- sudo ip link set eth-e2e netns "${KIND_PID}"
156- sudo nsenter -t "${KIND_PID}" -n ip addr add "${VM_SUBNET}.2/24" dev eth-e2e
157- sudo nsenter -t "${KIND_PID}" -n ip link set eth-e2e up
158-
159- - name : Install Machine CRD
160- run : python3 ./hack/agent/e2e-kind/e2e.py --verbose install-machine-crd
161-
162- - name : Start machina controller
163- run : python3 ./hack/agent/e2e-kind/e2e.py --verbose start-machina-controller
164-
165- - name : Validate machina controller
166- run : python3 ./hack/agent/e2e-kind/e2e.py --verbose validate-machina-controller
69+ - name : Set up machina resources
70+ uses : ./.github/actions/agent-e2e-machina-setup
16771
16872 # No Machine CR pre-created; agent self-registers during bootstrap.
16973 - name : Run agent to join VM to cluster
@@ -227,77 +131,49 @@ jobs:
227131 - name : Validate node repave upgrade
228132 run : python3 ./hack/agent/e2e-kind/e2e.py --verbose validate-node-repave-upgrade
229133
230- - name : Collect VM logs
134+ - name : Collect logs
231135 if : always()
232- run : |
233- mkdir -p logs
234- VM_DIR=".vm-e2e"
235- # Collect VM serial console log
236- cp "${VM_DIR}/${VM_NAME}.log" logs/vm-serial.log 2>/dev/null || true
237- SSH="ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 -i ${VM_DIR}/ssh/id_ed25519 ubuntu@${VM_IP}"
238- # Collect full journal from the VM host (best-effort)
239- $SSH "sudo journalctl --no-pager -l" > logs/vm-journal.log 2>/dev/null || true
240- # Collect unbounded-agent logs from the VM host
241- $SSH "sudo journalctl -u unbounded-agent --no-pager -l" > logs/vm-unbounded-agent.log 2>/dev/null || true
242- # Collect unbounded-agent-daemon logs
243- $SSH "sudo journalctl -u unbounded-agent-daemon --no-pager -l" > logs/vm-unbounded-agent-daemon.log 2>/dev/null || true
244- cp ".vm-e2e/machina-controller.log" logs/machina-controller.log 2>/dev/null || true
245- # Kubelet and containerd run inside the nspawn container, not on
246- # the host. Use 'journalctl -M <machine>' to read the container
247- # journal, and fall back to machinectl shell if that doesn't work.
248- # The nspawn machine name is fixed to kube1/kube2 (decoupled from
249- # the Kubernetes node name).
250- $SSH "sudo machinectl list --no-pager" > logs/vm-machines.txt 2>/dev/null || true
251- for MACHINE in kube1 kube2; do
252- $SSH "sudo journalctl -M ${MACHINE} --no-pager -l" > logs/nspawn-${MACHINE}-journal.log 2>/dev/null || true
253- $SSH "sudo journalctl -M ${MACHINE} -u kubelet --no-pager -l" > logs/nspawn-${MACHINE}-kubelet.log 2>/dev/null || true
254- $SSH "sudo journalctl -M ${MACHINE} -u containerd --no-pager -l" > logs/nspawn-${MACHINE}-containerd.log 2>/dev/null || true
255- $SSH "sudo machinectl status ${MACHINE} --no-pager" > logs/vm-machine-${MACHINE}-status.txt 2>/dev/null || true
256- $SSH "sudo machinectl shell ${MACHINE} /usr/bin/systemctl list-units --no-pager" > logs/nspawn-${MACHINE}-units.txt 2>/dev/null || true
257- done
258-
259- - name : Collect cluster state
136+ uses : ./.github/actions/agent-e2e-kind-logs
137+ with :
138+ artifact-name : agent-e2e-kind-logs
139+
140+ - name : Cleanup
260141 if : always()
261- run : |
262- mkdir -p logs
263- kubectl get nodes -o wide > logs/nodes.txt 2>&1 || true
264- kubectl describe nodes > logs/nodes-describe.txt 2>&1 || true
265- kubectl get pods -A -o wide > logs/pods.txt 2>&1 || true
266- kubectl get events -A --sort-by='.lastTimestamp' > logs/events.txt 2>&1 || true
267- # Collect Machine CRs (if CRD is installed)
268- kubectl get machines -o wide > logs/machines.txt 2>&1 || true
269- kubectl get machines -o yaml > logs/machines-full.yaml 2>&1 || true
270- kubectl get machineconfigurations -o wide > logs/machineconfigurations.txt 2>&1 || true
271- kubectl get machineconfigurations -o yaml > logs/machineconfigurations-full.yaml 2>&1 || true
272- kubectl get machineconfigurationversions -o wide > logs/machineconfigurationversions.txt 2>&1 || true
273- kubectl get machineconfigurationversions -o yaml > logs/machineconfigurationversions-full.yaml 2>&1 || true
274- kubectl get machineoperations -o wide > logs/machineoperations.txt 2>&1 || true
275- kubectl get machineoperations -o yaml > logs/machineoperations-full.yaml 2>&1 || true
276- # Collect kubelet logs from the Kind control-plane
277- docker exec kind-control-plane journalctl -u kubelet --no-pager -l > logs/kind-kubelet.log 2>&1 || true
278- # Collect kube-apiserver logs (critical for diagnosing TLS bootstrap / RBAC issues)
279- docker exec kind-control-plane crictl logs $(docker exec kind-control-plane crictl ps -a --name kube-apiserver -q 2>/dev/null | head -1) > logs/kube-apiserver.log 2>&1 || true
280- # Dump all ClusterRoleBindings to see what RBAC kubeadm/Kind created
281- kubectl get clusterrolebindings -o wide > logs/clusterrolebindings.txt 2>&1 || true
282- kubectl get clusterrolebindings -o yaml > logs/clusterrolebindings-full.yaml 2>&1 || true
283- # List CSRs to see if the kubelet attempted TLS bootstrap
284- kubectl get csr -o wide > logs/csrs.txt 2>&1 || true
285- kubectl describe csr > logs/csrs-describe.txt 2>&1 || true
286- # Dump bootstrap token secrets (redact token-secret values)
287- kubectl get secrets -n kube-system -l 'kubernetes.io/legacy-token-last-used' -o wide > logs/bootstrap-tokens.txt 2>&1 || true
288- kubectl get secrets -n kube-system --field-selector type=bootstrap.kubernetes.io/token -o yaml > logs/bootstrap-token-secrets.yaml 2>&1 || true
289- # Collect workload test pod details
290- kubectl describe pods -n e2e-workload-test > logs/workload-pods-describe.txt 2>&1 || true
291- kubectl logs -n e2e-workload-test --all-containers --prefix e2e-hello > logs/workload-hello.log 2>&1 || true
292- kubectl logs -n e2e-workload-test --all-containers --prefix e2e-dns-test > logs/workload-dns.log 2>&1 || true
293-
294- - name : Upload logs
295- uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
142+ run : python3 ./hack/agent/e2e-kind/e2e.py --verbose cleanup
143+
144+ agent-config-e2e :
145+ name : agent config e2e
146+ runs-on : ubuntu-24.04
147+ timeout-minutes : 60
148+ env :
149+ KIND_CLUSTER_NAME : agent-config-e2e
150+ VM_NAME : agent-config-e2e
151+ VM_SUBNET : " 192.168.110"
152+ VM_IP : " 192.168.110.10"
153+ AGENT_MACHINE_NAME : agent-config-e2e
154+ steps :
155+ - name : Checkout
156+ uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
157+
158+ - name : Set up test control plane
159+ uses : ./.github/actions/agent-e2e-kind-control-plane
160+ with :
161+ cluster-name : ${{ env.KIND_CLUSTER_NAME }}
162+ vm-subnet : ${{ env.VM_SUBNET }}
163+ create-vm : " false"
164+
165+ - name : Set up machina resources
166+ uses : ./.github/actions/agent-e2e-machina-setup
167+
168+ - name : Discover and validate node configs
169+ run : python3 ./hack/agent/e2e-kind/e2e.py --verbose validate-node-configs
170+
171+ - name : Collect logs
296172 if : always()
173+ uses : ./.github/actions/agent-e2e-kind-logs
297174 with :
298- name : agent-e2e-kind-logs
299- path : logs/
300- retention-days : 30
175+ artifact-name : agent-config-e2e-logs
176+ node-configs : " true"
301177
302178 - name : Cleanup
303179 if : always()
0 commit comments