docker-images/imagebuilder.sh

262 lines
9.6 KiB
Bash
Executable File

#!/usr/bin/env bash
if [[ ! -f "/.dockerenv" ]]; then
repo_root="$(git rev-parse --show-toplevel)";
else
repo_root="/srv";
fi
lantern_path="${repo_root}/lantern-build-engine";
IMAGEBUILDER_REGISTRY="${IMAGEBUILDER_REGISTRY:-registry.service.mooncarrot.space:5000}";
export IMAGEBUILDER_REGISTRY;
###############################################################################
#shellcheck disable=SC1090
source "${lantern_path}/lantern.sh";
if [[ -z "${BASE_PATH}" ]]; then
subtask_begin "BASE_PATH environment variable not found - setting base path to ${HC}${repo_root}/images${RS}";
BASE_PATH="${repo_root}/images";
subtask_end "$?";
fi
if [[ ! -d "${BASE_PATH}" ]]; then
echo "Error: The specified base path '${BASE_PATH}' doesn't exist.";
exit 1;
fi
# Make sure the current directory is the location of this script to simplify matters
cd "$(dirname "$(readlink -f "$0")")" || { echo "Error: Failed to cd"; exit 1; };
# Check out the lantern git submodule if needed
if [ ! -f "${lantern_path}/lantern.sh" ]; then git submodule update --init "${lantern_path}"; fi
# Create temporary directory
temp_dir="$(mktemp --tmpdir -d "imagebuilder-XXXXXXX")";
on_exit() {
task_begin "Cleaning up temporary directory";
rm -rf "${temp_dir}";
task_end "$?";
}
trap on_exit EXIT;
###############################################################################
subcommand="${1}";
shift;
if [[ -z "${subcommand}" ]]; then
CHEADING="${HC}${FCYN}";
CACTION="${FYEL}";#
CARG="${FMAG}"
echo -e "${HC}imagebuilder: Docker image (re)builder${RS}" >&2;
echo -e " By Starbeamrainbowlabs" >&2;
echo -e "" >&2;
echo -e "${CHEADING}Usage:${RS}" >&2;
echo -e " ${HC}${FGRN}./imagebuilder.sh${RS} ${CACTION}{action}${RS} ${LC}[${RS}${CARG}{arguments}${RS}${LC}]${RS}" >&2;
echo -e "" >&2;
echo -e "${CHEADING}Actions:${RS}" >&2;
echo -e " ${CACTION}build${RS} ${CARG}{imagename}${RS} [${CARG}{imagetag}${RS}]" >&2;
echo -e " Build the given image and upload it to the docker registry, optionally assigning a custom tag name" >&2;
echo -e " ${CACTION}list${RS}" >&2;
echo -e " List available images" >&2;
echo -e "" >&2;
echo -e "${CHEADING}Environment Variables:${RS}" >&2;
echo -e " ${CACTION}IMAGEBUILDER_REGISTRY${RS}" >&2;
echo -e " Set the url of the Docker registry (default: ${HC}registry.service.mooncarrot.space:5000${RS})" >&2;
echo -e " ${CACTION}BASE_PATH${RS}" >&2;
echo -e " Base path in which to look for image directories (defaults to the current working directory)" >&2;
echo -e "" >&2;
exit 0;
fi
###############################################################################
case "${subcommand}" in
# ██ ██ ███████ ████████
# ██ ██ ██ ██
# ██ ██ ███████ ██
# ██ ██ ██ ██
# ███████ ██ ███████ ██
list)
while read -r filepath; do
filepath_stripped="${filepath#"${BASE_PATH}"}";
if [[ -z "${filepath_stripped}" ]] || [[ ! -f "${filepath}/type.txt" ]]; then
continue;
fi
echo "${filepath_stripped}";
done < <(find "${BASE_PATH}" -maxdepth 1 -type d);
;;
# ██████ ██ ██ ██ ██ ██████
# ██ ██ ██ ██ ██ ██ ██ ██
# ██████ ██ ██ ██ ██ ██ ██
# ██ ██ ██ ██ ██ ██ ██ ██
# ██████ ██████ ██ ███████ ██████
build)
imagename="${1}";
imagetag="${2}";
if [[ -z "${imagename}" ]]; then
echo "Error: No image name specified.":
exit 1;
fi
imagedir="${BASE_PATH}/${imagename}";
if [[ ! -d "${imagedir}" ]]; then
echo -e "Error: An image with the name ${HC}${imagename}${RS} doesn't exist.";
exit 2;
fi
if [[ ! -f "${imagedir}/type.txt" ]]; then
echo -e "Error: No type.txt file was found for the image with the name ${HC}${imagename}${RS}.";
exit 3;
fi
# Determine the fully qualified tag that we're going to push to
docker_tag="${IMAGEBUILDER_REGISTRY}/${imagename}";
if [[ ! -z "${imagetag}" ]]; then
docker_tag="${docker_tag}:${imagetag}";
fi
echo -e "[${HOSTNAME}:imagebuilder] Fully qualified tag name: ${HC}${FGRN}${docker_tag}${RS}";
imagetype="$(tr -d "[:blank:]" <"${imagedir}/type.txt")";
case "${imagetype}" in
# ██████ ██████ ██████ ██ ██ ███████ ██████
# ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
# ██ ██ ██ ██ ██ █████ █████ ██████
# ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
# ██████ ██████ ██████ ██ ██ ███████ ██ ██
docker)
if [[ ! -f "${imagedir}/Dockerfile" ]]; then
echo -e "Error: Failed to find a Dockerfile at ${HC}${imagedir}/Dockerfile${RS}.";
exit 7;
fi
cd "${imagedir}" || { echo -e "Error: Failed to cd into ${HC}${imagedir}${RS}"; exit 1; };
if [[ -x "./pre.sh" ]]; then
task_begin "Executing pre-build hook";
execute ./pre.sh;
task_end "$?";
fi
task_begin "Building docker image";
echo "Tag: ${docker_tag}";
execute docker build --no-cache --pull --tag "${docker_tag}" --build-arg "REPO_LOCATION=${IMAGEBUILDER_REGISTRY}/" .;
task_end "$?";
task_begin "Pushing resulting docker image";
execute docker push "${docker_tag}";
task_end "$?";
if [[ -x "./post.sh" ]]; then
task_begin "Executing post-build hook";
execute ./post.sh;
task_end "$?";
fi
;;
# ██████ █████ ███████ ███████
# ██ ██ ██ ██ ██ ██
# ██████ ███████ ███████ █████
# ██ ██ ██ ██ ██ ██
# ██████ ██ ██ ███████ ███████
base|base-nopush)
builderscript="${imagedir}/${imagename}.sh";
if [[ ! -x "${builderscript}" ]]; then
echo -e "Error: Failed to find the base image builder script at ${HC}${builderscript}${RS} (is it executable?).";
exit 5;
fi
output_dir="${temp_dir}/${imagename}";
mkdir -p "${output_dir}";
task_begin "Building base image";
if [[ "${UID}" -ne 0 ]] && which fakeroot && which fakechroot; then
echo "Non-root user detected - using fakeroot & fakechroot";
execute fakechroot fakeroot "${builderscript}" "${output_dir}";
else
echo "root user or fakeroot & fakechroot not detected";
execute "${builderscript}" "${output_dir}";
fi
task_end "$?";
if [[ "${imagetype}" == "base-nopush" ]]; then
echo -e "${HC}Nopush mode invoked, not checking output directory or pushing to docker registry${RS}";
exit 0;
fi
if [[ ! -d "${output_dir}" ]]; then
echo -e "${FRED}${HC}Error: The builder script failed to create the output directory (expecting directory at ${FBLE}${output_dir}${FRED}, but found nothing).${RS}";
exit 6;
fi
task_begin "Importing resulting image into Docker";
image_filepath="$(find "${output_dir}" -iname "*.tar.gz" -printf '%p' -quit)";
docker_tag_local="$(docker import - <"${image_filepath}")";
task_end "$?";
task_begin "Tagging and pushing to registry";
execute docker tag "${docker_tag_local}" "${docker_tag}";
execute docker push "${docker_tag}";
task_end "$?";
;;
import)
task_begin "Finding remote image name";
if [[ ! -r "${imagedir}/imagename.txt" ]]; then
echo "Error: 'import' image type specified, but no imagename.txt file was found containing the (fully qualified) image name to pull from.";
exit 8;
fi
imagename_remote="$(tr -d "[:blank:]" <"${imagedir}/imagename.txt")"
if [[ -z "${imagename_remote}" ]]; then
echo "Error: An empty image name to pull isn't valid.";
exit 7;
fi
echo -e "[${HOSTNAME}:imagebuilder] Remote image name is ${FGRN}${HC}${imagename_remote}${RS}";
task_end "$?";
task_begin "Downloading image";
execute docker pull "${imagename_remote}";
task_end "$?" "Error: Failed to download image";
task_begin "Retagging image";
execute docker tag "${imagename_remote}" "${docker_tag}";
task_end "$?";
task_begin "Pushing image";
execute docker push "${docker_tag}";
task_end "$?";
;;
# ██ ██ ███ ██ ██ ██ ███ ██ ██████ ██ ██ ███ ██
# ██ ██ ████ ██ ██ ██ ████ ██ ██ ██ ██ ██ ████ ██
# ██ ██ ██ ██ ██ █████ ██ ██ ██ ██ ██ ██ █ ██ ██ ██ ██
# ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██
# ██████ ██ ████ ██ ██ ██ ████ ██████ ███ ███ ██ ████
*)
echo -e "Error: The image type ${HC}${imagetype}${RS} was not recognised. Currently recognised types: base, base-nopush, docker";
exit 4;
;;
esac
;;
*)
echo -e "Unknown subcommand '${HC}${subcommand}${RS}' (try calling imagebuilder.sh without any arguments)";
;;
esac