Add a bhyverc script using pidfiles.

This commit is contained in:
Tom Alexander 2025-08-23 20:20:06 -04:00
parent d1c6e358d4
commit 187a7aebe9
No known key found for this signature in database
GPG Key ID: D3A179C9A53C0EDE
4 changed files with 283 additions and 1 deletions

View File

@ -217,7 +217,7 @@ 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}" "$ip_range" up
fi
}

View File

@ -0,0 +1,226 @@
#!/usr/bin/env bash
#
set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Share a host directory to the guest via 9pfs.
#
# Inside the VM run:
# mount -t virtfs -o trans=virtio sharename /some/vm/path
# mount -t 9p -o cache=mmap -o msize=512000 sharename /mnt/9p
# mount -t 9p -o trans=virtio,cache=mmap,msize=512000 sharename /path/to/mountpoint
# bhyve_options="-s 28,virtio-9p,sharename=/"
# Enable Sound
# bhyve_options="-s 16,hda,play=/dev/dsp,rec=/dev/dsp"
# Example usage:
#
# doas bhyverc create-disk zdata/vm/poudriere /vm/poudriere 10
# doas bhyverc start poudriere zdata/vm/poudriere /vm/poudriere /vm/iso/FreeBSD-13.2-RELEASE-amd64-bootonly.iso
# doas bhyverc start poudriere zdata/vm/poudriere /vm/poudriere
: ${VERBOSE:="NO"} # or YES
if [ "$VERBOSE" = "YES" ]; then
set -x
fi
: ${CPU_CORES:="1"}
: ${MEMORY:="1G"}
: ${NETWORK:="NAT"} # or RAW or BOTH
: ${IP_RANGE:="10.215.1.1/24"} # Ignored for RAW networks
: ${INTERFACE_NAME:="jail_nat"} # or the external interface like lagg0 for RAW networks
: ${BRIDGE_NAME:="bridge_$INTERFACE_NAME"} # or bridge_raw for RAW networks
: ${VNC_ENABLE:="NO"}
: ${VNC_LISTEN:="127.0.0.1:5900"}
: ${VNC_WIDTH:="1920"}
: ${VNC_HEIGHT:="1080"}
############## Setup #########################
function die {
local status_code="$1"
shift
(>&2 echo "${@}")
exit "$status_code"
}
function log {
(>&2 echo "${@}")
}
############## Program #########################
function main {
local cmd
cmd=$1
shift
if [ "$cmd" = "start" ]; then
init
start "${@}"
elif [ "$cmd" = "stop" ]; then
init
stop "${@}"
elif [ "$cmd" = "status" ]; then
init
status "${@}"
elif [ "$cmd" = "console" ]; then
init
console "${@}"
elif [ "$cmd" = "_start_body" ]; then
init
start_body "${@}"
else
(>&2 echo "Unknown command: $cmd")
exit 1
fi
}
function start {
local num_vms="$#"
if [ "$num_vms" -gt 0 ]; then
for name in "$@"; do
log "Starting VM $name."
start_one "$name"
done
else
log "No VMs specified."
fi
}
function start_one {
local name="$1"
local tmux_name="$name"
/usr/local/bin/tmux new-session -d -s "$tmux_name" "$0" "_start_body" "$name"
# /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_opnsense.bash"
}
function start_body {
local name="$1"
local pidfile="/run/bhyverc/${name}/pid"
mkdir -p "/run/bhyverc/${name}"
trap "set +e; stop_one '${name}'" EXIT
local launch_cmd=()
launch_cmd+=(launch_pidfile "$pidfile" sleep 999)
(
IFS=$' \n\t'
bash -c "${launch_cmd[*]}"
)
}
function launch_pidfile {
local pidfile="$1"
shift 1
cat > "${pidfile}" <<< "$$"
set -x
exec "${@}"
}
export -f launch_pidfile
function stop {
local num_vms="$#"
if [ "$num_vms" -gt 0 ]; then
for name in "$@"; do
log "Stopping VM $name."
stop_one "$name"
done
else
log "No VMs specified."
fi
}
function stop_one {
local name="$1"
local pidfile="/run/bhyverc/${name}/pid"
if [ ! -e "$pidfile" ]; then
log "Pid file $pidfile does not exist."
return 0
fi
local bhyve_pid
bhyve_pid=$(cat "$pidfile")
if ps -p "$bhyve_pid" >/dev/null; then
# Send ACPI shutdown command
log "Sending ACPI shutdown to $bhyve_pid."
kill -SIGTERM "$bhyve_pid"
fi
while ps -p "$bhyve_pid" >/dev/null; do
log "Waiting for $bhyve_pid to exit."
sleep 2
done
bhyvectl "--vm=$name" --destroy || true
rm -f "$pidfile"
log "Finished stopping $name."
}
function status {
local num_vms="$#"
if [ "$num_vms" -gt 0 ]; then
for name in "$@"; do
status_one "$name"
done
else
log "No VMs specified."
fi
}
function status_one {
local name="$1"
local pidfile="/run/bhyverc/${name}/pid"
if [ ! -e "$pidfile" ]; then
log "$name is not running."
return 0
fi
local bhyve_pid
bhyve_pid=$(cat "$pidfile")
if ! ps -p "$bhyve_pid" >/dev/null; then
log "$name is not running."
return 0
fi
log "$name is running as pid $bhyve_pid."
}
function console {
local num_vms="$#"
if [ "$num_vms" -gt 0 ]; then
for name in "$@"; do
log "Attaching to console of VM $name."
console_one "$name"
done
else
log "No VMs specified."
fi
}
function console_one {
local name="$1"
local tmux_name="$name"
exec tmux a -t "$tmux_name"
}
function init {
mkdir -p /run/bhyverc
}
############## Bhyve ###########################
main "${@}"

View File

@ -0,0 +1,37 @@
#!/bin/sh
#
# REQUIRE: LOGIN FILESYSTEMS
# PROVIDE: bhyverc
# KEYWORD: shutdown
. /etc/rc.subr
name=bhyverc
rcvar=${name}_enable
start_cmd="${name}_start"
stop_cmd="${name}_stop"
status_cmd="${name}_status"
console_cmd="${name}_console"
extra_commands="console"
load_rc_config $name
bhyverc_start() {
export PATH="$PATH:/usr/local/bin"
exec /usr/local/bin/bhyverc start "${@}"
}
bhyverc_status() {
export PATH="$PATH:/usr/local/bin"
exec /usr/local/bin/bhyverc status "${@}"
}
bhyverc_stop() {
export PATH="$PATH:/usr/local/bin"
exec /usr/local/bin/bhyverc stop "${@}"
}
bhyverc_console() {
export PATH="$PATH:/usr/local/bin"
exec /usr/local/bin/bhyverc console "${@}"
}
run_rc_command "$@"

View File

@ -22,6 +22,25 @@
loop:
- src: bhyve_netgraph_bridge.bash
dest: /usr/local/bin/bhyve_netgraph_bridge
- src: bhyverc.bash
dest: /usr/local/bin/bhyverc
- name: Install rc script
copy:
src: "files/{{ item.src }}"
dest: "/usr/local/etc/rc.d/{{ item.dest|default(item.src) }}"
owner: root
group: wheel
mode: 0755
loop:
- src: bhyverc.sh
dest: bhyverc
- name: Enable bhyverc
community.general.sysrc:
name: bhyverc_enable
value: "YES"
path: /etc/rc.conf.d/bhyverc
- name: Create zfs dataset
zfs: