#!/usr/local/bin/cbsd
# shellcheck shell=sh disable=2034,2154,1091
#v13.0.8
MYARG=""
MYOPTARG="cbsdfile cur_env cwd jname multiple quiet upfile_destroy_failed"
MYDESC="create jail/bhyve/qemu env from CBSDfile, vagrant-like behavior"
CBSDMODULE="bhyve,jail,qemu"
ADDHELP="
${H3_COLOR}Description${N0_COLOR}:

In addition to dialog(1)-based utilities (jconstruct-tui/bconstruct-tui/xconstruct-tui)
and creating environments through arguments (jcreate/bcreate/xcreate) there is another
method for creating environments in CBSD, when the environment is described by a file.
This is similar to the Vagrant method, where the file stores all the enclosure
information in one place.

To create an environment with 'cbsd up' script, you must create a file named CBSDfile
and execute 'cbsd up' command in this directory.

Some parameters can be reassigned in the command line, e,g. one CBSDfile
to build an image of several versions.

By default, all the environments that are described in the CBSDfile will be created,
but you can regulate specific environments through the argument.

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}cbsdfile${N0_COLOR}              - alternative path to CBSDfile, could be relative to the
                         working directory, e.g: '/tmp/CBSDfile'.
 ${N2_COLOR}upfile_destroy_failed${N0_COLOR} - when '0' - do not destroy environment even if the create fails.
                         Mostly for debug purposes. Default is '1' - auto-destroy.
                         Same environment variables: UPFILE_DESTROY_FAILED

${H3_COLOR}Examples${N0_COLOR}:

 # cbsd up ver=13.0
 # cbsd up ver=12.2
 # cbsd up jail1 vm2

${H3_COLOR}See also${N0_COLOR}:

 cbsd destroy --help
 cbsd bconstruct-tui --help
 cbsd bconstruct --help
 cbsd bcreate --help
 cbsd jconstruct-tui --help
 cbsd jconstruct --help
 cbsd jcreate --help

"

EXTHELP="wf_cbsdfile"

. "${subrdir}"/nc.subr
. "${subrdir}"/strings.subr

# push original location: we need restore it before exit
OCBSD_PWD="${CBSD_PWD}"
cwd=
jname=
CLOUD_URL=
CLOUD_KEY=
upfile_destroy_failed=
oupfile_destroy_failed=
. "${subrdir}"/cbsdinit.subr

[ -n "${upfile_destroy_failed}" ] && oupfile_destroy_failed="${upfile_destroy_failed}"
[ -z "${upfile_destroy_failed}" ] && upfile_destroy_failed=1

# flags for multiple CBSDfile env
[ -z "${multiple}" ] && multiple=0
[ -z "${cur_env}" ] && cur_env=1

# skip notice for subcommand with CBSDfile/API
export CBSDFILE_RECURSIVE=1

# init CBSDfile data
if [ -n "${cwd}" ]; then
	[ ! -r "${cwd}"/CBSDfile ] && err 1 "${N1_COLOR}${CBSD_APP}: no such CBSDfile: ${N2_COLOR}${cwd}/CBSDfile${N0_COLOR}"
	cbsdfile="${cwd}/CBSDfile"
	cd "${cwd}" || err 1 "Can not cd to cwd"
fi

# exported OCBSD_PWD as original PWD path: we neet to restore it on exit
. "${subrdir}"/cbsdfile.subr

. "${subrdir}"/time.subr
. "${subrdir}"/up.subr

# MAIN
export NOINTER=1

if [ -n "${oupfile_destroy_failed}" ]; then
	UPFILE_DESTROY_FAILED="${oupfile_destroy_failed}"
fi
if [ -n "${UPFILE_DESTROY_FAILED}" ]; then
	upfile_destroy_failed="${UPFILE_DESTROY_FAILED}"
fi
[ -z "${upfile_destroy_failed}" ] && upfile_destroy_failed=1

export UPFILE_DESTROY_FAILED="${upfile_destroy_failed}"

if [ "${num_env}" -eq 1 ]; then
	st_time=$( ${DATE_CMD} +%s )

	if [ ${multiple} -gt 0 ]; then
		# sleep/delay a random amount of time between 2 and 10
		# to minimize the probability that a large number of machines 
		# will simultaneously attempt to up. except first (cur_env=1) env.
		if [ ${cur_env} -ne 1 ]; then
			rand_delay=$( ${AWK_CMD} -v min=2 -v max=10 'BEGIN{srand(); print int(min+rand()*(max-min+1))}' )
			sleep "${rand_delay}"
		fi
	fi

	# protection from multiple env
	if [ ${multiple} -eq 0 ]; then
		# global preup
		if fn_exists preup 2>/dev/null; then
			${ECHO} "${N1_COLOR}execute global preup function${N0_COLOR}"
			preup
			${ECHO} "${N1_COLOR}execute global preup function done${N0_COLOR}"
		fi
	fi

	if [ "${jail_num}" -eq 1 ]; then
		jname="${jail_list}"
		run_jail
	elif [ "${bhyve_num}" -eq 1 ]; then
		jname="${bhyve_list}"
		run_bhyve
	elif [ "${qemu_num}" -eq 1 ]; then
		jname="${qemu_list}"
		run_qemu
	fi
	end_time=$( ${DATE_CMD} +%s )
	diff_time=$(( end_time - st_time ))
	diff_time=$( displaytime ${diff_time} )

	# protection from multiple env
	if [ ${multiple} -eq 0 ]; then
		# global postup
		if fn_exists postup 2>/dev/null; then
			postup
		fi
	fi

	${ECHO} "${N1_COLOR}${CBSD_APP} done ${N2_COLOR}in ${diff_time}${N0_COLOR}" 1>&2
	cd ${OCBSD_PWD}
	exit 0
fi

# multiple run area
. "${subrdir}"/multiple.subr

${ECHO} "${N1_COLOR}Hint: Press ${N2_COLOR}'Ctrl+t'${N1_COLOR} to see last logfile line for active task${N0_COLOR}" 1>&2
task_owner="up_multiple"

task_id=
task_id_cur=

# global preup
if fn_exists preup 2>/dev/null; then
	${ECHO} "${N1_COLOR}execute global preup function${N0_COLOR}"
	preup
	${ECHO} "${N1_COLOR}execute global preup function done${N0_COLOR}"
fi

# spawn command for all jail
max_env=0
for i in ${jail_list} ${bhyve_list} ${qemu_list}; do
	max_env=$(( max_env + 1 ))
done

cur_env=1

# todo:
# SUDO_USER for DOAS?
for jname in ${jail_list} ${bhyve_list} ${qemu_list}; do
	# we must inherit CBSD_PWD via cwd= for cbsd-related function in postcreate_ action
	# shellcheck disable=2086
	task_id_cur=$( task mode=new logfile=${tmpdir}/${task_owner}.${jname}.log.$$ client_id=${jname} autoflush=0 owner=${task_owner} ${ENV_CMD} SUDO_USER="${SUDO_USER}" UPFILE_DESTROY_FAILED="${upfile_destroy_failed}" NOCOLOR=${NOCOLOR} /usr/local/bin/cbsd up multiple=${max_env} cur_env=${cur_env} cbsdfile=${Makefile} jname=${jname} cwd=${CBSD_PWD} )
	if [ -z "${task_id}" ]; then
		task_id="${task_id_cur}"
	else
		task_id="${task_id} ${task_id_cur}"
	fi
	multiple_task_id_all=$( echo "${task_id}" | ${TR_CMD} " " "," )
	cur_env=$(( cur_env + 1 ))
	sleep 1
done

st_time=$( ${DATE_CMD} +%s )

multiple_processing_spawn -o ${task_owner} -n "up"

# global postup
if fn_exists postup 2>/dev/null; then
	${ECHO} "${N1_COLOR}execute global postup function${N0_COLOR}"
	postup
	${ECHO} "${N1_COLOR}execute global postup function done${N0_COLOR}"
fi

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}"

cd ${OCBSD_PWD}

exit 0
