Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
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" |
