#!/bin/sh # Install a rollcall rack controller on this host (Debian/Ubuntu). Run as root # from this directory with the rollcall binary next to it, after enrolling: # # region$ rollcall controller join-code -name hall-b -addr REGION:443 # rack$ ./rollcall rack join -url http://ADDR-ON-THE-SEGMENT # # which writes /etc/rollcall/rack.json and the rack's certificate; from then on # rack and region talk over mutual TLS (rack.example.json shows the fields). # # The rack controller serves DHCP/TFTP (dnsmasq) on the VLANs the region # assigns to it, keeps boot and OS images in a local cache, runs BMC commands # and passes the node API through to the region. set -eu cd "$(dirname "$0")" [ -r /etc/rollcall/rack.json ] || { echo "enroll first: ./rollcall rack join CODE -url http://ADDR (code from: rollcall controller join-code on the region)" >&2; exit 1; } export DEBIAN_FRONTEND=noninteractive apt-get install -y -q dnsmasq ipmitool pxelinux syslinux-common syslinux-efi shim-signed grub-efi-amd64-signed jq openssl >/dev/null getent passwd rollcall >/dev/null || useradd --system --no-create-home --shell /usr/sbin/nologin --user-group rollcall [ -x ./rollcall ] && install -m 0755 rollcall /usr/local/bin/rollcall chgrp rollcall /etc/rollcall/rack.json && chmod 0640 /etc/rollcall/rack.json # certificate from rollcall rack join: readable by the service's group, the key by nobody else if [ -d /etc/rollcall/rack ]; then chgrp -R rollcall /etc/rollcall/rack && chmod 0750 /etc/rollcall/rack && chmod 0640 /etc/rollcall/rack/*-key.pem; fi TFTP=$(jq -r '(.tftp_root // "") | if . == "" then "/srv/tftp" else . end' /etc/rollcall/rack.json) CACHE=$(jq -r '(.cache_dir // "") | if . == "" then "/var/cache/rollcall" else . end' /etc/rollcall/rack.json) DNS=$(jq -r '(.dnsmasq_dir // "") | if . == "" then "/var/lib/rollcall/dnsmasq" else . end' /etc/rollcall/rack.json) # image cache: kernels/initrds are prefetched (TFTP cannot fetch on demand), the rest fills on first use install -d -o rollcall -g rollcall "$CACHE" "$CACHE/rollcall" "$CACHE/images" "$CACHE/os" # TFTP root: syslinux for BIOS and UEFI, per-MAC files written by the rack controller install -d "$TFTP" "$TFTP/efi64" install -d -o rollcall -g rollcall -m 2775 "$TFTP/pxelinux.cfg" cp /usr/lib/PXELINUX/pxelinux.0 "$TFTP/" for f in ldlinux.c32 menu.c32 libutil.c32 libcom32.c32 poweroff.c32; do cp /usr/lib/syslinux/modules/bios/$f "$TFTP/"; done cp /usr/lib/SYSLINUX.EFI/efi64/syslinux.efi "$TFTP/efi64/" for f in ldlinux.e64 menu.c32 libutil.c32 libcom32.c32; do cp /usr/lib/syslinux/modules/efi64/$f "$TFTP/efi64/"; done ln -sfn ../pxelinux.cfg "$TFTP/efi64/pxelinux.cfg" # UEFI, Secure Boot included: signed shim and GRUB; rollcall writes the GRUB menus next to pxelinux's if [ -f /usr/lib/shim/shimx64.efi.signed ] && [ -f /usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed ]; then install -m 0644 /usr/lib/shim/shimx64.efi.signed "$TFTP"/bootx64.efi install -m 0644 /usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed "$TFTP"/grubx64.efi install -d -o root -g rollcall -m 2775 "$TFTP"/grub else echo "WARNING: shim-signed or grub-efi-amd64-signed missing: UEFI machines cannot PXE-boot (apt install shim-signed grub-efi-amd64-signed)" >&2 fi ln -sfn "$CACHE/rollcall" "$TFTP/rollcall" ln -sfn "$CACHE/images" "$TFTP/images" ln -sfn ../rollcall "$TFTP/efi64/rollcall" ln -sfn ../images "$TFTP/efi64/images" # dnsmasq reads what the rack controller generates; until then it only answers local DNS install -d -o rollcall -g rollcall "$DNS" "$DNS/conf.d" for f in hosts hosts.dhcp; do [ -e "$DNS/$f" ] || install -m 0644 -o rollcall -g rollcall /dev/null "$DNS/$f"; done # bind-dynamic binds address by address, so systemd-resolved's 127.0.0.53 stub does not get in the way; # until the region assigns a VLAN only loopback is served printf '# rollcall rack controller: the configuration is generated from the region'"'"'s network model\nbind-dynamic\ninterface=lo\nconf-dir=/var/lib/rollcall-dnsmasq/,*.conf\n' > /etc/dnsmasq.d/rollcall.conf install -d -m 0755 /var/lib/rollcall-dnsmasq install -m 0755 rollcall-dnsmasq-reload.sh /usr/local/bin/rollcall-dnsmasq-reload.sh install -m 0755 rollcall-rack-update.sh /usr/local/bin/rollcall-rack-update.sh install -d -m 0755 -o rollcall -g rollcall /var/lib/rollcall/update install -d -m 0700 -o rollcall -g rollcall /var/lib/rollcall/rack-cert # renewed certificates (the joined ones are root's) install -m 0644 rollcall-dnsmasq.path rollcall-dnsmasq.service rollcall-rack.service rollcall-rack-update.path rollcall-rack-update.service /etc/systemd/system/ systemctl daemon-reload systemctl enable dnsmasq.service rollcall-dnsmasq.path rollcall-rack-update.path >/dev/null 2>&1 systemctl start rollcall-rack-update.path /usr/local/bin/rollcall-dnsmasq-reload.sh >/dev/null 2>&1 || true systemctl restart dnsmasq.service || { journalctl -u dnsmasq -n 5 --no-pager >&2; exit 1; } systemctl start rollcall-dnsmasq.path systemctl enable --now rollcall-rack.service systemctl restart rollcall-rack.service sleep 2 systemctl --no-pager status rollcall-rack.service | head -5