From 62b95711e7b232bad0dd2c54d972556a2a572df5 Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 18 Dec 2019 22:45:44 -0400 Subject: [PATCH] Add foreign jail import support, improved fstab utility --- CHANGELOG | 1 + bastille-init | 207 ++++++++++++++++++++++++++++++++-- gui/bastille_manager_util.php | 40 +++++-- version | 2 +- 4 files changed, 226 insertions(+), 24 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a3a748c..171abcf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ ====================== Version Description +1.0.25......Add foreign jail import support, improved fstab utility. 1.0.24......Improved Thick container upgrade process. 1.0.23......Improved container/base update process. 1.0.22......Handle container/base updates from the UI. diff --git a/bastille-init b/bastille-init index 16c2052..0579eb6 100755 --- a/bastille-init +++ b/bastille-init @@ -744,13 +744,13 @@ thickjail_upgrade() if [ "$(jls name | grep -w "${TARGET}")" ]; then # Upgrade a thick container. echo "=> Run the command below several times when asked to finish installing updates." - echo "bastille-init upgrade_install ${TARGET}" + echo "bastille-init install ${TARGET}" echo CURRENT_VERSION=$(jexec -l ${TARGET} freebsd-version) env PAGER="/bin/cat" ${FREEBSD_UPDATE}/freebsd-update --not-running-from-cron -f ${FREEBSD_UPDATE}/freebsd-update.conf \ -d ${CWDIR}/freebsd-update -b "${bastille_jailsdir}/${TARGET}/root" --currently-running "${CURRENT_VERSION}" -r ${RELEASE} upgrade echo - echo "=> Please run: 'bastille-init upgrade_install ${TARGET}' to finish installing updates." + echo "=> Please run: 'bastille-init install ${TARGET}' to finish installing updates." else echo "Container not running." echo "See 'bastille start ${TARGET}'." @@ -768,7 +768,7 @@ thickjail_upgrade() exit 0 } -thickjail_upgrade_install() +thickjail_install() { # Workaround since XigmaNAS does not ship with freebsd-update command. @@ -878,6 +878,187 @@ zfs_activate() fi } +jail_import() +{ + # Foreign jail import support using rsync. + + USAGE="Usage: ${SCRIPTNAME} -I [path]" + if [ -z "${TARGET}" ]; then + echo "${USAGE}"; exit 1 + elif [ ! -d "${TARGET}" ]; then + echo "${USAGE}"; exit 1 + elif [ "$(echo ${TARGET} | grep -w '\/')" ]; then + echo "${USAGE}"; exit 1 + fi + + if [ -d "${CWDIR}/jails" ]; then + # Check jail type and version. + THICK_JAIL="1" + EXCLUDE="" + if [ -d "${TARGET}/basejail" ]; then + THICK_JAIL="" + EXCLUDE="--exclude=rescue --exclude=usr/libdata" + RELENG=$(cat ${TARGET}/etc/freebsd-update.conf | grep -owE '\$FreeBSD\: releng/[0-9]{2}\.[0-9]' | cut -d '/' -f2) + if [ -z "${RELENG}" ]; then + # Just use/try the host version. + RELENG=${HOSTVERSION} + fi + + RELEASE="${RELENG}-RELEASE" + if [ ! -d "${bastille_releasesdir}/${RELEASE}" ]; then + echo "${RELEASE} base not found." + # Ask to fetch/extract new release. + while : + do + read -p "Do you want to bootstrap a new ${RELEASE} base now?? [y/N]:" yn + case ${yn} in + [Yy]) break;; + [Nn]) exit 0;; + esac + done + echo "Proceeding..." + bastille bootstrap ${RELEASE} + if [ ! $? -ne 0 ]; then + error_notify "An error has occurred while bootstrapping ${RELEASE} release." + fi + fi + fi + + # Get some jail info. + NAME_TRIM=$(echo ${TARGET} | awk '{print $1}' | grep -o '[^/]*$' | cut -d '-' -f1) + PATH_TRIM=$(echo ${TARGET} | sed "s/${NAME_TRIM}//g") + IPV4_ADDR=$(cat ${PATH_TRIM}conf/thebrig.conf | grep -wE "${NAME_TRIM}1|ip4.addr" | tail -n 1 | cut -d '|' -f2 | cut -d '/' -f1) + if [ -z "${IPV4_ADDR}" ]; then + # The user should manually set a new IP. + IPV4_ADDR="0.0.0.0" + fi + + # Check if ZFS is enabled on this system. + if [ "${bastille_zfs_enable}" = "YES" ]; then + if [ ! -z "${bastille_zfs_zpool}" ]; then + # ZFS importing. + if [ -f "${TARGET}/root/.profile" ]; then + if [ -d "${bastille_jailsdir}" ]; then + if [ ! -d "${bastille_jailsdir}/${NAME_TRIM}" ]; then + # Create required ZFS datasets. + echo "Creating required ZFS datasets..." + zfs create ${bastille_zfs_options} ${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NAME_TRIM} + zfs create ${bastille_zfs_options} -o mountpoint=${bastille_jailsdir}/${NAME_TRIM}/root ${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NAME_TRIM}/root + echo "Importing foreign jail '${NAME_TRIM}' to ${PRDNAME}..." + echo "Synchronizing '${NAME_TRIM}' data to ${bastille_jailsdir}/${NAME_TRIM}..." + rsync -a ${EXCLUDE} ${TARGET}/ ${bastille_jailsdir}/${NAME_TRIM}/root/ + echo "Generating new jail.conf file for ${NAME_TRIM}..." + generate_jailconf + else + error_notify "Looks like the jail '${NAME_TRIM}' already exist." + fi + else + error_notify "Looks like ${PRDNAME} isn't bootstrapped yet." + fi + else + error_notify "Looks like jail '${NAME_TRIM}' is incomplete/corrupted." + fi + fi + else + # Standard importing. + if [ -f "${TARGET}/root/.profile" ]; then + if [ -d "${bastille_jailsdir}" ]; then + if [ ! -d "${bastille_jailsdir}/${NAME_TRIM}" ]; then + echo "Importing foreign jail '${NAME_TRIM}' to ${PRDNAME}..." + echo "Synchronizing '${NAME_TRIM}' data to ${bastille_jailsdir}/${NAME_TRIM}..." + mkdir -p "${bastille_jailsdir}/${NAME_TRIM}/root" + rsync -a ${EXCLUDE} ${TARGET}/ ${bastille_jailsdir}/${NAME_TRIM}/root/ + echo "Generating new jail.conf file for ${NAME_TRIM}..." + generate_jailconf + else + error_notify "Looks like the jail '${NAME_TRIM}' already exist." + fi + else + error_notify "Looks ${PRDNAME} isn't bootstrapped yet." + fi + else + error_notify "Looks like jail '${NAME_TRIM}' is incomplete/corrupted." + fi + fi + else + error_notify "Looks like ${PRDNAME} isn't bootstrapped yet." + fi + + # Check the exit status. + if [ $? -ne 0 ]; then + error_notify "An error has occurred while importing ${NAME_TRIM}." + else + echo "Foreign jail '${NAME_TRIM}' imported successfully!" + exit 0 + fi +} + +generate_jailconf() +{ + if [ ! -f "${bastille_jail_conf}" ]; then + if [ -z "${bastille_jail_loopback}" ] && [ ! -z "${bastille_jail_external}" ]; then + local bastille_jail_conf_interface=${bastille_jail_external} + fi + if [ ! -z "${bastille_jail_loopback}" ] && [ -z "${bastille_jail_external}" ]; then + local bastille_jail_conf_interface=${bastille_jail_interface} + fi + + # Generate the jail configuration file. + cat << EOF > ${bastille_jailsdir}/${NAME_TRIM}/jail.conf +interface = ${bastille_jail_conf_interface}; +host.hostname = ${NAME_TRIM}; +exec.consolelog = ${bastille_logsdir}/${NAME_TRIM}_console.log; +path = ${bastille_jailsdir}/${NAME_TRIM}/root; +ip6 = disable; +securelevel = 2; +devfs_ruleset = 4; +enforce_statfs = 2; +exec.start = '/bin/sh /etc/rc'; +exec.stop = '/bin/sh /etc/rc.shutdown'; +exec.clean; +mount.devfs; +mount.fstab = ${bastille_jailsdir}/${NAME_TRIM}/fstab; + +${NAME_TRIM} { + ip4.addr = ${IPV4_ADDR}; +} +EOF + fi + + # Generate the fstab file. + if [ ! -f "${bastille_jailsdir}/${NAME_TRIM}/fstab" ]; then + echo "Generating new fstab file for ${NAME_TRIM}..." + if [ -z "${THICK_JAIL}" ]; then + echo -e "${bastille_releasesdir}/${RELEASE} ${bastille_jailsdir}/${NAME_TRIM}/root/.bastille nullfs ro 0 0" \ + > ${bastille_jailsdir}/${NAME_TRIM}/fstab + else + touch ${bastille_jailsdir}/${NAME_TRIM}/fstab + fi + fi + + # Symlinks required for thin jails. + if [ -z "${THICK_JAIL}" ]; then + cd ${bastille_jailsdir}/${NAME_TRIM}/root + USR_LIB32="usr/lib32" + if [ -d "${USR_LIB32}" ]; then + # Skip usr/lib32 symlink if the libs already exist. + USR_LIB32="" + fi + + for _link in bin boot lib libexec rescue sbin usr/bin usr/include usr/lib ${USR_LIB32} usr/libdata usr/libexec usr/sbin usr/share usr/src; do + ln -Ffhs /.bastille/${_link} ${_link} + done + mkdir -p usr/home + ln -fhs usr/home home + mv ${bastille_jailsdir}/${NAME_TRIM}/root/basejail ${bastille_jailsdir}/${NAME_TRIM}/root/.bastille + fi + + # Include the old fstab file for user reference. + if [ -f "${PATH_TRIM}conf/jails/fstab.${NAME_TRIM}" ]; then + cp ${PATH_TRIM}conf/jails/fstab.${NAME_TRIM} ${bastille_jailsdir}/${NAME_TRIM}/fstab.sample + fi +} + pkg_upgrade() { # Re-fetch bastille package and extract. @@ -1144,12 +1325,12 @@ NEWRELEASE="${4}" # Handle additional commands. case "${OPT}" in -upgrade_install|--upgrade_install) +install|--install) if [ $# -gt 2 ] || [ $# -lt 2 ]; then - echo "Usage: ${SCRIPTNAME} [upgrade_install|--upgrade_install] [container]" + echo "Usage: ${SCRIPTNAME} [install|--install] [container]" exit 1 fi - thickjail_upgrade_install + thickjail_install ;; upgrade|--upgrade) # Check container type to upgrade @@ -1182,9 +1363,9 @@ clean|--clean) ;; esac -while getopts ":ospruxUvgtBRZh" option; do +while getopts ":ospruxUvgtBRZIh" option; do case ${option} in - [h]) echo "Usage: ${SCRIPTNAME} -[option] | [container]"; + [h]) echo "Usage: ${SCRIPTNAME} -[option] | [container] | [path]"; echo "Options:" echo " -s Start All ${PRDNAME} Containers." echo " -p Stop All ${PRDNAME} Containers." @@ -1196,16 +1377,17 @@ while getopts ":ospruxUvgtBRZh" option; do echo " -B Backup a ${PRDNAME} container." echo " -R Restore a ${PRDNAME} container." echo " -Z Activate ZFS for ${PRDNAME} Extension." + echo " -I Import a foreign container to ${PRDNAME}." echo " -x Reset ${PRDNAME}/Extension config." echo " -U Uninstall ${PRDNAME} (Extension files only)." echo " -h Display this help message." echo echo "Advanced Usage: ${SCRIPTNAME} [option] [container] [release] | [newrelease]" echo "Options:" - echo " update|--update Update a container/release to base -pX release." - echo " upgrade|--upgrade Upgrade a container release to X.Y-RELEASE." - echo " upgrade_install|--upgrade_install Finish installing pending updates on Thick containers." - echo " clean|--clean Cleanup the FreeBSD update/upgrade cached files/folders." + echo " update|--update Update a container/release to base -pX release." + echo " upgrade|--upgrade Upgrade a container release to X.Y-RELEASE." + echo " install|--install Finish installing pending updates on Thick containers." + echo " clean|--clean Cleanup the FreeBSD update/upgrade cached files/folders." echo ""; exit 0;; [o]) OBI_INSTALL="ON";; # To prevent nested PHP-CGI call for installation with OBI. [s]) bastille_start;; @@ -1220,6 +1402,7 @@ while getopts ":ospruxUvgtBRZh" option; do [B]) jail_backup;; [R]) jail_restore;; [Z]) zfs_activate;; + [I]) jail_import;; [?]) echo "Invalid option, -h for usage."; exit 1;; esac done diff --git a/gui/bastille_manager_util.php b/gui/bastille_manager_util.php index 370f2f2..1011e4e 100644 --- a/gui/bastille_manager_util.php +++ b/gui/bastille_manager_util.php @@ -235,6 +235,8 @@ if($_POST): $item = $container['jailname']; $sourcedir = $pconfig['source_path']; $targetdir = $pconfig['target_path']; + $is_running = exec("/usr/sbin/jls | /usr/bin/grep -w '{$item}'"); + $paths_exist = exec("/bin/cat {$rootfolder}/jails/{$item}/fstab | /usr/bin/grep -w '{$sourcedir} {$targetdir}'"); if ($_POST['readonly']): $dir_mode = "ro"; @@ -242,19 +244,32 @@ if($_POST): $dir_mode = "rw"; endif; - $cmd = ("/bin/echo \"{$sourcedir} {$targetdir} nullfs {$dir_mode} 0 0\" >> {$rootfolder}/jails/{$item}/fstab"); - unset($output,$retval);mwexec2($cmd,$output,$retval); - if($retval == 0): - if ($_POST['createdir']): - mkdir("$targetdir"); + if (!$paths_exist): + $cmd = ("/bin/echo \"{$sourcedir} {$targetdir} nullfs {$dir_mode} 0 0\" >> {$rootfolder}/jails/{$item}/fstab"); + unset($output,$retval);mwexec2($cmd,$output,$retval); + if($retval == 0): + + if ($_POST['createdir']): + if (!is_dir("{$targetdir}")): + mkdir("$targetdir"); + endif; + if ($_POST['automount']): + if ($is_running): + exec("/sbin/mount_nullfs -o {$dir_mode} {$sourcedir} {$targetdir}"); + endif; + endif; + endif; + + $savemsg .= gtext("Edited the fstab successfully."); + //header('Location: bastille_manager_gui.php'); + //exit; + else: + $errormsg .= gtext("Failed to edit the fstab."); endif; - - $savemsg .= gtext("Container backup process completed successfully."); - //header('Location: bastille_manager_gui.php'); - //exit; else: - $errormsg .= gtext("Failed to backup container."); + $savemsg .= gtext("Directories already exist in the fstab."); endif; + endif; break; @@ -312,6 +327,7 @@ function action_change() { showElementById('advanced_tr', 'hide'); showElementById('readonly_tr', 'hide'); showElementById('createdir_tr', 'hide'); + showElementById('automount_tr', 'hide'); showElementById('jail_release_tr', 'hide'); showElementById('release_tr','hide'); showElementById('update_base_tr','hide'); @@ -348,6 +364,7 @@ function action_change() { showElementById('target_path_tr','show'); showElementById('readonly_tr','show'); showElementById('createdir_tr','show'); + showElementById('automount_tr','show'); break; case "delete": showElementById('confirmname_tr','show'); @@ -434,7 +451,8 @@ $document->render(); html_filechooser("source_path", gtext("Source Data Directory"), $pconfig['source_path'], gtext("Source data directory to be shared, full path here."), $source_path, true, 60); html_filechooser("target_path", gtext("Target Data Directory"), $pconfig['target_path'], gtext("Target data directory to be mapped, path within the jail only."), $target_path, true, 60); html_checkbox2('advanced',gettext('Advanced jail configuration Files'),!empty($pconfig['advanced']) ? true : false,gettext('I understand the risks, take me to the advanced jail config files.'),'',true); - html_checkbox2('readonly',gettext('Read-Only Mode'),!empty($pconfig['readonly']) ? true : false,gettext('Set target directory in Read-Only mode.'),'',false); + html_checkbox2('readonly',gettext('Read-Only Mode'),!empty($pconfig['readonly']) ? true : false,gettext('Set target directory in Read-Only mode.'),'',true); + html_checkbox2('automount',gettext('Auto-mount Nullfs'),!empty($pconfig['automount']) ? true : false,gettext('Auto-mount the nullfs mountpoint if the container is already running.'),'',true); html_checkbox2('createdir',gettext('Create Target Directory'),!empty($pconfig['createdir']) ? true : true,gettext('Create target directory if missing (recommended).'),'',true); if ($is_thickjail): html_checkbox2('update_base',gettext('Base update confirm'),!empty($pconfig['update_base']) ? true : false,gettext('This is a thin container, therefore the base release will be updated, this affects child containers.'),'',true); diff --git a/version b/version index 79728fe..4a4127c 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.0.24 +1.0.25