fix(raspberrypi): detect Raspberry Pi hardware in check mode (#719)

- set check_mode: false on the /proc/cpuinfo and /proc/device-tree/model
  probes, since ansible.builtin.command never executes under --check and
  returns rc 0 with "Command would have run if not in check mode"
- default a missing probe rc to 1 in the raspberry_pi gate so an undefined
  result cannot be read as "this host is a Raspberry Pi"
- add a structural regression test and hook it into pre-commit

Without this, site.yml --check marked every x86_64 host as a Raspberry Pi and
applied the distro specific setup tasks, failing on Ubuntu with
"Destination /boot/firmware/cmdline.txt does not exist".
This commit is contained in:
Marc Palacín authored and GitHub committed 2026-09-30 22:45:00 +00:00
1 parent 8fb1e26c63
commit 1b994f7479
3 files changed
+83 -1

No files matched your search

+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/env bash
set -Eeuo pipefail
repo_root="$(git rev-parse --show-toplevel)"
tasks_file="$repo_root/roles/raspberrypi/tasks/main.yml"
if [ ! -f "$tasks_file" ]; then
printf 'cannot find %s\n' "$tasks_file" >&2
exit 1
fi
# The role decides whether a host is a Raspberry Pi from the return code of two
# ansible.builtin.command probes. The command module never executes under
# --check: it returns rc 0 with "Command would have run if not in check mode".
# Without check_mode: false on both probes every host looks like a Raspberry Pi
# in a check run, so distro specific tasks (e.g. the Ubuntu cgroup
# cmdline.txt edit) run against hosts that must not be touched.
probe_count="$(grep -c -- 'check_mode: false' "$tasks_file" || true)"
if [ "$probe_count" -lt 2 ]; then
printf 'raspberrypi detection probes must set check_mode: false (found %s, expected 2)\n' \
"$probe_count" >&2
exit 1
fi
# Both probes must be the detection greps, not some other task.
for probe in \
'grep -E "Raspberry Pi|BCM2708|BCM2709|BCM2835|BCM2836" /proc/cpuinfo' \
'grep -E "Raspberry Pi" /proc/device-tree/model'; do
grep -Fq -- "$probe" "$tasks_file" || {
printf 'missing raspberry pi detection probe: %s\n' "$probe" >&2
exit 1
}
done
# The probes must stay registered under the names the gate consumes.
for var in grep_cpuinfo_raspberrypi grep_device_tree_model_raspberrypi; do
grep -Fq -- "register: $var" "$tasks_file" || {
printf 'detection probe is not registered as %s\n' "$var" >&2
exit 1
}
done
# The gate must keep keying on rc 0 and must tolerate a missing rc so an
# undefined result cannot be read as "this host is a Raspberry Pi".
grep -Eq -- 'when:.*grep_cpuinfo_raspberrypi\.rc.*== 0.*grep_device_tree_model_raspberrypi\.rc.*== 0' \
"$tasks_file" || {
printf 'raspberry_pi gate no longer tests both probe return codes for 0\n' >&2
exit 1
}
grep -Eq -- 'grep_cpuinfo_raspberrypi\.rc \| default\(1\)' "$tasks_file" || {
printf 'raspberry_pi gate does not default the /proc/cpuinfo probe rc\n' >&2
exit 1
}
grep -Eq -- 'grep_device_tree_model_raspberrypi\.rc \| default\(1\)' "$tasks_file" || {
printf 'raspberry_pi gate does not default the /proc/device-tree probe rc\n' >&2
exit 1
}
# The distro specific include must remain gated on the detection result so a
# non Raspberry Pi host skips setup/ and teardown/ entirely.
grep -Eq -- 'raspberry_pi\|default\(false\)' "$tasks_file" || {
printf 'OS specific tasks are no longer gated on raspberry_pi\n' >&2
exit 1
}
printf 'Raspberry Pi detection regression test passed\n'
+6
View File
@@ -76,6 +76,12 @@ repos:
language: system
pass_filenames: false
files: ^roles/prereq/(tasks/main|defaults/main)\.yml$|^\.github/scripts/test-disable-swap\.sh$
- id: raspberrypi-detection-test
name: Raspberry Pi detection test
entry: .github/scripts/test-raspberrypi-detection.sh
language: system
pass_filenames: false
files: ^roles/raspberrypi/(tasks/main|defaults/main)\.yml$|^\.github/scripts/test-raspberrypi-detection\.sh$
- id: cilium-bgp-manifest-test
name: Cilium BGP manifest test
entry: python3 .github/scripts/test-cilium-bgp-manifest.py
+8 -1
View File
@@ -1,20 +1,27 @@
---
# The probes below must run in check mode as well. The command module does not
# execute under --check, it returns rc 0 with "Command would have run if not in
# check mode", which would otherwise mark every host as a Raspberry Pi and make
# check runs apply the distro specific tasks. The rc values mean: 0 matched, 1 no
# match, 2 the file is absent (no /proc/device-tree on non ARM systems).
- name: Test for raspberry pi /proc/cpuinfo
ansible.builtin.command: grep -E "Raspberry Pi|BCM2708|BCM2709|BCM2835|BCM2836" /proc/cpuinfo
register: grep_cpuinfo_raspberrypi
failed_when: false
changed_when: false
check_mode: false
- name: Test for raspberry pi /proc/device-tree/model
ansible.builtin.command: grep -E "Raspberry Pi" /proc/device-tree/model
register: grep_device_tree_model_raspberrypi
failed_when: false
changed_when: false
check_mode: false
- name: Set raspberry_pi fact to true
ansible.builtin.set_fact:
raspberry_pi: true
when: grep_cpuinfo_raspberrypi.rc == 0 or grep_device_tree_model_raspberrypi.rc == 0
when: (grep_cpuinfo_raspberrypi.rc | default(1)) == 0 or (grep_device_tree_model_raspberrypi.rc | default(1)) == 0
- name: Set detected_distribution to Raspbian (ARM64 on Raspbian, Debian Buster/Bullseye/Bookworm)
ansible.builtin.set_fact: