rootfs-builder: support provisioning existing rootfs

Add the use case of provisioning an existing rootfs directory with the
components / configurations needed to generate a Kata compatible images.
This supports use cases such as using a rootfs built outside of
osbuilder, and providing a overlay for dracut built initrds.

Signed-off-by: Marco Vedovati <mvedovati@suse.com>
This commit is contained in:
Marco Vedovati 2019-06-12 18:54:55 +02:00
parent 7d38b84203
commit 39370c2aea
2 changed files with 273 additions and 204 deletions

View File

@ -1,13 +1,17 @@
* [Supported base OSs](#supported-base-oss) * [Building a Guest OS rootfs for Kata Containers](#building-a-guest-os-rootfs-for-kata-containers)
* [Rootfs requirements](#rootfs-requirements) * [Supported base OSs](#supported-base-oss)
* [Creating a rootfs](#creating-a-rootfs) * [Extra features](#extra-features)
* [Creating a rootfs with kernel modules](#creating-a-rootfs-with-kernel-modules) * [Supported distributions list](#supported-distributions-list)
* [Build a rootfs using Docker](#build-a-rootfs-using-docker) * [Generate Kata specific files](#generate-kata-specific-files)
* [Adding support for a new guest OS](#adding-support-for-a-new-guest-os) * [Rootfs requirements](#rootfs-requirements)
* [Create template files](#create-template-files) * [Creating a rootfs](#creating-a-rootfs)
* [Modify template files](#modify-template-files) * [Creating a rootfs with kernel modules](#creating-a-rootfs-with-kernel-modules)
* [Expected rootfs directory content](#expected-rootfs-directory-content) * [Build a rootfs using Docker](#build-a-rootfs-using-docker)
* [Optional - Customise the rootfs](#optional---customise-the-rootfs) * [Adding support for a new guest OS](#adding-support-for-a-new-guest-os)
* [Create template files](#create-template-files)
* [Modify template files](#modify-template-files)
* [Expected rootfs directory content](#expected-rootfs-directory-content)
* [Optional - Customise the rootfs](#optional---customise-the-rootfs)
* [Adding extra packages](#adding-extra-packages) * [Adding extra packages](#adding-extra-packages)
* [Arbitrary rootfs changes](#arbitrary-rootfs-changes) * [Arbitrary rootfs changes](#arbitrary-rootfs-changes)
@ -21,10 +25,25 @@ The `rootfs.sh` script builds a rootfs based on a particular Linux\*
distribution. The script supports multiple distributions and can be extended distribution. The script supports multiple distributions and can be extended
to add further ones. to add further ones.
To list the supported distributions, run: ### Extra features
#### Supported distributions list
Supported distributions can be listed with:
``` ```
$ ./rootfs.sh -h $ ./rootfs.sh -l
```
#### Generate Kata specific files
`rootfs.sh` can be used to only populate a target directory with the set of Kata
specific files and components integrable into a generic Linux rootfs to generate
a Kata guest OS image.
This feature can be used when creating a rootfs with a distribution not officially
supported by osbuilder.
It is also used when building the rootfs using the 'dracut' build method.
To obtain this, simply invoke `rootfs.sh` without specifying a target rootfs, e.g.:
```
mkdir kata-overlay
./rootfs.sh -r `pwd`/kata-overlay
``` ```
## Rootfs requirements ## Rootfs requirements

View File

@ -52,18 +52,31 @@ typeset -r CONFIG_ARCH_SH="config_${ARCH}.sh"
# build_rootfs() function. # build_rootfs() function.
typeset -r LIB_SH="rootfs_lib.sh" typeset -r LIB_SH="rootfs_lib.sh"
# rootfs distro name specified by the user
typeset distro=
# Absolute path to the rootfs root folder
typeset ROOTFS_DIR
# Absolute path in the rootfs to the "init" executable / symlink.
# Typically something like "${ROOTFS_DIR}/init
typeset init=
#$1: Error code if want to exit different to 0 #$1: Error code if want to exit different to 0
usage() usage()
{ {
error="${1:-0}" error="${1:-0}"
cat <<EOT cat <<EOT
Usage: ${script_name} [options] <distro> Usage: ${script_name} [options] [DISTRO]
Build a rootfs based on <distro> OS, to be included in a Kata Containers Build and setup a rootfs directory based on DISTRO OS, used to create
image. Kata Containers images or initramfs.
Supported <distro> values: When no DISTRO is provided, an existing base rootfs at ROOTFS_DIR is provisioned
with the Kata specific components and configuration.
Supported DISTRO values:
$(get_distros | tr "\n" " ") $(get_distros | tr "\n" " ")
Options: Options:
@ -75,7 +88,7 @@ Options:
yaml description. yaml description.
-r <directory> Specify the rootfs base directory. Overrides the ROOTFS_DIR -r <directory> Specify the rootfs base directory. Overrides the ROOTFS_DIR
environment variable. environment variable.
-t Print the test configuration for <distro> and exit -t DISTRO Print the test configuration for DISTRO and exit
immediately. immediately.
Environment Variables: Environment Variables:
@ -100,7 +113,7 @@ DISTRO_REPO Use host repositories to install guest packages.
GO_AGENT_PKG URL of the Git repository hosting the agent package. GO_AGENT_PKG URL of the Git repository hosting the agent package.
Default value: ${GO_AGENT_PKG} Default value: ${GO_AGENT_PKG}
GRACEFUL_EXIT If set, and if the <distro> configuration specifies a GRACEFUL_EXIT If set, and if the DISTRO configuration specifies a
non-empty BUILD_CAN_FAIL variable, do not return with an non-empty BUILD_CAN_FAIL variable, do not return with an
error code in case any of the build step fails. error code in case any of the build step fails.
This is used when running CI jobs, to tolerate failures for This is used when running CI jobs, to tolerate failures for
@ -112,7 +125,7 @@ KERNEL_MODULES_DIR Path to a directory containing kernel modules to include in
Default value: <empty> Default value: <empty>
ROOTFS_DIR Path to the directory that is populated with the rootfs. ROOTFS_DIR Path to the directory that is populated with the rootfs.
Default value: <${script_name} path>/rootfs-<distro-name> Default value: <${script_name} path>/rootfs-<DISTRO-name>
USE_DOCKER If set, build the rootfs inside a container (requires USE_DOCKER If set, build the rootfs inside a container (requires
Docker). Docker).
@ -137,7 +150,9 @@ get_distros() {
} }
get_test_config() { get_test_config() {
local distro="$1" local -r distro="$1"
[ -z "$distro" ] && die "No distro name specified"
local config="${script_dir}/${distro}/config.sh" local config="${script_dir}/${distro}/config.sh"
source ${config} source ${config}
@ -330,229 +345,264 @@ compare_versions()
true true
} }
while getopts a:hlo:r:t: opt check_env_variables()
do {
case $opt in # Fetch the first element from GOPATH as working directory
a) AGENT_VERSION="${OPTARG}" ;; # as go get only works against the first item in the GOPATH
h) usage ;; [ -z "$GOPATH" ] && die "GOPATH not set"
l) get_distros | sort && exit 0;; GOPATH_LOCAL="${GOPATH%%:*}"
o) OSBUILDER_VERSION="${OPTARG}" ;;
r) ROOTFS_DIR="${OPTARG}" ;;
t) get_test_config "${OPTARG}" && exit 0;;
esac
done
shift $(($OPTIND - 1)) [ "$AGENT_INIT" == "yes" -o "$AGENT_INIT" == "no" ] || die "AGENT_INIT($AGENT_INIT) is invalid (must be yes or no)"
# Fetch the first element from GOPATH as working directory [ -n "${KERNEL_MODULES_DIR}" ] && [ ! -d "${KERNEL_MODULES_DIR}" ] && die "KERNEL_MODULES_DIR defined but is not an existing directory"
# as go get only works against the first item in the GOPATH
[ -z "$GOPATH" ] && die "GOPATH not set"
GOPATH_LOCAL="${GOPATH%%:*}"
[ "$AGENT_INIT" == "yes" -o "$AGENT_INIT" == "no" ] || die "AGENT_INIT($AGENT_INIT) is invalid (must be yes or no)" [ -n "${OSBUILDER_VERSION}" ] || die "need osbuilder version"
}
[ -n "${KERNEL_MODULES_DIR}" ] && [ ! -d "${KERNEL_MODULES_DIR}" ] && die "KERNEL_MODULES_DIR defined but is not an existing directory" # Builds a rootfs based on the distro name provided as argument
build_rootfs_distro()
{
[ -n "${distro}" ] || usage 1
distro_config_dir="${script_dir}/${distro}"
[ -z "${OSBUILDER_VERSION}" ] && die "need osbuilder version" # Source config.sh from distro
rootfs_config="${distro_config_dir}/${CONFIG_SH}"
source "${rootfs_config}"
distro="$1" # Source arch-specific config file
rootfs_arch_config="${distro_config_dir}/${CONFIG_ARCH_SH}"
if [ -f "${rootfs_arch_config}" ]; then
source "${rootfs_arch_config}"
fi
[ -n "${distro}" ] || usage 1 [ -d "${distro_config_dir}" ] || die "Not found configuration directory ${distro_config_dir}"
distro_config_dir="${script_dir}/${distro}"
# Source config.sh from distro if [ -z "$ROOTFS_DIR" ]; then
rootfs_config="${distro_config_dir}/${CONFIG_SH}" ROOTFS_DIR="${script_dir}/rootfs-${OS_NAME}"
source "${rootfs_config}" fi
# Source arch-specific config file if [ -e "${distro_config_dir}/${LIB_SH}" ];then
rootfs_arch_config="${distro_config_dir}/${CONFIG_ARCH_SH}" rootfs_lib="${distro_config_dir}/${LIB_SH}"
if [ -f "${rootfs_arch_config}" ]; then info "rootfs_lib.sh file found. Loading content"
source "${rootfs_arch_config}" source "${rootfs_lib}"
fi fi
[ -d "${distro_config_dir}" ] || die "Not found configuration directory ${distro_config_dir}" CONFIG_DIR=${distro_config_dir}
check_function_exist "build_rootfs"
if [ -z "$ROOTFS_DIR" ]; then if [ -z "$INSIDE_CONTAINER" ] ; then
ROOTFS_DIR="${script_dir}/rootfs-${OS_NAME}" # Capture errors, but only outside of the docker container
fi trap error_handler ERR
fi
init="${ROOTFS_DIR}/sbin/init" mkdir -p ${ROOTFS_DIR}
if [ -e "${distro_config_dir}/${LIB_SH}" ];then detect_go_version ||
rootfs_lib="${distro_config_dir}/${LIB_SH}"
info "rootfs_lib.sh file found. Loading content"
source "${rootfs_lib}"
fi
CONFIG_DIR=${distro_config_dir}
check_function_exist "build_rootfs"
if [ -z "$INSIDE_CONTAINER" ] ; then
# Capture errors, but only outside of the docker container
trap error_handler ERR
fi
mkdir -p ${ROOTFS_DIR}
detect_go_version ||
die "Could not detect the required Go version for AGENT_VERSION='${AGENT_VERSION:-master}'." die "Could not detect the required Go version for AGENT_VERSION='${AGENT_VERSION:-master}'."
echo "Required Go version: $GO_VERSION" echo "Required Go version: $GO_VERSION"
if [ -z "${USE_DOCKER}" ] ; then if [ -z "${USE_DOCKER}" ] ; then
#Generate an error if the local Go version is too old #Generate an error if the local Go version is too old
foundVersion=$(go version | sed -E "s/^.+([0-9]+\.[0-9]+\.[0-9]+).*$/\1/g") foundVersion=$(go version | sed -E "s/^.+([0-9]+\.[0-9]+\.[0-9]+).*$/\1/g")
compare_versions "$GO_VERSION" $foundVersion || \ compare_versions "$GO_VERSION" $foundVersion || \
die "Your Go version $foundVersion is older than the minimum expected Go version $GO_VERSION" die "Your Go version $foundVersion is older than the minimum expected Go version $GO_VERSION"
else
image_name="${distro}-rootfs-osbuilder"
generate_dockerfile "${distro_config_dir}"
docker build \
--build-arg http_proxy="${http_proxy}" \
--build-arg https_proxy="${https_proxy}" \
-t "${image_name}" "${distro_config_dir}"
# fake mapping if KERNEL_MODULES_DIR is unset
kernel_mod_dir=${KERNEL_MODULES_DIR:-${ROOTFS_DIR}}
docker_run_args=""
docker_run_args+=" --rm"
docker_run_args+=" --runtime ${DOCKER_RUNTIME}"
if [ -z "${AGENT_SOURCE_BIN}" ] ; then
docker_run_args+=" --env GO_AGENT_PKG=${GO_AGENT_PKG}"
else else
docker_run_args+=" --env AGENT_SOURCE_BIN=${AGENT_SOURCE_BIN}" image_name="${distro}-rootfs-osbuilder"
docker_run_args+=" -v ${AGENT_SOURCE_BIN}:${AGENT_SOURCE_BIN}"
generate_dockerfile "${distro_config_dir}"
docker build \
--build-arg http_proxy="${http_proxy}" \
--build-arg https_proxy="${https_proxy}" \
-t "${image_name}" "${distro_config_dir}"
# fake mapping if KERNEL_MODULES_DIR is unset
kernel_mod_dir=${KERNEL_MODULES_DIR:-${ROOTFS_DIR}}
docker_run_args=""
docker_run_args+=" --rm"
docker_run_args+=" --runtime ${DOCKER_RUNTIME}"
if [ -z "${AGENT_SOURCE_BIN}" ] ; then
docker_run_args+=" --env GO_AGENT_PKG=${GO_AGENT_PKG}"
else
docker_run_args+=" --env AGENT_SOURCE_BIN=${AGENT_SOURCE_BIN}"
docker_run_args+=" -v ${AGENT_SOURCE_BIN}:${AGENT_SOURCE_BIN}"
fi
docker_run_args+=" $(docker_extra_args $distro)"
# Relabel volumes so SELinux allows access (see docker-run(1))
if command -v selinuxenabled > /dev/null && selinuxenabled ; then
for volume_dir in "${script_dir}" \
"${ROOTFS_DIR}" \
"${script_dir}/../scripts" \
"${kernel_mod_dir}" \
"${GOPATH_LOCAL}"; do
chcon -Rt svirt_sandbox_file_t "$volume_dir"
done
fi
#Make sure we use a compatible runtime to build rootfs
# In case Clear Containers Runtime is installed we dont want to hit issue:
#https://github.com/clearcontainers/runtime/issues/828
docker run \
--env https_proxy="${https_proxy}" \
--env http_proxy="${http_proxy}" \
--env AGENT_VERSION="${AGENT_VERSION}" \
--env ROOTFS_DIR="/rootfs" \
--env AGENT_BIN="${AGENT_BIN}" \
--env AGENT_INIT="${AGENT_INIT}" \
--env GOPATH="${GOPATH_LOCAL}" \
--env KERNEL_MODULES_DIR="${KERNEL_MODULES_DIR}" \
--env EXTRA_PKGS="${EXTRA_PKGS}" \
--env OSBUILDER_VERSION="${OSBUILDER_VERSION}" \
--env INSIDE_CONTAINER=1 \
--env SECCOMP="${SECCOMP}" \
--env DEBUG="${DEBUG}" \
-v "${script_dir}":"/osbuilder" \
-v "${ROOTFS_DIR}":"/rootfs" \
-v "${script_dir}/../scripts":"/scripts" \
-v "${kernel_mod_dir}":"${kernel_mod_dir}" \
-v "${GOPATH_LOCAL}":"${GOPATH_LOCAL}" \
$docker_run_args \
${image_name} \
bash /osbuilder/rootfs.sh "${distro}"
exit $?
fi fi
docker_run_args+=" $(docker_extra_args $distro)" build_rootfs ${ROOTFS_DIR}
}
# Relabel volumes so SELinux allows access (see docker-run(1)) # Used to create a minimal directory tree where the agent can be instaleld.
if command -v selinuxenabled > /dev/null && selinuxenabled ; then # This is used when a distro is not specified.
for volume_dir in "${script_dir}" \ prepare_overlay()
"${ROOTFS_DIR}" \ {
"${script_dir}/../scripts" \ pushd "${ROOTFS_DIR}" >> /dev/null
"${kernel_mod_dir}" \ mkdir -p ./etc ./lib/systemd ./sbin ./var
"${GOPATH_LOCAL}"; do ln -sf ./usr/lib/systemd/systemd ./init
chcon -Rt svirt_sandbox_file_t "$volume_dir" ln -sf ../../init ./lib/systemd/systemd
done ln -sf ../init ./sbin/init
popd >> /dev/null
}
# Setup an existing rootfs directory, based on the OPTIONAL distro name
# provided as argument
setup_rootfs()
{
[ -z "$distro" ] && prepare_overlay
info "Create symlink to /tmp in /var to create private temporal directories with systemd"
pushd "${ROOTFS_DIR}" >> /dev/null
if [ "$PWD" != "/" ] ; then
rm -rf ./var/cache/ ./var/lib ./var/log ./var/tmp
fi
ln -s ../tmp ./var/
# For some distros tmp.mount may not be installed by default in systemd paths
if ! [ -f "./etc/systemd/system/tmp.mount" ] && \
! [ -f "./usr/lib/systemd/system/tmp.mount" ] &&
[ "$AGENT_INIT" != "yes" ]; then
info "Install tmp.mount in ./etc/systemd/system"
cp ./usr/share/systemd/tmp.mount ./etc/systemd/system/tmp.mount
fi fi
#Make sure we use a compatible runtime to build rootfs popd >> /dev/null
# In case Clear Containers Runtime is installed we dont want to hit issue:
#https://github.com/clearcontainers/runtime/issues/828
docker run \
--env https_proxy="${https_proxy}" \
--env http_proxy="${http_proxy}" \
--env AGENT_VERSION="${AGENT_VERSION}" \
--env ROOTFS_DIR="/rootfs" \
--env AGENT_BIN="${AGENT_BIN}" \
--env AGENT_INIT="${AGENT_INIT}" \
--env GOPATH="${GOPATH_LOCAL}" \
--env KERNEL_MODULES_DIR="${KERNEL_MODULES_DIR}" \
--env EXTRA_PKGS="${EXTRA_PKGS}" \
--env OSBUILDER_VERSION="${OSBUILDER_VERSION}" \
--env INSIDE_CONTAINER=1 \
--env SECCOMP="${SECCOMP}" \
--env DEBUG="${DEBUG}" \
-v "${script_dir}":"/osbuilder" \
-v "${ROOTFS_DIR}":"/rootfs" \
-v "${script_dir}/../scripts":"/scripts" \
-v "${kernel_mod_dir}":"${kernel_mod_dir}" \
-v "${GOPATH_LOCAL}":"${GOPATH_LOCAL}" \
$docker_run_args \
${image_name} \
bash /osbuilder/rootfs.sh "${distro}"
exit $? [ -n "${KERNEL_MODULES_DIR}" ] && copy_kernel_modules ${KERNEL_MODULES_DIR} ${ROOTFS_DIR}
fi
build_rootfs ${ROOTFS_DIR} chrony_conf_file="${ROOTFS_DIR}/etc/chrony.conf"
pushd "${ROOTFS_DIR}" >> /dev/null if [ "${distro}" == "ubuntu" ] || [ "${distro}" == "debian" ] ; then
if [ "$PWD" != "/" ] ; then chrony_conf_file="${ROOTFS_DIR}/etc/chrony/chrony.conf"
rm -rf ./var/cache/ ./var/lib ./var/log fi
fi
info "Create symlink to /tmp in /var to create private temporal directories with systemd" info "Create ${ROOTFS_DIR}/etc"
rm -rf ./var/tmp mkdir -p "${ROOTFS_DIR}/etc"
ln -s ../tmp ./var/
# For some distros tmp.mount may not be installed by default in systemd paths info "Configure chrony file ${chrony_conf_file}"
if ! [ -f "./etc/systemd/system/tmp.mount" ] && \ cat >> "${chrony_conf_file}" <<EOT
! [ -f "./usr/lib/systemd/system/tmp.mount" ] &&
[ "$AGENT_INIT" != "yes" ]; then
info "Install tmp.mount in ./etc/systemd/system"
cp ./usr/share/systemd/tmp.mount ./etc/systemd/system/tmp.mount
fi
popd >> /dev/null
[ -n "${KERNEL_MODULES_DIR}" ] && copy_kernel_modules ${KERNEL_MODULES_DIR} ${ROOTFS_DIR}
chrony_conf_file="${ROOTFS_DIR}/etc/chrony.conf"
if [ ${distro} == ubuntu ] || [ ${distro} == debian ] ; then
chrony_conf_file="${ROOTFS_DIR}/etc/chrony/chrony.conf"
fi
info "Create ${ROOTFS_DIR}/etc"
mkdir -p "${ROOTFS_DIR}/etc"
info "Configure chrony file ${chrony_conf_file}"
cat >> "${chrony_conf_file}" <<EOT
refclock PHC /dev/ptp0 poll 3 dpoll -2 offset 0 refclock PHC /dev/ptp0 poll 3 dpoll -2 offset 0
# Step the system clock instead of slewing it if the adjustment is larger than # Step the system clock instead of slewing it if the adjustment is larger than
# one second, at any time # one second, at any time
makestep 1 -1 makestep 1 -1
EOT EOT
# Comment out ntp sources for chrony to be extra careful # Comment out ntp sources for chrony to be extra careful
# Reference: https://chrony.tuxfamily.org/doc/3.4/chrony.conf.html # Reference: https://chrony.tuxfamily.org/doc/3.4/chrony.conf.html
sed -i 's/^\(server \|pool \|peer \)/# &/g' ${chrony_conf_file} sed -i 's/^\(server \|pool \|peer \)/# &/g' ${chrony_conf_file}
chrony_systemd_service="${ROOTFS_DIR}/usr/lib/systemd/system/chronyd.service" # The CC on s390x for fedora needs to be manually set to gcc when the golang is downloaded from the main page.
if [ ${distro} == ubuntu ] || [ ${distro} == debian ] ; then # See issue: https://github.com/kata-containers/osbuilder/issues/217
chrony_systemd_service="${ROOTFS_DIR}/lib/systemd/system/chrony.service" [ "$distro" == "fedora" ] && [ "$ARCH" == "s390x" ] && export CC=gcc
fi
if [ -f "$chrony_systemd_service" ]; then AGENT_DIR="${ROOTFS_DIR}/usr/bin"
sed -i '/^\[Unit\]/a ConditionPathExists=\/dev\/ptp0' ${chrony_systemd_service} AGENT_DEST="${AGENT_DIR}/${AGENT_BIN}"
fi
# The CC on s390x for fedora needs to be manually set to gcc when the golang is downloaded from the main page. if [ -z "${AGENT_SOURCE_BIN}" ] ; then
# See issue: https://github.com/kata-containers/osbuilder/issues/217 info "Pull Agent source code"
[ "$distro" == fedora ] && [ "$ARCH" == "s390x" ] && export CC=gcc go get -d "${GO_AGENT_PKG}" || true
OK "Pull Agent source code"
AGENT_DIR="${ROOTFS_DIR}/usr/bin" info "Build agent"
AGENT_DEST="${AGENT_DIR}/${AGENT_BIN}" pushd "${GOPATH_LOCAL}/src/${GO_AGENT_PKG}"
[ -n "${AGENT_VERSION}" ] && git checkout "${AGENT_VERSION}" && OK "git checkout successful"
make clean
make INIT=${AGENT_INIT}
make install DESTDIR="${ROOTFS_DIR}" INIT=${AGENT_INIT} SECCOMP=${SECCOMP}
popd
else
cp ${AGENT_SOURCE_BIN} ${AGENT_DEST}
OK "cp ${AGENT_SOURCE_BIN} ${AGENT_DEST}"
fi
if [ -z "${AGENT_SOURCE_BIN}" ] ; then [ -x "${AGENT_DEST}" ] || die "${AGENT_DEST} is not installed in ${ROOTFS_DIR}"
info "Pull Agent source code" OK "Agent installed"
go get -d "${GO_AGENT_PKG}" || true
OK "Pull Agent source code"
info "Build agent" [ "${AGENT_INIT}" == "yes" ] && setup_agent_init "${AGENT_DEST}" "${init}"
pushd "${GOPATH_LOCAL}/src/${GO_AGENT_PKG}"
[ -n "${AGENT_VERSION}" ] && git checkout "${AGENT_VERSION}" && OK "git checkout successful"
make clean
make INIT=${AGENT_INIT}
make install DESTDIR="${ROOTFS_DIR}" INIT=${AGENT_INIT} SECCOMP=${SECCOMP}
popd
else
cp ${AGENT_SOURCE_BIN} ${AGENT_DEST}
OK "cp ${AGENT_SOURCE_BIN} ${AGENT_DEST}"
fi
[ -x "${AGENT_DEST}" ] || die "${AGENT_DEST} is not installed in ${ROOTFS_DIR}" info "Check init is installed"
OK "Agent installed" [ -x "${init}" ] || [ -L "${init}" ] || die "/sbin/init is not installed in ${ROOTFS_DIR}"
OK "init is installed"
[ "${AGENT_INIT}" == "yes" ] && setup_agent_init "${AGENT_DEST}" "${init}" info "Creating summary file"
create_summary_file "${ROOTFS_DIR}"
}
info "Check init is installed" parse_arguments()
[ -x "${init}" ] || [ -L "${init}" ] || die "/sbin/init is not installed in ${ROOTFS_DIR}" {
OK "init is installed" while getopts a:hlo:r:t: opt
do
case $opt in
a) AGENT_VERSION="${OPTARG}" ;;
h) usage ;;
l) get_distros | sort && exit 0;;
o) OSBUILDER_VERSION="${OPTARG}" ;;
r) ROOTFS_DIR="${OPTARG}" ;;
t) get_test_config "${OPTARG}" && exit -1;;
*) die "Found an invalid option";;
esac
done
info "Creating summary file" shift $(($OPTIND - 1))
create_summary_file "${ROOTFS_DIR}" distro="$1"
}
main()
{
parse_arguments $*
check_env_variables
init="${ROOTFS_DIR}/sbin/init"
if [ -n "$distro" ]; then
build_rootfs_distro
else
#Make sure ROOTFS_DIR is set correctly
[ -d "${ROOTFS_DIR}" ] || die "Invalid rootfs directory: '$ROOTFS_DIR'"
fi
setup_rootfs
}
main $*