#!/usr/local/bin/cbsd
#v12.0.4
MYARG=""
MYOPTARG="jname"
MYDESC="Destroy bhyve domain"
CBSDMODULE="bhyve"
EXTHELP="wf_bremove"
ADDHELP="

${H3_COLOR}Description${N0_COLOR}:

Destroy bhyve domain and all related data.

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}jname=${N0_COLOR} - target env name.

${H3_COLOR}Examples${N0_COLOR}:

 # cbsd bdestroy
 # cbsd bdestroy <env>
 # cbsd bdestroy jname=<env>

${H3_COLOR}See also${N0_COLOR}:

 cbsd destroy --help

"

. ${subrdir}/nc.subr
. ${tools}	# for select_jail_by_list

if [ -z "${1}" ]; then
	select_jail_by_list -s "List of local VMs:" -e bls -r ${sqlreplica}
	[ -z "${jname}" ] && err 1 "${N1_COLOR}No such domains${N0_COLOR}"
	if getyesno "Remove VM ${jname}. Are you sure? "; then
		echo
	else
		exit 0
	fi
fi

. ${cbsdinit}
. ${jfs}

if [ -n "${jname}" ]; then
	emulator="bhyve" # for jname_is_multiple
	jname_is_multiple

	if [ -n "${jail_list}" ]; then
		JLIST="${jail_list}"
	else
		JLIST=${jname}
	fi
else
	JLIST=$*
fi

[ -z "${JLIST}" ] && err 1 "Give me jname"

if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
	readconf cbsd_queue.conf
	[ -z "${cbsd_queue_backend}" ] && MOD_CBSD_QUEUE_DISABLED="1"
fi

. ${subrdir}/time.subr
st_time=$( ${DATE_CMD} +%s )

for jname in ${JLIST}; do
	DST="${jaildatadir}/${jname}-${jaildatapref}"
	JAILDIR="${jaildir}/${jname}"
	JAILFSTAB="${jailfstabdir}/${jailfstabpref}${jname}"
	JAILSYSRCCONF="${jailsysdir}/${jname}/rc.conf_${jname}"
	JAILRCCONF="${jailrcconfdir}/rc.conf_${jname}"
	unregister=0

	# get is_cloud settings (used for detect ZVOL_PARENT below)
	[ -r ${JAILSYSRCCONF} ] && . ${JAILSYSRCCONF}

	. ${subrdir}/rcconf.subr
	if [ $? -eq 1 ]; then
		if [ -r "${JAILRCCONF}" ]; then
			[ -r ${JAILRCCONF} ] && . ${JAILRCCONF}
			unregister=1
		else
			# remote?
			if [ ${sqlreplica} -eq 0 ]; then
				${ECHO} "${N1_COLOR}No such domain: ${N2_COLOR}${jname}${N0_COLOR}"
				continue
			fi
			remotenode=$( bwhereis ${jname} )
			if [ -z "${remotenode}" ]; then
				${ECHO} "${N1_COLOR}No such domain: ${N2_COLOR}${jname}${N0_COLOR}"
				continue
			fi
			for i in ${remotenode}; do
				if [ "${i}" = "${nodename}" ]; then
					${ECHO} "${N1_COLOR}Remote bremove: found on nodename ${N2_COLOR}${nodename}${N1_COLOR}. Skipped${N0_COLOR}"
					continue
				fi
				${ECHO} "${N1_COLOR}Remote jremove: ${N2_COLOR}${jname} ${N1_COLOR}on${N2_COLOR} ${i}${N0_COLOR}"
				rexe node=${i} cbsd bremove jname=${jname}
				if [ $? -eq 0 ]; then
					# updating state and put task for retrinv inventory
					${ECHO} "${N1_COLOR}Updating inventory...${N0_COLOR}"
					task autoflush=2 mode=new retrinv node=${i} tryoffline=1 data=db > /dev/null 2>&1
				fi
			done
			continue
		fi
	fi

	if [ "${protected}" = "1" ]; then
		${ECHO} "${N1_COLOR}Protected/locked jail. Skip for remove: ${N2_COLOR}${jname}${N0_COLOR}"
		continue
	fi

	# remove port expose
	[ -n "${ip4_addr}" ] && expose jname=${jname} mode=flush

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		[ -n "${cbsd_bhyve_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_bhyve_queue_name} id=${jname} cmd=bremove status=1
	fi

	. ${subrdir}/jcreate.subr
	export_bhyve_data_for_external_hook
	external_exec_master_script "remove.d"
	PARENT_SNAPSHOTS=
	DEPENDENT_VMS=
	PARENT_ZVOL=
	if [ ${unregister} -eq 0 ] ; then
		if [  ${jid} -ne 0 ]; then
			case "${emulator}" in
				bhyve)
					bstop jname=${jname} noacpi=1
					;;
				virtualbox)
					. ${subrdir}/virtualbox.subr
					vstop jname=${jname}
					;;
				*)
					jstop jname=${jname} fast=1
					;;
			esac
		fi
		# auto-promote if we have children
		if [ ${zfsfeat} -eq 1 -a "${mnt_start}" = "0" ]; then
			obase_vm_disks=$( cbsdsqlro storage_media "SELECT path FROM media WHERE jname='${jname}' and type='hdd'" )
			base_vm_disks=
			# skip for raw disk: /dev/ without zvol
			for i in ${obase_vm_disks}; do
				vm=$( echo ${i} | ${CUT_CMD} -f 1 -d '|' )
				disk_path=$( echo ${i} | ${CUT_CMD} -f 2 -d '|' )
				disk_zvol=$( ${READLINK_CMD} -f ${disk_path} )
				_res=$( substr --pos=0 --len=5 --str=${disk_path} )
				if [ "${_res}" = "/dev/" ]; then
					_res=$( substr --pos=0 --len=10 --str=${disk_zvol} )
					[ "${_res}" != "/dev/zvol/" ] && continue
				fi
				if [ -z "${base_vm_disks}" ]; then
					base_vm_disks="${disk_zvol}"
				else
					base_vm_disks="${base_vm_disks} ${disk_zvol}"
				fi
			done
			unset obase_vm_disks

			for vm_item in ${base_vm_disks}; do
				# detect for shared disk
				vm=$( echo ${vm_item} | ${CUT_CMD} -f 1 -d '|' )
				disk_path=$( echo ${vm_item} | ${CUT_CMD} -f 2 -d '|' )
				disk_zvol=$( ${READLINK_CMD} -f ${disk_path} )

				_res=$( substr --pos=0 --len=10 --str=${disk_zvol} )
				# can be raw, check for /dev/zvol
				[ "${_res}" != "/dev/zvol/" ] && continue

				disk_zvol=$( echo ${disk_zvol} | ${SED_CMD} 's;^/dev/zvol/;;' )

				[ -z "${disk_zvol}" ] && continue
				parent_snapshot=$( ${ZFS_CMD} get -Ho value origin ${disk_zvol} )
				if [ "${parent_snapshot}" = "-" ]; then
					continue
				fi

				original_disk=$( echo ${parent_snapshot} | ${SED_CMD} "s;@cbsd-original-${vm}-dsk.*\.vhd;;g" )
				for _disk_path in ${base_vm_disks}; do
					original_disk_path=$( ${READLINK_CMD} -f ${_disk_path} )
					if [ "/dev/zvol/${original_disk}" = "${original_disk_path}" ]; then
						DEPENDENT_VMS="${DEPENDENT_VMS}\n${vm}"
					fi
				done
			done

			if [ ! -z "${DEPENDENT_VMS}" ]; then
				dep_vms=$( echo ${DEPENDENT_VMS} | ${SORT_CMD} -u )
				err 1 "${N1_COLOR}The following machines depend on ${jname}:${N0_COLOR} ${dep_vms}" >&2
			fi
			for disk_path in ${base_vm_disks}; do
				[ ! -r ${disk_path} ] && continue
				disk_zvol=$( ${READLINK_CMD} -f ${disk_path} | ${SED_CMD} 's;^/dev/zvol/;;' )
				[ -z "${disk_zvol}" ] && continue
				PARENT_ZVOL="${PARENT_ZVOL} ${disk_zvol}"
				parent_snapshot=$( ${ZFS_CMD} get -Ho value origin ${disk_zvol} )
				if [ "${parent_snapshot}" != "-" ]; then
					PARENT_SNAPSHOTS="${PARENT_SNAPSHOTS} ${parent_snapshot}"
				fi
			done

			path_parent=$( ${ZFS_CMD} get -Ho value origin ${DST} )
			if [ "${path_parent}" != "-" ]; then
				PARENT_SNAPSHOTS="${PARENT_SNAPSHOTS} ${path_parent}"
			fi

		fi
		jcleanup jname=${jname}
		${UMOUNT_CMD} ${path} 2>/dev/null
	fi

	# scan for -boot snapshot created by cloud-init
	if [ "${is_cloud}" = "1" ]; then
		for i in $( ${FIND_CMD} ${data}/ -mindepth 1 -maxdepth 1 -type l ); do
			if is_getzvol ${i}; then
				if [ -n "${is_zvol}" ]; then
					_parent=$( ${ZFS_CMD} get -Ho value origin ${is_zvol} )
					if [ -n "${_parent}" ]; then
						_len=$( strlen ${_parent} )
						strpos --str="${_parent}" --search="@"
						_pos=$?
						if [ ${_pos} -ne 0 ]; then
							_pos=$(( _pos + 1 ))
							_snapname=$( substr --pos=${_pos} --len=${_len} --str=${_parent} )
							[ "${_snapname}" = "@boot-${jname}" ] && PARENT_ZVOL="${PARENT_ZVOL} ${_parent}"
						fi
					fi
				fi
			fi
		done
	fi

	# jailed process?
	# if we are not inside jail then check for jailed bhyve and remove hoster jail
	_jailed="0"	# no hoster jail
	pjailed=$( ${SYSCTL_CMD} -qn security.jail.jailed 2>/dev/null )
	[ -z "${pjailed}" ] && pjailed=0

	if [ "${pjailed}" = "0" ]; then
		# we a not jailed
		# bhyve is jailed and has jail?
		[ -r ${jailsysdir}/${jname}/local.sqlite ] && _jailed=$( cbsdsqlro ${jailsysdir}/${jname}/local.sqlite "SELECT jailed FROM settings LIMIT 1" )

		[ -z "${_jailed}" ] && _jailed="0"
		# when _jailed != 0 use this variable to jremove at the end of the scenatio
	fi

	[ -d "${DST}" ] && remove_data_dir ${DST}
	[ ${zfsfeat} -eq 1 ] && jsnapshot mode=destroyall_original jname=${jname}
	[ ${unregister} -eq 0 ] && junregister jname=${jname} rcfile=${JAILRCCONF}

	[ -d "${JAILFSTAB_DIR}" ] && removedir ${JAILFSTAB_DIR}
	[ -f "${JAILRCCONF}" ] && ${RM_CMD} -f ${JAILRCCONF}
	[ -f "${jailrcconfdir}/rc.conf_${jname}" ] && ${RM_CMD} -f "${jailrcconfdir}/rc.conf_${jname}"
	[ -d "${jailsysdir}/${jname}" ] && removedir "${jailsysdir}/${jname}"
	[ -h "${jailsysdir}/${jname}" ] && ${RM_CMD} -f "${jailsysdir}/${jname}"
	[ -f "${logdir}/${jname}.log" ] && ${RM_CMD} -f "${logdir}/${jname}.log"
	[ -d "${jaildir}/${jname}" ] && ${FIND_CMD} ${jaildir}/${jname}/ -mindepth 1 -type d -exec ${RMDIR_CMD} {} \; > /dev/null 2>&1
	[ -d "${jaildir}/${jname}" ] && ${RMDIR_CMD} ${jaildir}/${jname}
	for parent_snapshot in ${PARENT_SNAPSHOTS}; do
		${ZFS_CMD} destroy ${parent_snapshot}
	done

	for parent_zvol in ${PARENT_ZVOL}; do
		${ECHO} "${N1_COLOR}destroy parent zvol for ${jname}: ${N2_COLOR}${parent_zvol}${N0_COLOR}" 1>&2
		${ZFS_CMD} get -Ho value name ${parent_zvol} > /dev/null 2>&1 && ${ZFS_CMD} destroy ${parent_zvol}
	done

	vmdir="${workdir}/vm/${jname}"

	### xxx
	if [ "${zfsfeat}" = "1" ]; then
		readconf zfs.conf
		. ${subrdir}/zfs.subr
		zfsmnt "${vmdir}"
		_ret=$?
		if [ ${_ret} -eq 1 -o ${_ret} -eq 2 ]; then
			_msg=$( ${ZFS_CMD} destroy ${ZPOOL} )
			_ret=$?
			if [ ${_ret} -ne 0 ]; then
				${ECHO} "${N1_COLOR}bremove: zfs destroy error for: ${N2_COLOR}${ZPOOL}: ${N1_COLOR}${_msg}${N0_COLOR}"
			fi
		fi
	fi

	[ -d "${vmdir}" ] && ${RM_CMD} -rf ${vmdir}
	[ -h "${vmdir}" ] && ${RM_CMD} -f ${vmdir}

	# detach ppt
	cbsdsqlrw local "DELETE FROM bhyveppt WHERE jname='${jname}'"

	if [ "${emulator}" != "jail" ]; then
		# TODO: cbsd media unregister mode=removeall jname=jname
		cbsdsqlrw storage_media "DELETE FROM media WHERE jname=\"${jname}\" AND type = \"hdd\""

		A=$( cbsdsqlro storage_media SELECT name,path FROM media WHERE jname=\"${jname}\" AND type=\"iso\" )
		if [ -n "${A}" ]; then
			cd_name=
			cd_path=
			IFS="|"
			sqllist "${A}" cd_name cd_path
			IFS=" "
			media mode=unregister name="${cd_name}" path="${cd_path}" jname="${jname}" type="iso"
		fi
	fi

	if [ "${emulator}" = "virtualbox" ]; then
		. ${subrdir}/virtualbox.subr
		${VBOX_MGMT_CMD} unregistervm ${jname}
		[ -d "/root/VirtualBox VMs/${jname}" ] && ${RM_CMD} -rf "/root/VirtualBox VMs/${jname}"
	fi

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		[ -n "${cbsd_bhyve_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_bhyve_queue_name} id=${jname} cmd=bremove status=2
	fi

	if [ "${_jailed}" != "0" ]; then
		${ECHO} "${N1_COLOR}remove hoster jail: ${N2_COLOR}${_jailed}${N0_COLOR}"
		cbsdlogger NOTICE ${CBSD_APP}: remove bhyve [${jname}] hoster jail: ${_jailed}
		jset protected=0 jname=${_jailed}
		jremove jname="${_jailed}"
	fi
done

end_time=$( ${DATE_CMD} +%s )
diff_time=$(( end_time - st_time ))
diff_time=$( displaytime ${diff_time} )
${ECHO} "${N1_COLOR}${CBSD_APP} done ${N2_COLOR}in ${diff_time}${N0_COLOR}"
cbsdlogger NOTICE ${CBSD_APP}: bhyve domain ${JLIST} removed in ${diff_time}

exit 0
