A Pi 3B+ (stickah.local) shares a Phomemo PM246 to the LAN as a plain CUPS queue, so any machine can print 4x6 labels -- fulfillr-site's shipping labels in particular -- without installing the vendor driver, which is x86-64 only. The role builds the TSPL CUPS driver from source instead. It is Debian, not Fedora, so it lives in its own inventory and playbook (make deploy-labelprint / check-labelprint) and the home.debyl.io roles can never run against it. make bootfs renders its cloud-init first-boot files onto a freshly imaged SD card from the same templates the role uses. The Wi-Fi credentials for the home and rescue networks are in the vault. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
107 lines
4.0 KiB
YAML
107 lines
4.0 KiB
YAML
---
|
|
# Renders the Raspberry Pi's cloud-init first-boot files onto a freshly written
|
|
# SD card's boot partition:
|
|
#
|
|
# make bootfs BOOTFS=/Volumes/bootfs
|
|
#
|
|
# The image itself is still built by hand with rpi-imager -- this only writes
|
|
# the two cloud-init files onto it. Everything it writes comes from the same
|
|
# templates roles/labelprint uses, so the Pi boots with its Wi-Fi profiles and
|
|
# rescue access point already in place, and the first deploy has nothing to
|
|
# correct.
|
|
#
|
|
# The rendered files contain the Wi-Fi PSKs in the clear, as any Pi Wi-Fi setup
|
|
# does. They land on the SD card, never in this repo.
|
|
- hosts: localhost
|
|
gather_facts: false
|
|
connection: local
|
|
vars_files:
|
|
- vars/vault.yml
|
|
- roles/labelprint/defaults/main.yml
|
|
tasks:
|
|
- name: check that BOOTFS points at a Raspberry Pi boot partition
|
|
ansible.builtin.stat:
|
|
path: "{{ bootfs }}/config.txt"
|
|
register: labelprint_bootfs_check
|
|
tags: bootfs
|
|
|
|
- name: refuse to write to anything else
|
|
ansible.builtin.assert:
|
|
that: labelprint_bootfs_check.stat.exists
|
|
fail_msg: >-
|
|
{{ bootfs }} has no config.txt, so it is not a Raspberry Pi boot
|
|
partition. Write the image with rpi-imager first, then re-run with
|
|
BOOTFS pointing at the mounted boot volume.
|
|
tags: bootfs
|
|
|
|
- name: look for files rpi-imager already wrote
|
|
ansible.builtin.stat:
|
|
path: "{{ bootfs }}/{{ item }}"
|
|
register: labelprint_bootfs_existing
|
|
loop:
|
|
- user-data
|
|
- network-config
|
|
- cmdline.txt
|
|
tags: bootfs
|
|
|
|
# Keeps whatever rpi-imager put there, so a bad render can be undone by hand
|
|
# without reflashing. force:false means the first run's backup is the one
|
|
# that survives -- a second run must not overwrite it with our own output.
|
|
- name: back up the files rpi-imager wrote
|
|
ansible.builtin.copy:
|
|
src: "{{ bootfs }}/{{ item.item }}"
|
|
dest: "{{ bootfs }}/{{ item.item }}.rpi-imager.bak"
|
|
mode: "0644"
|
|
force: false
|
|
loop: "{{ labelprint_bootfs_existing.results }}"
|
|
loop_control:
|
|
label: "{{ item.item }}"
|
|
when: item.stat.exists
|
|
tags: bootfs
|
|
|
|
- name: render the cloud-init files
|
|
ansible.builtin.template:
|
|
src: "roles/labelprint/templates/bootfs/{{ item }}.j2"
|
|
dest: "{{ bootfs }}/{{ item }}"
|
|
mode: "0644"
|
|
loop:
|
|
- user-data
|
|
- network-config
|
|
tags: bootfs
|
|
|
|
- name: hash the rendered user-data
|
|
ansible.builtin.stat:
|
|
path: "{{ bootfs }}/user-data"
|
|
checksum_algorithm: sha1
|
|
register: labelprint_user_data_stat
|
|
tags: bootfs
|
|
|
|
- name: stamp the instance id with that hash
|
|
ansible.builtin.template:
|
|
src: roles/labelprint/templates/bootfs/meta-data.j2
|
|
dest: "{{ bootfs }}/meta-data"
|
|
mode: "0644"
|
|
vars:
|
|
labelprint_user_data_id: "{{ labelprint_user_data_stat.stat.checksum[:12] }}"
|
|
tags: bootfs
|
|
|
|
# rpi-imager writes `ds=nocloud;i=<id>` onto the kernel command line, and
|
|
# that id outranks the one in meta-data. Leave it alone and a card that has
|
|
# booted even once is seen by cloud-init as the same instance forever: it
|
|
# skips users, write_files and runcmd, silently, and the only symptom is a
|
|
# Pi that came up with none of this applied. Both places have to agree.
|
|
- name: pin the same instance id on the kernel command line
|
|
ansible.builtin.replace:
|
|
path: "{{ bootfs }}/cmdline.txt"
|
|
regexp: '(ds=nocloud[^\s]*?);i=[^\s]+'
|
|
replace: '\1;i={{ labelprint_hostname }}-{{ labelprint_user_data_stat.stat.checksum[:12] }}'
|
|
tags: bootfs
|
|
|
|
- name: what to do next
|
|
ansible.builtin.debug:
|
|
msg:
|
|
- "Wrote user-data, network-config, meta-data and cmdline.txt to {{ bootfs }}."
|
|
- "Instance id is {{ labelprint_hostname }}-{{ labelprint_user_data_stat.stat.checksum[:12] }}; the Pi re-applies this config whenever it changes."
|
|
- "Eject the volume, boot the Pi, then: make deploy-labelprint"
|
|
tags: bootfs
|