Msajor re-write of grub-bhyve support

Please see readme, all grub-bhyve guests (linux/openbsd/netbsd) will
need their configuration files changing. These changes are primarily to
allow users more control over the grub commands used, whilst removing a lot
of ugly redundant code from lib/vm-guest.
We now also support multiple guests with the stop command.
This commit is contained in:
Matt Churchyard
2016-04-05 10:29:47 +01:00
parent d162de6595
commit 44f8831ac9
16 changed files with 380 additions and 327 deletions

View File

@@ -15,10 +15,47 @@ Some of the main features include:
* Guest reboot handling
* Designed with multiple compute nodes + shared storage in mind (NFS/iSCSI/etc)
## IMPORTANT - Note for Linux/NetBSD & OpenBSD users moving from 0.9 to 0.10
The method of supporting these guests has been heavily changed in 0.10 to
allow more flexibility. These guests will no longer boot without making changes
to the configuration file. (Note the `vm configure guest` command can be used to open
the guest configuration in your default editor)
First of all, if you are using Linux, the guest configuration option needs to be changed to `linux`.
For NetBSD & OpenBSD, the following configuration options should be set.
guest="generic"
loader="grub"
Additionally, any grub commands needed to boot the guest (or the guest installer) need to also
be added to the configuration file. Please look at the sample templates in 0.10 for examples
on how these variables are set. This is what the configuration for OpenBSD 5.9 looks like:
grub_install0="kopenbsd -h com0 /5.9/amd64/bsd.rd"
grub_install1="boot"
grub_run_partition="openbsd1"
grub_run0="kopenbsd -h com0 -r sd0a /bsd"
grub_run1="boot"
The partition option is not required, the following is also functional:
grub_run0="kopenbsd -h com0 -r sd0a (hd0,openbsd1)/bsd"
grub_run1="boot"
(However some guests such as Ubuntu will boot automatically, without any boot commands specified,
if the correct partition is provided)
This of course means that it is now trivial to adjust these commands if needed, whereas in
previous versions of vm-bhyve, they were hard-coded.
If boot commands are specified, `grub-bhyve` is run in the background and commands are piped
in automatically by `vm-bhyve`. If no commands are specified, `grub-bhyve` is run on the guests
console, and so the bootloader can be accessed using `vm console guest` if required.
## Install
Download the latest release from Github, or download from the following URL
[http://churchers.hostingspace.co.uk/vm-bhyve-latest.tgz](http://churchers.hostingspace.co.uk/vm-bhyve-latest.tgz)
Download the latest release from Github, or install `sysutils/vm-bhyve`
To install, just run the following command inside the vm-bhyve source directory

View File

@@ -220,6 +220,8 @@ __confirm(){
__checkyesno(){
local _value="$1"
[ -z "${_value}" ] && return 1
case "$_value" in
[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
return 1

View File

@@ -375,6 +375,8 @@ __vm_start(){
return 1
fi
__vm_tmp_upgrade_check
# run background process to actually start bhyve
# this will run as long as vm is running, including restarting bhyve after guest reboot
$0 _run "${_name}" "${_iso}" >/dev/null 2>&1 &
@@ -390,20 +392,29 @@ __vm_stop(){
local _pid _loadpid
[ -z "${_name}" ] && __usage
[ ! -e "/dev/vmm/${_name}" ] && __err "${_name} doesn't appear to be a running virtual machine"
_pid=$(pgrep -fx "bhyve: ${_name}")
_loadpid=$(pgrep -fl "grub-bhyve|bhyveload" | grep " ${_name}\$" |cut -d' ' -f1)
while [ -n "${_name}" ]; do
[ ! -e "/dev/vmm/${_name}" ] && __err "${_name} doesn't appear to be a running virtual machine"
if [ -n "${_pid}" ]; then
kill "${_pid}"
elif [ -n "${_loadpid}" ]; then
__confirm "Guest is in bootloader stage, do you wish to force exit" || exit 0
kill "${_loadpid}"
bhyvectl --destroy --vm=${_name} >/dev/null 2>&1
else
__err "unable to locate process id for this virtual machine"
fi
_pid=$(pgrep -fx "bhyve: ${_name}")
_loadpid=$(pgrep -fl "grub-bhyve|bhyveload" | grep " ${_name}\$" |cut -d' ' -f1)
if [ -n "${_pid}" ]; then
echo "Sending poweroff to ${_name}"
kill "${_pid}"
elif [ -n "${_loadpid}" ]; then
if __confirm "Guest is in bootloader stage, do you wish to force exit"; then
echo "Killing ${_name}"
kill "${_loadpid}"
bhyvectl --destroy --vm=${_name} >/dev/null 2>&1
fi
else
__warn "unable to locate process id for this virtual machine"
fi
shift
_name="$1"
done
}
# 'vm reset'
@@ -597,3 +608,22 @@ __vm_config_set(){
sysrc -inqf "${vm_dir}/${_name}/${_name}.conf" "${_key}=${_value}" >/dev/null 2>&1
return $?
}
# temporary check for guests that need reconfiguring
#
__vm_tmp_upgrade_check(){
case "${_guest}" in
freebsd) ;&
linux) ;&
generic) ;&
windows) ;;
*)
echo "******"
echo " This guest needs to be updated to use newer grub-bhyve support"
echo " Please see the GitHub readme for more information"
echo "******"
exit 1
;;
esac
}

View File

@@ -51,241 +51,111 @@
# @param string _type=install|run whether this is an install or normal run
#
# BSDs
# FreeBSD
__guest_freebsd(){
local _wired=""
[ "${_wiredmem}" = "1" ] && _wired=" -S"
if [ "$1" = "install" ]; then
__log "guest" "${_name}" "bhyveload${_wired} -c ${_com} -m ${_memory} -d ${vm_dir}/.iso/${_iso} ${_name}"
bhyveload${_wired} -c "${_com}" -m "${_memory}" -d "${vm_dir}/.iso/${_iso}" "${_name}"
else
__log "guest" "${_name}" "bhyveload${_wired} -c ${_com} -m ${_memory} -d ${_bootdisk} ${_name}"
bhyveload${_wired} -c "${_com}" -m "${_memory}" -d "${_bootdisk}" "${_name}"
fi
_exit=$?
_loader="bhyveload"
__guest_generic "$1"
}
# NetBSD
__guest_netbsd(){
local _wired=""
[ "${_wiredmem}" = "1" ] && _wired=" -S"
if [ "$1" = "install" ]; then
__log_and_write "write" "${_name}" "device.map" "(cd0) ${vm_dir}/.iso/${_iso}"
__log_and_write "appnd" "${_name}" "device.map" "(hd1) ${_bootdisk}"
__log_and_write "write" "${_name}" "boot.cmd" "knetbsd -h -r cd0a (cd0)/netbsd"
__log_and_write "appnd" "${_name}" "boot.cmd" "boot"
__log "guest" "${_name}" "grub-bhyve${_wired} -r cd0 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name} < ${vm_dir}/${_name}/boot.cmd"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -r cd0 -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}" < "${vm_dir}/${_name}/boot.cmd"
else
__log_and_write "write" "${_name}" "device.map" "(hd1) ${_bootdisk}"
__guestpri_custom_grub && return 0
__log_and_write "write" "${_name}" "boot.cmd" "knetbsd -h -r ld0a (hd1,msdos1)/netbsd"
__log_and_write "appnd" "${_name}" "boot.cmd" "boot"
__log "guest" "${_name}" "grub-bhyve${_wired} -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name} < ${vm_dir}/${_name}/boot.cmd"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}" < "${vm_dir}/${_name}/boot.cmd"
fi
_exit=$?
}
# OpenBSD
# requires guest kernel version in config file
# one of the awkward guests that have version in kernel load path
__guest_openbsd(){
local _gver _arch _wired
[ "${_wiredmem}" = "1" ] && _wired=" -S"
__config_get "_gver" "guest_version"
__config_get "_arch" "arch"
if [ -z "${_gver}" ]; then
__log "guest" "${_name}" "openbsd machines require \"guest_version\" value in configuration"
_exit=15
else
if [ "$1" = "install" ]; then
__log_and_write "write" "${_name}" "device.map" "(hd0) ${_bootdisk}"
__log_and_write "appnd" "${_name}" "device.map" "(cd0) ${vm_dir}/.iso/${_iso}"
__log_and_write "write" "${_name}" "boot.cmd" "kopenbsd -h com0 /${_gver}/${_arch:-amd64}/bsd.rd"
__log_and_write "appnd" "${_name}" "boot.cmd" "boot"
__log "guest" "${_name}" "grub-bhyve${_wired} -r cd0 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name} < ${vm_dir}/${_name}/boot.cmd"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -r cd0 -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}" < "${vm_dir}/${_name}/boot.cmd"
else
__log_and_write "write" "${_name}" "device.map" "(hd0) ${_bootdisk}"
__guestpri_custom_grub && return 0
__log_and_write "write" "${_name}" "boot.cmd" "kopenbsd -h com0 -r sd0a (hd0,openbsd1)/bsd"
__log_and_write "appnd" "${_name}" "boot.cmd" "boot"
__log "guest" "${_name}" "grub-bhyve${_wired} -r hd0 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name} < ${vm_dir}/${_name}/boot.cmd"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -r hd0 -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}" < "${vm_dir}/${_name}/boot.cmd"
fi
_exit=$?
fi
}
# LINUXes
# Alpine
__guest_alpine(){
local _wired
[ "${_wiredmem}" = "1" ] && _wired=" -S"
if [ "$1" = "install" ]; then
__log_and_write "write" "${_name}" "device.map" "(hd0) ${_bootdisk}"
__log_and_write "appnd" "${_name}" "device.map" "(cd0) ${vm_dir}/.iso/${_iso}"
__log_and_write "write" "${_name}" "boot.cmd" "linux /boot/grsec initrd=/boot/initramfs-grsec alpine_dev=cdrom:iso9660 modules=loop,squashfs,sd-mod,usb-storage,sr-mod"
__log_and_write "appnd" "${_name}" "boot.cmd" "initrd /boot/initramfs-grsec"
__log_and_write "appnd" "${_name}" "boot.cmd" "boot"
__log "guest" "${_name}" "grub-bhyve${_wired} -r cd0 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name} < ${vm_dir}/${_name}/boot.cmd"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -r cd0 -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}" < "${vm_dir}/${_name}/boot.cmd"
else
__log_and_write "write" "${_name}" "device.map" "(hd0) ${_bootdisk}"
__guestpri_custom_grub && return 0
__log_and_write "write" "${_name}" "boot.cmd" "linux /boot/vmlinuz-grsec root=/dev/vda3 modules=ext4"
__log_and_write "appnd" "${_name}" "boot.cmd" "initrd /boot/initramfs-grsec"
__log_and_write "appnd" "${_name}" "boot.cmd" "boot"
__log "guest" "${_name}" "grub-bhyve${_wired} -r hd0,msdos1 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name} < ${vm_dir}/${_name}/boot.cmd"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -r hd0,msdos1 -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}" < "${vm_dir}/${_name}/boot.cmd"
fi
_exit=$?
}
# CentOS
__guest_centos(){
local _kernel="" _wired
[ "${_wiredmem}" = "1" ] && _wired=" -S"
__config_get "_kernel" "linux_kernel"
if [ -z "${_kernel}" ]; then
__log "guest" "${_name}" "centos machines require \"linux_kernel\" value in configuration"
_exit=15
else
if [ "$1" = "install" ]; then
__log_and_write "write" "${_name}" "device.map" "(hd0) ${_bootdisk}"
__log_and_write "appnd" "${_name}" "device.map" "(cd0) ${vm_dir}/.iso/${_iso}"
__log_and_write "write" "${_name}" "boot.cmd" "linux /isolinux/vmlinuz"
__log_and_write "appnd" "${_name}" "boot.cmd" "initrd /isolinux/initrd.img"
__log_and_write "appnd" "${_name}" "boot.cmd" "boot"
__log "guest" "${_name}" "grub-bhyve${_wired} -r cd0 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name} < ${vm_dir}/${_name}/boot.cmd"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -r cd0 -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}" < "${vm_dir}/${_name}/boot.cmd"
else
__log_and_write "write" "${_name}" "device.map" "(hd0) ${_bootdisk}"
__guestpri_custom_grub && return 0
__log_and_write "write" "${_name}" "boot.cmd" "linux /vmlinuz-${_kernel} root=/dev/mapper/centos-root"
__log_and_write "appnd" "${_name}" "boot.cmd" "initrd /initramfs-${_kernel}.img"
__log_and_write "appnd" "${_name}" "boot.cmd" "boot"
__log "guest" "${_name}" "grub-bhyve${_wired} -r hd0,msdos1 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name} < ${vm_dir}/${_name}/boot.cmd"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -r hd0,msdos1 -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}" < "${vm_dir}/${_name}/boot.cmd"
fi
_exit=$?
fi
}
# CentOS - using grub bootloader inside guest
__guest_centos-grub(){
local _wired
[ "${_wiredmem}" = "1" ] && _wired=" -S"
if [ "$1" = "install" ]; then
__guest_centos "$1"
return
else
__log_and_write "write" "${_name}" "device.map" "(hd0) ${_bootdisk}"
__guestpri_custom_grub && return 0
__log_and_write "write" "${_name}" "boot.cmd" ""
__log "guest" "${_name}" "grub-bhyve${_wired} -r hd0,msdos1 -m ${vm_dir}/${_name}/device.map -d /grub -M ${_memory} ${_name} < ${vm_dir}/${_name}/boot.cmd"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -r hd0,msdos1 -m "${vm_dir}/${_name}/device.map" -d "/grub" -M "${_memory}" "${_name}" < "${vm_dir}/${_name}/boot.cmd"
fi
_exit=$?
}
# Debian
__guest_debian(){
__guest_linux "$1"
}
# Ubuntu
__guest_ubuntu(){
__guest_linux "$1"
}
# Arch Linux
__guest_arch(){
local _date=$(date +%Y%m)
local _wired
[ "${_wiredmem}" = "1" ] && _wired=" -S"
if [ "$1" = "install" ]; then
__log_and_write "write" "${_name}" "device.map" "(hd0) ${_bootdisk}"
__log_and_write "appnd" "${_name}" "device.map" "(cd0) ${vm_dir}/.iso/${_iso}"
__log_and_write "write" "${_name}" "boot.cmd" "linux (cd0)/arch/boot/x86_64/vmlinuz archisobasedir=arch archisolabel=ARCH_${_date} ro"
__log_and_write "appnd" "${_name}" "boot.cmd" "initrd (cd0)/arch/boot/x86_64/archiso.img"
__log_and_write "appnd" "${_name}" "boot.cmd" "boot"
__log "guest" "${_name}" "grub-bhyve${_wired} -r cd0 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name} < ${vm_dir}/${_name}/boot.cmd"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -r cd0 -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}" < "${vm_dir}/${_name}/boot.cmd"
else
__guest_linux "$1"
return
fi
_exit=$?
}
# Basic Linux
# Linux
__guest_linux(){
local _wired
[ "${_wiredmem}" = "1" ] && _wired=" -S"
if [ "$1" = "install" ]; then
__log_and_write "write" "${_name}" "device.map" "(hd0) ${_bootdisk}"
__log_and_write "appnd" "${_name}" "device.map" "(cd0) ${vm_dir}/.iso/${_iso}"
__log "guest" "${_name}" "grub-bhyve${_wired} -c ${_com} -r cd0 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name}"
/usr/local/sbin/grub-bhyve${_wired} -c "${_com}" -r cd0 -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}"
else
__log_and_write "write" "${_name}" "device.map" "(hd0) ${_bootdisk}"
__guestpri_custom_grub && return 0
__log "guest" "${_name}" "grub-bhyve${_wired} -c ${_com} -r hd0,msdos1 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name}"
/usr/local/sbin/grub-bhyve${_wired} -c "${_com}" -r hd0,msdos1 -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}"
fi
_exit=$?
}
# Run custom grub commands if available
__guestpri_custom_grub(){
local _grub _wired
[ "${_wiredmem}" = "1" ] && _wired=" -S"
__config_get "_grub" "grub_commands"
if [ -n "${_grub}" ]; then
__log "guest" "${_name}" "using grub commands from ${vm_dir}/${_name}/${_grub}"
__log "guest" "${_name}" "grub-bhyve${_wired} -r cd0 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name} < ${vm_dir}/${_name}/${_grub}"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}" < "${vm_dir}/${_name}/${_grub}"
_exit=$?
return 0
fi
return 1
_loader="grub"
__guest_generic "$1"
}
# Windows
# No loader needed for any Win version
__guest_windows(){
_exit=0
}
# Generic guest
# With uefi, many guests may not need any special handling
#
# this now handles most guest types.
# we have config variable "loader" to set whether bhyveload or grub should be used.
# all grub commands are specified in guest config file
#
__guest_generic(){
_exit=0
local _type="$1"
local _wired _partition
local _root="hd0"
local _bcmd="${vm_dir}/${_name}/grub.cmd"
__config_get "_partition" "grub_run_partition"
[ "${_wiredmem}" = "1" ] && _wired=" -S"
[ -n "${_partition}" ] && _root="hd0,${_partition}"
if [ "${_type}" = "install" ]; then
if [ "${_loader}" = "bhyveload" ]; then
__log "guest" "${_name}" "bhyveload${_wired} -c ${_com}A -m ${_memory} -d ${vm_dir}/.iso/${_iso} ${_name}"
bhyveload${_wired} -c "${_com}A" -m "${_memory}" -d "${vm_dir}/.iso/${_iso}" "${_name}"
_exit=$?
elif [ "${_loader}" = "grub" ]; then
__log_and_write "write" "${_name}" "device.map" "(hd0) ${_bootdisk}"
__log_and_write "appnd" "${_name}" "device.map" "(cd0) ${vm_dir}/.iso/${_iso}"
__guest_get_commands "install"
if [ -e "${_bcmd}" ]; then
__log "guest" "${_name}" "grub-bhyve${_wired} -r cd0 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name} < ${_bcmd}"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -r cd0 -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}" < "${_bcmd}"
else
__log "guest" "${_name}" "grub-bhyve${_wired} -c ${_com}A -r cd0 -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name}"
/usr/local/sbin/grub-bhyve${_wired} -c "${_com}A" -r cd0 -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}"
fi
_exit=$?
fi
else
if [ "${_loader}" = "bhyveload" ]; then
__log "guest" "${_name}" "bhyveload${_wired} -c ${_com}A -m ${_memory} -d ${_bootdisk} ${_name}"
bhyveload${_wired} -c "${_com}A" -m "${_memory}" -d "${_bootdisk}" "${_name}"
_exit=$?
elif [ "${_loader}" = "grub" ]; then
__log_and_write "write" "${_name}" "device.map" "(hd0) ${_bootdisk}"
__guest_get_commands "run"
if [ -e "${_bcmd}" ]; then
__log "guest" "${_name}" "grub-bhyve${_wired} -r ${_root} -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name} < ${_bcmd}"
env -i TERM=xterm /usr/local/sbin/grub-bhyve${_wired} -r ${_root} -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}" < "${_bcmd}"
else
__log "guest" "${_name}" "grub-bhyve${_wired} -c ${_com}A -r ${_root} -m ${vm_dir}/${_name}/device.map -M ${_memory} ${_name}"
/usr/local/sbin/grub-bhyve${_wired} -c "${_com}A" -r ${_root} -m "${vm_dir}/${_name}/device.map" -M "${_memory}" "${_name}"
fi
_exit=$?
fi
fi
}
# Gets any grub-bhyve commands for this guest
# Not pretty but the best we can find that works.
# If there are no commands, grub-bhyve will run
# directly on the guests nmdm console. If there are
# we run grub-bhyve on stdout, and pipe commands in.
#
__guest_get_commands(){
local _type="$1"
local _command _num=0
unlink "${_bcmd}" >/dev/null 2>&1
__config_get "_command" "grub_${_type}${_num}"
[ -z "${_command}" ] && return 1
while [ -n "${_command}" ]; do
echo "${_command}" >> "${_bcmd}"
_num=$((_num + 1))
__config_get "_command" "grub_${_type}${_num}"
done
return 0
}

View File

@@ -36,7 +36,7 @@ __vm_run(){
local _name="$1"
local _iso="$2" _iso_dev
local _cpu _memory _bootdisk _bootdisk_dev _guest _wiredmem
local _guest_support _uefi _uuid _utc _debug _hostbridge
local _guest_support _uefi _uuid _utc _debug _hostbridge _loader
local _opts _devices _slot=4 _func=0 _taplist _exit
local _com _comports _comstring _logpath
local _conf="${vm_dir}/${_name}/${_name}.conf"
@@ -49,6 +49,7 @@ __vm_run(){
__config_get "_cpu" "cpu"
__config_get "_memory" "memory"
__config_get "_guest" "guest"
__config_get "_loader" "loader"
__config_get "_bootdisk" "disk0_name"
__config_get "_bootdisk_dev" "disk0_dev"
__config_get "_uefi" "uefi"
@@ -59,6 +60,7 @@ __vm_run(){
__config_get "_debug" "debug"
# set defaults
: ${_guest:=generic}
: ${_bootdisk_dev:=file}
: ${_comports:=com1}
: ${_uefi:=no}
@@ -68,6 +70,7 @@ __vm_run(){
__log "guest" "${_name}" "initialising"
__log "guest" "${_name}" " [guest: ${_guest}]"
__log "guest" "${_name}" " [loader: ${_loader:-default}]"
__log "guest" "${_name}" " [uefi: ${_uefi}]"
__log "guest" "${_name}" " [cpu: ${_cpu}]"
__log "guest" "${_name}" " [memory: ${_memory}]"
@@ -245,7 +248,7 @@ __vm_lock(){
# @param string - the name of the guest to unlock
#
__vm_unlock(){
rm "${vm_dir}/$1/run.lock" >/dev/null 2>&1
unlink "${vm_dir}/$1/run.lock" >/dev/null 2>&1
}
# create string for guest com ports
@@ -260,13 +263,13 @@ __vm_unlock(){
__vm_bhyve_device_comports(){
local _port _num=1 _nmdm=""
rm "${vm_dir}/${_name}/console" >/dev/null 2>&1
unlink "${vm_dir}/${_name}/console" >/dev/null 2>&1
for _port in ${_comports}; do
__vm_find_console "_nmdm" "${_nmdm}"
# use first com port for the loader
[ ${_num} -eq 1 ] && _com="/dev/nmdm${_nmdm}A"
[ ${_num} -eq 1 ] && _com="/dev/nmdm${_nmdm}"
echo "${_port}=/dev/nmdm${_nmdm}B" >> "${vm_dir}/${_name}/console"
_comstring="${_comstring}${_comstring:+ }-l ${_port},/dev/nmdm${_nmdm}A"
@@ -374,50 +377,61 @@ __vm_bhyve_device_networking(){
# we need at least a type
[ -z "${_type}" ] && break
# create interface
if [ -n "${_custom_tap}" ]; then
_tap="${_custom_tap}"
else
_tap=$(ifconfig tap create)
fi
# set a static mac if we don't have one
[ -z "${_mac}" ] && __vm_generate_static_mac
if [ -n "${_tap}" ]; then
# move slot if we've hit function 8
if [ ${_func} -ge 8 ]; then
_func=0
_slot=$((_slot + 1))
fi
__log "guest" "${_name}" "initialising network device ${_tap}"
ifconfig "${_tap}" description "vmnet-${_name}-${_num}-${_switch:-custom}" >/dev/null 2>&1
# set a static mac if we don't have one
[ -z "${_mac}" ] && __vm_generate_static_mac
if [ -n "${_switch}" ]; then
__switch_get_ident "_sid" "${_switch}"
if [ -n "${_sid}" ]; then
_mtu=$(ifconfig "${_sid}" | head -n1 | awk '{print $NF}')
if [ "${_mtu}" != "1500" ]; then
__log "guest" "${_name}" "setting mtu of ${_tap} to ${_mtu}"
ifconfig "${_tap}" mtu "${_mtu}" >/dev/null 2>&1
fi
__log "guest" "${_name}" "adding ${_tap} -> ${_sid} (${_switch})"
ifconfig "${_sid}" addm "${_tap}" >/dev/null 2>&1
[ $? -ne 0 ] && __log "guest" "${_name}" "failed to add ${_tap} to ${_sid}"
else
__log "guest" "${_name}" "failed to find virtual switch '${_switch}'"
fi
fi
if __switch_is_vale "${_switch}"; then
# create a vale port id
__switch_vale_port "_tap" "${_switch}" "${_mac}"
__log "guest" "${_name}" "adding vale interface ${_tap} (${_switch})"
_devices="${_devices} -s ${_slot}:${_func},${_type},${_tap}"
[ -n "${_mac}" ] && _devices="${_devices},mac=${_mac}"
_func=$((_func + 1))
[ -z "${_custom_tap}" ] && _taplist="${_taplist}${_taplist:+ }${_tap}"
else
# create interface
if [ -n "${_custom_tap}" ]; then
_tap="${_custom_tap}"
else
_tap=$(ifconfig tap create)
fi
if [ -n "${_tap}" ]; then
# move slot if we've hit function 8
if [ ${_func} -ge 8 ]; then
_func=0
_slot=$((_slot + 1))
fi
__log "guest" "${_name}" "initialising network device ${_tap}"
ifconfig "${_tap}" description "vmnet-${_name}-${_num}-${_switch:-custom}" >/dev/null 2>&1
if [ -n "${_switch}" ]; then
__switch_get_ident "_sid" "${_switch}"
if [ -n "${_sid}" ]; then
_mtu=$(ifconfig "${_sid}" | head -n1 | awk '{print $NF}')
if [ "${_mtu}" != "1500" ]; then
__log "guest" "${_name}" "setting mtu of ${_tap} to ${_mtu}"
ifconfig "${_tap}" mtu "${_mtu}" >/dev/null 2>&1
fi
__log "guest" "${_name}" "adding ${_tap} -> ${_sid} (${_switch})"
ifconfig "${_sid}" addm "${_tap}" >/dev/null 2>&1
[ $? -ne 0 ] && __log "guest" "${_name}" "failed to add ${_tap} to ${_sid}"
else
__log "guest" "${_name}" "failed to find virtual switch '${_switch}'"
fi
fi
_devices="${_devices} -s ${_slot}:${_func},${_type},${_tap}"
[ -n "${_mac}" ] && _devices="${_devices},mac=${_mac}"
_func=$((_func + 1))
[ -z "${_custom_tap}" ] && _taplist="${_taplist}${_taplist:+ }${_tap}"
fi
fi
_num=$((_num + 1))
@@ -637,27 +651,32 @@ __vm_confirm_stopped(){
return 0
}
# generate a static mac address for a guest
# generate a static mac address for a guest.
# we now make sure all interfaces have a static mac so
# there's no worry of guest problems due to it changing
# there's no worry of guest problems due to it changing.
# bhyve is allocated 58:9c:fc:0x:xx:xx, so we try and
# randomise the last 20 bits (5 hex digits).
# using guest name, interface number and time as seed,
# with an incrementing integer just in case we happen to
# get 5 zeros.
#
__vm_generate_static_mac(){
local _time=$(date +%s)
local _key _part="00:00"
local _key _part="0:00:00"
local _base _int=0
_base="${_name}:${_num}:${_time}"
# generate the last 4 bytes
# make sure we don't get 00:00 (see sys/net/ieee_oui.h)
while [ "${_part}" = "00:00" ]; do
# make sure we don't get 0:00:00 (see sys/net/ieee_oui.h)
while [ "${_part}" = "0:00:00" ]; do
_key="${_base}:${_int}"
_part=$(md5 -qs "${_key}" | awk 'BEGIN {FS="";OFS=":"}; {print $1$2,$3$4}')
_part=$(md5 -qs "${_key}" | awk 'BEGIN {FS="";OFS=":"}; {print $1,$2$3,$4$5}')
_int=$((_int + 1))
done
# add base bhyve OUI of 0x589cfc00
_mac="58:9c:fc:00:${_part}"
# add base bhyve OUI
_mac="58:9c:fc:0${_part}"
__log "guest" "${_name}" "generated static mac ${_mac} (based on '${_key}')"
__vm_config_set "${_name}" "network${_num}_mac" "${_mac}"

View File

@@ -500,6 +500,47 @@ __switch_nat_init(){
__restart_service "pf"
}
# check if a switch is a vale switch
# if so, we don't need to actually create anything.
# interfaces are created on demand when starting guests,
# and vale switches are dynamic
#
__switch_is_vale(){
local _switch="$1"
local _is_vale=$(sysrc -inqf "${vm_dir}/.config/switch" "vale_${_switch}")
[ -z "${_is_vale}" ] && return 1
if __checkyesno "${_is_vale}"; then
return 0
else
return 1
fi
}
# gets a unique port name for a vale interface
# we need to make sure vale switch name is the same
# for all interfaces on the same switch, but port is
# different
#
# @param string _var name of variable to put port name into
# @param string _switch the name of the switch
# @param string _port unique port identifier (usually mac address)
#
__switch_vale_port(){
local _var="$1"
local _switch="$1"
local _port="$2"
local _id_s _id_p
# get a switch id and port id
_id_s=$(md5 -qs "${_switch}" | awk '{print substr($0,0,5)}')
_id_p=$(md5 -qs "${_port}" | awk '{print substr($0,0,5)}')
# build full vale id
setvar "${_var}" "vale${_id_s}:${_id_p}"
}
# produce an error if the listed switch is not managed by vm-bhyve.
# we allow users to import existing bridges which they configure themselves.
# we don't allow vm-bhyve to mess with these, it's all up to the user

View File

@@ -134,7 +134,7 @@ __zfs_make_zvol(){
}
# format options for zfs commands
# options are stored in configuration separated by |
# options are stored in configuration separated by a space
# we need to replace that with -o
#
# @modifies $_val
@@ -303,7 +303,7 @@ __zfs_clone(){
# update new guest files
mv "${vm_dir}/${_name}/${_old}.conf" "${vm_dir}/${_name}/${_name}.conf"
rm "${vm_dir}/${_name}/vm-bhyve.log" >/dev/null 2>&1
unlink "${vm_dir}/${_name}/vm-bhyve.log" >/dev/null 2>&1
# update mac addresses and uuid
__config_load "${vm_dir}/${_name}/${_name}.conf"
@@ -469,8 +469,8 @@ __zfs_image_destroy(){
_file=$(sysrc -inqf "${vm_dir}/images/${_uuid}.manifest" filename)
[ -z "${_file}" ] && __err "unable to locate filename for the specified image"
rm "${vm_dir}/images/${_uuid}.manifest"
rm "${vm_dir}/images/${_file}"
unlink "${vm_dir}/images/${_uuid}.manifest"
unlink "${vm_dir}/images/${_file}"
}
# cmd 'vm image ...'

View File

@@ -1,7 +1,14 @@
guest="alpine"
guest="linux"
cpu=1
memory=512M
network0_type="virtio-net"
network0_switch="public"
disk0_type="virtio-blk"
disk0_name="disk0.img"
grub_install0="linux /boot/grsec initrd=/boot/initramfs-grsec alpine_dev=cdrom:iso9660 modules=loop,squashfs,sd-mod,usb-storage,sr-mod"
grub_install1="initrd /boot/initramfs-grsec"
grub_install2="boot"
grub_run_partition="msdos1"
grub_run0="linux /boot/vmlinuz-grsec root=/dev/vda3 modules=ext4"
grub_run1="initrd /boot/initramfs-grsec"
grub_run2="boot"

View File

@@ -1,8 +0,0 @@
guest="centos"
linux_kernel="3.10.0-229.el7.x86_64"
cpu=1
memory=512M
network0_type="virtio-net"
network0_switch="public"
disk0_type="virtio-blk"
disk0_name="disk0.img"

View File

@@ -0,0 +1,14 @@
guest="linux"
cpu=1
memory=512M
network0_type="virtio-net"
network0_switch="public"
disk0_type="virtio-blk"
disk0_name="disk0.img"
grub_install0="linux /isolinux/vmlinuz"
grub_install1="initrd /isolinux/initrd.img"
grub_install2="boot"
grub_run_partition="msdos1"
grub_run0="linux /vmlinuz-2.6.32-573.el6.x86_64 root=/dev/mapper/VolGroup-lv_root"
grub_run1="initrd /initramfs-2.6.32-573.el6.x86_64.img"
grub_run2="boot"

View File

@@ -1,7 +1,8 @@
guest="debian"
guest="linux"
cpu=1
memory=512M
network0_type="virtio-net"
network0_switch="public"
disk0_type="virtio-blk"
disk0_name="disk0.img"
grub_run_partition="msdos1"

View File

@@ -1,7 +1,13 @@
guest="netbsd"
guest="generic"
loader="grub"
cpu=1
memory=256M
network0_type="virtio-net"
network0_switch="public"
disk0_type="virtio-blk"
disk0_name="disk0.img"
grub_install0="knetbsd -h -r cd0a /netbsd"
grub_install1="boot"
grub_run_partition="msdos1"
grub_run0="knetbsd -h -r ld0a /netbsd"
grub_run1="boot"

View File

@@ -1,8 +1,13 @@
guest="openbsd"
guest_version="5.7"
guest="generic"
loader="grub"
cpu=1
memory=256M
network0_type="virtio-net"
network0_switch="public"
disk0_type="virtio-blk"
disk0_name="disk0.img"
grub_install0="kopenbsd -h com0 /5.9/amd64/bsd.rd"
grub_install1="boot"
grub_run_partition="openbsd1"
grub_run0="kopenbsd -h com0 -r sd0a /bsd"
grub_run1="boot"

View File

@@ -1,7 +1,8 @@
guest="ubuntu"
guest="linux"
cpu=1
memory=512M
network0_type="virtio-net"
network0_switch="public"
disk0_type="virtio-blk"
disk0_name="disk0.img"
grub_run_partition="msdos1"

2
vm
View File

@@ -24,7 +24,7 @@
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
VERSION=0.9.23
VERSION=0.10.1
PATH=${PATH}:/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin
BSD_VERSION=$(uname -K)

72
vm.8
View File

@@ -57,6 +57,7 @@
.Nm
.Cm stop
.Ar name
.Ar ...
.Nm
.Cm console
.Ar name
@@ -477,12 +478,17 @@ For each network adapter specified in the guest configuration, a
interface will be created. If possible, the tap interface will be attached the relevent
.Xr bridge 4
interface, based on the virtual switch specified in the guest configuration.
.It Cm stop Ar name
.It Cm stop Ar name Ar ...
Stop a named virtual machine. All
.Xr tap 4
and
.Xr nmdm 4
devices will be automatically cleaned up once the guest has exited.
.Pp
If a guest is stuck in the bootloader stage, you are given the option to forcibly stop it.
.Pp
Multiple guests can be specified to this command at the same time. Each one will be sent a
poweroff event.
.It Cm console Ar name Op Ar com1|com2
Connect to the console of the named virtual machine. Without network access, this is the primary
way of connecting to the guest once it is running.
@@ -683,9 +689,22 @@ An overview of the available configuration options is listed below.
.Bl -tag -width 17n
.It guest
Specify the type of guest to be installed in this virtual machine. Current valid options
for this are generic, freebsd, netbsd, openbsd, windows, centos, ubuntu, debian & alpine linux.
for this are generic, freebsd, linux & windows.
.It loader
Windows, Linux & FreeBSD guests will use the correct loader by default. For other
guests that require a loader to be used, this can set to
.Sy bhyveload
or
.Sy grub .
As an example, NetBSD & OpenBSD can be supported by using the
.Sy generic
guest type, and specifying the
.Sy grub
loader.
.It uefi
Set this (any non-empty value) for guests that need UEFI firmware.
Set this (any non-empty value) for guests that need UEFI firmware. If set to
.Sy csm ,
the BIOS compatibility UEFI-CSM firmware will be used.
.It cpu
A numeric value specifying the number of virtual CPU cores to assign to the guest.
.It memory
@@ -821,6 +840,34 @@ based on the hostname and guest name. Because this may change if guests are move
between systems, the
.Pa vm create
command automatically assigns a UUID to all newly created guests.
.It grub_installX
This option allows you to specify grub commands needed to boot the install media for
this guest.
.Sy X
should be an integer starting at 0, with additional grub commands using the next numbers
in sequence.
.Pp
If no install commands are specified,
.Sy grub-bhyve
will be run on the guests console, so you can use the standard
.Pa vm console
command to access the bootloader if needed.
.It grub_run_partition
Specify the partition that grub should look in for the grub configuration files.
Some guests, such as Ubuntu, will boot automatically if this variable is set correctly.
.It grub_runX
The option allows you to specify the grub commands needed to boot the guest from disk.
.Sy X
should be an integer starting at 0, with additional grub commands using the next numbers
in sequence.
.Pp
If no boot commands are specified,
.Sy grub-bhyve
will be run on the guests console, so you can use the standard
.Pa vm console
command to access the bootloader if needed.
.Pp
The sample templates contain examples of how the grub configuration variables can be used.
.It passthruX
Specify a device to pass through to the guest. You will need to reserve the device first
so that is it claimed by the ppt driver on boot.
@@ -842,19 +889,6 @@ Set this option to
if you want to create a
.Sy virtio-rnd
device for this guest.
.It grub_commands
Sometimes you may need to provide grub commands that differ from those generated by
.Pa vm-bhyve .
In this case, create a text file inside the guest's directory containing the commands
you need to run. Usually the last entry in the file should be
.Pa boot ,
followed by a newline. The newline is important, otherwise the last command may not
actually be executed.
.Pp
Once you have created the file, set this option to the name of the file. From that point
on, during a normal boot
.Pa vm-bhyve
will use the commands from this file rather than attempting to generate them automatically.
.It zfs_dataset_opts
This allows you to specify one or more ZFS properties to set on the dataset when a
guest is created. Because properties are assigned as the dataset is created, this option
@@ -876,12 +910,6 @@ Multiple properties can be specified, separated by a space. For example, the fol
will configure the ZVOL block size to 128k, and turn compression off.
.Pp
zfs_zvol_opts="volblocksize=128k compress=off"
.It linux_kernel
CentOS guests require the kernel to be loaded inside the boot loader. This option is
required for these guests and specifies the kernel version number to load. Hopefully
this requirement will be relaxed as
.Xr bhyve 8
development continues.
.El
.\" ============ SEE ALSO =============
.Sh SEE ALSO