From a04b52ec722f4e49f8b61996f2e9779f487909db Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 9 Jan 2024 17:31:12 -0500 Subject: [PATCH] Add a unifi vm. --- router/boot_loader.conf | 6 ++ router/etc_rc.conf | 16 ++++ router/launch_opnsense.bash | 5 +- router/launch_unifi.bash | 149 ++++++++++++++++++++++++++++++++++++ router/opnsense_rc.bash | 3 +- router/reboot | 8 ++ router/reload | 9 +++ router/rollback | 10 +++ router/snapshot | 10 +++ router/unifi_rc.bash | 47 ++++++++++++ router/unifi_vm_efibootmgr | 1 + 11 files changed, 261 insertions(+), 3 deletions(-) create mode 100644 router/boot_loader.conf create mode 100644 router/etc_rc.conf create mode 100644 router/launch_unifi.bash create mode 100644 router/reboot create mode 100644 router/reload create mode 100644 router/rollback create mode 100644 router/snapshot create mode 100644 router/unifi_rc.bash create mode 100644 router/unifi_vm_efibootmgr diff --git a/router/boot_loader.conf b/router/boot_loader.conf new file mode 100644 index 0000000..2d10ef7 --- /dev/null +++ b/router/boot_loader.conf @@ -0,0 +1,6 @@ +security.bsd.allow_destructive_dtrace=0 +cryptodev_load="YES" +zfs_load="YES" +vmm_load="YES" +pptdevs="1/0/0 2/0/0 3/0/0 4/0/0 5/0/0 7/0/0" +autoboot_delay="0" diff --git a/router/etc_rc.conf b/router/etc_rc.conf new file mode 100644 index 0000000..a3ffdf9 --- /dev/null +++ b/router/etc_rc.conf @@ -0,0 +1,16 @@ +clear_tmp_enable="YES" +syslogd_flags="-ss" +hostname="turtle" +#ifconfig_bridgeif="DHCP" +#ifconfig_bridgeif_ipv6="inet6 accept_rtadv" +wlans_rtwn0="wlan0" +ifconfig_wlan0="WPA DHCP" +ifconfig_wlan0_ipv6="inet6 accept_rtadv" +create_args_wlan0="country US regdomain FCC" +sshd_enable="YES" +ntpd_enable="YES" +ntpd_sync_on_start="YES" +moused_nondefault_enable="NO" +# Set dumpdev to "AUTO" to enable crash dumps, "NO" to disable +dumpdev="NO" +zfs_enable="YES" diff --git a/router/launch_opnsense.bash b/router/launch_opnsense.bash index 5d95444..0a11fb9 100644 --- a/router/launch_opnsense.bash +++ b/router/launch_opnsense.bash @@ -59,7 +59,7 @@ function start_vm { fi local bridge_name="bridge_vm" - local host_interface_name="bridge_if" + local host_interface_name="bridgeif" assert_bridge "$host_interface_name" "$bridge_name" local mac_address @@ -133,8 +133,9 @@ EOF mkpeer ${host_interface_name}: bridge ether link0 name ${host_interface_name}:ether $bridge_name EOF - ifconfig "$(ngctl msg "${host_interface_name}:" getifname | grep Args | cut -d '"' -f 2)" name "${host_interface_name}" #"$ip_range" up + ifconfig "$(ngctl msg "${host_interface_name}:" getifname | grep Args | cut -d '"' -f 2)" name "${host_interface_name}" up + dhclient "${host_interface_name}" # (set +e; service netif start wlan0) & fi } diff --git a/router/launch_unifi.bash b/router/launch_unifi.bash new file mode 100644 index 0000000..9537c65 --- /dev/null +++ b/router/launch_unifi.bash @@ -0,0 +1,149 @@ +#!/usr/local/bin/bash +# +set -euo pipefail +IFS=$'\n\t' +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +: ${CD:=""} +: ${VNC_ENABLE:="NO"} +: ${VNC_LISTEN:="127.0.0.1:5900"} +: ${PID_FILE:="/var/run/unifi.pid"} + +############## Setup ######################### + +function cleanup { + for vm in "${vms[@]}"; do + log "Destroying bhyve vm $vm" + bhyvectl "--vm=$vm" --destroy + log "Destroyed bhyve vm $vm" + done +} +vms=() +for sig in EXIT INT QUIT HUP TERM; do + trap "set +e; sleep 10; cleanup" "$sig" +done + +function die { + local status_code="$1" + shift + (>&2 echo "${@}") + exit "$status_code" +} + +function log { + (>&2 echo "${@}") +} + +############## Program ######################### + +function main { + start_vm +} + +function start_vm { + local name="unifi" + + + + # -H release the CPU when guest issues HLT instruction. Otherwise 100% of core will be consumed. + # -s 3,ahci-cd,/vm/.iso/archlinux-2023.04.01-x86_64.iso \ + # -s 29,fbuf,tcp=0.0.0.0:5900,w=1920,h=1080,wait \ + # -s 29,fbuf,tcp=0.0.0.0:5900,w=1920,h=1080 \ + + # TODO: Look into using nmdm instead of stdio for serial console + if [ -n "$CD" ]; then + additional_args+=("-s" "5,ahci-cd,$CD") + fi + if [ "$VNC_ENABLE" = "YES" ]; then + additional_args+=("-s" "29,fbuf,tcp=$VNC_LISTEN,w=1920,h=1080") + fi + + local bridge_name="bridge_vm" + wait_for_bridge "$bridge_name" + + local mac_address + mac_address=$(calculate_mac_address "$name") + + local bridge_link_name + bridge_link_name=$(detect_available_link "${bridge_name}") + + additional_args+=("-s" "2:0,virtio-net,netgraph,path=${bridge_name}:,peerhook=${bridge_link_name},mac=${mac_address}") + vms+=("$name") + while true; do + set -x + set +e + bhyve \ + -D \ + -c 1 \ + -m 2G \ + -H \ + -s 0,hostbridge \ + -s "4,nvme,/dev/zvol/zroot/vm/unifi/disk0" \ + -s 30,xhci,tablet \ + -s 31,lpc -l com1,stdio \ + -l "bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd,/vm/unifi/BHYVE_UEFI_VARS.fd" \ + "${additional_args[@]}" \ + "$name" + # local bhyvepid=$! + # echo "$bhyvepid" > "$PID_FILE" + # wait $bhyvepid + local exit_code=$? + set +x + set -e + if [ $exit_code -eq 0 ]; then + echo "Rebooting." + sleep 5 + elif [ $exit_code -eq 1 ]; then + echo "Powered off." + break + elif [ $exit_code -eq 2 ]; then + echo "Halted." + break + elif [ $exit_code -eq 3 ]; then + echo "Triple fault." + break + elif [ $exit_code -eq 4 ]; then + echo "Exited due to an error." + break + fi + done +} + +function ng_exists { + ngctl status "${1}" >/dev/null 2>&1 +} + +function wait_for_bridge { + local bridge_name="$1" + while ! ng_exists "${bridge_name}:"; do + echo "${bridge_name} does not yet exist, sleeping." + sleep 10 + done +} + +function detect_available_link { + local bridge_name="$1" + local linknum=1 + while true; do + local link_name="link${linknum}" + if ! ng_exists "${bridge_name}:${link_name}"; then + echo "$link_name" + return + fi + linknum=$((linknum + 1)) + if [ "$linknum" -gt 90 ]; then + (>&2 echo "No available links on bridge $bridge_name") + exit 1 + fi + done +} + +function calculate_mac_address { + local name="$1" + local source + source=$(md5 -r -s "$name" | awk '{print $1}') + echo "06:${source:0:2}:${source:2:2}:${source:4:2}:${source:6:2}:${source:8:2}" +} + + +main "${@}" diff --git a/router/opnsense_rc.bash b/router/opnsense_rc.bash index 753c3ba..3e79aa4 100644 --- a/router/opnsense_rc.bash +++ b/router/opnsense_rc.bash @@ -1,7 +1,8 @@ #!/bin/sh # -# REQUIRE: LOGIN +# REQUIRE: FILESYSTEMS kld # PROVIDE: opnsense +# BEFORE: netif . /etc/rc.subr name=opnsense diff --git a/router/reboot b/router/reboot new file mode 100644 index 0000000..8a13fed --- /dev/null +++ b/router/reboot @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# +: ${PID:="95762"} +: ${TMUX_NAME:="opnsense"} + +doas kill "$PID" +while doas tmux has-session -t "$TMUX_NAME" 2>/dev/null; do sleep 1; done +doas shutdown -r now diff --git a/router/reload b/router/reload new file mode 100644 index 0000000..92b995d --- /dev/null +++ b/router/reload @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# +: ${PID:="19711"} +: ${TMUX_NAME:="opnsense"} + +doas kill "$PID" +while doas tmux has-session -t "$TMUX_NAME" 2>/dev/null; do sleep 1; done +sleep 1 +doas service opnsense start diff --git a/router/rollback b/router/rollback new file mode 100644 index 0000000..a5a0975 --- /dev/null +++ b/router/rollback @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# +: ${PID:="37880"} +: ${SNAPSHOT:="zroot/vm/opnsense/disk0@20240108_00_initial_working_state"} +: ${TMUX_NAME:="opnsense"} + +doas kill "$PID" +while doas tmux has-session -t "$TMUX_NAME" 2>/dev/null; do sleep 1; done +doas zfs rollback -r "$SNAPSHOT" +doas service opnsense start diff --git a/router/snapshot b/router/snapshot new file mode 100644 index 0000000..0504d94 --- /dev/null +++ b/router/snapshot @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# +: ${PID:="74229"} +: ${SNAPSHOT:="zroot/vm/opnsense/disk0@20240108_02_configured"} +: ${TMUX_NAME:="opnsense"} + +doas kill "$PID" +while doas tmux has-session -t "$TMUX_NAME" 2>/dev/null; do sleep 1; done +doas zfs snapshot -r "$SNAPSHOT" +doas service opnsense start diff --git a/router/unifi_rc.bash b/router/unifi_rc.bash new file mode 100644 index 0000000..8647513 --- /dev/null +++ b/router/unifi_rc.bash @@ -0,0 +1,47 @@ +#!/bin/sh +# +# REQUIRE: FILESYSTEMS kld +# PROVIDE: unifi +# BEFORE: netif + +. /etc/rc.subr +name=opnsense +rcvar=${name}_enable +start_cmd="${name}_start" +stop_cmd="${name}_stop" +status_cmd="${name}_status" +load_rc_config $name + +tmux_name="unifi" + +opnsense_start() { + # /usr/local/bin/tmux new-session -d -s "$tmux_name" "/usr/bin/env VNC_ENABLE=YES VNC_LISTEN=0.0.0.0:5900 /usr/local/bin/bash /home/talexander/launch_opnsense.bash" + /usr/local/bin/tmux new-session -d -s "$tmux_name" "/usr/bin/env VNC_ENABLE=NO VNC_LISTEN=0.0.0.0:5900 /usr/local/bin/bash /home/talexander/launch_unifi.bash" +} + +opnsense_status() { + if /usr/local/bin/tmux has-session -t $tmux_name 2>/dev/null; then + echo "$tmux_name is running." + else + echo "$tmux_name is not running." + return 1 + fi +} + +opnsense_stop() { + /usr/local/bin/tmux has-session -t $tmux_name 2>/dev/null && ( + /usr/local/bin/tmux kill-session -t $tmux_name + sleep 10 + bhyvectl --vm=unifi --destroy + # kill `cat /var/run/opnsense.pid` + ) + opnsense_wait_for_end +} + +opnsense_wait_for_end() { + while /usr/local/bin/tmux has-session -t $tmux_name 2>dev/null; do + sleep 1 + done +} + +run_rc_command "$1" diff --git a/router/unifi_vm_efibootmgr b/router/unifi_vm_efibootmgr new file mode 100644 index 0000000..3c8d8aa --- /dev/null +++ b/router/unifi_vm_efibootmgr @@ -0,0 +1 @@ +efibootmgr --create --disk /dev/nvme0n1p1 --label "Arch Linux" --loader /vmlinuz-linux-lts --unicode 'rw root=/dev/disk/by-partlabel/Arch rw initrd=\initramfs-linux-lts.img console=ttyS0,115200n8'