mirror of
https://github.com/churchers/vm-bhyve.git
synced 2026-01-04 03:54:31 +01:00
Don't think any of the remaining commands really need the ability to specify multiple guests.
322 lines
8.5 KiB
Bash
322 lines
8.5 KiB
Bash
#!/bin/sh
|
|
#-------------------------------------------------------------------------+
|
|
# Copyright (C) 2015 Matt Churchyard (churchers@gmail.com)
|
|
# All rights reserved
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted providing that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
# make sure we have the right environment
|
|
#
|
|
util::setup(){
|
|
util::load_module "vmm"
|
|
util::load_module "nmdm"
|
|
util::load_module "if_bridge"
|
|
util::load_module "if_tap"
|
|
|
|
sysctl net.link.tap.up_on_open=1 >/dev/null 2>&1
|
|
}
|
|
|
|
# load a kernel module
|
|
#
|
|
# @param string _mod the module name
|
|
#
|
|
util::load_module(){
|
|
local _mod="$1"
|
|
kldstat -qm ${_mod} >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
kldload ${_mod} >/dev/null 2>&1
|
|
[ $? -ne 0 ] && util::err "unable to load ${_mod}.ko!"
|
|
fi
|
|
}
|
|
|
|
# check if system have bhyve support
|
|
# we look for POPCNT feature which is required
|
|
# and should be listed on both Intel & AMD systems
|
|
#
|
|
# @modifies VM_NO_UG
|
|
#
|
|
util::check_bhyve_support(){
|
|
local _mesg _result
|
|
|
|
# basic checks
|
|
[ `id -u` -ne 0 ] && util::err "virtual machines can only be managed by root"
|
|
[ ${VERSION_BSD} -lt 1000000 ] && util::err "please upgrade to FreeBSD 10 or newer for bhyve support"
|
|
|
|
# get features2 line which should include popcnt
|
|
_mesg=$(grep -E '^[ ]+Features2' /var/run/dmesg.boot | tail -n 1)
|
|
|
|
# only check if we found it
|
|
if [ -n "${_mesg}" ]; then
|
|
|
|
# look for pop cnt
|
|
_result=$(echo "${_mesg}" |grep "POPCNT")
|
|
[ -z "${_result}" ] && util::err "it doesn't look like your cpu supports bhyve (missing POPCNT)"
|
|
fi
|
|
|
|
# check ept for intel
|
|
_mesg=$(grep -E '^[ ]+VT-x' /var/run/dmesg.boot | tail -n 1)
|
|
|
|
if [ -n "${_mesg}" ]; then
|
|
|
|
# look for ept
|
|
_result=$(echo "${_mesg}" |grep "EPT")
|
|
[ -z "${_result}" ] && util::err "it doesn't look like your cpu supports bhyve (missing EPT)"
|
|
|
|
# look for unrestricted guest
|
|
_result=$(echo "${_mesg}" |grep ",UG")
|
|
[ -z "${_result}" ] && VM_NO_UG="1"
|
|
fi
|
|
}
|
|
|
|
# check for vt-d support
|
|
# following neel@ wiki we search for DMAR acpi table
|
|
#
|
|
# @return success if host has vt-d
|
|
#
|
|
util::check_bhyve_iommu(){
|
|
local _mesg
|
|
|
|
_mesg=$(acpidump -t |grep DMAR)
|
|
[ -z "${_mesg}" ] && return 1
|
|
|
|
return 0
|
|
}
|
|
|
|
# restart a local service
|
|
# checks if service is running and either starts or restarts
|
|
#
|
|
# @param string _serv the name of the service
|
|
#
|
|
util::restart_service(){
|
|
local _serv="$1"
|
|
local _cmd="restart"
|
|
|
|
# see if it's actually running
|
|
service ${_serv} status >/dev/null 2>&1
|
|
[ $? -ne 0 ] && _cmd="start"
|
|
|
|
service ${_serv} ${_cmd} >/dev/null 2>&1
|
|
[ $? -ne 0 ] && util::warn "failed to ${_cmd} service ${_serv}"
|
|
}
|
|
|
|
# show version
|
|
#
|
|
util::version(){
|
|
echo "vm-bhyve: Bhyve virtual machine management v${VERSION} (build ${VERSION_INT})"
|
|
}
|
|
|
|
# show version & usage information
|
|
# we exit after running this
|
|
#
|
|
util::usage(){
|
|
util::version
|
|
cat << EOT
|
|
Usage: vm ...
|
|
version
|
|
init
|
|
set [setting=value] [...]
|
|
get [all|setting] [...]
|
|
switch list
|
|
switch info [name] [...]
|
|
switch create <name>
|
|
switch import <name> <bridge>
|
|
switch vlan <name> <vlan|0>
|
|
switch nat <name> <on|off>
|
|
switch add <name> <interface>
|
|
switch remove <name> <interface>
|
|
switch destroy <name>
|
|
datastore list
|
|
datastore add <name> <spec>
|
|
datastore remove <name>
|
|
list
|
|
info [name] [...]
|
|
create [-d datastore] [-t template] [-s size] <name>
|
|
[-fi] install <name> <iso>
|
|
[-fi] start <name> [...]
|
|
stop <name> [...]
|
|
console <name> [com1|com2]
|
|
rename <name> <new-name>
|
|
add [-d device] [-t type] [-s size|switch] <name>
|
|
startall
|
|
stopall
|
|
reset <name>
|
|
poweroff <name>
|
|
configure <name>
|
|
destroy <name>
|
|
passthru
|
|
clone <name[@snapshot]> <new-name>
|
|
snapshot [-f] <name[@snapshot]>
|
|
rollback [-r] <name@snapshot>
|
|
iso [url]
|
|
image list
|
|
image create [-d description] [-u] <name>
|
|
image destroy <uuid>
|
|
image provision [-d datastore] <uuid> <newname>
|
|
EOT
|
|
exit 1
|
|
}
|
|
|
|
# error
|
|
# display an error message and exit immediately
|
|
#
|
|
# @param string - the message to display
|
|
#
|
|
util::err(){
|
|
echo "${0}: ERROR: $1" >&2
|
|
exit 1
|
|
}
|
|
|
|
# warn
|
|
# display warning, but do not exit
|
|
#
|
|
# @param string - the message to display
|
|
#
|
|
util::warn(){
|
|
echo "${0}: WARNING: $1" >&2
|
|
}
|
|
|
|
# log_rotate
|
|
# simple rotation of log files
|
|
# if we hit 1MB, which should cover a fair amount of history,
|
|
# we move existing log and and create a new one.
|
|
# one keep 1 previous file, as that should be enough
|
|
#
|
|
# @param string _type whether to rotate guest or main log
|
|
#
|
|
util::log_rotate(){
|
|
local _type="$1"
|
|
local _lf="vm-bhyve.log"
|
|
local _file _size _guest
|
|
|
|
case "${_type}" in
|
|
guest)
|
|
_guest="$2"
|
|
_file="${VM_DS_PATH}/${_guest}/${_lf}"
|
|
;;
|
|
system)
|
|
_file="${vm_dir}/${_lf}"
|
|
;;
|
|
esac
|
|
|
|
if [ -e "${_file}" ]; then
|
|
_size=$(stat "${_file}" | cut -d' ' -f8)
|
|
|
|
if [ -n "${_size}" -a "${_size}" -ge 1048576 ]; then
|
|
unlink "${_file}.0.gz" >/dev/null 2>&1
|
|
mv "${_file}" "${_file}.0"
|
|
gzip "${_file}.0"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# log to file
|
|
# writes the date and a message to the specified log
|
|
# the global log is in $vm_dir/vm-bhyve.log
|
|
# guest logs are $vm_dir/{guest}/vm-bhyve.log
|
|
#
|
|
# @param string _type=guest|system log to global vm-bhyve log or guest
|
|
# @param optional string _guest if _type=guest, the guest name, otherwise do not provide at all
|
|
# @param string _message the message to log
|
|
#
|
|
util::log(){
|
|
local _type="$1"
|
|
local _lf="vm-bhyve.log"
|
|
local _guest _message _file _date
|
|
|
|
case "${_type}" in
|
|
guest)
|
|
_guest="$2"
|
|
_message="$3"
|
|
_file="${VM_DS_PATH}/${_guest}/${_lf}"
|
|
;;
|
|
system)
|
|
_message="$2"
|
|
_file="${vm_dir}/${_lf}"
|
|
;;
|
|
esac
|
|
|
|
echo "$(date +'%b %d %T'): ${_message}" >> "${_file}"
|
|
}
|
|
|
|
# write content to a file, and log what we
|
|
# did to the guest log file
|
|
# it's useful to be able to see what files vm-bhyve is creating
|
|
# and the contents so we write that to the log.
|
|
# The file is created in $vm_dir/{guest}
|
|
#
|
|
# @param string _type=write|appnd create file or append to it
|
|
# @param string _guest the guest name
|
|
# @param string _file the file name to write to
|
|
# @param string _message the data to write
|
|
#
|
|
util::log_and_write(){
|
|
local _type="$1"
|
|
local _guest="$2"
|
|
local _file="${VM_DS_PATH}/${_guest}/$3"
|
|
local _message="$4"
|
|
|
|
if [ "${_type}" = "write" ]; then
|
|
util::log "guest" "${_guest}" "create file ${_file}"
|
|
echo "${_message}" > "${_file}"
|
|
else
|
|
echo "${_message}" >> "${_file}"
|
|
fi
|
|
|
|
util::log "guest" "${_guest}" " -> ${_message}"
|
|
}
|
|
|
|
# confirm yes or no
|
|
#
|
|
# @param string _msh message to display
|
|
# @return int success if confirmed
|
|
#
|
|
util::confirm(){
|
|
local _msg="$1"
|
|
local _resp
|
|
|
|
while read -p "${_msg} (y/n)? " _resp; do
|
|
case "${_resp}" in
|
|
y*) return 0 ;;
|
|
n*) return 1 ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# our own checkyesno copy
|
|
# doesn't warn for unsupported values
|
|
# also returns as 'yes' unless value is specifically no/off/false/0
|
|
#
|
|
# @param _value the value to test
|
|
# @return int 1 if set to "off/false/no/0", 0 otherwise
|
|
#
|
|
util::checkyesno(){
|
|
local _value="$1"
|
|
|
|
[ -z "${_value}" ] && return 1
|
|
|
|
case "$_value" in
|
|
[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
|
|
return 1 ;;
|
|
*) return 0 ;;
|
|
esac
|
|
}
|