55# Functions:
66# validate_node_joined <vm_name> - Wait for a specific node to appear in kubectl
77# validate_all_nodes - Verify MSI, token, and kubeadm nodes joined
8+ # validate_npd_status <vm_name> <vm_ip> - Verify node-problem-detector is active
89# validate_node_absent <vm_name> - Wait for a node to disappear from kubectl
910# validate_all_nodes_absent - Verify all flex nodes are gone after unjoin
1011# smoke_test <vm_name> <label> - Schedule an nginx pod on a node
@@ -73,6 +74,93 @@ validate_node_ip() {
7374 return 1
7475}
7576
77+ # ---------------------------------------------------------------------------
78+ # validate_npd_status - Ensure node-problem-detector is active and reporting
79+ # ---------------------------------------------------------------------------
80+ validate_npd_status () {
81+ local vm_name=" $1 "
82+ local vm_ip=" $2 "
83+ local timeout=" ${E2E_NODE_JOIN_TIMEOUT} "
84+ local elapsed=0
85+ local npd_condition_jsonpath=' {.status.conditions[?(@.type=="KernelDeadlock")].status}'
86+ local condition_error=" ${E2E_WORK_DIR} /npd-condition-${vm_name} .err"
87+ local quoted_timeout
88+
89+ log_info " Validating node-problem-detector on '${vm_name} '..."
90+
91+ if ! [[ " ${timeout} " =~ ^[0-9]+$ ]]; then
92+ log_error " E2E_NODE_JOIN_TIMEOUT must be numeric, got '${timeout} '"
93+ return 1
94+ fi
95+ printf -v quoted_timeout " %q" " ${timeout} "
96+
97+ remote_exec " ${vm_ip} " " E2E_NODE_JOIN_TIMEOUT=${quoted_timeout} bash -s" << 'REMOTE '
98+ set -euo pipefail
99+
100+ deadline=$((SECONDS + E2E_NODE_JOIN_TIMEOUT))
101+ active_machine_error="/tmp/aks-flex-node-e2e-active-machine-$$.err"
102+ status_error="/tmp/aks-flex-node-e2e-npd-status-$$.err"
103+ while true; do
104+ if [[ ! -f /etc/aks-flex-node/daemon-state.json ]]; then
105+ active_machine=""
106+ echo "/etc/aks-flex-node/daemon-state.json is missing" > "${active_machine_error}"
107+ else
108+ active_machine="$(sudo python3 - <<'PY' 2>"${active_machine_error}" || true
109+ import json
110+ with open("/etc/aks-flex-node/daemon-state.json", encoding="utf-8") as state:
111+ print(json.load(state).get("activeMachine", ""))
112+ PY
113+ )"
114+ fi
115+ if [[ -n "${active_machine}" ]] && sudo machinectl show "${active_machine}" &>/dev/null; then
116+ status="$(sudo systemd-run --machine="${active_machine}" --quiet --pipe systemctl is-active node-problem-detector.service 2>"${status_error}" || true)"
117+ if [[ "${status}" == "active" ]]; then
118+ echo "node-problem-detector.service is active in ${active_machine}"
119+ exit 0
120+ fi
121+ fi
122+
123+ if (( SECONDS >= deadline )); then
124+ echo "node-problem-detector.service did not become active"
125+ if [[ -s "${active_machine_error}" ]]; then
126+ cat "${active_machine_error}"
127+ fi
128+ if [[ -s "${status_error}" ]]; then
129+ cat "${status_error}"
130+ fi
131+ sudo machinectl list --no-pager || true
132+ if [[ -n "${active_machine:-}" ]]; then
133+ sudo systemd-run --machine="${active_machine}" --quiet --pipe systemctl status node-problem-detector.service --no-pager -l || true
134+ sudo systemd-run --machine="${active_machine}" --quiet --pipe journalctl -u node-problem-detector.service -n 50 --no-pager || true
135+ fi
136+ exit 1
137+ fi
138+
139+ sleep 5
140+ done
141+ REMOTE
142+
143+ local kernel_deadlock
144+ while [[ " ${elapsed} " -lt " ${timeout} " ]]; do
145+ kernel_deadlock=" $( kubectl get node " ${vm_name} " -o jsonpath=" ${npd_condition_jsonpath} " 2> " ${condition_error} " || true) "
146+ if [[ " ${kernel_deadlock} " == " False" ]]; then
147+ log_success " node-problem-detector is active and reporting on '${vm_name} '"
148+ return 0
149+ fi
150+
151+ sleep 10
152+ elapsed=$(( elapsed + 10 ))
153+ log_debug " Waiting for node-problem-detector condition on ${vm_name} ... (${elapsed} /${timeout} s)"
154+ done
155+
156+ log_error " node-problem-detector did not report KernelDeadlock=False on '${vm_name} ' within ${timeout} s"
157+ if [[ -s " ${condition_error} " ]]; then
158+ cat " ${condition_error} " >&2
159+ fi
160+ kubectl describe node " ${vm_name} " 2>&1 || true
161+ return 1
162+ }
163+
76164# ---------------------------------------------------------------------------
77165# validate_all_nodes - Check all MSI, token, and kubeadm VMs joined
78166# ---------------------------------------------------------------------------
@@ -91,17 +179,24 @@ validate_all_nodes() {
91179 --admin
92180
93181 local msi_vm_name token_vm_name kubeadm_vm_name
182+ local msi_vm_ip token_vm_ip kubeadm_vm_ip
94183 local token_vm_private_ip
95184 msi_vm_name=" $( state_get msi_vm_name) "
96185 token_vm_name=" $( state_get token_vm_name) "
97186 kubeadm_vm_name=" $( state_get kubeadm_vm_name) "
187+ msi_vm_ip=" $( state_get msi_vm_ip) "
188+ token_vm_ip=" $( state_get token_vm_ip) "
189+ kubeadm_vm_ip=" $( state_get kubeadm_vm_ip) "
98190 token_vm_private_ip=" $( state_get token_vm_private_ip) "
99191
100192 local failed=0
101193 validate_node_joined " ${msi_vm_name} " || failed=1
102194 validate_node_joined " ${token_vm_name} " || failed=1
103195 validate_node_joined " ${kubeadm_vm_name} " || failed=1
104196 validate_node_ip " ${token_vm_name} " " ${token_vm_private_ip} " || failed=1
197+ validate_npd_status " ${msi_vm_name} " " ${msi_vm_ip} " || failed=1
198+ validate_npd_status " ${token_vm_name} " " ${token_vm_ip} " || failed=1
199+ validate_npd_status " ${kubeadm_vm_name} " " ${kubeadm_vm_ip} " || failed=1
105200
106201 if [[ " ${failed} " -eq 1 ]]; then
107202 log_error " One or more nodes failed to join"
0 commit comments