Files
Bastian de BylandClaude Opus 5 6cd4d56de1 feat(labelprint): 4x6 label print proxy on a Raspberry Pi
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>
2026-09-13 23:14:45 -04:00

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