BHyVeお手軽スクリプト

BHyVeを安直に動かしたいという目的で作った、「[BHyVeお手軽スクリプト](https://docs.google.com/presentation/d/1VDCIlRDlyBuOWnbWu_g0rTxaVx9gvet-mdQ0WaIWBBQ/edit?usp=sharing)」を公開します。

基本ZFS用ですが、ufsでも使えます。事前にvmm.koをロードする必要があります。

このファイルを適当な名前(例えば bhyve-util等)で保存して、システム名-コマンド名でシンボリックリンクを貼ります。

```
$ ln -s bhyve-util freebsd0-boot
$ ln -s bhyve-util freebsd0-boottty
$ ln -s bhyve-util freebsd0-clean
$ ln -s bhyve-util freebsd0-console
$ ln -s bhyve-util freebsd0-install
$ ln -s bhyve-util freebsd0-resources
$ ln -s bhyve-util freebsd0-shutdown
```

内部の __config_system 関数内の設定を必要に応じて修正します。1回目はfreebsd0-installを実行し、インストール後に freebsd0-boot を実行すれば動きます。

とりあえず、FreeBSD アドベントカレンダーを埋めてる目的で、今日はここまで(かなりヒドイ)。

2018-12-20 追記
**更新版を公開**しました。「[続 BHyVe お手軽スクリプト](https://qiita.com/belgianbeer/items/5ddf8751580e8d6b651e) 」を見てください。

```
#!/bin/sh
#
#  BHyVe での Grubを使うOSのインストール/起動スクリプト
#  プログラム名
#   システム名-install		bhyveへのインストール
#   システム名-boot		インストール済みシステムの起動
#   システム名-boottty		consoleをttyで起動 (*-boot -t でも同じ)
#   システム名-console		null-modem経由でコンソールへ接続
#   システム名-resources	リソースの表示
#   システム名-shutodnw		VMMのシャットダウン
#   システム名-clean		VMMのクリア
#

export PATH=/usr/local/bin:/usr/local/sbin:/bin:/usr/bin:/sbin:/usr/sbin

cpu=1			# VMのデフォルトのCPU数
mem=256M		# VMのデフォルトのメモリサイズ
bridge=bridge0		# デフォルトのbridge if
zvol_pre=zroot/vm	# VM用ZFS Volumeのprefix
iso_prefix=/home/archives/ISO	# ISO image のあるPathのprefix
zvol_opt='-o volmode=dev -o volblocksize=4k'	# ZFS Volumeのプロパティ

do_daemon=daemon		# daemon コマンド

#  VMのリソース割り当て
#
#   新たなVMを増やす場合
#     case文のエントリーを増やす
#     _id に新規の番号を割り当てる
#     適当なISOイメージを割り当てる
#
#  con: consoleが接続されるヌルモデムのデバイス名 ex. /dev/nmdm0A
#  tap:  tap IFの名前   ex tap0
#        tapX と /dev/nmdmXA の Xの番号は一致し、_id に設定した値を使う
#  zvol: VM用 zfs volume
#	 システム名とZFSのvolume名は同じ名前であることを前提としている
#  hd0:  システムディスク 通常 /dev/zvol/${zvol_pre}/${system}
#  cd0:  インストール用のISOイメージ
#  freebsd:  ターゲットOSがfreebsdならばYES
#  grub_inst_cmd: (optional) grub-bhyveでinstallに必要なコマンド列
#  grub_boot_cmd: (optional) grub-bhyveでbootに必要なコマンド列
#
__config_system () {
	local _id _iso _ver _kern _ramfs _root

	case ${system} in

	ubuntu0)
		_id=0
		_iso=Ubuntu/ubuntu-16.04-server-amd64.iso
		;;
	debian0)
		_id=1
		_iso=Debian/debian-8.4.0-amd64-netinst.iso
		;;
	centos0)
		_id=2
		_iso=CentOS/CentOS-7-x86_64-Minimal-1511.iso
		_ver="3.10.0-327"	# install時のCentOS 7のオリジナル
		_ver="3.10.0-327.18.2"	# update によって適宜更新する
		_ver="3.10.0-327.22.2"	# update によって適宜更新する
		_ver="3.10.0-327.28.2"	# update によって適宜更新する
		_ver="3.10.0-327.28.3"	# update によって適宜更新する
		_root=/dev/mapper/centos-root
		_kern="(hd0,msdos1)/vmlinuz-${_ver}.el7.x86_64"
		_ramfs="(hd0,msdos1)/initramfs-${_ver}.el7.x86_64.img"
		grub_inst_cmd="linux (cd0)/isolinux/vmlinuz; initrd (cd0)/isolinux/initrd.img"
		grub_boot_cmd="linux ${_kern} root=${_root}; initrd ${_ramfs}"
		;;
	openbsd0)
		_id=3
		_iso=OpenBSD/install59.iso
		_ver=5.9
		grub_inst_cmd="kopenbsd -h com0 (cd0)/${_ver}/amd64/bsd.rd"
		grub_boot_cmd="kopenbsd -h com0 -r sd0a (hd0,openbsd1)/bsd"
		;;
	netbsd0)
		_id=4
		_iso=NetBSD/NetBSD-7.0.1-amd64.iso
		grub_inst_cmd="knetbsd -h -r cd0a (cd0)/netbsd"
		grub_boot_cmd="knetbsd -h -r /dev/rld0a (hd0,netbsd1)/netbsd"
		;;
	freebsd0)
		_id=5
		_iso=FreeBSD/FreeBSD-10.3-RELEASE-amd64-disc1.iso
		freebsd=YES
		;;
	fbsdzfs0)
		_id=6
		_iso=FreeBSD/FreeBSD-10.3-RELEASE-amd64-disc1.iso
		freebsd=YES
		mem=512M
		;;
	ubuntubsd0)
		_id=7
		_iso=ubuntuBSD/ubuntuBSD-15.10~BETA5-amd64.iso
		;;
	*)
		echo "*** ${0##*/} is bad name" 1>&2 ; exit 1
		;;
	esac

	tap=tap${_id}
	con=/dev/nmdm${_id}A
	zvol=${zvol:-${zvol_pre}/${system}}
	hd0=${hd0:-/dev/zvol/${zvol}}
	cd0=${cd0:-${iso_prefix}/${_iso}}
}

__check_running () {
	pgrep -qf "bhyve: ${system}"
	return $?
}

# Bhyve 用ZFS volumeの作成 (HOGE-ressouces 時)
__make_zvol () {
	if [ -e "${hd0}" ]; then
		echo "*** ${hd0} already exist" 1>&2
	else
		sudo zfs create ${s_flag} -V ${V_size} ${zvol_opt} ${zvol} || exit
	fi
}

# Bhyve 用tap ifの作成
__make_tap () {

	if ifconfig "${tap}" >/dev/null 2>&1; then
		echo "*** ${tap} already exist" 1>&2
	else
		sudo ifconfig ${tap} create
		sudo ifconfig ${bridge} addm ${tap}
	fi
}

# ディスクイメージがあるかどうかの確認
__check_resouces() {
	local _badconfig

	if [ ! -e "${hd0}" ]; then
		echo "*** ${hd0} not found." 1>&2
		_badconfig=YES
	fi

	if [ x"${install}" = xYES -a ! -e "${cd0}" ]; then
		echo "*** ${cd0} not found." 1>&2
		_badconfig=YES
	fi

	if [ x"${_badconfig}" = x"YES" ]; then
		exit 1		# 問題があれば終了
	fi
}

__connect_console() {	# nmdmデバイス経由でコンソールへ接続する
	local nmdm 

	nmdm=`echo ${con} | tr 'A' 'B'`
	exec sudo cu -l ${nmdm}
}

__print_resources () {
	if [ "x${V_size}" != x ]; then
		__make_zvol
	fi
	echo tap=${tap}
	echo con=${con}
	echo zvol=${zvol}
	echo hd0=${hd0}
	echo cd0=${cd0}
}

__grub_install () {
	local _st

	cat <<- EOT > ${map}
	(hd0) ${hd0}
	(cd0) ${cd0}
	EOT

	if [ x${grub_inst_cmd} = x ]; then
		sudo grub-bhyve -m ${map} -r cd0 -M ${mem} ${system}
	else
		sudo grub-bhyve -m ${map} -r cd0 -M ${mem} ${system} <<- EOT
		${grub_inst_cmd}
		boot
		EOT
	fi
	_st=$?
	rm -f ${map}

	# インストーラの起動
	[ ${_st} -eq 0 ] && exec sudo bhyve -A -H -P \
		-c ${cpu} \
		-m ${mem} \
		-l com1,stdio \
		-s 0:0,hostbridge \
		-s 1:0,lpc \
		-s 2:0,virtio-net,${tap} \
		-s 3:0,virtio-blk,${hd0} \
		-s 4:0,ahci-cd,${cd0} \
		${system}
}

__clean_vm () {
	if pgrep -fq "bhyve: ${system}"
	then
		echo "*** ${system} is running" 1>&2
		exit 2
	fi

	if [ -e /dev/vmm/${system} ] ;
	then
		sudo bhyvectl --destroy --vm=${system} # VMのクリア
	fi

	if ifconfig ${tap} >/dev/null 2>&1
	then
		sudo ifconfig ${bridge} deletem ${tap}
		sudo ifconfig ${tap} destroy
	fi
}

__shutdown_vm () {
	local _pid _i

	if ! _pid=$(pgrep -f "bhyve: ${system}")
	then
		echo "*** ${system} is not running" 1>&2
		exit 2
	fi

	sudo kill ${_pid}

	test ${q_flag} || echo -n "Waiting for shutdown ${system} " 1>&2
	_i=0
	while pgrep -qf "bhyve: ${system}"
	do
		_i=$((_i + 1))
		if [ ${_i} -ge 150 ]	# shutdownを2分半までは待つ
		then
			echo "**** ${system}: can not shutdown!" 1>&2
			exit 2
		fi
		sleep 1
		test ${q_flag} || echo -n '.' 1>&2
	done
	__clean_vm 
	test ${q_flag} || echo " Done." 1>&2
}

__grub_boot () {
	local _st

	# boot用のmapファイルの作成
	cat <<- EOT > ${map}
	(hd0) ${hd0}
	EOT

	[ ! -z "${hd1}" ] && hd2nd="-s 4:0,virtio-blk,${hd1}"

	# Boot用の Grubの起動
	#
	if [ x"${grub_boot_cmd}" = x -o x"${p_flag}" = xYES ]; then
		sudo grub-bhyve -m ${map} -r hd0,msdos1 -M ${mem} ${system}
	else
		sudo grub-bhyve -m ${map} -r hd0,msdos1 -M ${mem} ${system} <<- EOT
		${grub_boot_cmd}
		boot
		EOT
	fi
	_st=$?

	rm -f ${map} 

	# bhyveの起動
	[ ${_st} -eq 0 ] && exec sudo ${do_daemon} bhyve -A -H -P \
		-c ${cpu} \
		-m ${mem} \
		-l com1,${con} \
		-s 0:0,hostbridge \
		-s 1:0,lpc \
		-s 2:0,virtio-net,${tap} \
		-s 3:0,virtio-blk,${hd0} ${hd2nd} \
		${system}
}

__freebsd_install () {
	sudo bhyveload -c stdio -m ${mem} -d ${cd0} ${system} &&
	sudo bhyve -H -A -P  \
		-c ${cpu} \
		-m ${mem} \
		-l com1,stdio \
		-s 0:0,hostbridge \
		-s 1:0,lpc \
		-s 2:0,virtio-net,${tap} \
		-s 3:0,virtio-blk,${hd0} ${hd2nd} \
		-s 31:0,ahci-cd,${cd0} \
		${system}
}

__freebsd_boot () {

	[ ! -z "${hd1}" ] && hd2nd="-s 4:0,virtio-blk,${hd1}"

	sudo bhyveload -c stdio -m ${mem} -d ${hd0} ${system} &&
	exec sudo ${do_daemon} bhyve -H -A -P  \
		-c ${cpu} \
		-m ${mem} \
		-l com1,${con} \
		-s 0:0,hostbridge \
		-s 1:0,lpc \
		-s 2:0,virtio-net,${tap} \
		-s 3:0,virtio-blk,${hd0} ${hd2nd} \
		${system}
}

# ----- ここからメイン -----

prog=${0##*/}
system=${prog%-*}	# "XXX-hogehoge"の"XXX"をシステム名
cmd=${prog##*-}		#  "hogehoge"をコマンド名

__config_system

# -t オプションがあればサーバーをバックグラウンド処理にしない
# -c cpu数
# -m メモリサイズ
# -V size 指定サイズのvolumeの作成 (*-resources のみ)
# -I tap の作成 (*-resources のみ)
#
while getopts 'qpstc:m:IV:' cmd_arg; do
	case "${cmd_arg}" in
	t)      con=stdio ; unset do_daemon ;;
	c)      cpu=${OPTARG} ;;
	m)	mem=${OPTARG} ;;
	I)	I_flag=YES ;;
	s)	s_flag=-s ;;
	p)	p_flag=YES ;;
	q)	q_flag=YES ;;
	V)	V_size=${OPTARG} ;;
	*)	echo "Usage: ${0##*/} [ -t ]" 1>&2; exit 2;;
	esac
done
shift $((OPTIND - 1))

# コマンドの判断
#
case ${cmd} in
clean)		__clean_vm ; exit ;;
resources)	__print_resources ; exit ;;
boot)		;;
boottty)	con=stdio ; unset do_daemon ;;
install)	install=YES ;;
console)	__connect_console ;;
shutdown)	__shutdown_vm ; exit ;; 
*)		echo "*** ${cmd}: Unknown Commmand" 1>&2 ; exit 2 ;;
esac

__check_resouces
__clean_vm
__make_tap

cd /tmp		# ワーキングディレクトリを /tmp に変更

if [ x${freebsd} = xYES ]; then
	if [ x${install} = xYES ]; then
		__freebsd_install
	else
		__freebsd_boot
	fi
else
	map=`mktemp /tmp/_bhyve-map-${system}-XXXXXX` # grub-bhyve用mapファイル

	if [ x${install} = xYES ]; then
		__grub_install
	else
		__grub_boot
	fi
fi
```