Trigger Phrases
- validate platform config
- validate provisioned host
- check provisioned node health
- validate k3s platform readiness
- post provision local validation
- host health check
Required Inputs
- enib_home: absolute path to this repository root (default: current workspace root)
- kubeconfig_path: expected kubeconfig path (default:
/etc/rancher/k3s/k3s.yaml)
Preconditions
Run silently without user prompts:
- Skill file exists and is readable:
test -f <enib_home>/skills/validate-platform-config/SKILL.md
- Verify this skill is running on the provisioned host (local execution model):
test -f /etc/cloud/config-file
- Required local tools exist:
command -v grepcommand -v ipcommand -v systemctlcommand -v lscpucommand -v lspcicommand -v curl
- Probe sudo non-interactively before any sudo fallback command:
sudo -n true- if exit code is
0, recordSUDO_NONINTERACTIVE=yes - if non-zero, record
SUDO_NONINTERACTIVE=noand skip sudo fallback commands later (do not fail preconditions)
Prompt only for missing required inputs:
- Ask only for missing
enib_homeand/orkubeconfig_path.
Steps
- Detect the
host_typefrom local configuration.
- command:
grep -E '^host_type' /etc/cloud/config-file 2>/dev/null || echo 'host_type=unknown'
- parse the output to extract the value (e.g.
kubernetes,container, orunknown) - store as
HOST_TYPEfor conditional branching in Steps 2 and 3
- If HOST_TYPE=kubernetes: Validate k3s pods and device plugins.
- command (try in order until one succeeds):
kubectl get pods -A --no-headersKUBECONFIG=~/.kube/config kubectl get pods -A --no-headers- if
SUDO_NONINTERACTIVE=yes:sudo -n kubectl get pods -A --no-headers - if
SUDO_NONINTERACTIVE=yes:sudo -n k3s kubectl get pods -A --no-headers
- required pod name prefixes and expected status:
intel-gpu-pluginindefaultnamespace,Running,READY 1/1intel-npu-pluginindefaultnamespace,Running,READY 1/1corednsinkube-system,Running,READY 1/1local-path-provisionerinkube-system,Running,READY 1/1metrics-serverinkube-system,Running,READY 1/1nfd-gcinnode-feature-discovery,Running,READY 1/1nfd-masterinnode-feature-discovery,Running,READY 1/1nfd-workerinnode-feature-discovery,Running,READY 1/1
- also validate binaries:
command -v kubectlcommand -v k3sls -l /usr/local/bin/kubectl /usr/local/bin/k3s 2>/dev/null || truesystemctl is-enabled k3s 2>/dev/null || truesystemctl is-active k3s 2>/dev/null || true
- expected:
k3sfound in PATHkubectlfound in PATH (binary or symlink)- one of expected locations exists:
/usr/local/bin/kubectl,/usr/bin/kubectl - one of expected locations exists:
/usr/local/bin/k3s,/usr/bin/k3s - k3s service is enabled and active
- If HOST_TYPE!=kubernetes (container or unknown): Validate Docker, Docker Compose, and Container Device Interface (CDI).
- commands:
command -v dockerdocker --version 2>/dev/null || truedocker compose version 2>/dev/null || truels -l /usr/local/bin/docker /usr/bin/docker 2>/dev/null || truesystemctl is-enabled docker 2>/dev/null || truesystemctl is-active docker 2>/dev/null || truedocker info 2>/dev/null | grep -E 'Server Version|Storage Driver|Cgroup|data-root' || truels /etc/cdi/ 2>/dev/null || truels /var/run/cdi/ 2>/dev/null || truecat /etc/cdi/*.json 2>/dev/null | python3 -c "import sys,json; [print(d.get('kind','?')) for d in json.load(sys.stdin).get('cdiDevices',json.load(open('/dev/stdin'))) if isinstance(d,dict)]" 2>/dev/null || ls /etc/cdi/ 2>/dev/null || truedocker info 2>/dev/null | grep -i cdi || true
- expected:
dockerfound in PATH- Docker version reported
- Docker Compose plugin available (
docker compose versionsucceeds) - Docker service is enabled and active
- CDI spec files present in
/etc/cdi/or/var/run/cdi/(e.g.intel-gpu.json,intel-npu.json) - CDI devices exposed to Docker runtime
- Validate cloud-init completion.
- commands:
cloud-init status --long || truetest -f /var/lib/cloud/instance/boot-finished && echo CLOUD_INIT_BOOT_FINISHED=1 || echo CLOUD_INIT_BOOT_FINISHED=0grep -Ei 'error|failed|traceback' /var/log/cloud-init.log | tail -n 20 || true
- expected:
- cloud-init reports
status: done /var/lib/cloud/instance/boot-finishedexists- no blocking cloud-init errors relevant to first boot provisioning
- cloud-init reports
- Validate network connectivity and assigned IP.
- commands:
ip -o -4 addr show scope globalip route show defaultping -c 2 -W 2 8.8.8.8 >/dev/null 2>&1 && echo NET_INTERNET=ok || echo NET_INTERNET=failgetent hosts github.com >/dev/null 2>&1 && echo DNS=ok || echo DNS=failcurl -I --max-time 8 https://github.com >/dev/null 2>&1 && echo HTTPS_EGRESS=ok || echo HTTPS_EGRESS=fail
- expected:
- at least one global IPv4 address assigned
- default route present
- connectivity result is classified explicitly:
- direct internet OK:
NET_INTERNET=ok - restricted/proxy-likely:
NET_INTERNET=failandDNS=ok - DNS/config issue:
DNS=fail
- direct internet OK:
- if
NET_INTERNET=failandDNS=ok, do not hard-fail validation; report as "likely proxy required" with proxy evidence from Step 6
- Collect proxy values (brief).
- command:
grep -hsE '^(https?_proxy|no_proxy)=' /etc/environment 2>/dev/null | head -5 || echo 'no proxy configured'
- expected:
- report proxy variables from
/etc/environmentif set; otherwise report "no proxy configured" - do NOT dump k3s.service.env or docker proxy.conf unless network checks in Step 6 indicate proxy issues
- report proxy variables from
- Inventory CPU/GPU/NPU devices.
- commands:
nproclscpulscpu | grep -E 'Model name|Vendor ID|CPU family|Model:|Stepping'grep -E '^(model name|flags|cpu cores|siblings)' /proc/cpuinfo | head -20cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver 2>/dev/null || truecat /proc/cpuinfo | grep -E 'cpu family|model|stepping|flags' | head -10if ls /sys/devices/system/cpu/cpu*/topology/core_type >/dev/null 2>&1; then for f in /sys/devices/system/cpu/cpu*/topology/core_type; do cat "$f"; done | awk '{c[$1]++} END {for (t in c) printf "CORE_TYPE_RAW_%s_COUNT=%d\n", t, c[t]}' | sort; else echo CORE_TYPE_EXPOSED=no; fiif ls /sys/devices/system/cpu/cpu*/topology/core_type >/dev/null 2>&1; then for f in /sys/devices/system/cpu/cpu*/topology/core_type; do cat "$f"; done | awk '{c[$1]++} END {printf "P_CORE_COUNT=%d\n", c[2]+0; printf "E_CORE_COUNT=%d\n", c[1]+0; printf "LPE_CORE_COUNT=%d\n", c[3]+0}'; else echo "P_CORE_COUNT=unavailable"; echo "E_CORE_COUNT=unavailable"; echo "LPE_CORE_COUNT=unavailable"; fifor cpu in /sys/devices/system/cpu/cpu*/topology/thread_siblings_list; do [ -f "$cpu" ] && echo "$cpu=$(cat $cpu)"; done | head -10lspci -nn | grep -Ei 'vga|3d|display|npu|neural|vpu|accel|intel' || truels -l /dev/dri 2>/dev/null || true
- expected:
- Total CPU core count and logical processors reported
- P-core, E-core, and LPE-core counts are reported when
core_typeis exposed - raw
core_typecounts are always reported alongside decoded counts for traceability - if
core_typeis not exposed by the kernel or platform, report P/E/LPE counts asunavailable - CPU model, family, stepping, and feature flags documented
- CPU codename is reported only when verified from trusted identifiers (family/model/stepping mapping); never infer codename from model name text alone
- if codename cannot be verified confidently, report
CPU_CODENAME=unverifiedinstead of guessing - CPU frequency scaling driver reported
- Core type information from
/sys/devices/system/cpu/cpu*/topology/core_typeis decoded using common Linux hybrid mapping (2=P,1=E,3=LPE) and may vary by kernel/platform - Thread siblings mapping for logical CPU layout
- GPU presence determined from Peripheral Component Interconnect (PCI) and/or
/dev/dri - NPU presence determined from PCI scan output
- If GPU is present, report GPU Virtual Function (VF) counts.
- commands:
for f in /sys/class/drm/card*/device/sriov_numvfs; do [ -f "$f" ] && echo "$f=$(cat $f)"; donefor f in /sys/class/drm/card*/device/sriov_totalvfs; do [ -f "$f" ] && echo "$f=$(cat $f)"; done
- expected:
- report per-GPU
sriov_numvfsandsriov_totalvfs - if GPU exists but no SR-IOV files are present, report as unsupported/not enabled.
- report per-GPU
- Check SR-IOV service if
enable_sriovis set to true.
- first check:
grep -E '^enable_sriov' /etc/cloud/config-file 2>/dev/null || echo 'enable_sriov=unset'
- if value is
true, validate:systemctl is-enabled intel-sriov-vf.service 2>/dev/null || echo 'not-found'
- expected:
- if enabled: report
intel-sriov-vf.serviceis enabled — VFs will be preserved across reboots - if disabled/not-found: report service not enabled — VFs will NOT persist across reboots
- if
enable_sriovis nottrue, SKIP this check
- if enabled: report
Validation
Validation section is criteria-only. Do not render the pass/fail results table here.
host_typeis detected and reported; conditional checks branch accordingly.- If kubernetes: All required k3s pods listed in Step 2 are found in the correct namespaces and are healthy (
Running,1/1);kubectlandk3sbinaries are present. - If container/unknown: Docker and Docker Compose are available, Docker service is active, and CDI specification files are present.
- cloud-init completion indicators are successful.
- Network check reports assigned IP and route; connectivity is classified as direct or proxy/restricted with explicit reason.
- Proxy values are collected briefly from
/etc/environment; expanded only if network issues are detected. - CPU/GPU/NPU inventory is collected with clear present/absent status.
- CPU codename labeling is verification-based and avoids false platform naming.
- GPU VF data is reported when the GPU exists.
- SR-IOV service (
intel-sriov-vf.service) is validated whenenable_sriov=truein config-file.
Rollback
This is a read-only validation skill. No rollback required.
Safety Rules
- Prefer read-only commands; do not alter target host configuration in this skill.
- Do not use destructive or privileged write operations.
- If a check fails, continue collecting remaining checks and return a complete report.
Expected Result Summary
Render the report as the following tables.
Run Metadata
| Field | Value |
|---|---|
| Preconditions | PASS/FAIL |
| Execution mode | local |
| Host context | provisioned host |
| Sudo fallback availability | yes/no from sudo -n true probe |
Validation Results
| Check Area | Status | Evidence | Notes |
|---|---|---|---|
| host_type detection | PASS/FAIL/WARN | value from /etc/cloud/config-file |
kubernetes, container, or unknown |
| k3s pods (kubernetes only) | PASS/FAIL/WARN/SKIP | key pod states from kubectl get pods -A |
skipped if host_type!=kubernetes |
| k3s binaries (kubernetes only) | PASS/FAIL/WARN/SKIP | command -v k3s, kubectl |
skipped if host_type!=kubernetes |
| docker + compose (container only) | PASS/FAIL/WARN/SKIP | docker --version, docker compose version |
skipped if host_type=kubernetes |
| CDI specs (container only) | PASS/FAIL/WARN/SKIP | /etc/cdi/, /var/run/cdi/ contents |
skipped if host_type=kubernetes |
| cloud-init | PASS/FAIL/WARN | cloud-init status, boot-finished marker |
include relevant error lines |
| network and IP | PASS/FAIL/WARN | IP/route, NET_INTERNET, DNS, HTTPS_EGRESS |
classify restricted/proxy-likely cases |
| proxy values | PASS/FAIL/WARN | /etc/environment summary |
only expanded if network issues detected |
| SR-IOV service | PASS/FAIL/WARN/SKIP | intel-sriov-vf.service state |
skipped if enable_sriov!=true |
| CPU/GPU/NPU inventory | PASS/FAIL/WARN | CPU topology, lspci, /dev/dri |
codename must be verified or unverified |
| GPU VF counts | PASS/FAIL/WARN | sriov_numvfs, sriov_totalvfs |
unsupported/not-enabled if files missing |
Observed Proxy Values
| Variable | Value |
|---|---|
http_proxy |
<value or unset> |
https_proxy |
<value or unset> |
no_proxy |
<value or unset> |
GPU VF Counts
| Device | sriov_numvfs |
sriov_totalvfs |
|---|---|---|
/sys/class/drm/card<N> |
<n> |
<total> |
Failures and Troubleshooting
| Failed Check | Raw Evidence | Troubleshooting Note |
|---|---|---|
<check area> |
<snippet> |
<action> |
Troubleshooting Notes
- If
kubectlfails due to kubeconfig permissions, retry withk3s kubectl. - If Docker is installed but inactive, include
systemctl status docker --no-pagerand recentjournalctl -u docker -n 50 --no-pageroutput. - If reading k3s.service.env or docker proxy.conf returns "Permission denied" and
SUDO_NONINTERACTIVE=yes, try:sudo -n cat /etc/systemd/system/k3s.service.envorsudo -n cat /etc/systemd/system/docker.service.d/proxy.confrespectively. - If pods are
PendingorCrashLoopBackOff, includekubectl describeand recent logs for those pods. - If cloud-init is not complete, inspect
/var/log/cloud-init-output.logand relevant systemd units. - If
NET_INTERNET=failbutDNS=ok, classify as "likely proxy required/restricted ICMP" and include proxy values, route output, andHTTPS_EGRESSresult in findings. - If detected CPU codename conflicts with known platform information (for example Panther Lake vs Lunar Lake), treat codename as
unverifiedunless family/model/stepping mapping confirms it. - If GPU exists but VF count is 0, report whether SR-IOV is disabled or unsupported on that platform.