#!/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