mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-07-04 21:18:46 +02:00
On HAOS >=17.3 the Supervisor Docker network gained IPv6, so core-mariadb resolves to an IPv6 address first. The official MariaDB addon only grants its service user from the IPv4 supervisor subnet, so connections from IPv6 fail with "Access denied". Resolve the hostname to its IPv4 address before connecting in every addon that consumes bashio::services 'mysql' 'host': photoprism, monica, fireflyiii, seafile, zoneminder. Fall back to the raw hostname if resolution fails so IPv4-only setups keep working unchanged.
300 lines
11 KiB
Bash
Executable File
300 lines
11 KiB
Bash
Executable File
#!/usr/bin/with-contenv bashio
|
|
# shellcheck shell=bash
|
|
set -e
|
|
|
|
#################
|
|
# Set structure #
|
|
#################
|
|
|
|
mkdir -p /config/storage
|
|
cp -rf /var/www/html/storage/* /config/storage/
|
|
rm -r /var/www/html/storage
|
|
ln -sf /config/storage /var/www/html/storage
|
|
chown -R www-data:www-data /config
|
|
|
|
###################
|
|
# Define database #
|
|
###################
|
|
|
|
database="$(bashio::config 'database')"
|
|
bashio::log.info "Data selected : $database"
|
|
|
|
case "$database" in
|
|
|
|
# Use sqlite
|
|
sqlite)
|
|
DB_DATABASE="/config/database.sqlite"
|
|
export DB_DATABASE
|
|
DB_CONNECTION=sqlite
|
|
export DB_CONNECTION
|
|
touch "$DB_DATABASE"
|
|
mkdir -p /var/www/html/database
|
|
ln -sf "$DB_DATABASE" /var/www/html/database/database.sqlite
|
|
chown www-data:www-data "$DB_DATABASE"
|
|
bashio::log.blue "Using $DB_DATABASE"
|
|
;;
|
|
|
|
# Use Mariadb_addon
|
|
MariaDB_addon)
|
|
# Use MariaDB
|
|
DB_CONNECTION=mysql
|
|
export DB_CONNECTION
|
|
bashio::log.green "Using MariaDB addon. Requirements: running MariaDB addon. Discovering values..."
|
|
if ! bashio::services.available 'mysql'; then
|
|
bashio::log.fatal "Local database access should be provided by the MariaDB addon"
|
|
bashio::exit.nok "Please ensure it is installed and started"
|
|
fi
|
|
|
|
# Resolve MariaDB hostname to IPv4: on HAOS >=17.3 the Supervisor network
|
|
# gained IPv6, but the MariaDB addon only grants its user from the IPv4
|
|
# subnet (issue #2688). Fall back to the raw hostname if resolution fails.
|
|
mariadb_host_raw="$(bashio::services "mysql" "host")"
|
|
mariadb_host_ipv4="$(getent ahostsv4 "$mariadb_host_raw" 2> /dev/null | awk '{print $1; exit}')"
|
|
DB_HOST="${mariadb_host_ipv4:-$mariadb_host_raw}"
|
|
if [ "$DB_HOST" != "$mariadb_host_raw" ]; then
|
|
bashio::log.info "Resolved ${mariadb_host_raw} -> ${DB_HOST} (forcing IPv4)"
|
|
fi
|
|
|
|
# Use values
|
|
bashio::log.blue "DB_HOST=$DB_HOST" && sed -i "1a export DB_HOST=$DB_HOST" /usr/local/bin/entrypoint.sh
|
|
DB_PORT=$(bashio::services "mysql" "port") && bashio::log.blue "DB_PORT=$DB_PORT" && sed -i "1a export DB_PORT=$DB_PORT" /usr/local/bin/entrypoint.sh
|
|
DB_DATABASE=monica && bashio::log.blue "DB_DATABASE=$DB_DATABASE" && sed -i "1a export DB_DATABASE=$DB_DATABASE" /usr/local/bin/entrypoint.sh
|
|
DB_USERNAME=$(bashio::services "mysql" "username") && bashio::log.blue "DB_USERNAME=$DB_USERNAME" && sed -i "1a export DB_USERNAME=$DB_USERNAME" /usr/local/bin/entrypoint.sh
|
|
DB_PASSWORD=$(bashio::services "mysql" "password") && bashio::log.blue "DB_PASSWORD=$DB_PASSWORD" && sed -i "1a export DB_PASSWORD=$DB_PASSWORD" /usr/local/bin/entrypoint.sh
|
|
export DB_HOST
|
|
export DB_PORT
|
|
export DB_DATABASE
|
|
export DB_USERNAME
|
|
export DB_PASSWORD
|
|
|
|
bashio::log.warning "Monica is using the MariaDB addon"
|
|
bashio::log.warning "Please ensure this is included in your backups"
|
|
bashio::log.warning "Uninstalling the MariaDB addon will remove any data"
|
|
|
|
# Create database
|
|
mysql --skip-ssl --host="$DB_HOST" --port="$DB_PORT" --user="$DB_USERNAME" --password="$DB_PASSWORD" -e"CREATE DATABASE IF NOT EXISTS $DB_DATABASE;"
|
|
|
|
;;
|
|
|
|
# Use Mariadb_addon
|
|
Mysql_external)
|
|
DB_CONNECTION=mysql
|
|
export DB_CONNECTION
|
|
for var in DB_DATABASE DB_HOST DB_PASSWORD DB_PORT DB_USERNAME; do
|
|
# Verify all variables are set
|
|
if ! bashio::config.has_value "$var"; then
|
|
bashio::log.fatal "You have selected to not use the automatic MariaDB detection by manually configuring the addon options, but the option $var is not set."
|
|
exit 1
|
|
fi
|
|
"$var=$(bashio::config "var")"
|
|
export "${var?}"
|
|
bashio::log.blue "$var=$(bashio::config "var")"
|
|
done
|
|
# Alert if MariaDB is available
|
|
if bashio::services.available 'mysql'; then
|
|
bashio::log.warning "The MariaDB addon is available, but you have selected to use your own database by manually configuring the addon options"
|
|
fi
|
|
|
|
# Create database
|
|
mysql --skip-ssl --host="$DB_HOST" --port="$DB_PORT" --user="$DB_USERNAME" --password="$DB_PASSWORD" -e"CREATE DATABASE IF NOT EXISTS $DB_DATABASE;"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
###########
|
|
# APP_KEY #
|
|
###########
|
|
|
|
# Get APP_KEY from bashio::config
|
|
APP_KEY=$(bashio::config "APP_KEY")
|
|
|
|
# Check if APP_KEY is not 32 characters long
|
|
if [ -z "$APP_KEY" ] || [ ${#APP_KEY} -lt 32 ]; then
|
|
APP_KEY="$(
|
|
echo -n 'base64:'
|
|
openssl rand -base64 32
|
|
)"
|
|
bashio::addon.option "APP_KEY" "${APP_KEY}"
|
|
bashio::log.warning "The APP_KEY set was invalid, generated a random one: ${APP_KEY}. Restarting to take it into account"
|
|
echo "${APP_KEY}" >> /config/APP_KEY
|
|
bashio::addon.restart
|
|
fi
|
|
APP_KEY="$(bashio::config "APP_KEY")"
|
|
export APP_KEY
|
|
|
|
bashio::log.info "Preparing Meilisearch"
|
|
MEILISEARCH_URL="${MEILISEARCH_URL:-http://127.0.0.1:7700}"
|
|
export MEILISEARCH_URL
|
|
|
|
MEILISEARCH_URI="${MEILISEARCH_URL#*://}"
|
|
MEILISEARCH_HOST_PORT="${MEILISEARCH_URI%%/*}"
|
|
MEILISEARCH_HOST="${MEILISEARCH_HOST_PORT%%:*}"
|
|
MEILISEARCH_PORT="${MEILISEARCH_HOST_PORT##*:}"
|
|
if [ "${MEILISEARCH_PORT}" = "${MEILISEARCH_HOST_PORT}" ]; then
|
|
MEILISEARCH_PORT=""
|
|
fi
|
|
|
|
MEILISEARCH_LOCAL=false
|
|
if [[ -n "${MEILISEARCH_PORT}" && ! ${MEILISEARCH_PORT} =~ ^[0-9]+$ ]]; then
|
|
bashio::log.warning "Ignoring bundled Meilisearch because MEILISEARCH_URL uses a non-numeric port (${MEILISEARCH_PORT})."
|
|
elif [[ "${MEILISEARCH_HOST}" =~ ^(127\.0\.0\.1|localhost)$ ]]; then
|
|
MEILISEARCH_LOCAL=true
|
|
if [ -z "${MEILISEARCH_PORT}" ]; then
|
|
MEILISEARCH_PORT="7700"
|
|
fi
|
|
MEILISEARCH_ADDR="${MEILISEARCH_HOST}:${MEILISEARCH_PORT}"
|
|
else
|
|
MEILISEARCH_ADDR="127.0.0.1:7700"
|
|
fi
|
|
|
|
if [[ "${MEILISEARCH_LOCAL}" == true ]]; then
|
|
bashio::log.info "Starting bundled Meilisearch instance at ${MEILISEARCH_ADDR}"
|
|
MEILISEARCH_DB_PATH="/data/meilisearch"
|
|
mkdir -p "${MEILISEARCH_DB_PATH}"
|
|
|
|
MEILISEARCH_ENV_KEY="$(bashio::config 'meilisearch_key')"
|
|
GENERATED_MEILI_KEY_FILE="/data/meilisearch_master_key"
|
|
|
|
# Treat unset/"null" config as empty so we don't feed an invalid key to Meilisearch
|
|
if [ "${MEILISEARCH_ENV_KEY}" = "null" ]; then
|
|
MEILISEARCH_ENV_KEY=""
|
|
fi
|
|
|
|
# Reject too-short keys so the service can start even with a bad config
|
|
if [ -n "${MEILISEARCH_ENV_KEY}" ] && [ "${#MEILISEARCH_ENV_KEY}" -lt 16 ]; then
|
|
bashio::log.warning "Configured meilisearch_key is shorter than 16 bytes; generating a secure key instead."
|
|
MEILISEARCH_ENV_KEY=""
|
|
fi
|
|
|
|
# Fall back to MEILI_MASTER_KEY when present and valid
|
|
if [ -z "${MEILISEARCH_ENV_KEY}" ]; then
|
|
if [ -n "${MEILI_MASTER_KEY:-}" ] && [ "${#MEILI_MASTER_KEY}" -ge 16 ]; then
|
|
MEILISEARCH_ENV_KEY="${MEILI_MASTER_KEY}"
|
|
elif [ -n "${MEILI_MASTER_KEY:-}" ] && [ "${#MEILI_MASTER_KEY}" -lt 16 ]; then
|
|
bashio::log.warning "Provided MEILI_MASTER_KEY is shorter than 16 bytes; generating a secure key instead."
|
|
fi
|
|
fi
|
|
|
|
# Persist and reuse a generated key when none was provided
|
|
if [ -z "${MEILISEARCH_ENV_KEY}" ]; then
|
|
if [ -s "${GENERATED_MEILI_KEY_FILE}" ]; then
|
|
MEILISEARCH_ENV_KEY="$(cat "${GENERATED_MEILI_KEY_FILE}")"
|
|
else
|
|
MEILISEARCH_ENV_KEY="$(openssl rand -hex 32)"
|
|
echo "${MEILISEARCH_ENV_KEY}" > "${GENERATED_MEILI_KEY_FILE}"
|
|
chmod 600 "${GENERATED_MEILI_KEY_FILE}"
|
|
bashio::log.info "Generated persistent Meilisearch master key at ${GENERATED_MEILI_KEY_FILE}."
|
|
fi
|
|
fi
|
|
|
|
MEILISEARCH_KEY="${MEILISEARCH_ENV_KEY}"
|
|
export MEILISEARCH_KEY
|
|
MEILISEARCH_ENVIRONMENT="${MEILI_ENV:-production}"
|
|
MEILISEARCH_NO_ANALYTICS="${MEILI_NO_ANALYTICS:-true}"
|
|
|
|
S6_SUPERVISED_DIR="/run/s6/services"
|
|
if [ ! -d "${S6_SUPERVISED_DIR}" ]; then
|
|
S6_SUPERVISED_DIR="/var/run/s6/services"
|
|
fi
|
|
|
|
S6_SVSCANCTL_BIN="$(command -v s6-svscanctl || true)"
|
|
if [ -z "${S6_SVSCANCTL_BIN}" ] && [ -x /command/s6-svscanctl ]; then
|
|
S6_SVSCANCTL_BIN="/command/s6-svscanctl"
|
|
fi
|
|
|
|
meilisearch_fail() {
|
|
local message="$1"
|
|
local exit_code="${2:-1}"
|
|
|
|
bashio::log.error "${message}"
|
|
|
|
if [ -n "${S6_SVSCANCTL_BIN}" ]; then
|
|
if ! "${S6_SVSCANCTL_BIN}" -t "${S6_SUPERVISED_DIR}" 2>/dev/null; then
|
|
bashio::log.error "Unable to signal s6-svscanctl to stop services"
|
|
fi
|
|
else
|
|
bashio::log.error "s6-svscanctl binary not found; unable to stop services gracefully"
|
|
fi
|
|
|
|
if [ "${exit_code}" -eq 0 ]; then
|
|
exit_code=1
|
|
fi
|
|
|
|
exit "${exit_code}"
|
|
}
|
|
|
|
meilisearch_ensure_running() {
|
|
if kill -0 "${MEILISEARCH_PID}" 2>/dev/null; then
|
|
return 0
|
|
fi
|
|
|
|
local exit_code=0
|
|
|
|
set +e
|
|
wait "${MEILISEARCH_PID}"
|
|
exit_code=$?
|
|
set -e
|
|
|
|
local wait_code="${exit_code}"
|
|
if [ "${exit_code}" -eq 0 ]; then
|
|
exit_code=1
|
|
fi
|
|
|
|
meilisearch_fail "Meilisearch exited unexpectedly (code ${wait_code}). Stopping add-on." "${exit_code}"
|
|
}
|
|
|
|
MEILISEARCH_CMD=(
|
|
env \
|
|
MEILI_ENV="${MEILISEARCH_ENVIRONMENT}" \
|
|
MEILI_NO_ANALYTICS="${MEILISEARCH_NO_ANALYTICS}" \
|
|
meilisearch \
|
|
--http-addr "${MEILISEARCH_ADDR}" \
|
|
--db-path "${MEILISEARCH_DB_PATH}"
|
|
)
|
|
|
|
if [ -n "${MEILISEARCH_ENV_KEY}" ]; then
|
|
MEILISEARCH_CMD+=(--master-key "${MEILISEARCH_ENV_KEY}")
|
|
fi
|
|
|
|
"${MEILISEARCH_CMD[@]}" &
|
|
MEILISEARCH_PID=$!
|
|
|
|
bashio::log.info "Waiting for Meilisearch TCP socket"
|
|
for attempt in $(seq 1 30); do
|
|
if bash -c "cat < /dev/null > /dev/tcp/${MEILISEARCH_HOST}/${MEILISEARCH_PORT}" 2>/dev/null; then
|
|
break
|
|
fi
|
|
|
|
meilisearch_ensure_running
|
|
|
|
if [ "${attempt}" -eq 30 ]; then
|
|
meilisearch_fail "Meilisearch TCP socket did not become ready in time. Stopping add-on."
|
|
fi
|
|
|
|
sleep 1
|
|
done
|
|
|
|
bashio::log.info "Waiting for Meilisearch health endpoint"
|
|
MEILISEARCH_HEALTH_URL="${MEILISEARCH_URL%/}/health"
|
|
for attempt in $(seq 1 30); do
|
|
if curl -fs "${MEILISEARCH_HEALTH_URL}" | grep -q '"status":"available"'; then
|
|
bashio::log.info "Meilisearch is ready"
|
|
break
|
|
fi
|
|
meilisearch_ensure_running
|
|
|
|
if [ "${attempt}" -eq 30 ]; then
|
|
meilisearch_fail "Meilisearch did not become ready in time. Stopping add-on."
|
|
fi
|
|
|
|
sleep 1
|
|
done
|
|
else
|
|
bashio::log.info "Detected external Meilisearch endpoint (${MEILISEARCH_URL}); skipping bundled service startup"
|
|
fi
|
|
|
|
bashio::log.info "Starting Monica"
|
|
|
|
entrypoint.sh apache2-foreground
|