#! /bin/sh # Auto-install OpenBSD/amd64 7.7 on QEMU. # # First published at https://www.skreutz.com/posts/autoinstall-openbsd-on-qemu/ # on 22 July 2020. # # Copyright (c) 2020 Stefan Kreutz # # Permission to use, copy, modify, and distribute this software for any purpose # with or without fee is hereby granted, provided that the above copyright # notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. set -o errexit set -o nounset # Trusted HTTPS OpenBSD mirror to fetch the base public key from. # See . HTTPS_MIRROR="${HTTPS_MIRROR-https://ftp.openbsd.org/pub/OpenBSD/}" # Untrusted rsync OpenBSD mirror. # See . RSYNC_MIRROR="${RSYNC_MIRROR-rsync://mirror.leaseweb.com/openbsd/}" # File name of the disk image. DISK_FILE="${DISK_FILE-disk.qcow2}" # Size of the disk image. DISK_SIZE="${DISK_SIZE-64G}" # Number of virtual CPUs. CPU_COUNT="${CPU_COUNT-$(grep -c ^processor /proc/cpuinfo)}" # Size of virtual memory. MEMORY_SIZE="${MEMORY_SIZE-4G}" # File name of the public SSH key to authorize. SSH_KEY="${SSH_KEY-${HOME}/.ssh/id_ed25519.pub}" # Check required commands. for cmd in curl qemu-img qemu-system-x86_64 rsync signify socat ssh do if ! command -v "${cmd}" >/dev/null then ( >&2 printf "command not found: %s\\n" "${cmd}" ) exit 1 fi done # Fetch base public key from trusted HTTPS mirror. mkdir -p mirror/pub/OpenBSD/7.7 if [ ! -e mirror/pub/OpenBSD/7.7/openbsd-77-base.pub ] then curl \ --silent \ --output mirror/pub/OpenBSD/7.7/openbsd-77-base.pub \ "${HTTPS_MIRROR}7.7/openbsd-77-base.pub" printf "Fetched base public key from %s\\n" "${HTTPS_MIRROR}" fi # Fetch kernel, PXE bootstrap program, and file sets from untrusted rsync # mirror. if [ ! -d mirror/pub/OpenBSD/7.7/amd64 ] then mkdir -p tmp printf "Fetching installation files ...\\n" rsync --archive --files-from=- --quiet \ "${RSYNC_MIRROR}7.7/amd64/" \ tmp/ \ << EOF SHA256.sig base77.tgz bsd bsd.mp bsd.rd comp77.tgz game77.tgz man77.tgz pxeboot xbase77.tgz xfont77.tgz xserv77.tgz xshare77.tgz BUILDINFO EOF ( cd tmp && signify -C -q \ -p ../mirror/pub/OpenBSD/7.7/openbsd-77-base.pub \ -x SHA256.sig \ -- bsd bsd.* pxeboot *77.tgz ) mv tmp mirror/pub/OpenBSD/7.7/amd64 printf "Fetched kernel, PXE bootstrap program, and file sets from %s\\n" "${RSYNC_MIRROR}" fi # Create autoinstall(8) configuration if not exists. if [ ! -e mirror/install.conf ] then cat << EOF > mirror/install.conf Change the default console to com0 = yes Which speed should com0 use = 115200 System hostname = openbsd Password for root = ************* Allow root ssh login = no Setup a user = puffy Password for user = ************* Public ssh key for user = $( cat "${SSH_KEY}" ) What timezone are you in = UTC Location of sets = http HTTP Server = 10.0.2.2 Unable to connect using https. Use http instead = yes URL to autopartitioning template for disklabel = http://10.0.2.2/disklabel Set name(s) = site77.tgz Checksum test for site77.tgz failed. Continue anyway = yes Unverified sets: site77.tgz. Continue without verification = yes EOF printf "Created example response file for autoinstall(8) at ./mirror/install.conf\\n" fi # Create disklabel(8) configuration if not exists. # Assume disk size of at least 54G. if [ ! -e mirror/disklabel ] then cat << EOF > mirror/disklabel / 1G swap 8G /tmp 4G /var 4G /usr 6G /usr/X11R6 1G /usr/local 20G /usr/src 3G /usr/obj 6G /home 1G-* EOF printf "Created example disklabel(8) template at ./mirror/disklabel.conf\\n" fi # Create site-specific file set if not exists. if [ ! -d site ] then mkdir site cat << EOF > site/install.site #! /bin/ksh set -o errexit # Reset OpenBSD mirror server used by pkg_add(1) and other commands. echo "https://cdn.openbsd.org/pub/OpenBSD" > /etc/installurl # Permit user group wheel to run any command as root without entering their # password using doas(1). echo "permit nopass keepenv :wheel" > /etc/doas.conf # Patch the base system on the first boot. #echo "syspatch && shutdown -r now" >> /etc/rc.firsttime EOF chmod +x site/install.site printf "Created example site-specific file set at ./site\\n" fi # Package site-specific file set if not exists or changed. site_dir_changed="$( find site -exec stat -c %Y {} \; | sort -r | head -n 1 )" if [ ! -e mirror/pub/OpenBSD/7.7/amd64/site77.tgz ] || [ "$( stat -c %Y mirror/pub/OpenBSD/7.7/amd64/site77.tgz )" -lt "${site_dir_changed}" ] then rm -f mirror/pub/OpenBSD/7.7/amd64/site77.tgz ( cd site && tar -czf ../mirror/pub/OpenBSD/7.7/amd64/site77.tgz . ) ( cd mirror/pub/OpenBSD/7.7/amd64 && ls -l > index.txt ) fi # Create TFTP directory if not exists. if [ ! -d tftp ] then mkdir tftp ln -s ../mirror/pub/OpenBSD/7.7/amd64/pxeboot tftp/auto_install ln -s ../mirror/pub/OpenBSD/7.7/amd64/bsd.rd tftp/bsd.rd mkdir tftp/etc cat << EOF > tftp/etc/boot.conf stty com0 115200 set tty com0 boot tftp:/bsd.rd EOF printf "Created example boot(8) configuration at ./tftp/etc/boot.conf\\n" fi # Remove existing disk image if configuration changed. if [ -e "${DISK_FILE}" ] then vm_created="$( stat -c %W "${DISK_FILE}" )" for f in mirror/install.conf mirror/disklabel mirror/pub/OpenBSD/7.7/amd64/site77.tgz tftp/etc/boot.conf do if [ "${vm_created}" -lt "$( stat -c %Y "$f" )" ] then printf "Re-creating virtual machine due to changed configuration: %s\\n" "$f" rm "${DISK_FILE}" fi done fi # Create disk image if not exists, and wait until mirror is served. if [ ! -e "${DISK_FILE}" ] then qemu-img create -q -f qcow2 "${DISK_FILE}" -o nocow=on "${DISK_SIZE}" printf "Created %s copy-on-write disk image at %s\\n" "${DISK_SIZE}" "${DISK_FILE}" while [ ! "$( curl --silent --location --write-out '%{http_code}\n' --output /dev/null http://127.0.0.1/install.conf )" = 200 ] do ( >&2 printf "Please serve the directory ./mirror at http://127.0.0.1/ (port 80)\n" ) sleep 5 done fi # Auto-install OpenBSD. printf "Starting virtual machine ...\\n" qemu-system-x86_64 \ -enable-kvm \ -smp "cpus=${CPU_COUNT}" \ -m "${MEMORY_SIZE}" \ -drive "file=${DISK_FILE},media=disk,if=virtio" \ -device e1000,netdev=n1 \ -netdev "user,id=n1,hostname=openbsd-vm,tftp=tftp,bootfile=auto_install,hostfwd=tcp::2222-:22" \ -nographic