From b817aa8445ace8c5e58cdff88e7f0e0a275a8e15 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 9 Apr 2017 17:34:43 +0100 Subject: [PATCH] Issue #174: Add -g option for Groot and integ tests for user namespace --- .travis.yml | 11 ++- README.md | 77 +++++++++++++++++--- bin/groot | 2 +- bin/junest | 77 +++++++------------- lib/checks/check.sh | 62 ++++++++++++++++ lib/core/build.sh | 46 +----------- lib/core/chroot.sh | 87 +++++++++++++++++------ lib/core/common.sh | 110 +++++++++++++++++++++-------- lib/core/namespace.sh | 48 +++---------- lib/core/proot.sh | 5 +- tests/unit-tests/test-chroot.sh | 45 ++++++++---- tests/unit-tests/test-common.sh | 46 ++++++++---- tests/unit-tests/test-groot.sh | 20 +++--- tests/unit-tests/test-junest.sh | 86 ++++++++-------------- tests/unit-tests/test-namespace.sh | 44 +++--------- 15 files changed, 433 insertions(+), 333 deletions(-) create mode 100755 lib/checks/check.sh diff --git a/.travis.yml b/.travis.yml index a1b6078..4e4536a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,9 +17,14 @@ install: script: - bash --version - - bash ./tests/unit-tests/unit-tests.sh - bash ./tests/checkstyle/checkstyle.sh - - junest --check ./bin/junest + - bash ./tests/unit-tests/unit-tests.sh + + # Multiple tests against different execution modes: + - junest -f -- ${PWD}/lib/checks/check.sh + - junest -u -- ${PWD}/lib/checks/check.sh --skip-aur-tests + - sudo -E ${PWD}/bin/junest -g -- ${PWD}/lib/checks/check.sh --run-root-tests - yes | junest --delete - - JUNEST_HOME=~/.junest-arm junest --check ./bin/junest --skip-root-tests + + - JUNEST_HOME=~/.junest-arm junest -f -- ./lib/checks/check.sh - yes | JUNEST_HOME=~/.junest-arm junest --delete diff --git a/README.md b/README.md index e747c4e..492e284 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The Arch Linux based distro that runs upon any Linux distros without root access |Project Status|Donation|Communication| |:------------:|:------:|:-----------:| -| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) [![Gratipay](https://img.shields.io/badge/Gratipay-Donate%20to%20JuNest-green.svg)](https://gratipay.com/junest/) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) [![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/Google Groups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | +| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) [![Gratipay](https://img.shields.io/badge/Gratipay-Donate%20to%20JuNest-green.svg)](https://gratipay.com/junest/) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) [![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/GoogleGroups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | **Table of Contents** - [Description](#description) @@ -48,19 +48,62 @@ JuNest follows the [Arch Linux philosophy](https://wiki.archlinux.org/index.php/ Quickstart ========== -There are three different ways you can run JuNest: + +Backend programs +---------------- +There are three different ways you can run JuNest depending on the backend program you decide to use. + +### PRoot based ### +[Proot](https://wiki.archlinux.org/index.php/Proot) represents the default +program used for accessing to the JuNest environments. +The main reason to choose Proot as default backend program is because +it represents a portable solution that works well in most of GNU/Linux distros available. +One of the major drawbacks is the fact that Proot is not officially +supported anymore, therefore, Proot bugs may no longer be fixed. + +In order to run JuNest via Proot: - As normal user - Allow to make basic operations: ```junest``` - As fakeroot - Allow to install/remove packages: ```junest -f``` -- As root - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -r``` +### Linux namespaces based ### +The [Linux namespaces](http://man7.org/linux/man-pages/man7/namespaces.7.html) +represents the next generation backend program for JuNest. +The major drawback about the namespace is portability, as certain requirements +need to be satisfied: 1) Only starting from Linux 3.8, unprivileged processes can +create the required user and mount namespaces. +2) Moreover, the Linux kernel distro must have the user namespace enabled. +Hopefully, in the future the major GNU/Linux distros will start enabling such feature by default. +For instance, Ubuntu (version 14.04+) already has such feature enabled. +In order to run JuNest via Linux namespaces: + +- As fakeroot - Allow to install/remove packages: ```junest -u``` + +### Chroot based ### +This solution suits only for privileged users. JuNest provides the possibility +to run the environment via `chroot` program. +In particular, it uses a special program called `GRoot`, an enhanced `chroot` +wrapper that allows to bind mount directories specified by the user, such as +/proc, /sys, /dev, /tmp and $HOME, before +executing any programs inside the JuNest sandbox. In case the mounting will not +work, JuNest is even providing the possibility to run the environment directly via +the pure `chroot` command. + +In order to run JuNest via `chroot` solutions: + +- As root via `GRoot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -g``` + +- As root via `chroot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -r``` + +After running JuNest +-------------------- If the JuNest image has not been downloaded yet, the script will download -the image and will place it to the default directory ~/.junest. -You can change the default directory by changing the environment variable *JUNEST\_HOME*. +the image from the repository and will place it to the default directory `~/.junest`. +You can change the default directory by changing the environment variable `JUNEST_HOME`. -If you are new on Archlinux and you are not familiar with *pacman* package manager +If you are new on Arch Linux and you are not familiar with `pacman` package manager visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta). Installation @@ -90,7 +133,7 @@ Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): ### Installation using AUR (Arch Linux only) ### If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/): - yogurt -S junest-git + yaourt -S junest-git export PATH=/opt/junest/bin:$PATH ## Method two ## @@ -98,7 +141,7 @@ Alternatively, another installation method would be to directly download the JuN ARCH= mkdir ~/.junest - curl https://dl.dropboxusercontent.com/u/42449030/junest/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest + curl https://s3-eu-west-1.amazonaws.com/junest-repo/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest export PATH=~/.junest/opt/junest/bin:$PATH Advanced usage @@ -141,12 +184,12 @@ To bind a host directory to a guest location, you can use proot arguments: junest -p "-b /mnt/mydata:/home/user/mydata" -Check out the proot options with: +This will works with PRoot, Namespace and GRoot backend programs. +Check out the backend program options by passing `--help` option: - junest -p "--help" + junest [-u|-g] -p "--help" ## Systemd integration ## - Although JuNest has not been designed to be a complete container, it is even possible to virtualize the process tree thanks to the [systemd container](https://wiki.archlinux.org/index.php/Systemd-nspawn). The JuNest containter allows to run services inside the container that can be @@ -345,6 +388,18 @@ Troubleshooting > since JuNest will try to preserve the JuNest environment by assigning ownership > of the files to the real user. +## Not enabled User namespace or kernel too old ## + +> **Q**: Why do I get warning when I run JuNest via Linux namespaces? + + $> junest -u + User namespace is not enabled or Kernel too old (<3.8). Proceeding anyway... + +> **A**: This means that JuNest detected that the host OS either +> does not have a newer Linux version or the user namespace is not enabled. +> JuNest does not stop the execution of the program but it attempts to run it +> anyway. Try to use Proot as backend program in case is not possible to invoke namespaces. + More documentation ================== There are additional tutorials in the diff --git a/bin/groot b/bin/groot index 97ccfef..4033705 100755 --- a/bin/groot +++ b/bin/groot @@ -56,7 +56,7 @@ function chroot_maybe_add_mount() { } function chroot_setup() { - $OPT_NO_UMOUNT || check_and_trap 'chroot_teardown' EXIT + $OPT_NO_UMOUNT || check_and_trap 'chroot_teardown' QUIT EXIT ABRT KILL TERM INT if ! chroot_maybe_add_mount "! $MOUNTPOINT -q '$CHROOTDIR'" --bind "$CHROOTDIR" "$CHROOTDIR" then diff --git a/bin/junest b/bin/junest index 9d2a527..a2b96e5 100755 --- a/bin/junest +++ b/bin/junest @@ -36,18 +36,17 @@ usage() { echo echo -e "Access options:" echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" - echo -e "-r, --root Run $NAME with root privileges via GRoot" + echo -e "-g, --groot Run $NAME with root privileges via GRoot" + echo -e "-r, --root Run $NAME with root privileges via classic chroot" + echo -e "-u, --namespace Use Linux Namespace (with GRoot) instead of PRoot" echo -e "-p, --backend-args Arguments for backend program (PRoot or GRoot)" echo -e " ($CMD -p \"--help\" to check out the PRoot options" - echo -e " $CMD -u -p \"--help\" to check out the GRoot options)" - echo -e "-u, --user-namespace Use Linux User Namespace instead of PRoot" + echo -e " $CMD -g -p \"--help\" to check out the GRoot options" + echo -e " $CMD -r -p \"--help\" to check out the chroot options)" echo echo -e "Building options:" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" echo -e "-n, --disable-validation Disable the $NAME image validation" - echo -e "-c, --check <${CMD}_script> Validate the env located in ${JUNEST_HOME}" - echo -e " using ${CMD}_script. This will alterate the environment" - echo -e "-s, --skip-root-tests Skip the root tests during the validation process" echo echo -e "General options:" echo -e "-h, --help Show this help message" @@ -60,33 +59,17 @@ version() { check_cli(){ if $OPT_BUILD_IMAGE - then - if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_CHECK - then - die "The build image option must be used exclusively" - fi - fi - if $OPT_SKIP_ROOT_TEST then if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ $OPT_FAKEROOT || $OPT_ROOT then - die "The skip root tests option must be used with either build image or check options" - fi - fi - if $OPT_CHECK - then - if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_BUILD_IMAGE - then - die "The validation image option must be used exclusively" + die "The build image option must be used exclusively" fi fi if $OPT_DISABLE_VALIDATION then if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_CHECK + $OPT_FAKEROOT || $OPT_ROOT then die "The disable validation option must be used with the build image option only" fi @@ -94,7 +77,7 @@ check_cli(){ if $OPT_DELETE then if $OPT_BUILD_IMAGE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION || $OPT_CHECK + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION then die "The $NAME delete option must be used exclusively" fi @@ -102,7 +85,7 @@ check_cli(){ if $OPT_HELP then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION || $OPT_CHECK + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION then die "The $NAME help option must be used exclusively" fi @@ -110,7 +93,7 @@ check_cli(){ if $OPT_VERSION then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION || $OPT_CHECK + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION then die "The $NAME version option must be used exclusively" fi @@ -122,7 +105,7 @@ check_cli(){ if $OPT_BACKEND_ARGS || $OPT_ARCH then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || \ - $OPT_ROOT || $OPT_VERSION || $OPT_DISABLE_VALIDATION || $OPT_CHECK + $OPT_ROOT || $OPT_VERSION || $OPT_DISABLE_VALIDATION then die "Invalid syntax: Proot and arch args are not allowed with the other options" fi @@ -130,7 +113,7 @@ check_cli(){ if [ "$ARGS" != "" ] then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ - $OPT_VERSION || $OPT_DISABLE_VALIDATION || $OPT_CHECK + $OPT_VERSION || $OPT_DISABLE_VALIDATION then die "No arguments are needed. For the CLI syntax run: $CMD --help" fi @@ -145,6 +128,7 @@ function parse_arguments(){ IMAGE_FILE="" OPT_FAKEROOT=false OPT_ROOT=false + OPT_GROOT=false OPT_USER_NAMESPACE=false OPT_BACKEND_ARGS=false BACKEND_ARGS="" @@ -152,9 +136,7 @@ function parse_arguments(){ ARCH_ARG="" OPT_BUILD_IMAGE=false OPT_DISABLE_VALIDATION=false - OPT_CHECK=false CHECK_ARG="" - OPT_SKIP_ROOT_TEST=false OPT_DELETE=false OPT_HELP=false OPT_VERSION=false @@ -164,13 +146,12 @@ function parse_arguments(){ -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; -r|--root) OPT_ROOT=true ; shift ;; - -u|--user-namespace) OPT_USER_NAMESPACE=true ; shift ;; + -g|--groot) OPT_GROOT=true ; shift ;; + -u|--namespace) OPT_USER_NAMESPACE=true ; shift ;; -p|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;; -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; - -c|--check) OPT_CHECK=true ; shift ; CHECK_ARG=$1; shift ;; - -s|--skip-root-tests) OPT_SKIP_ROOT_TEST=true ; shift ;; -d|--delete) OPT_DELETE=true ; shift ;; -h|--help) OPT_HELP=true ; shift ;; -V|--version) OPT_VERSION=true ; shift ;; @@ -192,14 +173,11 @@ function execute_operation(){ $OPT_VERSION && version && return if $OPT_BUILD_IMAGE; then - build_image_env $OPT_DISABLE_VALIDATION $OPT_SKIP_ROOT_TEST + build_image_env $OPT_DISABLE_VALIDATION return elif $OPT_DELETE; then delete_env return - elif $OPT_CHECK; then - check_env "${JUNEST_HOME}" "${CHECK_ARG}" $OPT_SKIP_ROOT_TEST - return fi if ! is_env_installed @@ -217,22 +195,21 @@ function execute_operation(){ [ -z "${ARCH_ARG}" ] || \ die "The option --arch cannot be specified since JuNest has already been downloaded in $JUNEST_HOME" + local run_env if $OPT_USER_NAMESPACE; then - if $OPT_FAKEROOT; then - run_env_as_fakeroot_with_namespace "${BACKEND_ARGS}" "${ARGS[@]}" - else - run_env_as_user_with_namespace "${BACKEND_ARGS}" "${ARGS[@]}" - fi + run_env=run_env_with_namespace + elif $OPT_FAKEROOT; then + run_env=run_env_as_fakeroot + elif $OPT_ROOT; then + run_env=run_env_as_chroot + elif $OPT_GROOT; then + run_env=run_env_as_groot else - if $OPT_FAKEROOT; then - run_env_as_fakeroot "${BACKEND_ARGS}" "${ARGS[@]}" - elif $OPT_ROOT; then - run_env_as_root "${ARGS[@]}" - else - run_env_as_user "${BACKEND_ARGS}" "${ARGS[@]}" - fi + run_env=run_env_as_user fi + $run_env "${BACKEND_ARGS}" "${ARGS[@]}" + } function main() { diff --git a/lib/checks/check.sh b/lib/checks/check.sh new file mode 100755 index 0000000..4a0cd73 --- /dev/null +++ b/lib/checks/check.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# +# This modules is used for: +# - Running checks against the building JuNest image +# - Integration tests on JuNest script against different execution modes (i.e. -f, -u, -r modes) +# +# Dependencies: +# - None +# +# vim: ft=sh + +set -eu + +OPT_RUN_ROOT_TESTS=${1:-false} +RUN_ROOT_TESTS=false +[[ ${OPT_RUN_ROOT_TESTS} == "--run-root-tests" ]] && RUN_ROOT_TESTS=true + +OPT_SKIP_AUR_TESTS=${1:-false} +SKIP_AUR_TESTS=false +[[ ${OPT_SKIP_AUR_TESTS} == "--skip-aur-tests" ]] && SKIP_AUR_TESTS=true + +JUNEST_HOME=${JUNEST_HOME:-$HOME/.junest} + +# JUNEST_BASE can be overridden for testing purposes. +# There is no need for doing it for normal usage. +JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/../..)}" + +source "${JUNEST_BASE}/lib/utils/utils.sh" +source "${JUNEST_BASE}/lib/core/common.sh" + +info "Validating JuNest located in ${JUNEST_HOME}..." + +info "Initial JuNest setup..." +echo "Server = ${DEFAULT_MIRROR}" >> /etc/pacman.d/mirrorlist +pacman --noconfirm -Syy +pacman --noconfirm -S base-devel + +info "Checking essential executables work..." +pacman -Qi pacman 1> /dev/null +yogurt -V 1> /dev/null +/opt/proot/proot-$ARCH --help 1> /dev/null + +repo_package1=tree +echo "Checking ${repo_package1} package from official repo..." +pacman --noconfirm -S ${repo_package1} +tree -L 1 +pacman --noconfirm -Rsn ${repo_package1} + +repo_package2=iftop +info "Checking ${repo_package2} package from official repo..." +pacman --noconfirm -S ${repo_package2} +$RUN_ROOT_TESTS && iftop -t -s 5 +pacman --noconfirm -Rsn ${repo_package2} + +if ! $SKIP_AUR_TESTS +then + aur_package=tcptraceroute + info "Checking ${aur_package} package from AUR repo..." + yogurt -A --noconfirm -S ${aur_package} + $RUN_ROOT_TESTS && tcptraceroute localhost + pacman --noconfirm -Rsn ${aur_package} +fi diff --git a/lib/core/build.sh b/lib/core/build.sh index 1945185..4a00f22 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -40,7 +40,6 @@ function build_image_env(){ _check_package git local disable_validation=$1 - local skip_root_tests=$2 local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) sudo mkdir -p ${maindir}/root @@ -88,7 +87,8 @@ function build_image_env(){ then mkdir -p ${maindir}/root_test $TAR -zxpf ${imagefile} -C "${maindir}/root_test" - check_env "${maindir}/root_test" "${maindir}/root_test/opt/${CMD}/bin/${CMD}" $skip_root_tests + JUNEST_HOME="${maindir}/root_test" ${maindir}/root_test/opt/${CMD}/bin/${CMD} -f ./lib/checks/check.sh + JUNEST_HOME="${maindir}/root_test" sudo -E ${maindir}/root_test/opt/${CMD}/bin/${CMD} -g ./lib/checks/check.sh --run-root-tests fi sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} @@ -97,45 +97,3 @@ function build_image_env(){ trap - QUIT EXIT ABRT KILL TERM INT sudo rm -fr "$maindir" } - -function check_env(){ - local testdir=$1 - local cmd=$2 - local skip_root_tests=$3 - info "Validating ${NAME} located in ${testdir} using the ${cmd} script..." - echo "Server = ${DEFAULT_MIRROR}" >> ${testdir}/etc/pacman.d/mirrorlist - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Syy - - # Check most basic executables work - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r pacman -Qi pacman 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -- pacman -Qi pacman 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -f -- pacman -Qi pacman 1> /dev/null - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r yogurt -V 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -- yogurt -V 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -V 1> /dev/null - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r /opt/proot/proot-$ARCH --help 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -- /opt/proot/proot-$ARCH --help 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -f -- /opt/proot/proot-$ARCH --help 1> /dev/null - - local repo_package=tree - info "Installing ${repo_package} package from official repo using proot..." - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} - JUNEST_HOME=${testdir} ${cmd} tree - JUNEST_HOME=${testdir} ${cmd} -f tree - - local repo_package=iftop - info "Installing ${repo_package} package from official repo using root..." - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r iftop -t -s 5 - - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S base-devel - local aur_package=tcptraceroute - info "Installing ${aur_package} package from AUR repo using proot..." - JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -A --noconfirm -S ${aur_package} - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r tcptraceroute localhost - - info "Removing the previous packages..." - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Rsn tcptraceroute tree iftop - - JUNEST_HOME=${testdir} ${cmd} -u -- ls -la -} diff --git a/lib/core/chroot.sh b/lib/core/chroot.sh index ff8465d..9a104aa 100644 --- a/lib/core/chroot.sh +++ b/lib/core/chroot.sh @@ -8,27 +8,12 @@ # # vim: ft=sh -####################################### -# Run JuNest as real root. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# UID (RO) : The user ID. -# SUDO_USER (RO) : The sudo user ID. -# SUDO_GID (RO) : The sudo group ID. -# SH (RO) : Contains the default command to run in JuNest. -# Arguments: -# cmd ($@?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. -# Returns: -# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. -# Output: -# - : The command output. -####################################### -function run_env_as_root(){ - source ${JUNEST_HOME}/etc/junest/info - [ "$JUNEST_ARCH" != "$ARCH" ] && \ - die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH" +function _run_env_as_xroot(){ + local cmd=$1 + local backend_args="$2" + shift 2 + + check_same_arch local uid=$UID # SUDO_USER is more reliable compared to SUDO_UID @@ -41,5 +26,63 @@ function run_env_as_root(){ trap - QUIT EXIT ABRT KILL TERM INT trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT - JUNEST_ENV=1 chroot_cmd "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" + copy_common_files + + check_nested_env + + JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" +} + +####################################### +# Run JuNest as real root via GRoot command. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# UID (RO) : The user ID. +# SUDO_USER (RO) : The sudo user ID. +# SUDO_GID (RO) : The sudo group ID. +# SH (RO) : Contains the default command to run in JuNest. +# Arguments: +# backend_args ($1) : The arguments to pass to proot +# cmd ($2-?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. +# Output: +# - : The command output. +####################################### +function run_env_as_groot(){ + local backend_args="$1" + shift + + provide_common_bindings + local bindings=${RESULT} + unset RESULT + + _run_env_as_xroot "$GROOT $bindings" "$backend_args" "$@" +} + +####################################### +# Run JuNest as real root via chroot command. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# UID (RO) : The user ID. +# SUDO_USER (RO) : The sudo user ID. +# SUDO_GID (RO) : The sudo group ID. +# SH (RO) : Contains the default command to run in JuNest. +# Arguments: +# backend_args ($1) : The arguments to pass to proot +# cmd ($2-?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. +# Output: +# - : The command output. +####################################### +function run_env_as_chroot(){ + local backend_args="$1" + shift + + _run_env_as_xroot chroot_cmd "$backend_args" "$@" } diff --git a/lib/core/common.sh b/lib/core/common.sh index d7e050c..17b0d5b 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -19,20 +19,9 @@ NESTED_ENVIRONMENT=106 VARIABLE_NOT_SET=107 NO_CONFIG_FOUND=108 -if [ "$JUNEST_ENV" == "1" ] -then - die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed" -elif [ ! -z $JUNEST_ENV ] && [ "$JUNEST_ENV" != "0" ] -then - die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set" -fi - -[ -z ${JUNEST_HOME} ] && JUNEST_HOME=~/.${CMD} -[ -z ${JUNEST_BASE} ] && JUNEST_BASE=${JUNEST_HOME}/opt/junest -if [ -z ${JUNEST_TEMPDIR} ] || [ ! -d ${JUNEST_TEMPDIR} ] -then - JUNEST_TEMPDIR=/tmp -fi +JUNEST_HOME=${JUNEST_HOME:-~/.${CMD}} +JUNEST_BASE=${JUNEST_BASE:-${JUNEST_HOME}/opt/junest} +JUNEST_TEMPDIR=${JUNEST_TEMPDIR:-/tmp} # The update of the variable PATH ensures that the executables are # found on different locations @@ -99,36 +88,55 @@ LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" # image. function ln_cmd(){ - $LN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$LN $@ + $LN "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$LN "$@" } function getent_cmd(){ - $GETENT $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$GETENT $@ + $GETENT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$GETENT "$@" } function cp_cmd(){ - $CP $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CP $@ + $CP "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CP "$@" } function rm_cmd(){ - $RM $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$RM $@ + $RM "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$RM "$@" } function chown_cmd(){ - $CHOWN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CHOWN $@ + $CHOWN "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CHOWN "$@" } function mkdir_cmd(){ - $MKDIR $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR $@ + $MKDIR "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR "$@" } function zgrep_cmd(){ # No need for LD_EXEC as zgrep is a POSIX shell script - $ZGREP $@ || ${JUNEST_HOME}/usr/bin/$ZGREP $@ + $ZGREP "$@" || ${JUNEST_HOME}/usr/bin/$ZGREP "$@" +} + +function download_cmd(){ + $WGET "$@" || $CURL "$@" +} + +function chroot_cmd(){ + $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CLASSIC_CHROOT "$@" } function unshare_cmd(){ - $UNSHARE $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE $@ + # Most of the distros do not have the `unshare` command updated + # with --user option available. + # Hence, give priority to the `unshare` executable in JuNest image. + if $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE --user "${SH[@]}" "-c" ":" + then + $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE "${@}" + elif $UNSHARE --user "${SH[@]}" "-c" ":" + then + $UNSHARE "$@" + else + die "Error: Something went wrong with unshare command. Exiting" + fi } function proot_cmd(){ @@ -141,20 +149,60 @@ function proot_cmd(){ then PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${@}" else - die "Error: Check if the ${CMD} arguments are correct and if the kernel is too old use the option ${CMD} -p \"-k 3.10\"" + die "Error: Something went wrong with proot command. Exiting" fi } -function download_cmd(){ - $WGET $@ || $CURL $@ -} - -function chroot_cmd(){ - $GROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CLASSIC_CHROOT "$@" -} - ############## COMMON FUNCTIONS ############### +####################################### +# Check if the executable is being running inside a JuNest environment. +# +# Globals: +# JUNEST_ENV (RO) : The boolean junest env check +# NESTED_ENVIRONMENT (RO) : The nest env exception +# VARIABLE_NOT_SET (RO) : The var not set exception +# NAME (RO) : The JuNest name +# Arguments: +# None +# Returns: +# VARIABLE_NOT_SET : If no JUNEST_ENV is not properly set +# NESTED_ENVIRONMENT : If the script is executed inside JuNest env +# Output: +# None +####################################### +function check_nested_env() { + if [[ $JUNEST_ENV == "1" ]] + then + die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed" + elif [[ ! -z $JUNEST_ENV ]] && [[ $JUNEST_ENV != "0" ]] + then + die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set" + fi +} + +####################################### +# Check if the architecture between Host OS and Guest OS is the same. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home path. +# ARCHITECTURE_MISMATCH (RO) : The arch mismatch exception +# ARCH (RO) : The host OS arch +# JUNEST_ARCH (RO) : The JuNest arch +# Arguments: +# None +# Returns: +# ARCHITECTURE_MISMATCH : If arch between host and guest is not the same +# Output: +# None +####################################### +function check_same_arch() { + source ${JUNEST_HOME}/etc/junest/info + [ "$JUNEST_ARCH" != "$ARCH" ] && \ + die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH" + return 0 +} + ####################################### # Provide the proot common binding options for both normal user and fakeroot. # The list of bindings can be found in `proot --help`. This function excludes diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 8854c43..9f4596f 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -46,6 +46,12 @@ function _run_env_with_namespace(){ local backend_args="$1" shift + check_nested_env + + provide_common_bindings + local bindings=${RESULT} + unset RESULT + # Use option -n in groot because umount do not work sometimes. # As soon as the process terminates, the namespace # will terminate too with its own mounted directories. @@ -59,7 +65,7 @@ function _run_env_with_namespace(){ ####################################### -# Run JuNest as normal user via user namespace. +# Run JuNest as fakeroot user via user namespace. # # Globals: # JUNEST_HOME (RO) : The JuNest home directory. @@ -70,15 +76,18 @@ function _run_env_with_namespace(){ # cmd ($2-?) : The command to run inside JuNest environment. # Default command is defined by SH variable. # Returns: +# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. # Depends on the unshare command outcome. # Output: # - : The command output. ####################################### -function run_env_as_user_with_namespace() { +function run_env_with_namespace() { local backend_args="$1" shift _check_user_namespace + check_same_arch + copy_common_files copy_file /etc/hosts.equiv copy_file /etc/netgroup @@ -87,40 +96,5 @@ function run_env_as_user_with_namespace() { #copy_file /etc/localtime copy_passwd_and_group - provide_common_bindings - local bindings=${RESULT} - unset RESULT - - # TODO make sure to run the environment as normal user - _run_env_with_namespace "$backend_args" "$@" -} - -####################################### -# Run JuNest as fakeroot via user namespace. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# GROOT (RO) : The groot program. -# SH (RO) : Contains the default command to run in JuNest. -# Arguments: -# backend_args ($1) : The arguments to pass to proot -# cmd ($2-?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. -# Returns: -# Depends on the unshare command outcome. -# Output: -# - : The command output. -####################################### -function run_env_as_fakeroot_with_namespace() { - local backend_args="$1" - shift - _check_user_namespace - - copy_common_files - - provide_common_bindings - local bindings=${RESULT} - unset RESULT - _run_env_with_namespace "$backend_args" "$@" } diff --git a/lib/core/proot.sh b/lib/core/proot.sh index edad2c3..f678d9d 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -12,6 +12,7 @@ function _run_env_with_proot(){ local proot_args="$1" shift + check_nested_env if [ "$1" != "" ] then JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" @@ -58,7 +59,7 @@ function _run_env_with_qemu(){ ####################################### function run_env_as_fakeroot(){ (( EUID == 0 )) && \ - die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." + die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead." local backend_args="$1" shift @@ -91,7 +92,7 @@ function run_env_as_fakeroot(){ ####################################### function run_env_as_user(){ (( EUID == 0 )) && \ - die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." + die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead." local backend_args="$1" shift diff --git a/tests/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh index 04b22a7..aa491e5 100755 --- a/tests/unit-tests/test-chroot.sh +++ b/tests/unit-tests/test-chroot.sh @@ -18,6 +18,7 @@ function oneTimeSetUp(){ function setUp(){ cwdSetUp junestSetUp + init_mocks } function tearDown(){ @@ -25,28 +26,42 @@ function tearDown(){ cwdTearDown } -function test_run_env_as_root_different_arch(){ - echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info - assertCommandFailOnStatus 104 run_env_as_root pwd -} - -function _test_run_env_as_root() { +function init_mocks() { chroot_cmd() { [ "$JUNEST_ENV" != "1" ] && return 1 - echo $@ + echo "chroot_cmd $@" } - - assertCommandSuccess run_env_as_root $@ + GROOT=chroot_cmd } -function test_run_env_as_root_cmd(){ - _test_run_env_as_root pwd - assertEquals "$JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" +function test_run_env_as_groot_cmd(){ + assertCommandSuccess run_env_as_groot "" pwd + assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" } -function test_run_env_as_classic_root_no_cmd(){ - _test_run_env_as_root - assertEquals "$JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" +function test_run_env_as_groot_no_cmd(){ + assertCommandSuccess run_env_as_groot "" + assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" +} + +function test_run_env_as_groot_cmd_with_backend_args(){ + assertCommandSuccess run_env_as_groot "-n -b /home/blah" pwd + assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" +} + +function test_run_env_as_chroot_cmd(){ + assertCommandSuccess run_env_as_chroot "" pwd + assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" +} + +function test_run_env_as_chroot_no_cmd(){ + assertCommandSuccess run_env_as_chroot "" + assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" +} + +function test_run_env_as_chroot_cmd_with_backend_args(){ + assertCommandSuccess run_env_as_chroot "-n -b /home/blah" pwd + assertEquals "chroot_cmd -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" } source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index a95c32a..e9286fa 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -20,10 +20,20 @@ function oneTimeTearDown(){ } function setUp(){ - ld_exec() { + ld_exec_mock() { echo "ld_exec $@" } - LD_EXEC=ld_exec + ld_exec_mock_false() { + echo "ld_exec $@" + return 1 + } + LD_EXEC=ld_exec_mock + + unshare_mock() { + echo "unshare $@" + } + UNSHARE=unshare_mock + } function test_ln(){ @@ -117,26 +127,23 @@ function test_zgrep(){ } function test_unshare(){ - UNSHARE=echo assertCommandSuccess unshare_cmd new_program - assertEquals "new_program" "$(cat $STDOUTF)" + assertCommandSuccess unshare_cmd new_program + assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE --user /bin/sh --login -c :\nld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE new_program")" "$(cat $STDOUTF)" - UNSHARE=false assertCommandSuccess unshare_cmd new_program - assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false new_program" "$(cat $STDOUTF)" + LD_EXEC=ld_exec_mock_false assertCommandSuccess unshare_cmd new_program + assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/unshare_mock --user /bin/sh --login -c :\nunshare --user /bin/sh --login -c :\nunshare new_program")" "$(cat $STDOUTF)" UNSHARE=false LD_EXEC=false assertCommandFail unshare_cmd new_program } function test_chroot(){ - GROOT=echo assertCommandSuccess chroot_cmd root + CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root assertEquals "root" "$(cat $STDOUTF)" - GROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root - assertEquals "root" "$(cat $STDOUTF)" - - GROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root + CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root assertEquals "ld_exec $JUNEST_HOME/usr/bin/false root" "$(cat $STDOUTF)" - GROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root + CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root } function test_proot_cmd_compat(){ @@ -187,11 +194,22 @@ function test_copy_passwd_and_group_failure(){ } function test_nested_env(){ - JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -c "source $JUNEST_ROOT/lib/utils/utils.sh; source $JUNEST_ROOT/lib/core/common.sh" + JUNEST_ENV=1 assertCommandFailOnStatus 106 check_nested_env } function test_nested_env_not_set_variable(){ - JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -c "source $JUNEST_ROOT/lib/utils/utils.sh; source $JUNEST_ROOT/lib/core/common.sh" + JUNEST_ENV=aaa assertCommandFailOnStatus 107 check_nested_env } +function test_check_same_arch_not_same(){ + echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info + assertCommandFailOnStatus 104 check_same_arch +} + +function test_check_same_arch(){ + echo "JUNEST_ARCH=$ARCH" > ${JUNEST_HOME}/etc/junest/info + assertCommandSuccess check_same_arch +} + + source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-groot.sh b/tests/unit-tests/test-groot.sh index 472e027..c7b5f36 100755 --- a/tests/unit-tests/test-groot.sh +++ b/tests/unit-tests/test-groot.sh @@ -79,39 +79,39 @@ function test_groot_mountpoint_exist(){ } MOUNTPOINT=mountpoint_mock assertCommandSuccess main chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_mountpoint_does_not_exist(){ assertCommandSuccess main chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind(){ assertCommandSuccess main -b /tmp chrootdir [[ -d chrootdir/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_file(){ touch file_src assertCommandSuccess main -b ${PWD}/file_src:/file_src chrootdir [[ -f chrootdir/file_src ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_not_existing_node(){ assertCommandFailOnStatus $NOT_EXISTING_FILE main -b ${PWD}/file_src:/file_src chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_not_absolute_path_node(){ touch file_src assertCommandFailOnStatus $NOT_ABSOLUTE_PATH main -b file_src:/file_src chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_guest_host(){ assertCommandSuccess main -b /tmp:/home/tmp chrootdir [[ -d chrootdir/home/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_multiple_bind(){ assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir @@ -119,11 +119,11 @@ function test_groot_with_multiple_bind(){ assertEquals 0 $? [[ -d chrootdir/dev ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_command(){ assertCommandSuccess main chrootdir ls -la -h - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" } function test_groot_with_bind_and_command(){ assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir ls -la -h @@ -131,7 +131,7 @@ function test_groot_with_bind_and_command(){ assertEquals 0 $? [[ -d chrootdir/dev ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" } function test_groot_with_bind_no_umount(){ assertCommandSuccess main -n chrootdir diff --git a/tests/unit-tests/test-junest.sh b/tests/unit-tests/test-junest.sh index c9f2d4a..2176cea 100755 --- a/tests/unit-tests/test-junest.sh +++ b/tests/unit-tests/test-junest.sh @@ -26,14 +26,7 @@ function version(){ } function build_image_env(){ local disable_validation=$1 - local skip_root_tests=$2 - echo "build_image_env($disable_validation,$skip_root_tests)" -} -function check_env(){ - local env_home=$1 - local cmd_script=$2 - local skip_root_tests=$3 - echo "check_env($env_home,$cmd_script,$skip_root_tests)" + echo "build_image_env($disable_validation)" } function delete_env(){ echo "delete_env" @@ -49,23 +42,21 @@ function run_env_as_fakeroot(){ shift echo "run_env_as_fakeroot($backend_args,$@)" } -function run_env_as_root(){ - echo "run_env_as_root $@" +function run_env_as_groot(){ + echo "run_env_as_groot $@" +} +function run_env_as_chroot(){ + echo "run_env_as_chroot $@" } function run_env_as_user(){ local backend_args="$1" shift echo "run_env_as_user($backend_args,$@)" } -function run_env_as_fakeroot_with_namespace(){ +function run_env_with_namespace(){ local backend_args="$1" shift - echo "run_env_as_fakeroot_with_namespace($backend_args,$@)" -} -function run_env_as_user_with_namespace(){ - local backend_args="$1" - shift - echo "run_env_as_user_with_namespace($backend_args,$@)" + echo "run_env_with_namespace($backend_args,$@)" } function test_help(){ @@ -82,27 +73,13 @@ function test_version(){ } function test_build_image_env(){ assertCommandSuccess main -b - assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)" + assertEquals "build_image_env(false)" "$(cat $STDOUTF)" assertCommandSuccess main --build-image - assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)" - assertCommandSuccess main -b -s - assertEquals "build_image_env(false,true)" "$(cat $STDOUTF)" + assertEquals "build_image_env(false)" "$(cat $STDOUTF)" assertCommandSuccess main -b -n - assertEquals "build_image_env(true,false)" "$(cat $STDOUTF)" - assertCommandSuccess main -b -n -s - assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)" - assertCommandSuccess main --build-image --disable-validation --skip-root-tests - assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)" -} -function test_check_env(){ - assertCommandSuccess main -c myscript - assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)" - assertCommandSuccess main --check myscript - assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)" - assertCommandSuccess main -c myscript -s - assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)" - assertCommandSuccess main --check myscript --skip-root-tests - assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)" + assertEquals "build_image_env(true)" "$(cat $STDOUTF)" + assertCommandSuccess main --build-image --disable-validation + assertEquals "build_image_env(true)" "$(cat $STDOUTF)" } function test_delete_env(){ assertCommandSuccess main -d @@ -168,36 +145,31 @@ function test_run_env_as_user(){ assertCommandFail main -a "myarch" -- command -ls } -function test_run_env_as_root(){ +function test_run_env_as_groot(){ + assertCommandSuccess main -g + assertEquals "run_env_as_groot " "$(cat $STDOUTF)" + assertCommandSuccess main -g command + assertEquals "run_env_as_groot command" "$(cat $STDOUTF)" +} +function test_run_env_as_chroot(){ assertCommandSuccess main -r - assertEquals "run_env_as_root " "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot " "$(cat $STDOUTF)" assertCommandSuccess main -r command - assertEquals "run_env_as_root command" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot command" "$(cat $STDOUTF)" } -function test_run_env_as_fakeroot_with_namespace(){ +function test_run_env_with_namespace(){ assertCommandSuccess main -u -f - assertEquals "run_env_as_fakeroot_with_namespace(,)" "$(cat $STDOUTF)" - assertCommandSuccess main --user-namespace --fakeroot - assertEquals "run_env_as_fakeroot_with_namespace(,)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)" + assertCommandSuccess main --namespace --fakeroot + assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)" assertCommandSuccess main -u -f -p "-b arg" - assertEquals "run_env_as_fakeroot_with_namespace(-b arg,)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(-b arg,)" "$(cat $STDOUTF)" assertCommandSuccess main -u -f -p "-b arg" -- command -kv - assertEquals "run_env_as_fakeroot_with_namespace(-b arg,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(-b arg,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main -u -f command --as - assertEquals "run_env_as_fakeroot_with_namespace(,command --as)" "$(cat $STDOUTF)" -} -function test_run_env_as_user_with_namespace(){ - assertCommandSuccess main -u - assertEquals "run_env_as_user_with_namespace(,)" "$(cat $STDOUTF)" - - assertCommandSuccess main -u -p "-b arg" - assertEquals "run_env_as_user_with_namespace(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess main -u -p "-b arg" -- command -ll - assertEquals "run_env_as_user_with_namespace(-b arg,command -ll)" "$(cat $STDOUTF)" - assertCommandSuccess main -u command -ls - assertEquals "run_env_as_user_with_namespace(,command -ls)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(,command --as)" "$(cat $STDOUTF)" } function test_check_cli(){ diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index e09db0a..9cc60a7 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -78,64 +78,36 @@ function test_is_user_namespace_enabled_with_config(){ assertCommandSuccess _is_user_namespace_enabled } -function test_run_env_as_user_with_namespace() { - assertCommandSuccess run_env_as_user_with_namespace "" "" +function test_run_env_with_namespace() { + assertCommandSuccess run_env_with_namespace "" "" assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_as_user_with_namespace_with_bindings() { - assertCommandSuccess run_env_as_user_with_namespace "-b /usr -b /lib:/tmp/lib" "" +function test_run_env_with_namespace_with_bindings() { + assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "" assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_as_user_with_namespace_with_command() { - assertCommandSuccess run_env_as_user_with_namespace "" "ls -la" +function test_run_env_with_namespace_with_command() { + assertCommandSuccess run_env_with_namespace "" "ls -la" assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_as_user_with_namespace_with_bindings_and_command() { - assertCommandSuccess run_env_as_user_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la" +function test_run_env_with_namespace_with_bindings_and_command() { + assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la" assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_as_fakeroot_with_namespace() { - assertCommandSuccess run_env_as_fakeroot_with_namespace "" "" - assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" - - _test_copy_common_files -} - -function test_run_env_as_fakeroot_with_namespace_with_bindings() { - assertCommandSuccess run_env_as_fakeroot_with_namespace "-b /usr -b /lib:/tmp/lib" "" - assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" - - _test_copy_common_files -} - -function test_run_env_as_fakeroot_with_namespace_with_command() { - assertCommandSuccess run_env_as_fakeroot_with_namespace "" "ls -la" - assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" - - _test_copy_common_files -} - -function test_run_env_as_fakeroot_with_namespace_with_bindings_and_command() { - assertCommandSuccess run_env_as_fakeroot_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la" - assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" - - _test_copy_common_files -} - source $JUNEST_ROOT/tests/utils/shunit2