docker-mailserver/setup.sh.10.2.0
2021-09-12 08:49:01 -04:00

240 lines
5.3 KiB
Bash
Executable file

#! /bin/bash
# version v1.0.0
# executed manually / via Make
# task wrapper for various setup scripts
SCRIPT='setup.sh'
set -euEo pipefail
trap '__err "${FUNCNAME[0]:-?}" "${BASH_COMMAND:-?}" "${LINENO:-?}" "${?:-?}"' ERR
function __err
{
[[ ${4} -gt 1 ]] && exit 1
local ERR_MSG='--- \e[31m\e[1mUNCHECKED ERROR\e[0m'
ERR_MSG+="\n - script = ${SCRIPT:-${0}}"
ERR_MSG+="\n - function = ${1} / ${2}"
ERR_MSG+="\n - line = ${3}"
ERR_MSG+="\n - exit code = ${4}"
ERR_MSG+='\n'
echo -e "${ERR_MSG}"
}
function _show_local_usage
{
local WHITE="\e[37m"
local ORANGE="\e[38;5;214m"
local LBLUE="\e[94m"
local RESET="\e[0m"
# shellcheck disable=SC2059
printf "${ORANGE}OPTIONS${RESET}
${LBLUE}Config path, container or image adjustments${RESET}
-i IMAGE_NAME
Provides the name of the docker-mailserver image. The default value is
${WHITE}docker.io/mailserver/docker-mailserver:latest${RESET}
-c CONTAINER_NAME
Provides the name of the running container.
-p PATH
Provides the config folder path to the temporary container (does not work if docker-mailserver container already exists).
${LBLUE}SELinux${RESET}
-z
Allows container access to the bind mount content that is shared among
multiple containers on a SELinux-enabled host.
-Z
Allows container access to the bind mount content that is private and
unshared with other containers on a SELinux-enabled host.
${ORANGE}EXIT STATUS${RESET}
Exit status is 0 if the command was successful. If there was an unexpected error, an error
message is shown describing the error. In case of an error, the script will exit with exit
status 1.
"
}
function _get_absolute_script_directory
{
if [[ "$(uname)" == "Darwin" ]]
then
readlink() {
# requires coreutils
greadlink "${@:+$@}"
}
fi
if dirname "$(readlink -f "${0}")" &>/dev/null
then
DIR="$(dirname "$(readlink -f "${0}")")"
elif realpath -e -L "${0}" &>/dev/null
then
DIR="$(realpath -e -L "${0}")"
DIR="${DIR%/setup.sh}"
fi
}
DIR="$(pwd)"
_get_absolute_script_directory
CRI=
CONFIG_PATH=
CONTAINER_NAME=
DEFAULT_CONFIG_PATH="${DIR}/config"
IMAGE_NAME=
INFO=
USE_TTY=
USE_SELINUX=
VOLUME=
WISHED_CONFIG_PATH=
function _check_root
{
if [[ ${EUID} -ne 0 ]]
then
echo "Curently, DMS doesn't support podman's rootless mode.
Please run this script as root user."
exit 1
fi
}
function _update_config_path
{
if [[ -n ${CONTAINER_NAME} ]]
then
VOLUME=$(${CRI} inspect "${CONTAINER_NAME}" \
--format="{{range .Mounts}}{{ println .Source .Destination}}{{end}}" | \
grep "/tmp/docker-mailserver$" 2>/dev/null || :)
fi
if [[ -n ${VOLUME} ]]
then
CONFIG_PATH=$(echo "${VOLUME}" | awk '{print $1}')
fi
}
function _docker_image_exists
{
${CRI} history -q "${1}" &>/dev/null
return ${?}
}
function _docker_image
{
# start temporary container with specified image
if ! _docker_image_exists "${IMAGE_NAME}"
then
echo "Image '${IMAGE_NAME}' not found. Pulling ..."
${CRI} pull "${IMAGE_NAME}"
fi
${CRI} run --rm "${USE_TTY}" \
-v "${CONFIG_PATH}:/tmp/docker-mailserver${USE_SELINUX}" \
"${IMAGE_NAME}" "${@:+$@}"
}
function _docker_container
{
if [[ -n ${CONTAINER_NAME} ]]
then
${CRI} exec "${USE_TTY}" "${CONTAINER_NAME}" "${@:+$@}"
else
# if no container is running, run a temporary one:
# https://github.com/docker-mailserver/docker-mailserver/pull/1874#issuecomment-809781531
_docker_image "${@:+$@}"
fi
}
function _main
{
if command -v docker &>/dev/null
then
CRI=docker
elif command -v podman &>/dev/null
then
CRI=podman
_check_root
else
echo "No supported Container Runtime Interface detected."
exit 1
fi
INFO=$(${CRI} ps --no-trunc --format "{{.Image}};{{.Names}}" --filter \
label=org.opencontainers.image.title="docker-mailserver" | tail -1)
IMAGE_NAME=${INFO%;*}
CONTAINER_NAME=${INFO#*;}
if [[ -z ${IMAGE_NAME} ]]
then
IMAGE_NAME=${NAME:-docker.io/mailserver/docker-mailserver:latest}
fi
if test -t 0
then
USE_TTY="-ti"
else
# GitHub Actions will fail (or really anything else
# lacking an interactive tty) if we don't set a
# value here; "-t" alone works for these cases.
USE_TTY="-t"
fi
local OPTIND
while getopts ":c:i:p:zZ" OPT
do
case ${OPT} in
( i ) IMAGE_NAME="${OPTARG}" ;;
( z | Z ) USE_SELINUX=":${OPTARG}" ;;
( c ) CONTAINER_NAME="${OPTARG}" ;;
( p )
case "${OPTARG}" in
( /* ) WISHED_CONFIG_PATH="${OPTARG}" ;;
( * ) WISHED_CONFIG_PATH="${DIR}/${OPTARG}" ;;
esac
if [[ ! -d ${WISHED_CONFIG_PATH} ]]
then
echo "Specified directory '${WISHED_CONFIG_PATH}' doesn't exist" >&2
exit 1
fi
;;
( * )
echo "Invalid option: -${OPT}" >&2
exit 1
;;
esac
done
shift $(( OPTIND - 1 ))
if [[ -z ${WISHED_CONFIG_PATH} ]]
then
# no wished config path
_update_config_path
if [[ -z ${CONFIG_PATH} ]]
then
CONFIG_PATH=${DEFAULT_CONFIG_PATH}
fi
else
CONFIG_PATH=${WISHED_CONFIG_PATH}
fi
_docker_container setup "${@:+$@}"
[[ ${1} == 'help' ]] && _show_local_usage
return 0
}
_main "${@:+$@}"