Archived
feat: unify Docker entrypoint
This commit is contained in:
@@ -0,0 +1,365 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
|
||||
pi_web_docker_host_yaml_quote() {
|
||||
value=$1
|
||||
escaped=$(printf '%s' "$value" | sed "s/'/''/g")
|
||||
printf "'%s'" "$escaped"
|
||||
}
|
||||
|
||||
pi_web_docker_host_socket_path_from_endpoint() {
|
||||
endpoint=$1
|
||||
case "$endpoint" in
|
||||
unix://*) printf '%s\n' "${endpoint#unix://}" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
pi_web_docker_host_mac_desktop_socket_path() {
|
||||
[ -n "${HOME:-}" ] || return 1
|
||||
printf '%s/.docker/run/docker.sock\n' "$HOME"
|
||||
}
|
||||
|
||||
pi_web_docker_host_endpoint_is_linux_expected() {
|
||||
endpoint=$1
|
||||
[ "$endpoint" = unix:///var/run/docker.sock ]
|
||||
}
|
||||
|
||||
pi_web_docker_host_endpoint_is_mac_expected() {
|
||||
endpoint=$1
|
||||
if ! socket_path=$(pi_web_docker_host_socket_path_from_endpoint "$endpoint" 2>/dev/null); then
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "$socket_path" in
|
||||
/var/run/docker.sock)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
if mac_socket_path=$(pi_web_docker_host_mac_desktop_socket_path 2>/dev/null); then
|
||||
[ "$socket_path" = "$mac_socket_path" ] && return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
pi_web_docker_host_socket_source_for_endpoint() {
|
||||
endpoint=$1
|
||||
pi_web_docker_host_socket_path_from_endpoint "$endpoint"
|
||||
}
|
||||
|
||||
pi_web_docker_host_detect_docker_gid() {
|
||||
case "${PI_WEB_DETECTED_DOCKER_HOST_PROFILE:-}" in
|
||||
mac-docker-desktop)
|
||||
printf '0\n'
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
socket_path=/var/run/docker.sock
|
||||
if [ -n "${PI_WEB_DETECTED_DOCKER_ENDPOINT:-}" ]; then
|
||||
if detected_socket_path=$(pi_web_docker_host_socket_path_from_endpoint "$PI_WEB_DETECTED_DOCKER_ENDPOINT" 2>/dev/null); then
|
||||
socket_path=$detected_socket_path
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -S "$socket_path" ]; then
|
||||
if gid=$(stat -c '%g' "$socket_path" 2>/dev/null); then
|
||||
printf '%s\n' "$gid"
|
||||
return 0
|
||||
fi
|
||||
if gid=$(stat -f '%g' "$socket_path" 2>/dev/null); then
|
||||
printf '%s\n' "$gid"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -S /var/run/docker.sock ]; then
|
||||
if gid=$(stat -c '%g' /var/run/docker.sock 2>/dev/null); then
|
||||
printf '%s\n' "$gid"
|
||||
return 0
|
||||
fi
|
||||
if gid=$(stat -f '%g' /var/run/docker.sock 2>/dev/null); then
|
||||
printf '%s\n' "$gid"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if command -v getent >/dev/null 2>&1; then
|
||||
if gid=$(getent group docker | awk -F: 'NR == 1 { print $3 }'); then
|
||||
if [ -n "$gid" ]; then
|
||||
printf '%s\n' "$gid"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
printf '0\n'
|
||||
}
|
||||
|
||||
pi_web_docker_host_detect_profile() {
|
||||
PI_WEB_DETECTED_HOST_OS=$(uname -s 2>/dev/null || printf 'unknown')
|
||||
PI_WEB_DETECTED_DOCKER_CONTEXT=
|
||||
PI_WEB_DETECTED_DOCKER_ENDPOINT=
|
||||
PI_WEB_DETECTED_DOCKER_HOST_ENV=${DOCKER_HOST:-}
|
||||
PI_WEB_DETECTED_DOCKER_EFFECTIVE_ENDPOINT=
|
||||
PI_WEB_DETECTED_DOCKER_SOCKET_SOURCE=
|
||||
PI_WEB_DETECTED_DOCKER_OS=
|
||||
PI_WEB_DETECTED_DOCKER_HOST_PROFILE=
|
||||
PI_WEB_DETECTED_HOSTEXEC_MODE=disabled
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR=
|
||||
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR="docker CLI is required"
|
||||
return 1
|
||||
fi
|
||||
|
||||
PI_WEB_DETECTED_DOCKER_CONTEXT=$(docker context show 2>/dev/null || printf 'unknown')
|
||||
if [ -n "$PI_WEB_DETECTED_DOCKER_CONTEXT" ] && [ "$PI_WEB_DETECTED_DOCKER_CONTEXT" != unknown ]; then
|
||||
PI_WEB_DETECTED_DOCKER_ENDPOINT=$(docker context inspect "$PI_WEB_DETECTED_DOCKER_CONTEXT" --format '{{if .Endpoints.docker}}{{.Endpoints.docker.Host}}{{end}}' 2>/dev/null || printf '')
|
||||
fi
|
||||
|
||||
case "$PI_WEB_DETECTED_HOST_OS" in
|
||||
Linux)
|
||||
if [ -n "$PI_WEB_DETECTED_DOCKER_HOST_ENV" ] && ! pi_web_docker_host_endpoint_is_linux_expected "$PI_WEB_DETECTED_DOCKER_HOST_ENV"; then
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR="native Linux installs require DOCKER_HOST to be unset or exactly unix:///var/run/docker.sock, not $PI_WEB_DETECTED_DOCKER_HOST_ENV"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -n "$PI_WEB_DETECTED_DOCKER_ENDPOINT" ] && ! pi_web_docker_host_endpoint_is_linux_expected "$PI_WEB_DETECTED_DOCKER_ENDPOINT"; then
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR="native Linux installs require the local /var/run/docker.sock Docker context, not $PI_WEB_DETECTED_DOCKER_ENDPOINT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
PI_WEB_DETECTED_DOCKER_EFFECTIVE_ENDPOINT=${PI_WEB_DETECTED_DOCKER_HOST_ENV:-$PI_WEB_DETECTED_DOCKER_ENDPOINT}
|
||||
PI_WEB_DETECTED_DOCKER_SOCKET_SOURCE=/var/run/docker.sock
|
||||
if [ ! -S "$PI_WEB_DETECTED_DOCKER_SOCKET_SOURCE" ]; then
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR="native Linux installs require a local Docker socket at /var/run/docker.sock"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
Darwin)
|
||||
if [ -n "$PI_WEB_DETECTED_DOCKER_ENDPOINT" ] && ! pi_web_docker_host_endpoint_is_mac_expected "$PI_WEB_DETECTED_DOCKER_ENDPOINT"; then
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR="macOS installs require a Docker Desktop local Unix socket context, not $PI_WEB_DETECTED_DOCKER_ENDPOINT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -n "$PI_WEB_DETECTED_DOCKER_HOST_ENV" ]; then
|
||||
if ! pi_web_docker_host_endpoint_is_mac_expected "$PI_WEB_DETECTED_DOCKER_HOST_ENV"; then
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR="macOS installs require DOCKER_HOST to be unset or a Docker Desktop local Unix socket, not $PI_WEB_DETECTED_DOCKER_HOST_ENV"
|
||||
return 1
|
||||
fi
|
||||
PI_WEB_DETECTED_DOCKER_EFFECTIVE_ENDPOINT=$PI_WEB_DETECTED_DOCKER_HOST_ENV
|
||||
else
|
||||
PI_WEB_DETECTED_DOCKER_EFFECTIVE_ENDPOINT=$PI_WEB_DETECTED_DOCKER_ENDPOINT
|
||||
fi
|
||||
|
||||
if [ -n "$PI_WEB_DETECTED_DOCKER_EFFECTIVE_ENDPOINT" ]; then
|
||||
if ! pi_web_docker_host_endpoint_is_mac_expected "$PI_WEB_DETECTED_DOCKER_EFFECTIVE_ENDPOINT"; then
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR="macOS installs require a Docker Desktop local Unix socket, not ${PI_WEB_DETECTED_DOCKER_EFFECTIVE_ENDPOINT:-unknown}"
|
||||
return 1
|
||||
fi
|
||||
PI_WEB_DETECTED_DOCKER_SOCKET_SOURCE=$(pi_web_docker_host_socket_source_for_endpoint "$PI_WEB_DETECTED_DOCKER_EFFECTIVE_ENDPOINT") || return 1
|
||||
elif mac_socket_path=$(pi_web_docker_host_mac_desktop_socket_path 2>/dev/null) && [ -S "$mac_socket_path" ]; then
|
||||
PI_WEB_DETECTED_DOCKER_SOCKET_SOURCE=$mac_socket_path
|
||||
else
|
||||
PI_WEB_DETECTED_DOCKER_SOCKET_SOURCE=/var/run/docker.sock
|
||||
fi
|
||||
|
||||
if [ ! -S "$PI_WEB_DETECTED_DOCKER_SOCKET_SOURCE" ]; then
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR="Docker Desktop socket is not accessible at $PI_WEB_DETECTED_DOCKER_SOCKET_SOURCE"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR="unsupported host OS: $PI_WEB_DETECTED_HOST_OS"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR="docker daemon is not reachable by this user"
|
||||
return 1
|
||||
fi
|
||||
PI_WEB_DETECTED_DOCKER_OS=$(docker info --format '{{.OperatingSystem}}' 2>/dev/null || printf '')
|
||||
|
||||
case "$PI_WEB_DETECTED_HOST_OS" in
|
||||
Linux)
|
||||
case "$PI_WEB_DETECTED_DOCKER_CONTEXT:$PI_WEB_DETECTED_DOCKER_OS" in
|
||||
*desktop-linux*|*"Docker Desktop"*)
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR="Docker Desktop on Linux is not supported by this installer because it runs containers inside a VM instead of the native Linux host"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
PI_WEB_DETECTED_DOCKER_HOST_PROFILE=linux-native-docker
|
||||
PI_WEB_DETECTED_HOSTEXEC_MODE=nsenter
|
||||
;;
|
||||
Darwin)
|
||||
case "$PI_WEB_DETECTED_DOCKER_CONTEXT:$PI_WEB_DETECTED_DOCKER_OS:$PI_WEB_DETECTED_DOCKER_EFFECTIVE_ENDPOINT" in
|
||||
*desktop-linux*|*"Docker Desktop"*|*"/.docker/run/docker.sock"*)
|
||||
PI_WEB_DETECTED_DOCKER_HOST_PROFILE=mac-docker-desktop
|
||||
PI_WEB_DETECTED_HOSTEXEC_MODE=disabled
|
||||
;;
|
||||
*)
|
||||
PI_WEB_DOCKER_HOST_PROFILE_ERROR="macOS installs currently require Docker Desktop; detected context '$PI_WEB_DETECTED_DOCKER_CONTEXT' endpoint '${PI_WEB_DETECTED_DOCKER_EFFECTIVE_ENDPOINT:-unknown}'"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
pi_web_docker_host_write_volume() {
|
||||
source_path=$1
|
||||
target_path=$2
|
||||
read_only=${3:-false}
|
||||
|
||||
{
|
||||
printf ' - type: bind\n'
|
||||
printf ' source: %s\n' "$(pi_web_docker_host_yaml_quote "$source_path")"
|
||||
printf ' target: %s\n' "$(pi_web_docker_host_yaml_quote "$target_path")"
|
||||
if [ "$read_only" = true ]; then
|
||||
printf ' read_only: true\n'
|
||||
fi
|
||||
} >>"$PI_WEB_DOCKER_HOST_OVERRIDE_TEMP"
|
||||
}
|
||||
|
||||
pi_web_docker_host_write_existing_volume() {
|
||||
source_path=$1
|
||||
target_path=$2
|
||||
read_only=${3:-false}
|
||||
|
||||
if [ -e "$source_path" ]; then
|
||||
pi_web_docker_host_write_volume "$source_path" "$target_path" "$read_only"
|
||||
fi
|
||||
}
|
||||
|
||||
pi_web_docker_host_write_extra_volumes() {
|
||||
extra_paths=$1
|
||||
|
||||
for extra_path in $extra_paths; do
|
||||
case "$extra_path" in
|
||||
/*) ;;
|
||||
*)
|
||||
printf '%s\n' "PI_WEB_DOCKER_EXTRA_HOST_PATHS entries must be absolute paths: $extra_path" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ ! -e "$extra_path" ]; then
|
||||
printf '%s\n' "PI_WEB_DOCKER_EXTRA_HOST_PATHS entry does not exist: $extra_path" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
pi_web_docker_host_write_volume "$extra_path" "$extra_path" false
|
||||
done
|
||||
}
|
||||
|
||||
pi_web_docker_host_write_compose_override() {
|
||||
target_file=$1
|
||||
host_profile=$2
|
||||
extra_paths=${3:-}
|
||||
control_path=${4:-}
|
||||
target_dir=$(dirname "$target_file")
|
||||
mkdir -p "$target_dir" || return 1
|
||||
PI_WEB_DOCKER_HOST_OVERRIDE_TEMP=$target_file.$$
|
||||
|
||||
case "$host_profile" in
|
||||
linux-native-docker) hostexec_mode=nsenter ;;
|
||||
mac-docker-desktop) hostexec_mode=disabled ;;
|
||||
*)
|
||||
printf '%s\n' "unsupported PI WEB Docker host profile: $host_profile" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
cat >"$PI_WEB_DOCKER_HOST_OVERRIDE_TEMP" <<EOF
|
||||
# Generated by PI WEB Docker host profile detection. Do not edit by hand.
|
||||
# Re-run the installer or docker/pi-web-docker --dev to refresh this file.
|
||||
|
||||
x-pi-web-host-volumes: &pi-web-host-volumes
|
||||
EOF
|
||||
|
||||
socket_source=${PI_WEB_DETECTED_DOCKER_SOCKET_SOURCE:-/var/run/docker.sock}
|
||||
pi_web_docker_host_write_volume "$socket_source" /var/run/docker.sock false
|
||||
|
||||
case "$host_profile" in
|
||||
linux-native-docker)
|
||||
pi_web_docker_host_write_existing_volume /home /home false
|
||||
pi_web_docker_host_write_existing_volume /srv /srv false
|
||||
pi_web_docker_host_write_existing_volume /opt /opt false
|
||||
pi_web_docker_host_write_volume / /host true
|
||||
;;
|
||||
mac-docker-desktop)
|
||||
pi_web_docker_host_write_existing_volume /Users /Users false
|
||||
pi_web_docker_host_write_existing_volume /Volumes /Volumes false
|
||||
pi_web_docker_host_write_existing_volume /private /private false
|
||||
;;
|
||||
esac
|
||||
|
||||
if ! pi_web_docker_host_write_extra_volumes "$extra_paths"; then
|
||||
rm -f "$PI_WEB_DOCKER_HOST_OVERRIDE_TEMP"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -n "$control_path" ]; then
|
||||
if [ ! -e "$control_path" ]; then
|
||||
printf '%s\n' "PI WEB Docker control path does not exist: $control_path" >&2
|
||||
rm -f "$PI_WEB_DOCKER_HOST_OVERRIDE_TEMP"
|
||||
return 1
|
||||
fi
|
||||
pi_web_docker_host_write_volume "$control_path" "$control_path" false
|
||||
fi
|
||||
|
||||
cat >>"$PI_WEB_DOCKER_HOST_OVERRIDE_TEMP" <<EOF
|
||||
|
||||
services:
|
||||
sessiond:
|
||||
environment:
|
||||
HOSTEXEC_MODE: $hostexec_mode
|
||||
volumes: *pi-web-host-volumes
|
||||
|
||||
web:
|
||||
environment:
|
||||
HOSTEXEC_MODE: $hostexec_mode
|
||||
volumes: *pi-web-host-volumes
|
||||
EOF
|
||||
|
||||
mv "$PI_WEB_DOCKER_HOST_OVERRIDE_TEMP" "$target_file"
|
||||
}
|
||||
|
||||
pi_web_docker_host_print_detection_failure() {
|
||||
printf '%s\n' "PI WEB Docker setup could not determine a supported host profile." >&2
|
||||
printf '%s\n' "" >&2
|
||||
printf '%s\n' "Detected:" >&2
|
||||
printf ' host OS: %s\n' "${PI_WEB_DETECTED_HOST_OS:-unknown}" >&2
|
||||
printf ' docker context: %s\n' "${PI_WEB_DETECTED_DOCKER_CONTEXT:-unknown}" >&2
|
||||
printf ' docker endpoint: %s\n' "${PI_WEB_DETECTED_DOCKER_ENDPOINT:-unknown}" >&2
|
||||
printf ' DOCKER_HOST: %s\n' "${PI_WEB_DETECTED_DOCKER_HOST_ENV:-unset}" >&2
|
||||
printf ' effective endpoint: %s\n' "${PI_WEB_DETECTED_DOCKER_EFFECTIVE_ENDPOINT:-unknown}" >&2
|
||||
printf ' docker socket source: %s\n' "${PI_WEB_DETECTED_DOCKER_SOCKET_SOURCE:-unknown}" >&2
|
||||
printf ' docker OS: %s\n' "${PI_WEB_DETECTED_DOCKER_OS:-unknown}" >&2
|
||||
printf '%s\n' "" >&2
|
||||
printf '%s\n' "Supported profiles:" >&2
|
||||
printf '%s\n' " - native Linux Docker Engine using /var/run/docker.sock" >&2
|
||||
printf '%s\n' " - Docker Desktop for Mac" >&2
|
||||
if [ -n "${PI_WEB_DOCKER_HOST_PROFILE_ERROR:-}" ]; then
|
||||
printf '%s\n' "" >&2
|
||||
printf 'Reason: %s\n' "$PI_WEB_DOCKER_HOST_PROFILE_ERROR" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
pi_web_docker_compose() {
|
||||
if docker compose version >/dev/null 2>&1; then
|
||||
docker compose "$@"
|
||||
elif command -v docker-compose >/dev/null 2>&1; then
|
||||
docker-compose "$@"
|
||||
else
|
||||
printf '%s\n' "Docker Compose is required (docker compose plugin or docker-compose)" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
Reference in New Issue
Block a user