comparison files/fbhyve.in @ 474:57f253106ed6

Implement fbhyve, a management system that runs bhyve virtual machines within tmux sessions
author Franz Glasner <fzglas.hg@dom66.de>
date Tue, 27 Aug 2024 21:47:57 +0200
parents 6ecd16725818
children 827371176fec
comparison
equal deleted inserted replaced
473:c3125616d0ec 474:57f253106ed6
1 #!/bin/sh 1 #!/bin/sh
2 # -*- indent-tabs-mode: nil -*-
2 3
3 # PROVIDE: fbhyve 4 # PROVIDE: fbhyve
4 # REQUIRE: LOGIN 5 # REQUIRE: LOGIN FILESYSTEMS
5 # KEYWORD: shutdown nojail 6 # KEYWORD: shutdown nojail
6 # 7 #
7 8
8 # @(#)%%SIMPLEVERSIONTAG%% 9 # @(#)%%SIMPLEVERSIONTAG%%
9 10
10 # 11 #
11 # Add the following lines to /etc/rc.conf to enable bhyve: 12 # Add the following lines to /etc/rc.conf to enable bhyve:
13 #
12 # fbhyve_enable (bool): Set to "NO" by default. 14 # fbhyve_enable (bool): Set to "NO" by default.
13 # Set it to "YES" to enable bhyve 15 # Acts as default for all listed VMs.
14 # bhyve_profiles (str): Set to "" by default. 16 # Set it to "YES" to enable bhyve.
15 # Define your profiles here. 17 # fbhyve_list (str): Set to "" by default.
16 # bhyve_tapdev (str): Set to "tap0" by default. 18 # Define the names of your VMs here.
17 # Set to the tap(4) device to use. 19 # fbhyve_tmux_session_prefix (str): All tmux session names will have this
18 # bhyve_diskdev (str): Must be set, no default. 20 # prefix string.
19 # Set to the disk device to use. 21 # fbhyve_configdir (str): Where by default config files for all VMs live.
20 # bhyve_ncpu (int): Set to 1 by default. 22 # Default: $PREFIX/etc/fbhyve
21 # Set to the number of CPUs for the VM. 23 #
22 # bhyve_memsize (int): Set to 512 by default. 24 #
23 # Set to the number of MB of memory for the VM. 25 # fbhyve_<vm>_enable (bool): Allow to enable or disable a specific VM.
26 # Set to $fbhyve_enable by default.
27 # fbhyve_<vm>_config (str): The bhyve configuration file to use to.
28 # The default is $fbhyve_configdir/<vm>.conf
29 #
24 30
25 . /etc/rc.subr 31 . /etc/rc.subr
26 32
27 name="fbhyve" 33 name="fbhyve"
28 rcvar=fbhyve_enable 34 desc="Manage system bhyve virtual machines"
35 rcvar="fbhyve_enable"
29 36
30 start_precmd="bhyve_prestart" 37 start_precmd="fbhyve_pre_start"
31 status_cmd="bhyve_status" 38 stop_postcmd="fbhyve_post_stop"
32 poll_cmd="bhyve_poll" 39 status_cmd="fbhyve_status"
33 stop_cmd="bhyve_stop"
34 _session=$name
35 command="/usr/local/bin/tmux"
36 procname="-sh"
37 40
38 [ -z "$bhyve_tapdev" ] && bhyve_tapdev="tap0"
39 [ -z "$bhyve_diskdev" ] && bhyve_diskdev="none"
40 [ -z "$bhyve_ncpu" ] && bhyve_ncpu="1"
41 [ -z "$bhyve_memsize" ] && bhyve_memsize="512"
42 41
43 load_rc_config $name 42 load_rc_config $name
44 43
45 : {fbhyve_enable:="NO"} 44 : ${fbhyve_enable:="NO"}
46 : {fbhyve_configdir:="%%PREFIX%%/etc/fbhyve"} 45 : ${fbhyve_list=}
46 : ${fbhyve_tmux_session_prefix:="${name}_"}
47 : ${fbhyve_configdir:="%%FBHYVE_ETCDIR%%"}
47 48
48 49
49 if [ -n "$2" ]; then 50 _fbhyve_vm_exists() {
50 profile="$2" 51 local _p
51 _session="${_session}_${profile}" 52 for _p in ${fbhyve_list}; do
52 if [ "x${bhyve_profiles}" != "x" ]; then 53 [ "${_p}" = "$1" ] && return 0;
53 eval fbhyve_enable="\${${_session}_enable:-${fbhyve_enable}}" 54 done
54 eval bhyve_tapdev="\${${_session}_tapdev:-${bhyve_tapdev}}" 55 return 1
55 eval bhyve_diskdev="\${${_session}_diskdev:-${bhyve_diskdev}}" 56 }
56 eval bhyve_ncpu="\${${_session}_ncpu:-${bhyve_ncpu}}" 57
57 eval bhyve_memsize="\${${_session}_memsize:-${bhyve_memsize}}" 58
58 else 59 if [ $# -eq 2 ]; then
59 echo "$0: extra argument ignored" 60 _vm="$2"
60 fi 61 if ! _fbhyve_vm_exists "${_vm}"; then
62 echo "ERROR: no VM named \`${_vm}' in \`fbhyve_list'" 1>&2
63 exit 1
64 fi
65 echo "-- VM: ${_vm} --"
66 _session="${fbhyve_tmux_session_prefix}${_vm}"
67 _window="${_session}_console"
68 eval fbhyve_enable="\${fbhyve_${_vm}_enable:-${fbhyve_enable}}"
69 eval fbhyve_config="\${fbhyve_${_vm}_config:-\"${fbhyve_configdir}/${_vm}.conf\"}"
61 else 70 else
62 if [ "x${bhyve_profiles}" != "x" -a "x$1" != "x" ]; then 71 _ec=0
63 for profile in ${bhyve_profiles}; do 72 _swap=$*; shift; _vmarglist=$*
64 eval _enable="\${bhyve_${profile}_enable}" 73 _vmlist=${_vmarglist:-${fbhyve_list}}
65 case "x${_enable:-${fbhyve_enable}}" in 74 set -- ${_swap}
66 x|x[Nn][Oo]|x[Nn][Oo][Nn][Ee]) 75 for _vm in ${_vmlist}; do
67 continue 76 "$0" "$1" "${_vm}"
68 ;; 77 _vmec=$?
69 x[Yy][Ee][Ss]) 78 if [ ${_vmec} -gt ${_ec} ]; then
70 ;; 79 _ec=${_vmec}
71 *) 80 fi
72 if test -z "$_enable"; then 81 done
73 _var=fbhyve_enable 82 exit ${_ec}
74 else
75 _var=bhyve_"${profile}"_enable
76 fi
77 echo "Bad value" \
78 "'${_enable:-${fbhyve_enable}}'" \
79 "for ${_var}. " \
80 "Profile ${profile} skipped."
81 continue
82 ;;
83 esac
84 echo "===> bhyve profile: ${profile}"
85 /usr/local/etc/rc.d/bhyve $1 ${profile}
86 retcode="$?"
87 if [ "0${retcode}" -ne 0 ]; then
88 failed="${profile} (${retcode}) ${failed:-}"
89 else
90 success="${profile} ${success:-}"
91 fi
92 done
93 exit 0
94 fi
95 profile=$name
96 fi 83 fi
97 84
98 pidfile="/var/run/${_session}.pid" 85 _rundir="%%FBHYVE_RUNDIR%%"
86 pidfile="${_rundir}/${_vm}.pid"
87 procname="bhyve:" # something like bhyve: <vmname> (bhyve)
88
89 required_dirs="${_rundir}"
90 required_files="${fbhyve_config}"
91
92 command="%%LOCALBASE%%/bin/tmux"
93
94 command_args="new-session -ds ${_session} -n ${_window} \"sh -c 'echo \\\$\\\$ >\\\"${pidfile}\\\"; /usr/sbin/bhyve -k \\\"${fbhyve_config}\\\" \\\"${_vm}\\\"'\""
99 95
100 96
101 bhyve_prestart() 97 fbhyve_status()
102 { 98 {
103 case ${bhyve_diskdev} in 99 local _pid _rc
104 [Nn][Oo][Nn][Ee] | '') 100
105 echo "No ${_session}_diskdev set. Quitting." 1>&2 101 _rc=0
106 return 1; 102 _pid=$(check_pidfile "$pidfile" "$procname")
107 ;; 103 if [ -n "${_pid}" ]; then
108 esac 104 echo "VM ${_vm} is running as pid $_pid."
109 if [ ! -c "${bhyve_diskdev}" -a ! -f "${bhyve_diskdev}" ]; then 105 else
110 echo "${bhyve_diskdev} doesn't exist or is not suitable as a diskdev" 1>&2 106 echo "VM ${_vm} is not running."
111 return 1; 107 _rc=1
112 fi 108 fi
109
110 if ${command} has-session -t ${_session} 2>/dev/null; then
111 echo "tmux session ${_session} exists."
112 if [ ${_rc} -gt 0 ]; then
113 _rc=2
114 fi
115 else
116 echo "tmux session ${_session} does not exist."
117 if [ ${_rc} -gt 0 ]; then
118 _rc=2
119 fi
120 fi
121 return ${_rc}
113 } 122 }
114 123
115 bhyve_status() 124
116 { 125 fbhyve_pre_start() {
117 if ${command} has-session -t ${_session} 2>/dev/null; then 126 if ! load_kld -m vmm vmm.ko; then
118 echo "${_session} is running." 127 echo "ERROR: Cannot load kernel module \`vmm'" 1>&2
119 else 128 return 1
120 echo "${_session} is not running." 129 fi
121 return 1 130 if [ -e "/dev/vmm/${_vm}" ]; then
122 fi 131 echo "ERROR: VM \`${_vm}' already created in the VM monitor" 1>&2
132 return 1
133 fi
134 if ${command} has-session -t "${_session}" 2>/dev/null; then
135 echo "ERROR: tmux session \`${_session}' already exists" 1>&2
136 return 1
137 fi
138 return 0
123 } 139 }
124 140
125 bhyve_poll() 141
126 { 142 fbhyve_post_stop() {
127 echo -n "Waiting for session: ${_session}" 143 if [ -e "/dev/vmm/${_vm}" ]; then
128 while ${command} has-session -t ${_session} 2>/dev/null; do 144 /usr/sbin/bhyvectl --vm="${_vm}" --destroy
129 sleep 1 145 fi
130 done 146 if ${command} has-session -t "${_session}" 2>/dev/null; then
131 echo 147 ${command} kill-session -t "${_session}"
148 fi
149 rm -f "${pidfile}"
150 return 0
132 } 151 }
133 152
134 bhyve_stop()
135 {
136 if ${command} has-session -t ${_session} 2>/dev/null; then
137 echo "Stopping ${_session}."
138 ${command} kill-session -t ${_session}
139 while ${command} has-session -t ${_session} 2>/dev/null; do
140 sleep 1
141 done
142 fi
143 rm -f ${pidfile}
144 }
145
146 command_args="new-session -ds ${_session} \"sh -c 'echo \\\$PPID >${pidfile}; while true; do /usr/sbin/bhyvectl --vm=${_session} --destroy; /usr/sbin/bhyveload -m ${bhyve_memsize} -d ${bhyve_diskdev} ${_session} && /usr/sbin/bhyve -c ${bhyve_ncpu} -m ${bhyve_memsize} -AI -H -P -g 0 -s 0:0,hostbridge -s 1:0,virtio-net,${bhyve_tapdev} -s 2:0,virtio-blk,${bhyve_diskdev} -s 31,lpc -l com1,stdio ${_session} || break; done'\""
147 153
148 run_rc_command "$1" 154 run_rc_command "$1"