Removing the SSH banner only hid the symptom. userconfig.service is a
Type=oneshot unit that runs
whiptail --inputbox "Which user would you like to rename:" 20 60 pi
on tty8 and waits for an answer, which on a headless Pi never comes - it had
been sitting in "activating" for four and a half hours on musicdolphin. It is
WantedBy=multi-user.target, so that target never finished activating either, and
the boot job for it was still queued from boot. Anything ordered
After=multi-user.target then gets a start job that queues behind it and hangs
forever: musicmouse.service never started, and the ansible task that starts it
blocked until killed.
The pi user already exists on these images, so the wizard has nothing to do.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
184 lines
6.3 KiB
YAML
184 lines
6.3 KiB
YAML
---
|
|
- name: Refresh apt cache
|
|
ansible.builtin.apt:
|
|
update_cache: "yes"
|
|
cache_valid_time: "7200"
|
|
- name: Detect Raspi Model
|
|
ansible.builtin.slurp:
|
|
src: /sys/firmware/devicetree/base/model
|
|
register: pi_standard_setup_raspberry_model
|
|
- name: Show Raspi Model
|
|
ansible.builtin.debug:
|
|
msg: "{{ pi_standard_setup_raspberry_model.content | b64decode }}"
|
|
- name: Add authorized SSH key to root account
|
|
ansible.posix.authorized_key:
|
|
user: root
|
|
key: "{{ lookup('file', 'sshkey.pub') }}"
|
|
state: present
|
|
- name: Activate root login with key
|
|
ansible.builtin.lineinfile:
|
|
path: /etc/ssh/sshd_config
|
|
regexp: "^#?PermitRootLogin"
|
|
line: "PermitRootLogin prohibit-password"
|
|
notify: Restart sshd
|
|
- name: Deactive SSH accepting locale vars (leads to warnings)
|
|
ansible.builtin.lineinfile:
|
|
path: /etc/ssh/sshd_config
|
|
regexp: "^#?AcceptEnv LANG LC_*"
|
|
line: "#AcceptEnv LANG LC_*"
|
|
notify: Restart sshd
|
|
- name: Remove first-run "SSH may not work until a valid user has been set up" banner
|
|
ansible.builtin.file:
|
|
path: /etc/ssh/sshd_config.d/rename_user.conf
|
|
state: absent
|
|
notify: Restart sshd
|
|
- name: Check for the Raspberry Pi first-boot user wizard
|
|
ansible.builtin.stat:
|
|
path: /lib/systemd/system/userconfig.service
|
|
register: pi_standard_setup_userconfig
|
|
|
|
- name: Disable the Raspberry Pi first-boot user wizard
|
|
# Removing the SSH banner above only hides the symptom. The wizard itself is a
|
|
# Type=oneshot unit that runs `whiptail --inputbox "Which user would you like to
|
|
# rename:"` on tty8 and waits for an answer that never comes on a headless box - it
|
|
# sits in "activating" forever. Because it is WantedBy=multi-user.target, that target
|
|
# never finishes activating either, and every unit ordered After=multi-user.target
|
|
# (musicmouse.service among them) gets a start job that queues behind it and hangs.
|
|
# The pi user already exists on these images, so there is nothing for it to do.
|
|
ansible.builtin.systemd:
|
|
name: userconfig.service
|
|
state: stopped
|
|
enabled: false
|
|
masked: true
|
|
when: pi_standard_setup_userconfig.stat.exists
|
|
- name: Get hostname
|
|
ansible.builtin.command: "raspi-config nonint get_hostname"
|
|
register: pi_standard_setup_pi_hostname
|
|
changed_when: false
|
|
check_mode: false # read-only; must run in --check so .stdout isn't empty
|
|
- name: Change hostname {{ pi_standard_setup_new_hostname }}
|
|
ansible.builtin.command: "raspi-config nonint do_hostname {{ pi_standard_setup_new_hostname }}"
|
|
when: pi_standard_setup_new_hostname | length > 0 and pi_standard_setup_pi_hostname.stdout != pi_standard_setup_new_hostname
|
|
register: pi_standard_setup_set_hostname
|
|
changed_when: true
|
|
notify: Reboot
|
|
- name: Get hostname
|
|
ansible.builtin.command: "raspi-config nonint get_hostname"
|
|
register: pi_standard_setup_pi_hostname
|
|
changed_when: false
|
|
check_mode: false # read-only; must run in --check so .stdout isn't empty
|
|
# raspi-config's do_hostname only rewrites the 127.0.1.1 line if it already
|
|
# contains the *old* hostname. Ours said "raspberrypi", so every rename since
|
|
# the first one has silently left this stale.
|
|
- name: Point 127.0.1.1 at the current hostname
|
|
ansible.builtin.lineinfile:
|
|
path: /etc/hosts
|
|
regexp: '^127\.0\.1\.1\s'
|
|
line: "127.0.1.1\t{{ pi_standard_setup_pi_hostname.stdout }}"
|
|
- name: Get current boot target
|
|
ansible.builtin.command: "systemctl get-default"
|
|
register: pi_standard_setup_boot_target
|
|
changed_when: false
|
|
check_mode: false # read-only; must run in --check so .stdout isn't empty
|
|
- name: Set boot mode to CLI
|
|
ansible.builtin.command: "raspi-config nonint do_boot_behaviour B1"
|
|
when: pi_standard_setup_boot_target.stdout != "multi-user.target"
|
|
changed_when: true
|
|
# I2 Change Timezone
|
|
- name: Change timezone
|
|
community.general.timezone:
|
|
name: "{{ pi_standard_setup_timezone }}"
|
|
- name: Generate locale
|
|
community.general.locale_gen:
|
|
name: en_US.UTF-8
|
|
state: present
|
|
- name: Set default locale
|
|
ansible.builtin.lineinfile:
|
|
path: /etc/default/locale
|
|
regexp: "^LANG="
|
|
line: "LANG=en_US.UTF-8"
|
|
create: true
|
|
mode: "0644"
|
|
- name: Change password of default pi account
|
|
ansible.builtin.user:
|
|
name: pi
|
|
update_password: always
|
|
password: "{{ lookup('keepass', 'ansible://default_rpi_password') | password_hash('sha512', 65534 | random(seed=inventory_hostname) | string) }}"
|
|
- name: Install Packages (vim, git, basic python stuff)
|
|
ansible.builtin.apt:
|
|
name:
|
|
- vim
|
|
- git
|
|
- python3
|
|
- python3-pip
|
|
- python3-wheel
|
|
- telnet
|
|
cache_valid_time: 7200
|
|
state: present
|
|
- name: Copy vim config
|
|
ansible.builtin.copy:
|
|
src: vimrc
|
|
dest: /root/.vimrc
|
|
mode: "0644"
|
|
- name: Copy git config
|
|
ansible.builtin.copy:
|
|
src: gitconfig
|
|
dest: /root/.gitconfig
|
|
mode: "0644"
|
|
# Wifi
|
|
- name: Change WiFi country
|
|
ansible.builtin.command: "raspi-config nonint do_wifi_country {{ pi_standard_setup_wifi_country }}"
|
|
when: configure_wifi
|
|
changed_when: true
|
|
- name: Set WiFi credentials
|
|
ansible.builtin.command: "raspi-config nonint do_wifi_ssid_passphrase {{ pi_standard_setup_wifi_ssid }} {{ lookup('keepass', 'bauer_wifi') }}"
|
|
when: configure_wifi
|
|
changed_when: true
|
|
- name: Install watchdog
|
|
ansible.builtin.apt:
|
|
name: watchdog
|
|
cache_valid_time: "7200"
|
|
state: present
|
|
when: not pi_standard_setup_wifi_ssid is defined
|
|
- name: Configure watchdog
|
|
ansible.builtin.blockinfile:
|
|
path: /etc/watchdog.conf
|
|
block: |
|
|
interface = wlan0
|
|
retry-timeout = 90
|
|
ping = {{ router_ip }}
|
|
interval = 15
|
|
when: configure_wifi
|
|
- name: Start watchdog
|
|
ansible.builtin.systemd: # state=restarted not working, also not manually
|
|
name: watchdog
|
|
state: started
|
|
enabled: "yes"
|
|
daemon_reload: "yes"
|
|
when: configure_wifi
|
|
# Message of the day
|
|
- name: Set Message of the day
|
|
ansible.builtin.copy:
|
|
src: motd/{{ pi_standard_setup_pi_hostname.stdout }}
|
|
dest: /etc/motd
|
|
mode: "0644"
|
|
# LED off script
|
|
- name: Copy led off script
|
|
ansible.builtin.copy:
|
|
src: raspi-leds-off.sh
|
|
dest: /usr/sbin/raspi-leds-off.sh
|
|
mode: "u+rwx"
|
|
notify: Restart raspi-leds-off
|
|
- name: Copy led off service
|
|
ansible.builtin.copy:
|
|
src: raspi-leds-off.service
|
|
dest: /lib/systemd/system/
|
|
mode: "0644"
|
|
notify: Restart raspi-leds-off
|
|
- name: Activate led off service
|
|
ansible.builtin.systemd:
|
|
name: raspi-leds-off
|
|
state: started
|
|
enabled: "yes"
|
|
daemon_reload: "yes"
|