From 407dfffbf130e831534522642355425cb9d0c039 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 15 Aug 2024 14:35:30 +1000 Subject: [PATCH 01/21] partial revert on 0cb4378923cfd862525b12cc86db87e7917a55e3 (releaseStatus hack) --- update.sh | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/update.sh b/update.sh index 61de896..7656d41 100755 --- a/update.sh +++ b/update.sh @@ -255,20 +255,6 @@ for version in "${versions[@]}"; do | jq -r --arg version "${version%-*}" '.major_releases[] | select(.release_id == $version) | [ .release_status ] , [ .release_support_type ] | @tsv')" releaseStatus=${release[0]:-Unknown} supportType=${release[1]:-Unknown} - if [ "$releaseStatus" == Unknown ]; then - case "$version" in - 11.5*) - releaseStatus=Stable - ;; - 11.6*) - releaseStatus=RC - ;; - main*) - releaseStatus=Alpha - ;; - esac - supportType="Short Term Support" - fi update_version done From 376c7ec7130fab4f42636c3ef69b3d9ae68b223a Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 15 Aug 2024 14:36:39 +1000 Subject: [PATCH 02/21] revert b34b76eb883ea262db762517947e2cb2776f112b version fix --- update.sh | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/update.sh b/update.sh index 7656d41..4055f78 100755 --- a/update.sh +++ b/update.sh @@ -240,16 +240,7 @@ for version in "${versions[@]}"; do if [ ! -d "$version" ]; then version=${version%.[[:digit:]]*} else - case "$version" in - 11.5*) - mariaVersion=11.5.2 - ;; - 11.6*) - mariaVersion=11.6.1 - ;; - *) - mariaversion - esac + mariaversion fi readarray -t release <<< "$(curl -fsSL "$DOWNLOADS_REST_API/mariadb/" \ | jq -r --arg version "${version%-*}" '.major_releases[] | select(.release_id == $version) | [ .release_status ] , [ .release_support_type ] | @tsv')" From d8668a590aed6936e1bbd107b35ceedf29dea76a Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 3 Sep 2024 13:54:31 +1000 Subject: [PATCH 03/21] test: break config file --- .test/run.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.test/run.sh b/.test/run.sh index f4d07e8..1107e0e 100755 --- a/.test/run.sh +++ b/.test/run.sh @@ -961,12 +961,14 @@ zstd "${initdb}"/*zst* # ERROR 1045 (28000): Access denied docker exec "$cname" healthcheck.sh --connect - # break port docker exec "$cname" sed -i -e 's/\(port=\)/\14/' /var/lib/mysql/.my-healthcheck.cnf - docker exec "$cname" healthcheck.sh --connect || echo "ok, broken port is a connection failure" + # break config file + docker exec "$cname" sed -i -e 's/-client]$//' /var/lib/mysql/.my-healthcheck.cnf + docker exec "$cname" healthcheck.sh --connect || echo "ok, broken config file is a failure" + killoff docker volume rm "$tmpvol" From e47764f0a3b03b5152e37be80a47eda071c38e7b Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 3 Sep 2024 15:33:45 +1000 Subject: [PATCH 04/21] 11.1 EOL --- 11.1/Dockerfile | 142 -------- 11.1/docker-entrypoint.sh | 720 -------------------------------------- 11.1/healthcheck.sh | 388 -------------------- update.sh | 10 +- versions.json | 14 - 5 files changed, 2 insertions(+), 1272 deletions(-) delete mode 100644 11.1/Dockerfile delete mode 100755 11.1/docker-entrypoint.sh delete mode 100755 11.1/healthcheck.sh diff --git a/11.1/Dockerfile b/11.1/Dockerfile deleted file mode 100644 index b78992a..0000000 --- a/11.1/Dockerfile +++ /dev/null @@ -1,142 +0,0 @@ -# vim:set ft=dockerfile: -FROM ubuntu:jammy - -# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added -RUN groupadd -r mysql && useradd -r -g mysql mysql --home-dir /var/lib/mysql - -# add gosu for easy step-down from root -# https://github.com/tianon/gosu/releases -# gosu key is B42F6819007F00F88E364FD4036A9C25BF357DD4 -ENV GOSU_VERSION 1.17 - -ARG GPG_KEYS=177F4010FE56CA3336300305F1656F24C74CD1D8 -# pub rsa4096 2016-03-30 [SC] -# 177F 4010 FE56 CA33 3630 0305 F165 6F24 C74C D1D8 -# uid [ unknown] MariaDB Signing Key -# sub rsa4096 2016-03-30 [E] -# install "libjemalloc2" as it offers better performance in some cases. Use with LD_PRELOAD -# install "pwgen" for randomizing passwords -# install "tzdata" for /usr/share/zoneinfo/ -# install "xz-utils" for .sql.xz docker-entrypoint-initdb.d files -# install "zstd" for .sql.zst docker-entrypoint-initdb.d files -# hadolint ignore=SC2086 -RUN set -eux; \ - apt-get update; \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - ca-certificates \ - gpg \ - gpgv \ - libjemalloc2 \ - pwgen \ - tzdata \ - xz-utils \ - zstd ; \ - savedAptMark="$(apt-mark showmanual)"; \ - apt-get install -y --no-install-recommends \ - dirmngr \ - gpg-agent \ - wget; \ - rm -rf /var/lib/apt/lists/*; \ - dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ - wget -q -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ - wget -q -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ - GNUPGHOME="$(mktemp -d)"; \ - export GNUPGHOME; \ - gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ - for key in $GPG_KEYS; do \ - gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key"; \ - done; \ - gpg --batch --export "$GPG_KEYS" > /etc/apt/trusted.gpg.d/mariadb.gpg; \ - if command -v gpgconf >/dev/null; then \ - gpgconf --kill all; \ - fi; \ - gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ - gpgconf --kill all; \ - rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ - apt-mark auto '.*' > /dev/null; \ - [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark >/dev/null; \ - apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ - chmod +x /usr/local/bin/gosu; \ - gosu --version; \ - gosu nobody true - -RUN mkdir /docker-entrypoint-initdb.d - -# Ensure the container exec commands handle range of utf8 characters based of -# default locales in base image (https://github.com/docker-library/docs/blob/135b79cc8093ab02e55debb61fdb079ab2dbce87/ubuntu/README.md#locales) -ENV LANG C.UTF-8 - -# OCI annotations to image -LABEL org.opencontainers.image.authors="MariaDB Community" \ - org.opencontainers.image.title="MariaDB Database" \ - org.opencontainers.image.description="MariaDB Database for relational SQL" \ - org.opencontainers.image.documentation="https://hub.docker.com/_/mariadb/" \ - org.opencontainers.image.base.name="docker.io/library/ubuntu:jammy" \ - org.opencontainers.image.licenses="GPL-2.0" \ - org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ - org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="11.1.6" \ - org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" - -# bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=1:11.1.6+maria~ubu2204 -ENV MARIADB_VERSION $MARIADB_VERSION -# release-status:Stable -# release-support-type:Short Term Support -# (https://downloads.mariadb.org/rest-api/mariadb/) - -# Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions -ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.1.6/repo/ubuntu/ jammy main main/debug" - -RUN set -e;\ - echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ - { \ - echo 'Package: *'; \ - echo 'Pin: release o=MariaDB'; \ - echo 'Pin-Priority: 999'; \ - } > /etc/apt/preferences.d/mariadb -# add repository pinning to make sure dependencies from this MariaDB repo are preferred over Debian dependencies -# libmariadbclient18 : Depends: libmysqlclient18 (= 5.5.42+maria-1~wheezy) but 5.5.43-0+deb7u1 is to be installed - -# the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) -# also, we set debconf keys to make APT a little quieter -# hadolint ignore=DL3015 -RUN set -ex; \ - { \ - echo "mariadb-server" mysql-server/root_password password 'unused'; \ - echo "mariadb-server" mysql-server/root_password_again password 'unused'; \ - } | debconf-set-selections; \ - apt-get update; \ -# postinst script creates a datadir, so avoid creating it by faking its existance. - mkdir -p /var/lib/mysql/mysql ; touch /var/lib/mysql/mysql/user.frm ; \ -# mariadb-backup is installed at the same time so that `mysql-common` is only installed once from just mariadb repos - apt-get install -y --no-install-recommends mariadb-server="$MARIADB_VERSION" mariadb-backup socat \ - ; \ - rm -rf /var/lib/apt/lists/*; \ -# purge and re-create /var/lib/mysql with appropriate ownership - rm -rf /var/lib/mysql /etc/mysql/mariadb.conf.d/50-mariadb_safe.cnf; \ - mkdir -p /var/lib/mysql /run/mysqld; \ - chown -R mysql:mysql /var/lib/mysql /run/mysqld; \ -# ensure that /run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime - chmod 1777 /run/mysqld; \ -# comment out a few problematic configuration values - find /etc/mysql/ -name '*.cnf' -print0 \ - | xargs -0 grep -lZE '^(bind-address|log|user\s)' \ - | xargs -rt -0 sed -Ei 's/^(bind-address|log|user\s)/#&/'; \ -# don't reverse lookup hostnames, they are usually another container - printf "[mariadb]\nhost-cache-size=0\nskip-name-resolve\n" > /etc/mysql/mariadb.conf.d/05-skipcache.cnf; \ -# Issue #327 Correct order of reading directories /etc/mysql/mariadb.conf.d before /etc/mysql/conf.d (mount-point per documentation) - if [ -L /etc/mysql/my.cnf ]; then \ -# 10.5+ - sed -i -e '/includedir/ {N;s/\(.*\)\n\(.*\)/\n\2\n\1/}' /etc/mysql/mariadb.cnf; \ - fi - - -VOLUME /var/lib/mysql - -COPY healthcheck.sh /usr/local/bin/healthcheck.sh -COPY docker-entrypoint.sh /usr/local/bin/ -ENTRYPOINT ["docker-entrypoint.sh"] - -EXPOSE 3306 -CMD ["mariadbd"] diff --git a/11.1/docker-entrypoint.sh b/11.1/docker-entrypoint.sh deleted file mode 100755 index 27e411b..0000000 --- a/11.1/docker-entrypoint.sh +++ /dev/null @@ -1,720 +0,0 @@ -#!/bin/bash -set -eo pipefail -shopt -s nullglob - -# logging functions -mysql_log() { - local type="$1"; shift - printf '%s [%s] [Entrypoint]: %s\n' "$(date --rfc-3339=seconds)" "$type" "$*" -} -mysql_note() { - mysql_log Note "$@" -} -mysql_warn() { - mysql_log Warn "$@" >&2 -} -mysql_error() { - mysql_log ERROR "$@" >&2 - exit 1 -} - -# usage: file_env VAR [DEFAULT] -# ie: file_env 'XYZ_DB_PASSWORD' 'example' -# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of -# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) -file_env() { - local var="$1" - local fileVar="${var}_FILE" - local def="${2:-}" - if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then - mysql_error "Both $var and $fileVar are set (but are exclusive)" - fi - local val="$def" - if [ "${!var:-}" ]; then - val="${!var}" - elif [ "${!fileVar:-}" ]; then - val="$(< "${!fileVar}")" - fi - export "$var"="$val" - unset "$fileVar" -} - -# set MARIADB_xyz from MYSQL_xyz when MARIADB_xyz is unset -# and make them the same value (so user scripts can use either) -_mariadb_file_env() { - local var="$1"; shift - local maria="MARIADB_${var#MYSQL_}" - file_env "$var" "$@" - file_env "$maria" "${!var}" - if [ "${!maria:-}" ]; then - export "$var"="${!maria}" - fi -} - -# check to see if this file is being run or sourced from another script -_is_sourced() { - # https://unix.stackexchange.com/a/215279 - [ "${#FUNCNAME[@]}" -ge 2 ] \ - && [ "${FUNCNAME[0]}" = '_is_sourced' ] \ - && [ "${FUNCNAME[1]}" = 'source' ] -} - -# usage: docker_process_init_files [file [file [...]]] -# ie: docker_process_init_files /always-initdb.d/* -# process initializer files, based on file extensions -docker_process_init_files() { - # mysql here for backwards compatibility "${mysql[@]}" - # ShellCheck: mysql appears unused. Verify use (or export if used externally) - # shellcheck disable=SC2034 - mysql=( docker_process_sql ) - - echo - local f - for f; do - case "$f" in - *.sh) - # https://github.com/docker-library/postgres/issues/450#issuecomment-393167936 - # https://github.com/docker-library/postgres/pull/452 - if [ -x "$f" ]; then - mysql_note "$0: running $f" - "$f" - else - mysql_note "$0: sourcing $f" - # ShellCheck can't follow non-constant source. Use a directive to specify location. - # shellcheck disable=SC1090 - . "$f" - fi - ;; - *.sql) mysql_note "$0: running $f"; docker_process_sql < "$f"; echo ;; - *.sql.gz) mysql_note "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;; - *.sql.xz) mysql_note "$0: running $f"; xzcat "$f" | docker_process_sql; echo ;; - *.sql.zst) mysql_note "$0: running $f"; zstd -dc "$f" | docker_process_sql; echo ;; - *) mysql_warn "$0: ignoring $f" ;; - esac - echo - done -} - -# arguments necessary to run "mariadbd --verbose --help" successfully (used for testing configuration validity and for extracting default/configured values) -_verboseHelpArgs=( - --verbose --help -) - -mysql_check_config() { - local toRun=( "$@" "${_verboseHelpArgs[@]}" ) errors - if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then - mysql_error $'mariadbd failed while attempting to check config\n\tcommand was: '"${toRun[*]}"$'\n\t'"$errors" - fi -} - -# Fetch value from server config -# We use mariadbd --verbose --help instead of my_print_defaults because the -# latter only show values present in config files, and not server defaults -mysql_get_config() { - local conf="$1"; shift - "$@" "${_verboseHelpArgs[@]}" 2>/dev/null \ - | awk -v conf="$conf" '$1 == conf && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }' - # match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)" -} - -# Do a temporary startup of the MariaDB server, for init purposes -docker_temp_server_start() { - "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ - --expire-logs-days=0 \ - --loose-innodb_buffer_pool_load_at_startup=0 \ - & - declare -g MARIADB_PID - MARIADB_PID=$! - mysql_note "Waiting for server startup" - # only use the root password if the database has already been initialized - # so that it won't try to fill in a password file when it hasn't been set yet - extraArgs=() - if [ -z "$DATABASE_ALREADY_EXISTS" ]; then - extraArgs+=( '--dont-use-mysql-root-password' ) - fi - local i - for i in {30..0}; do - if docker_process_sql "${extraArgs[@]}" --database=mysql \ - <<<'SELECT 1' &> /dev/null; then - break - fi - sleep 1 - done - if [ "$i" = 0 ]; then - mysql_error "Unable to start server." - fi -} - -# Stop the server. When using a local socket file mariadb-admin will block until -# the shutdown is complete. -docker_temp_server_stop() { - kill "$MARIADB_PID" - wait "$MARIADB_PID" -} - -# Verify that the minimally required password settings are set for new databases. -docker_verify_minimum_env() { - # Restoring from backup requires no environment variables - declare -g DATABASE_INIT_FROM_BACKUP - for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do - if [ -f "${file}" ]; then - DATABASE_INIT_FROM_BACKUP='true' - return - fi - done - if [ -z "$MARIADB_ROOT_PASSWORD" ] && [ -z "$MARIADB_ROOT_PASSWORD_HASH" ] && [ -z "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] && [ -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then - mysql_error $'Database is uninitialized and password option is not specified\n\tYou need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ROOT_PASSWORD_HASH, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' - fi - # More preemptive exclusions of combinations should have been made before *PASSWORD_HASH was added, but for now we don't enforce due to compatibility. - if [ -n "$MARIADB_ROOT_PASSWORD" ] || [ -n "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] || [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ] && [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then - mysql_error "Cannot specify MARIADB_ROOT_PASSWORD_HASH and another MARIADB_ROOT_PASSWORD* option." - fi - if [ -n "$MARIADB_PASSWORD" ] && [ -n "$MARIADB_PASSWORD_HASH" ]; then - mysql_error "Cannot specify MARIADB_PASSWORD_HASH and MARIADB_PASSWORD option." - fi - if [ -n "$MARIADB_REPLICATION_USER" ]; then - if [ -z "$MARIADB_MASTER_HOST" ]; then - # its a master, we're creating a user - if [ -z "$MARIADB_REPLICATION_PASSWORD" ] && [ -z "$MARIADB_REPLICATION_PASSWORD_HASH" ]; then - mysql_error "MARIADB_REPLICATION_PASSWORD or MARIADB_REPLICATION_PASSWORD_HASH not found to create replication user for master" - fi - else - # its a replica - if [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; then - mysql_error "MARIADB_REPLICATION_PASSWORD is mandatory to specify the replication on the replica image." - fi - if [ -n "$MARIADB_REPLICATION_PASSWORD_HASH" ] ; then - mysql_warn "MARIADB_REPLICATION_PASSWORD_HASH cannot be specified on a replica" - fi - fi - fi - if [ -n "$MARIADB_MASTER_HOST" ] && { [ -z "$MARIADB_REPLICATION_USER" ] || [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; }; then - mysql_error "For a replica, MARIADB_REPLICATION_USER and MARIADB_REPLICATION is mandatory." - fi -} - -# creates folders for the database -# also ensures permission for user mysql of run as root -docker_create_db_directories() { - local user; user="$(id -u)" - - # TODO other directories that are used by default? like /var/lib/mysql-files - # see https://github.com/docker-library/mysql/issues/562 - mkdir -p "$DATADIR" - - if [ "$user" = "0" ]; then - # this will cause less disk access than `chown -R` - find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) - # See https://github.com/MariaDB/mariadb-docker/issues/363 - if [ "${SOCKET:0:1}" != '@' ]; then # not abstract sockets - find "${SOCKET%/*}" -maxdepth 0 \! -user mysql \( -exec chown mysql: '{}' \; -o -true \) - fi - - # memory.pressure - local cgroup; cgroup=$( "$DATADIR"/.my-healthcheck.cnf - $maskPreserve -} - -# Initializes database with timezone info and root password, plus optional extra db/user -docker_setup_db() { - # Load timezone info into database - if [ -z "$MARIADB_INITDB_SKIP_TZINFO" ]; then - # --skip-write-binlog usefully disables binary logging - # but also outputs LOCK TABLES to improve the IO of - # Aria (MDEV-23326) for 10.4+. - mariadb-tzinfo-to-sql --skip-write-binlog /usr/share/zoneinfo \ - | docker_process_sql --dont-use-mysql-root-password --database=mysql - # tell docker_process_sql to not use MYSQL_ROOT_PASSWORD since it is not set yet - fi - # Generate random root password - if [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then - MARIADB_ROOT_PASSWORD="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" - export MARIADB_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=$MARIADB_ROOT_PASSWORD - mysql_note "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD" - fi - - # Creates root users for non-localhost hosts - local rootCreate= - local rootPasswordEscaped= - if [ -n "$MARIADB_ROOT_PASSWORD" ]; then - # Sets root password and creates root users for non-localhost hosts - rootPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}") - fi - - # default root to listen for connections from anywhere - if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then - # ref "read -d ''", no, we don't care if read finds a terminating character in this heredoc - # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 - if [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then - read -r -d '' rootCreate <<-EOSQL || true - CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY PASSWORD '${MARIADB_ROOT_PASSWORD_HASH}' ; - GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; - GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; - EOSQL - else - read -r -d '' rootCreate <<-EOSQL || true - CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ; - GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; - GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; - EOSQL - fi - fi - - local mysqlAtLocalhost= - local mysqlAtLocalhostGrants= - # Install mysql@localhost user - if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ]; then - read -r -d '' mysqlAtLocalhost <<-EOSQL || true - CREATE USER mysql@localhost IDENTIFIED VIA unix_socket; - EOSQL - if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then - if [ "$MARIADB_MYSQL_LOCALHOST_GRANTS" != USAGE ]; then - mysql_warn "Excessive privileges ON *.* TO mysql@localhost facilitates risks to the confidentiality, integrity and availability of data stored" - fi - mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; - fi - fi - - local createHealthCheckUsers - createHealthCheckUsers=$(create_healthcheck_users) - - local rootLocalhostPass= - if [ -z "$MARIADB_ROOT_PASSWORD_HASH" ]; then - # handle MARIADB_ROOT_PASSWORD_HASH for root@localhost after /docker-entrypoint-initdb.d - rootLocalhostPass="SET PASSWORD FOR 'root'@'localhost'= PASSWORD('${rootPasswordEscaped}');" - fi - - local createDatabase= - # Creates a custom database and user if specified - if [ -n "$MARIADB_DATABASE" ]; then - mysql_note "Creating database ${MARIADB_DATABASE}" - createDatabase="CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\`;" - fi - - local createUser= - local userGrants= - if [ -n "$MARIADB_PASSWORD" ] || [ -n "$MARIADB_PASSWORD_HASH" ] && [ -n "$MARIADB_USER" ]; then - mysql_note "Creating user ${MARIADB_USER}" - if [ -n "$MARIADB_PASSWORD_HASH" ]; then - createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY PASSWORD '$MARIADB_PASSWORD_HASH';" - else - # SQL escape the user password, \ followed by ' - local userPasswordEscaped - userPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_PASSWORD}") - createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$userPasswordEscaped';" - fi - - if [ -n "$MARIADB_DATABASE" ]; then - mysql_note "Giving user ${MARIADB_USER} access to schema ${MARIADB_DATABASE}" - userGrants="GRANT ALL ON \`${MARIADB_DATABASE//_/\\_}\`.* TO '$MARIADB_USER'@'%';" - fi - fi - - # To create replica user - local createReplicaUser= - local changeMasterTo= - local startReplica= - if [ -n "$MARIADB_REPLICATION_USER" ] ; then - if [ -z "$MARIADB_MASTER_HOST" ]; then - # on master - mysql_note "Creating user ${MARIADB_REPLICATION_USER}" - createReplicaUser=$(create_replica_user) - else - # on replica - local rplPasswordEscaped - rplPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_REPLICATION_PASSWORD}") - # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. - # shellcheck disable=SC2153 - changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" - fi - fi - - mysql_note "Securing system users (equivalent to running mysql_secure_installation)" - # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set - # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. - docker_process_sql --dont-use-mysql-root-password --database=mysql --binary-mode <<-EOSQL - -- Securing system users shouldn't be replicated - SET @orig_sql_log_bin= @@SESSION.SQL_LOG_BIN; - SET @@SESSION.SQL_LOG_BIN=0; - -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set - SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); - - DROP USER IF EXISTS root@'127.0.0.1', root@'::1'; - EXECUTE IMMEDIATE CONCAT('DROP USER IF EXISTS root@\'', @@hostname,'\''); - - ${rootLocalhostPass} - ${rootCreate} - ${mysqlAtLocalhost} - ${mysqlAtLocalhostGrants} - ${createHealthCheckUsers} - -- end of securing system users, rest of init now... - SET @@SESSION.SQL_LOG_BIN=@orig_sql_log_bin; - -- create users/databases - ${createDatabase} - ${createUser} - ${createReplicaUser} - ${userGrants} - - ${changeMasterTo} - ${startReplica} - EOSQL -} - -# create a new installation -docker_mariadb_init() -{ - - # check dir permissions to reduce likelihood of half-initialized database - ls /docker-entrypoint-initdb.d/ > /dev/null - - if [ -n "$DATABASE_INIT_FROM_BACKUP" ]; then - shopt -s dotglob - for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do - mkdir -p "$DATADIR"/.init - tar --auto-compress --extract --file "$file" --directory="$DATADIR"/.init - mariadb-backup --target-dir="$DATADIR"/.init --datadir="$DATADIR"/.restore --move-back - - mv "$DATADIR"/.restore/** "$DATADIR"/ - if [ -f "$DATADIR/.init/backup-my.cnf" ]; then - mv "$DATADIR/.init/backup-my.cnf" "$DATADIR/.my.cnf" - mysql_note "Adding startup configuration:" - my_print_defaults --defaults-file="$DATADIR/.my.cnf" --mariadbd - fi - rm -rf "$DATADIR"/.init "$DATADIR"/.restore - if [ "$(id -u)" = "0" ]; then - # this will cause less disk access than `chown -R` - find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) - fi - done - if _check_if_upgrade_is_needed; then - docker_mariadb_upgrade "$@" - fi - return - fi - docker_init_database_dir "$@" - - mysql_note "Starting temporary server" - docker_temp_server_start "$@" - mysql_note "Temporary server started." - - docker_setup_db - docker_process_init_files /docker-entrypoint-initdb.d/* - # Wait until after /docker-entrypoint-initdb.d is performed before setting - # root@localhost password to a hash we don't know the password for. - if [ -n "${MARIADB_ROOT_PASSWORD_HASH}" ]; then - mysql_note "Setting root@localhost password hash" - docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL - SET @@SESSION.SQL_LOG_BIN=0; - SET PASSWORD FOR 'root'@'localhost'= '${MARIADB_ROOT_PASSWORD_HASH}'; - EOSQL - fi - - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" - - echo - mysql_note "MariaDB init process done. Ready for start up." - echo -} - -# backup the mysql database -docker_mariadb_backup_system() -{ - if [ -n "$MARIADB_DISABLE_UPGRADE_BACKUP" ] \ - && [ "$MARIADB_DISABLE_UPGRADE_BACKUP" = 1 ]; then - mysql_note "MariaDB upgrade backup disabled due to \$MARIADB_DISABLE_UPGRADE_BACKUP=1 setting" - return - fi - local backup_db="system_mysql_backup_unknown_version.sql.zst" - local oldfullversion="unknown_version" - if [ -r "$DATADIR"/mariadb_upgrade_info ]; then - read -r -d '' oldfullversion < "$DATADIR"/mariadb_upgrade_info || true - if [ -n "$oldfullversion" ]; then - backup_db="system_mysql_backup_${oldfullversion}.sql.zst" - fi - fi - - mysql_note "Backing up system database to $backup_db" - if ! mariadb-dump --skip-lock-tables --replace --databases mysql --socket="${SOCKET}" | zstd > "${DATADIR}/${backup_db}"; then - mysql_error "Unable backup system database for upgrade from $oldfullversion." - fi - mysql_note "Backing up complete" -} - -# perform mariadb-upgrade -# backup the mysql database if this is a major upgrade -docker_mariadb_upgrade() { - if [ -z "$MARIADB_AUTO_UPGRADE" ] \ - || [ "$MARIADB_AUTO_UPGRADE" = 0 ]; then - mysql_note "MariaDB upgrade (mariadb-upgrade or creating healthcheck users) required, but skipped due to \$MARIADB_AUTO_UPGRADE setting" - return - fi - mysql_note "Starting temporary server" - docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start - mysql_note "Temporary server started." - - docker_mariadb_backup_system - - if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then - mysql_note "Creating healthcheck users" - local createHealthCheckUsers - createHealthCheckUsers=$(create_healthcheck_users) - docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL - -- Healthcheck users shouldn't be replicated - SET @@SESSION.SQL_LOG_BIN=0; - -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set - SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); - FLUSH PRIVILEGES; - $createHealthCheckUsers -EOSQL - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" - - if _check_if_upgrade_is_needed; then - # need a restart as FLUSH PRIVILEGES isn't reversable - mysql_note "Restarting temporary server for upgrade" - docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start - else - return 0 - fi - fi - - mysql_note "Starting mariadb-upgrade" - mariadb-upgrade --upgrade-system-tables - mysql_note "Finished mariadb-upgrade" - - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" -} - - -_check_if_upgrade_is_needed() { - if [ ! -f "$DATADIR"/mariadb_upgrade_info ]; then - mysql_note "MariaDB upgrade information missing, assuming required" - return 0 - fi - local mariadbVersion - mariadbVersion="$(_mariadb_version)" - IFS='.-' read -ra newversion <<<"$mariadbVersion" - IFS='.-' read -ra oldversion < "$DATADIR"/mariadb_upgrade_info || true - - if [[ ${#newversion[@]} -lt 2 ]] || [[ ${#oldversion[@]} -lt 2 ]] \ - || [[ ${oldversion[0]} -lt ${newversion[0]} ]] \ - || [[ ${oldversion[0]} -eq ${newversion[0]} && ${oldversion[1]} -lt ${newversion[1]} ]]; then - return 0 - fi - if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then - mysql_note "MariaDB heathcheck configation file missing, assuming desirable" - return 0 - fi - mysql_note "MariaDB upgrade not required" - return 1 -} - -# check arguments for an option that would cause mariadbd to stop -# return true if there is one -_mysql_want_help() { - local arg - for arg; do - case "$arg" in - -'?'|--help|--print-defaults|-V|--version) - return 0 - ;; - esac - done - return 1 -} - -_main() { - # if command starts with an option, prepend mariadbd - if [ "${1:0:1}" = '-' ]; then - set -- mariadbd "$@" - fi - - #ENDOFSUBSTITUTIONS - # skip setup if they aren't running mysqld or want an option that stops mysqld - if [ "$1" = 'mariadbd' ] || [ "$1" = 'mysqld' ] && ! _mysql_want_help "$@"; then - mysql_note "Entrypoint script for MariaDB Server ${MARIADB_VERSION} started." - - mysql_check_config "$@" - # Load various environment variables - docker_setup_env "$@" - docker_create_db_directories - - # If container is started as root user, restart as dedicated mysql user - if [ "$(id -u)" = "0" ]; then - mysql_note "Switching to dedicated user 'mysql'" - exec gosu mysql "${BASH_SOURCE[0]}" "$@" - fi - - # there's no database, so it needs to be initialized - if [ -z "$DATABASE_ALREADY_EXISTS" ]; then - docker_verify_minimum_env - - docker_mariadb_init "$@" - # MDEV-27636 mariadb_upgrade --check-if-upgrade-is-needed cannot be run offline - #elif mariadb-upgrade --check-if-upgrade-is-needed; then - elif _check_if_upgrade_is_needed; then - docker_mariadb_upgrade "$@" - fi - fi - exec "$@" -} - -# If we are sourced from elsewhere, don't perform any further actions -if ! _is_sourced; then - _main "$@" -fi diff --git a/11.1/healthcheck.sh b/11.1/healthcheck.sh deleted file mode 100755 index 4cee59c..0000000 --- a/11.1/healthcheck.sh +++ /dev/null @@ -1,388 +0,0 @@ -#!/bin/bash -# -# Healthcheck script for MariaDB -# -# Runs various tests on the MariaDB server to check its health. Pass the tests -# to run as arguments. If all tests succeed, the server is considered healthy, -# otherwise it's not. -# -# Arguments are processed in strict order. Set replication_* options before -# the --replication option. This allows a different set of replication checks -# on different connections. -# -# --su{=|-mysql} is option to run the healthcheck as a different unix user. -# Useful if mysql@localhost user exists with unix socket authentication -# Using this option disregards previous options set, so should usually be the -# first option. -# -# Some tests require SQL privileges. -# -# TEST MINIMUM GRANTS REQUIRED -# connect none* -# innodb_initialized USAGE -# innodb_buffer_pool_loaded USAGE -# galera_online USAGE -# galera_ready USAGE -# replication REPLICATION_CLIENT (<10.5)or REPLICA MONITOR (10.5+) -# mariadbupgrade none, however unix user permissions on datadir -# -# The SQL user used is the default for the mariadb client. This can be the unix user -# if no user(or password) is set in the [mariadb-client] section of a configuration -# file. --defaults-{file,extra-file,group-suffix} can specify a file/configuration -# different from elsewhere. -# -# Note * though denied error message will result in error log without -# any permissions. USAGE recommend to avoid this. - -set -eo pipefail - -_process_sql() -{ - mariadb ${nodefaults:+--no-defaults} \ - ${def['file']:+--defaults-file=${def['file']}} \ - ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ - ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ - --protocol socket \ - -B "$@" -} - -# TESTS - - -# CONNECT -# -# Tests that a connection can be made over TCP, the final state -# of the entrypoint and is listening. The authentication used -# isn't tested. -connect() -{ - local s - # short cut mechanism, to work with --require-secure-transport - s=$(_process_sql --skip-column-names -e 'select @@skip_networking') - case "$s" in - 0|1) - connect_s=$s - return "$s"; - ;; - esac - # falling back to tcp if there wasn't a connection answer. - s=$(mariadb ${nodefaults:+--no-defaults} \ - ${def['file']:+--defaults-file=${def['file']}} \ - ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ - ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ - -h localhost --protocol tcp \ - --skip-column-names --batch --skip-print-query-on-error \ - -e 'select @@skip_networking' 2>&1) - - case "$s" in - 1) # skip-networking=1 (no network) - ;& - ERROR\ 2002\ \(HY000\):*) - # cannot connect - connect_s=1 - ;; - 0) # skip-networking=0 - ;& - ERROR\ 1820\ \(HY000\)*) # password expire - ;& - ERROR\ 4151\ \(HY000\):*) # account locked - ;& - ERROR\ 1226\ \(42000\)*) # resource limit exceeded - ;& - ERROR\ 1[0-9][0-9][0-9]\ \(28000\):*) - # grep access denied and other 28000 client errors - we did connect - connect_s=0 - ;; - *) - >&2 echo "Unknown error $s" - connect_s=1 - ;; - esac - return $connect_s -} - -# INNODB_INITIALIZED -# -# This tests that the crash recovery of InnoDB has completed -# along with all the other things required to make it to a healthy -# operational state. Note this may return true in the early -# states of initialization. Use with a connect test to avoid -# these false positives. -innodb_initialized() -{ - local s - s=$(_process_sql --skip-column-names -e "select 1 from information_schema.ENGINES WHERE engine='innodb' AND support in ('YES', 'DEFAULT', 'ENABLED')") - [ "$s" == 1 ] -} - -# INNODB_BUFFER_POOL_LOADED -# -# Tests the load of the innodb buffer pool as been complete -# implies innodb_buffer_pool_load_at_startup=1 (default), or if -# manually SET innodb_buffer_pool_load_now=1 -innodb_buffer_pool_loaded() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='Innodb_buffer_pool_load_status'") - if [[ $s =~ 'load completed' ]]; then - return 0 - fi - return 1 -} - -# GALERA_ONLINE -# -# Tests that the galera node is in the SYNCed state -galera_online() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_LOCAL_STATE'") - # 4 from https://galeracluster.com/library/documentation/node-states.html#node-state-changes - # not https://xkcd.com/221/ - if [[ $s -eq 4 ]]; then - return 0 - fi - return 1 -} - -# GALERA_READY -# -# Tests that the Galera provider is ready. -galera_ready() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_READY'") - if [ "$s" = "ON" ]; then - return 0 - fi - return 1 -} - -# REPLICATION -# -# Tests the replication has the required set of functions: -# --replication_all -> Checks all replication sources -# --replication_name=n -> sets the multisource connection name tested -# --replication_io -> IO thread is running -# --replication_sql -> SQL thread is running -# --replication_seconds_behind_master=n -> less than or equal this seconds of delay -# --replication_sql_remaining_delay=n -> less than or equal this seconds of remaining delay -# (ref: https://mariadb.com/kb/en/delayed-replication/) -replication() -{ - # SHOW REPLICA available 10.5+ - # https://github.com/koalaman/shellcheck/issues/2383 - # shellcheck disable=SC2016,SC2026 - _process_sql -e "SHOW ${repl['all']:+all} REPLICA${repl['all']:+S} ${repl['name']:+'${repl['name']}'} STATUS\G" | \ - { - # required for trim of leading space. - shopt -s extglob - # Row header - read -t 5 -r - # read timeout - [ $? -gt 128 ] && return 1 - while IFS=":" read -t 1 -r n v; do - # Trim leading space - n=${n##+([[:space:]])} - # Leading space on all values by the \G format needs to be trimmed. - v=${v:1} - case "$n" in - Slave_IO_Running) - if [ -n "${repl['io']}" ] && [ "$v" = 'No' ]; then - return 1 - fi - ;; - Slave_SQL_Running) - if [ -n "${repl['sql']}" ] && [ "$v" = 'No' ]; then - return 1 - fi - ;; - Seconds_Behind_Master) - # A NULL value is the IO thread not running: - if [ -n "${repl['seconds_behind_master']}" ] && - { [ "$v" = NULL ] || - (( "${repl['seconds_behind_master']}" < "$v" )); }; then - return 1 - fi - ;; - SQL_Remaining_Delay) - # Unlike Seconds_Behind_Master, sql_remaining_delay will hit NULL - # once replication is caught up - https://mariadb.com/kb/en/delayed-replication/ - if [ -n "${repl['sql_remaining_delay']}" ] && - [ "$v" != NULL ] && - (( "${repl['sql_remaining_delay']}" < "$v" )); then - return 1 - fi - ;; - esac - done - # read timeout - [ $? -gt 128 ] && return 1 - return 0 - } - # reachable in command not found(?) - # shellcheck disable=SC2317 - return $? -} - -# mariadbupgrade -# -# Test the lock on the file $datadir/mariadb_upgrade_info -# https://jira.mariadb.org/browse/MDEV-27068 -mariadbupgrade() -{ - local f="$datadir/mariadb_upgrade_info" - if [ -r "$f" ]; then - flock --exclusive --nonblock -n 9 9<"$f" - return $? - fi - return 0 -} - - -# MAIN - -if [ $# -eq 0 ]; then - echo "At least one argument required" >&2 - exit 1 -fi - -#ENDOFSUBSTITUTIONS -# Marks the end of mysql -> mariadb name changes in 10.6+ -# Global variables used by tests -declare -A repl -declare -A def -nodefaults= -connect_s= -datadir=/var/lib/mysql -if [ -f $datadir/.my-healthcheck.cnf ]; then - def['extra_file']=$datadir/.my-healthcheck.cnf -fi - -_repl_param_check() -{ - case "$1" in - seconds_behind_master) ;& - sql_remaining_delay) - if [ -z "${repl['io']}" ]; then - repl['io']=1 - echo "Forcing --replication_io=1, $1 requires IO thread to be running" >&2 - fi - ;; - all) - if [ -n "${repl['name']}" ]; then - unset 'repl[name]' - echo "Option --replication_all incompatible with specified source --replication_name, clearing replication_name" >&2 - fi - ;; - name) - if [ -n "${repl['all']}" ]; then - unset 'repl[all]' - echo "Option --replication_name incompatible with --replication_all, clearing replication_all" >&2 - fi - ;; - esac -} - -_test_exists() { - declare -F "$1" > /dev/null - return $? -} - -while [ $# -gt 0 ]; do - case "$1" in - --su=*) - u="${1#*=}" - shift - exec gosu "${u}" "${BASH_SOURCE[0]}" "$@" - ;; - --su) - shift - u=$1 - shift - exec gosu "$u" "${BASH_SOURCE[0]}" "$@" - ;; - --su-mysql) - shift - exec gosu mysql "${BASH_SOURCE[0]}" "$@" - ;; - --replication_*=*) - # Change the n to what is between _ and = and make lower case - n=${1#*_} - n=${n%%=*} - n=${n,,*} - # v is after the = - v=${1#*=} - repl[$n]=$v - _repl_param_check "$n" - ;; - --replication_*) - # Without =, look for a non --option next as the value, - # otherwise treat it as an "enable", just equate to 1. - # Clearing option is possible with "--replication_X=" - n=${1#*_} - n=${n,,*} - if [ "${2:0:2}" == '--' ]; then - repl[$n]=1 - else - repl[$n]=$2 - shift - fi - _repl_param_check "$n" - ;; - --datadir=*) - datadir=${1#*=} - ;; - --datadir) - shift - datadir=${1} - ;; - --no-defaults) - def=() - nodefaults=1 - ;; - --defaults-file=*|--defaults-extra-file=*|--defaults-group-suffix=*) - n=${1:11} # length --defaults- - n=${n%%=*} - n=${n//-/_} - # v is after the = - v=${1#*=} - def[$n]=$v - nodefaults= - ;; - --defaults-file|--defaults-extra-file|--defaults-group-suffix) - n=${1:11} # length --defaults- - n=${n//-/_} - if [ "${2:0:2}" == '--' ]; then - def[$n]="" - else - def[$n]=$2 - shift - fi - nodefaults= - ;; - --*) - test=${1#--} - ;; - *) - echo "Unknown healthcheck option $1" >&2 - exit 1 - esac - if [ -n "$test" ]; then - if ! _test_exists "$test" ; then - echo "healthcheck unknown option or test '$test'" >&2 - exit 1 - elif ! "$test"; then - echo "healthcheck $test failed" >&2 - exit 1 - fi - test= - fi - shift -done -if [ "$connect_s" != "0" ]; then - # we didn't pass a connnect test, so the current success status is suspicious - # return what connect thinks. - connect - exit $? -fi diff --git a/update.sh b/update.sh index 4055f78..d71f517 100755 --- a/update.sh +++ b/update.sh @@ -11,8 +11,6 @@ declare -A suites=( [10.5]='focal' [10.6]='focal' [10.11]='jammy' - [11.0]='jammy' - [11.1]='jammy' [11.2]='jammy' ) @@ -140,17 +138,13 @@ update_version() -e '/^ENV MARIADB_MAJOR/d' \ -e 's/-\$MARIADB_MAJOR//' \ "$dir/Dockerfile" - if [[ $vmin =~ 11.[12] ]]; then + if [ "$vmin" = 11.2 ]; then sed -i -e '/--skip-ssl/d' \ "$dir/docker-entrypoint.sh" "$dir/healthcheck.sh" sed -i -e 's/ && userdel.*//' \ "$dir/Dockerfile" fi - if [ "$vmin" == 11.1 ]; then - sed -i -e 's/50-mysqld_safe.cnf/50-mariadb_safe.cnf/' "$dir/Dockerfile" - else - sed -i -e 's/ \/[^ ]*50-mysqld_safe.cnf//' "$dir/Dockerfile" - fi + sed -i -e 's/ \/[^ ]*50-mysqld_safe.cnf//' "$dir/Dockerfile" ;& esac diff --git a/versions.json b/versions.json index 6d21183..30d3540 100644 --- a/versions.json +++ b/versions.json @@ -41,20 +41,6 @@ "s390x" ] }, - "11.1": { - "milestone": "11.1", - "version": "11.1.6", - "fullVersion": "1:11.1.6+maria~ubu2204", - "releaseStatus": "Stable", - "supportType": "Short Term Support", - "base": "ubuntu:jammy", - "arches": [ - "amd64", - "arm64v8", - "ppc64le", - "s390x" - ] - }, "10.11": { "milestone": "10.11", "version": "10.11.9", From 51412843942dd3f5ded1f3b5e78f6c7420c48fc4 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 16 Sep 2024 17:39:47 +1000 Subject: [PATCH 05/21] main: 11.7 currently --- main-ubi/Dockerfile | 6 +++--- main-ubi/docker-entrypoint.sh | 2 +- main/Dockerfile | 6 +++--- main/docker-entrypoint.sh | 2 +- update.sh | 3 ++- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/main-ubi/Dockerfile b/main-ubi/Dockerfile index 7be4e69..c4c7b7b 100644 --- a/main-ubi/Dockerfile +++ b/main-ubi/Dockerfile @@ -36,7 +36,7 @@ COPY MariaDB.repo /etc/yum.repos.d/ # https://access.redhat.com/documentation/en-us/red_hat_software_certification/2024/html/red_hat_openshift_software_certification_policy_guide/assembly-requirements-for-container-images_openshift-sw-cert-policy-introduction#con-image-metadata-requirements_openshift-sw-cert-policy-container-images LABEL name="MariaDB Server" \ vendor="MariaDB Community" \ - version="main.0" \ + version="11.7.0" \ release="Refer to Annotations org.opencontainers.image.{revision,source}" \ summary="MariaDB Database" \ description="MariaDB Database for relational SQL" @@ -50,11 +50,11 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="main.0" \ + org.opencontainers.image.version="11.7.0" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=main.0 +ARG MARIADB_VERSION=11.7.0 ENV MARIADB_VERSION=$MARIADB_VERSION # release-status:Alpha # release-support-type:Unknown diff --git a/main-ubi/docker-entrypoint.sh b/main-ubi/docker-entrypoint.sh index 6e27486..1ae157e 100755 --- a/main-ubi/docker-entrypoint.sh +++ b/main-ubi/docker-entrypoint.sh @@ -224,7 +224,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "main.0-MariaDB" + echo -n "11.7.0-MariaDB" } # initializes the database directory diff --git a/main/Dockerfile b/main/Dockerfile index 3ccc1c0..4e59706 100644 --- a/main/Dockerfile +++ b/main/Dockerfile @@ -75,18 +75,18 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="main.0" \ + org.opencontainers.image.version="11.7.0" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=1:main.0+maria~ubu2404 +ARG MARIADB_VERSION=1:11.7.0+maria~ubu2404 ENV MARIADB_VERSION $MARIADB_VERSION # release-status:Alpha # release-support-type:Unknown # (https://downloads.mariadb.org/rest-api/mariadb/) # Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions -ARG REPOSITORY="http://archive.mariadb.org/mariadb-main.0/repo/ubuntu/ noble main main/debug" +ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.7.0/repo/ubuntu/ noble main main/debug" RUN set -e;\ echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ diff --git a/main/docker-entrypoint.sh b/main/docker-entrypoint.sh index 6e27486..1ae157e 100755 --- a/main/docker-entrypoint.sh +++ b/main/docker-entrypoint.sh @@ -224,7 +224,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "main.0-MariaDB" + echo -n "11.7.0-MariaDB" } # initializes the database directory diff --git a/update.sh b/update.sh index d71f517..2ca1477 100755 --- a/update.sh +++ b/update.sh @@ -5,6 +5,7 @@ set -Eeuo pipefail # development_version=main +development_version_real=11.7 defaultSuite='noble' declare -A suites=( @@ -204,7 +205,7 @@ in_development() releaseStatus=Alpha supportType=Unknown version=$development_version - mariaVersion=${development_version}.0 + mariaVersion=${development_version_real}.0 update_version } From 70d5dbb8052e1d67f69ac25783537afd457afa34 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Wed, 4 Sep 2024 13:44:06 +1000 Subject: [PATCH 06/21] MDEV-34943 Disable replication start on initialization START REPLIA was issued during initializing which mean that even before /docker-entrypoint/initdb.d there was initializtion going on. Entrypoints that needed data initialzation didn't complete with this nicely. Also if there wasn't any initialization there would be little time for the replication to acheive anything before being shutdown ready for the final start. Moved --skip-slave-start to the default docker_temp_server_start implementation. Technically this is a compaibility break that is likely to be of significants if: * /docker-entrypoint/initdb.d contains a script waiting for replication to catch up. The recitifcation to the previous behaviour is: /docker-entrypoint/initdb.d contains a SQL to START REPLICA. Recommend also having another script that is: until healthcheck.sh --replication_io \ --replication_sql \ --replication_seconds_behind_master=0 \ --replication --no-connect; do sleep 1 done Closes #614 --- 10.11-ubi/docker-entrypoint.sh | 10 +++------- 10.11/docker-entrypoint.sh | 10 +++------- 10.5/docker-entrypoint.sh | 10 +++------- 10.6-ubi/docker-entrypoint.sh | 10 +++------- 10.6/docker-entrypoint.sh | 10 +++------- 11.2/docker-entrypoint.sh | 10 +++------- 11.4-ubi/docker-entrypoint.sh | 10 +++------- 11.4/docker-entrypoint.sh | 10 +++------- docker-entrypoint.sh | 10 +++------- main-ubi/docker-entrypoint.sh | 10 +++------- main/docker-entrypoint.sh | 10 +++------- 11 files changed, 33 insertions(+), 77 deletions(-) diff --git a/10.11-ubi/docker-entrypoint.sh b/10.11-ubi/docker-entrypoint.sh index df95a14..7f77ab4 100755 --- a/10.11-ubi/docker-entrypoint.sh +++ b/10.11-ubi/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ & declare -g MARIADB_PID @@ -458,7 +459,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -471,7 +471,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -502,7 +501,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -598,8 +596,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -624,8 +621,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi diff --git a/10.11/docker-entrypoint.sh b/10.11/docker-entrypoint.sh index df95a14..7f77ab4 100755 --- a/10.11/docker-entrypoint.sh +++ b/10.11/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ & declare -g MARIADB_PID @@ -458,7 +459,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -471,7 +471,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -502,7 +501,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -598,8 +596,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -624,8 +621,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi diff --git a/10.5/docker-entrypoint.sh b/10.5/docker-entrypoint.sh index f4e5515..ea26650 100755 --- a/10.5/docker-entrypoint.sh +++ b/10.5/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ & declare -g MARIADB_PID @@ -449,7 +450,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -462,7 +462,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -493,7 +492,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -589,8 +587,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -615,8 +612,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi diff --git a/10.6-ubi/docker-entrypoint.sh b/10.6-ubi/docker-entrypoint.sh index 3c8debb..4ff446e 100755 --- a/10.6-ubi/docker-entrypoint.sh +++ b/10.6-ubi/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ & declare -g MARIADB_PID @@ -450,7 +451,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -463,7 +463,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -494,7 +493,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -590,8 +588,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -616,8 +613,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi diff --git a/10.6/docker-entrypoint.sh b/10.6/docker-entrypoint.sh index 3c8debb..4ff446e 100755 --- a/10.6/docker-entrypoint.sh +++ b/10.6/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ & declare -g MARIADB_PID @@ -450,7 +451,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -463,7 +463,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -494,7 +493,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -590,8 +588,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -616,8 +613,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi diff --git a/11.2/docker-entrypoint.sh b/11.2/docker-entrypoint.sh index 80764f1..ea7eb70 100755 --- a/11.2/docker-entrypoint.sh +++ b/11.2/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ & declare -g MARIADB_PID @@ -458,7 +459,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -471,7 +471,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -502,7 +501,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -598,8 +596,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -624,8 +621,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi diff --git a/11.4-ubi/docker-entrypoint.sh b/11.4-ubi/docker-entrypoint.sh index 243c430..1192a4a 100755 --- a/11.4-ubi/docker-entrypoint.sh +++ b/11.4-ubi/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ & @@ -460,7 +461,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -473,7 +473,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -504,7 +503,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -600,8 +598,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -626,8 +623,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi diff --git a/11.4/docker-entrypoint.sh b/11.4/docker-entrypoint.sh index 243c430..1192a4a 100755 --- a/11.4/docker-entrypoint.sh +++ b/11.4/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ & @@ -460,7 +461,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -473,7 +473,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -504,7 +503,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -600,8 +598,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -626,8 +623,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 4b1a3be..1cab70d 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ & @@ -460,7 +461,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -473,7 +473,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -504,7 +503,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -600,8 +598,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -626,8 +623,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi diff --git a/main-ubi/docker-entrypoint.sh b/main-ubi/docker-entrypoint.sh index 1ae157e..d3bf557 100755 --- a/main-ubi/docker-entrypoint.sh +++ b/main-ubi/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ & @@ -460,7 +461,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -473,7 +473,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -504,7 +503,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -600,8 +598,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -626,8 +623,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi diff --git a/main/docker-entrypoint.sh b/main/docker-entrypoint.sh index 1ae157e..d3bf557 100755 --- a/main/docker-entrypoint.sh +++ b/main/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ & @@ -460,7 +461,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -473,7 +473,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -504,7 +503,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -600,8 +598,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -626,8 +623,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi From 4540d625156ec58dd3b2babfc84dd8c41ad91252 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 17 Sep 2024 17:26:03 +1000 Subject: [PATCH 07/21] healthcheck.sh add --no-connect option There is an implicit --connect option in healthcheck so that a normal use can be sure MariaDB is running on a tcp socket. There is a case in /docker-entrypoint-initdb.d where its desirable to perform healthchecks for components without a --connect. In this case, use --no-connect in the healthcheck to avoid an implicit --connect test. --- 10.11-ubi/healthcheck.sh | 5 +++++ 10.11/healthcheck.sh | 5 +++++ 10.5/healthcheck.sh | 5 +++++ 10.6-ubi/healthcheck.sh | 5 +++++ 10.6/healthcheck.sh | 5 +++++ 11.2/healthcheck.sh | 5 +++++ 11.4-ubi/healthcheck.sh | 5 +++++ 11.4/healthcheck.sh | 5 +++++ healthcheck.sh | 5 +++++ main-ubi/healthcheck.sh | 5 +++++ main/healthcheck.sh | 5 +++++ 11 files changed, 55 insertions(+) diff --git a/10.11-ubi/healthcheck.sh b/10.11-ubi/healthcheck.sh index c0fb93b..07b4fe3 100755 --- a/10.11-ubi/healthcheck.sh +++ b/10.11-ubi/healthcheck.sh @@ -361,6 +361,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; diff --git a/10.11/healthcheck.sh b/10.11/healthcheck.sh index c0fb93b..07b4fe3 100755 --- a/10.11/healthcheck.sh +++ b/10.11/healthcheck.sh @@ -361,6 +361,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; diff --git a/10.5/healthcheck.sh b/10.5/healthcheck.sh index d925ed5..8f91a55 100755 --- a/10.5/healthcheck.sh +++ b/10.5/healthcheck.sh @@ -361,6 +361,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; diff --git a/10.6-ubi/healthcheck.sh b/10.6-ubi/healthcheck.sh index c0fb93b..07b4fe3 100755 --- a/10.6-ubi/healthcheck.sh +++ b/10.6-ubi/healthcheck.sh @@ -361,6 +361,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; diff --git a/10.6/healthcheck.sh b/10.6/healthcheck.sh index c0fb93b..07b4fe3 100755 --- a/10.6/healthcheck.sh +++ b/10.6/healthcheck.sh @@ -361,6 +361,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; diff --git a/11.2/healthcheck.sh b/11.2/healthcheck.sh index 4cee59c..dcc4db2 100755 --- a/11.2/healthcheck.sh +++ b/11.2/healthcheck.sh @@ -361,6 +361,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; diff --git a/11.4-ubi/healthcheck.sh b/11.4-ubi/healthcheck.sh index ad0b17f..62be345 100755 --- a/11.4-ubi/healthcheck.sh +++ b/11.4-ubi/healthcheck.sh @@ -363,6 +363,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; diff --git a/11.4/healthcheck.sh b/11.4/healthcheck.sh index ad0b17f..62be345 100755 --- a/11.4/healthcheck.sh +++ b/11.4/healthcheck.sh @@ -363,6 +363,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; diff --git a/healthcheck.sh b/healthcheck.sh index ad0b17f..62be345 100755 --- a/healthcheck.sh +++ b/healthcheck.sh @@ -363,6 +363,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; diff --git a/main-ubi/healthcheck.sh b/main-ubi/healthcheck.sh index ad0b17f..62be345 100755 --- a/main-ubi/healthcheck.sh +++ b/main-ubi/healthcheck.sh @@ -363,6 +363,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; diff --git a/main/healthcheck.sh b/main/healthcheck.sh index ad0b17f..62be345 100755 --- a/main/healthcheck.sh +++ b/main/healthcheck.sh @@ -363,6 +363,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; From 12c877197f55de561614a82cd275c1219b9d60ce Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 19 Sep 2024 16:43:28 +1000 Subject: [PATCH 08/21] Replication fix - updates for 11.6 --- 11.5-ubi/Dockerfile | 113 ------ 11.5-ubi/MariaDB.repo | 7 - 11.5-ubi/docker-entrypoint.sh | 722 ---------------------------------- 11.5-ubi/docker.cnf | 15 - 11.5-ubi/healthcheck.sh | 390 ------------------ 11.5/Dockerfile | 142 ------- 11.5/docker-entrypoint.sh | 722 ---------------------------------- 11.5/healthcheck.sh | 390 ------------------ 11.6-ubi/docker-entrypoint.sh | 10 +- 11.6-ubi/healthcheck.sh | 5 + 11.6/docker-entrypoint.sh | 10 +- 11.6/healthcheck.sh | 5 + 12 files changed, 16 insertions(+), 2515 deletions(-) delete mode 100644 11.5-ubi/Dockerfile delete mode 100644 11.5-ubi/MariaDB.repo delete mode 100755 11.5-ubi/docker-entrypoint.sh delete mode 100644 11.5-ubi/docker.cnf delete mode 100755 11.5-ubi/healthcheck.sh delete mode 100644 11.5/Dockerfile delete mode 100755 11.5/docker-entrypoint.sh delete mode 100755 11.5/healthcheck.sh diff --git a/11.5-ubi/Dockerfile b/11.5-ubi/Dockerfile deleted file mode 100644 index 32355e7..0000000 --- a/11.5-ubi/Dockerfile +++ /dev/null @@ -1,113 +0,0 @@ -FROM redhat/ubi9-minimal - -# user 999/ group 999, that we want to use for compatibility with the ubuntu image. -RUN groupadd --gid 999 -r mysql && \ - useradd -r -g mysql mysql --home-dir /var/lib/mysql --uid 999 - -ENV GOSU_VERSION 1.17 -RUN set -eux; \ - rpmArch="$(rpm --query --queryformat='%{ARCH}' rpm)"; \ - case "$rpmArch" in \ - aarch64) dpkgArch='arm64' ;; \ - armv7*) dpkgArch='armhf' ;; \ - i686) dpkgArch='i386' ;; \ - ppc64le) dpkgArch='ppc64el' ;; \ - s390x|riscv64) dpkgArch=$rpmArch ;; \ - x86_64) dpkgArch='amd64' ;; \ - *) echo >&2 "error: unknown/unsupported architecture '$rpmArch'"; exit 1 ;; \ - esac; \ - curl --fail --location --output /usr/local/bin/gosu https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${dpkgArch} ; \ - curl --fail --location --output /usr/local/bin/gosu.asc https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${dpkgArch}.asc; \ - GNUPGHOME="$(mktemp -d)"; \ - export GNUPGHOME; \ - gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ - chmod a+x /usr/local/bin/gosu; \ - gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ - gpgconf --kill all; \ - rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ - gosu --version; \ - gosu nobody true - -COPY --chmod=0644 docker.cnf /etc/my.cnf.d/ - -COPY MariaDB.repo /etc/yum.repos.d/ - -# HasRequiredLabel requirement from Red Hat OpenShift Software Certification -# https://access.redhat.com/documentation/en-us/red_hat_software_certification/2024/html/red_hat_openshift_software_certification_policy_guide/assembly-requirements-for-container-images_openshift-sw-cert-policy-introduction#con-image-metadata-requirements_openshift-sw-cert-policy-container-images -LABEL name="MariaDB Server" \ - vendor="MariaDB Community" \ - version="11.5.2" \ - release="Refer to Annotations org.opencontainers.image.{revision,source}" \ - summary="MariaDB Database" \ - description="MariaDB Database for relational SQL" - -# OCI annotations to image -LABEL org.opencontainers.image.authors="MariaDB Community" \ - org.opencontainers.image.title="MariaDB Database" \ - org.opencontainers.image.description="MariaDB Database for relational SQL" \ - org.opencontainers.image.documentation="https://hub.docker.com/_/mariadb/" \ - org.opencontainers.image.base.name="docker.io/redhat/ubi9-minimal" \ - org.opencontainers.image.licenses="GPL-2.0" \ - org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ - org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="11.5.2" \ - org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" - -# bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=11.5.2 -ENV MARIADB_VERSION=$MARIADB_VERSION -# release-status:Stable -# release-support-type:Short Term Support -# (https://downloads.mariadb.org/rest-api/mariadb/) - -# missing pwgen(epel), jemalloc(epel) (as entrypoint/user extensions) -# procps, pv(epel) - missing dependencies of galera sst script -# tzdata re-installed as only a fake version is part of the ubi-minimal base image. -# FF8AD1344597106ECE813B918A3872BF3228467C is the Fedora RPM key -# 177F4010FE56CA3336300305F1656F24C74CD1D8 is the MariaDB Server RPM key -RUN set -eux ; \ - curl --fail https://pagure.io/fedora-web/websites/raw/master/f/sites/getfedora.org/static/keys/FF8AD1344597106ECE813B918A3872BF3228467C.txt --output /tmp/epelkey.txt ; \ - GNUPGHOME="$(mktemp -d)"; export GNUPGHOME ; \ - gpg --batch --import /tmp/epelkey.txt ; \ - gpg --batch --armor --export FF8AD1344597106ECE813B918A3872BF3228467C > /tmp/epelkey.txt ; \ - rpmkeys --import /tmp/epelkey.txt ; \ - curl --fail https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm --output /tmp/epel-release-latest-9.noarch.rpm ; \ - rpm -K /tmp/epel-release-latest-9.noarch.rpm ; \ - rpm -ivh /tmp/epel-release-latest-9.noarch.rpm ; \ - rm /tmp/epelkey.txt /tmp/epel-release-latest-9.noarch.rpm ; \ - curl --fail https://supplychain.mariadb.com/MariaDB-Server-GPG-KEY --output /tmp/MariaDB-Server-GPG-KEY ; \ - gpg --batch --import /tmp/MariaDB-Server-GPG-KEY; \ - gpg --batch --armor --export 177F4010FE56CA3336300305F1656F24C74CD1D8 > /tmp/MariaDB-Server-GPG-KEY ; \ - rpmkeys --import /tmp/MariaDB-Server-GPG-KEY ; \ - rm -rf "$GNUPGHOME" /tmp/MariaDB-Server-GPG-KEY ; \ - unset GNUPGHOME ; \ - microdnf update -y ; \ - microdnf reinstall -y tzdata ; \ - microdnf install -y procps-ng zstd xz jemalloc pwgen pv ; \ - mkdir -p /etc/mysql/conf.d /etc/mysql/mariadb.conf.d/ /var/lib/mysql/mysql /run/mariadb /usr/lib64/galera ; \ - chmod ugo+rwx,o+t /run/mariadb ; \ - microdnf install -y MariaDB-backup-${MARIADB_VERSION} MariaDB-server-${MARIADB_VERSION} ; \ - # compatibility with DEB Galera packaging - ln -s /usr/lib64/galera-4/libgalera_smm.so /usr/lib/libgalera_smm.so ; \ - # compatibility with RPM Galera packaging - ln -s /usr/lib64/galera-4/libgalera_smm.so /usr/lib64/galera/libgalera_smm.so ; \ - microdnf clean all ; \ - rmdir /var/lib/mysql/mysql ; \ - chown -R mysql:mysql /var/lib/mysql /run/mariadb ; \ - mkdir /licenses ; \ - ln -s /usr/share/doc/MariaDB-server-${MARIADB_VERSION}/COPYING /licenses/GPL-2 ; \ - ln -s /usr/share/licenses /licenses/package-licenses ; \ - ln -s Apache-2.0-license /licenses/gosu - -VOLUME /var/lib/mysql - -RUN mkdir /docker-entrypoint-initdb.d - -COPY healthcheck.sh /usr/local/bin/healthcheck.sh -COPY docker-entrypoint.sh /usr/local/bin/ - -ENTRYPOINT ["docker-entrypoint.sh"] - -USER mysql -EXPOSE 3306 -CMD ["mariadbd"] diff --git a/11.5-ubi/MariaDB.repo b/11.5-ubi/MariaDB.repo deleted file mode 100644 index 777b623..0000000 --- a/11.5-ubi/MariaDB.repo +++ /dev/null @@ -1,7 +0,0 @@ -[mariadb] -name = MariaDB -#baseurl = https://rpm.mariadb.org/11.5/rhel/$releasever/$basearch -baseurl = https://archive.mariadb.org/mariadb-11.5/yum/rhel/$releasever/$basearch -#microdnf cannot read to the second key here. -#gpgkey=https://archive.mariadb.org/PublicKey -gpgcheck=1 diff --git a/11.5-ubi/docker-entrypoint.sh b/11.5-ubi/docker-entrypoint.sh deleted file mode 100755 index 5e54494..0000000 --- a/11.5-ubi/docker-entrypoint.sh +++ /dev/null @@ -1,722 +0,0 @@ -#!/bin/bash -set -eo pipefail -shopt -s nullglob - -# logging functions -mysql_log() { - local type="$1"; shift - printf '%s [%s] [Entrypoint]: %s\n' "$(date --rfc-3339=seconds)" "$type" "$*" -} -mysql_note() { - mysql_log Note "$@" -} -mysql_warn() { - mysql_log Warn "$@" >&2 -} -mysql_error() { - mysql_log ERROR "$@" >&2 - exit 1 -} - -# usage: file_env VAR [DEFAULT] -# ie: file_env 'XYZ_DB_PASSWORD' 'example' -# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of -# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) -file_env() { - local var="$1" - local fileVar="${var}_FILE" - local def="${2:-}" - if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then - mysql_error "Both $var and $fileVar are set (but are exclusive)" - fi - local val="$def" - if [ "${!var:-}" ]; then - val="${!var}" - elif [ "${!fileVar:-}" ]; then - val="$(< "${!fileVar}")" - fi - export "$var"="$val" - unset "$fileVar" -} - -# set MARIADB_xyz from MYSQL_xyz when MARIADB_xyz is unset -# and make them the same value (so user scripts can use either) -_mariadb_file_env() { - local var="$1"; shift - local maria="MARIADB_${var#MYSQL_}" - file_env "$var" "$@" - file_env "$maria" "${!var}" - if [ "${!maria:-}" ]; then - export "$var"="${!maria}" - fi -} - -# check to see if this file is being run or sourced from another script -_is_sourced() { - # https://unix.stackexchange.com/a/215279 - [ "${#FUNCNAME[@]}" -ge 2 ] \ - && [ "${FUNCNAME[0]}" = '_is_sourced' ] \ - && [ "${FUNCNAME[1]}" = 'source' ] -} - -# usage: docker_process_init_files [file [file [...]]] -# ie: docker_process_init_files /always-initdb.d/* -# process initializer files, based on file extensions -docker_process_init_files() { - # mysql here for backwards compatibility "${mysql[@]}" - # ShellCheck: mysql appears unused. Verify use (or export if used externally) - # shellcheck disable=SC2034 - mysql=( docker_process_sql ) - - echo - local f - for f; do - case "$f" in - *.sh) - # https://github.com/docker-library/postgres/issues/450#issuecomment-393167936 - # https://github.com/docker-library/postgres/pull/452 - if [ -x "$f" ]; then - mysql_note "$0: running $f" - "$f" - else - mysql_note "$0: sourcing $f" - # ShellCheck can't follow non-constant source. Use a directive to specify location. - # shellcheck disable=SC1090 - . "$f" - fi - ;; - *.sql) mysql_note "$0: running $f"; docker_process_sql < "$f"; echo ;; - *.sql.gz) mysql_note "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;; - *.sql.xz) mysql_note "$0: running $f"; xzcat "$f" | docker_process_sql; echo ;; - *.sql.zst) mysql_note "$0: running $f"; zstd -dc "$f" | docker_process_sql; echo ;; - *) mysql_warn "$0: ignoring $f" ;; - esac - echo - done -} - -# arguments necessary to run "mariadbd --verbose --help" successfully (used for testing configuration validity and for extracting default/configured values) -_verboseHelpArgs=( - --verbose --help -) - -mysql_check_config() { - local toRun=( "$@" "${_verboseHelpArgs[@]}" ) errors - if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then - mysql_error $'mariadbd failed while attempting to check config\n\tcommand was: '"${toRun[*]}"$'\n\t'"$errors" - fi -} - -# Fetch value from server config -# We use mariadbd --verbose --help instead of my_print_defaults because the -# latter only show values present in config files, and not server defaults -mysql_get_config() { - local conf="$1"; shift - "$@" "${_verboseHelpArgs[@]}" 2>/dev/null \ - | awk -v conf="$conf" '$1 == conf && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }' - # match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)" -} - -# Do a temporary startup of the MariaDB server, for init purposes -docker_temp_server_start() { - "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ - --expire-logs-days=0 \ - --loose-innodb_buffer_pool_load_at_startup=0 \ - --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ - & - declare -g MARIADB_PID - MARIADB_PID=$! - mysql_note "Waiting for server startup" - # only use the root password if the database has already been initialized - # so that it won't try to fill in a password file when it hasn't been set yet - extraArgs=() - if [ -z "$DATABASE_ALREADY_EXISTS" ]; then - extraArgs+=( '--dont-use-mysql-root-password' ) - fi - local i - for i in {30..0}; do - if docker_process_sql "${extraArgs[@]}" --database=mysql \ - --skip-ssl --skip-ssl-verify-server-cert \ - <<<'SELECT 1' &> /dev/null; then - break - fi - sleep 1 - done - if [ "$i" = 0 ]; then - mysql_error "Unable to start server." - fi -} - -# Stop the server. When using a local socket file mariadb-admin will block until -# the shutdown is complete. -docker_temp_server_stop() { - kill "$MARIADB_PID" - wait "$MARIADB_PID" -} - -# Verify that the minimally required password settings are set for new databases. -docker_verify_minimum_env() { - # Restoring from backup requires no environment variables - declare -g DATABASE_INIT_FROM_BACKUP - for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do - if [ -f "${file}" ]; then - DATABASE_INIT_FROM_BACKUP='true' - return - fi - done - if [ -z "$MARIADB_ROOT_PASSWORD" ] && [ -z "$MARIADB_ROOT_PASSWORD_HASH" ] && [ -z "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] && [ -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then - mysql_error $'Database is uninitialized and password option is not specified\n\tYou need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ROOT_PASSWORD_HASH, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' - fi - # More preemptive exclusions of combinations should have been made before *PASSWORD_HASH was added, but for now we don't enforce due to compatibility. - if [ -n "$MARIADB_ROOT_PASSWORD" ] || [ -n "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] || [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ] && [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then - mysql_error "Cannot specify MARIADB_ROOT_PASSWORD_HASH and another MARIADB_ROOT_PASSWORD* option." - fi - if [ -n "$MARIADB_PASSWORD" ] && [ -n "$MARIADB_PASSWORD_HASH" ]; then - mysql_error "Cannot specify MARIADB_PASSWORD_HASH and MARIADB_PASSWORD option." - fi - if [ -n "$MARIADB_REPLICATION_USER" ]; then - if [ -z "$MARIADB_MASTER_HOST" ]; then - # its a master, we're creating a user - if [ -z "$MARIADB_REPLICATION_PASSWORD" ] && [ -z "$MARIADB_REPLICATION_PASSWORD_HASH" ]; then - mysql_error "MARIADB_REPLICATION_PASSWORD or MARIADB_REPLICATION_PASSWORD_HASH not found to create replication user for master" - fi - else - # its a replica - if [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; then - mysql_error "MARIADB_REPLICATION_PASSWORD is mandatory to specify the replication on the replica image." - fi - if [ -n "$MARIADB_REPLICATION_PASSWORD_HASH" ] ; then - mysql_warn "MARIADB_REPLICATION_PASSWORD_HASH cannot be specified on a replica" - fi - fi - fi - if [ -n "$MARIADB_MASTER_HOST" ] && { [ -z "$MARIADB_REPLICATION_USER" ] || [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; }; then - mysql_error "For a replica, MARIADB_REPLICATION_USER and MARIADB_REPLICATION is mandatory." - fi -} - -# creates folders for the database -# also ensures permission for user mysql of run as root -docker_create_db_directories() { - local user; user="$(id -u)" - - # TODO other directories that are used by default? like /var/lib/mysql-files - # see https://github.com/docker-library/mysql/issues/562 - mkdir -p "$DATADIR" - - if [ "$user" = "0" ]; then - # this will cause less disk access than `chown -R` - find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) - # See https://github.com/MariaDB/mariadb-docker/issues/363 - if [ "${SOCKET:0:1}" != '@' ]; then # not abstract sockets - find "${SOCKET%/*}" -maxdepth 0 \! -user mysql \( -exec chown mysql: '{}' \; -o -true \) - fi - - # memory.pressure - local cgroup; cgroup=$( "$DATADIR"/.my-healthcheck.cnf - $maskPreserve -} - -# Initializes database with timezone info and root password, plus optional extra db/user -docker_setup_db() { - # Load timezone info into database - if [ -z "$MARIADB_INITDB_SKIP_TZINFO" ]; then - # --skip-write-binlog usefully disables binary logging - # but also outputs LOCK TABLES to improve the IO of - # Aria (MDEV-23326) for 10.4+. - mariadb-tzinfo-to-sql --skip-write-binlog /usr/share/zoneinfo \ - | docker_process_sql --dont-use-mysql-root-password --database=mysql - # tell docker_process_sql to not use MYSQL_ROOT_PASSWORD since it is not set yet - fi - # Generate random root password - if [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then - MARIADB_ROOT_PASSWORD="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" - export MARIADB_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=$MARIADB_ROOT_PASSWORD - mysql_note "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD" - fi - - # Creates root users for non-localhost hosts - local rootCreate= - local rootPasswordEscaped= - if [ -n "$MARIADB_ROOT_PASSWORD" ]; then - # Sets root password and creates root users for non-localhost hosts - rootPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}") - fi - - # default root to listen for connections from anywhere - if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then - # ref "read -d ''", no, we don't care if read finds a terminating character in this heredoc - # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 - if [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then - read -r -d '' rootCreate <<-EOSQL || true - CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY PASSWORD '${MARIADB_ROOT_PASSWORD_HASH}' ; - GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; - GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; - EOSQL - else - read -r -d '' rootCreate <<-EOSQL || true - CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ; - GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; - GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; - EOSQL - fi - fi - - local mysqlAtLocalhost= - local mysqlAtLocalhostGrants= - # Install mysql@localhost user - if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ]; then - read -r -d '' mysqlAtLocalhost <<-EOSQL || true - CREATE USER mysql@localhost IDENTIFIED VIA unix_socket; - EOSQL - if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then - if [ "$MARIADB_MYSQL_LOCALHOST_GRANTS" != USAGE ]; then - mysql_warn "Excessive privileges ON *.* TO mysql@localhost facilitates risks to the confidentiality, integrity and availability of data stored" - fi - mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; - fi - fi - - local createHealthCheckUsers - createHealthCheckUsers=$(create_healthcheck_users) - - local rootLocalhostPass= - if [ -z "$MARIADB_ROOT_PASSWORD_HASH" ]; then - # handle MARIADB_ROOT_PASSWORD_HASH for root@localhost after /docker-entrypoint-initdb.d - rootLocalhostPass="SET PASSWORD FOR 'root'@'localhost'= PASSWORD('${rootPasswordEscaped}');" - fi - - local createDatabase= - # Creates a custom database and user if specified - if [ -n "$MARIADB_DATABASE" ]; then - mysql_note "Creating database ${MARIADB_DATABASE}" - createDatabase="CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\`;" - fi - - local createUser= - local userGrants= - if [ -n "$MARIADB_PASSWORD" ] || [ -n "$MARIADB_PASSWORD_HASH" ] && [ -n "$MARIADB_USER" ]; then - mysql_note "Creating user ${MARIADB_USER}" - if [ -n "$MARIADB_PASSWORD_HASH" ]; then - createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY PASSWORD '$MARIADB_PASSWORD_HASH';" - else - # SQL escape the user password, \ followed by ' - local userPasswordEscaped - userPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_PASSWORD}") - createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$userPasswordEscaped';" - fi - - if [ -n "$MARIADB_DATABASE" ]; then - mysql_note "Giving user ${MARIADB_USER} access to schema ${MARIADB_DATABASE}" - userGrants="GRANT ALL ON \`${MARIADB_DATABASE//_/\\_}\`.* TO '$MARIADB_USER'@'%';" - fi - fi - - # To create replica user - local createReplicaUser= - local changeMasterTo= - local startReplica= - if [ -n "$MARIADB_REPLICATION_USER" ] ; then - if [ -z "$MARIADB_MASTER_HOST" ]; then - # on master - mysql_note "Creating user ${MARIADB_REPLICATION_USER}" - createReplicaUser=$(create_replica_user) - else - # on replica - local rplPasswordEscaped - rplPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_REPLICATION_PASSWORD}") - # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. - # shellcheck disable=SC2153 - changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" - fi - fi - - mysql_note "Securing system users (equivalent to running mysql_secure_installation)" - # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set - # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. - docker_process_sql --dont-use-mysql-root-password --database=mysql --binary-mode <<-EOSQL - -- Securing system users shouldn't be replicated - SET @orig_sql_log_bin= @@SESSION.SQL_LOG_BIN; - SET @@SESSION.SQL_LOG_BIN=0; - -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set - SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); - - DROP USER IF EXISTS root@'127.0.0.1', root@'::1'; - EXECUTE IMMEDIATE CONCAT('DROP USER IF EXISTS root@\'', @@hostname,'\''); - - ${rootLocalhostPass} - ${rootCreate} - ${mysqlAtLocalhost} - ${mysqlAtLocalhostGrants} - ${createHealthCheckUsers} - -- end of securing system users, rest of init now... - SET @@SESSION.SQL_LOG_BIN=@orig_sql_log_bin; - -- create users/databases - ${createDatabase} - ${createUser} - ${createReplicaUser} - ${userGrants} - - ${changeMasterTo} - ${startReplica} - EOSQL -} - -# create a new installation -docker_mariadb_init() -{ - - # check dir permissions to reduce likelihood of half-initialized database - ls /docker-entrypoint-initdb.d/ > /dev/null - - if [ -n "$DATABASE_INIT_FROM_BACKUP" ]; then - shopt -s dotglob - for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do - mkdir -p "$DATADIR"/.init - tar --auto-compress --extract --file "$file" --directory="$DATADIR"/.init - mariadb-backup --target-dir="$DATADIR"/.init --datadir="$DATADIR"/.restore --move-back - - mv "$DATADIR"/.restore/** "$DATADIR"/ - if [ -f "$DATADIR/.init/backup-my.cnf" ]; then - mv "$DATADIR/.init/backup-my.cnf" "$DATADIR/.my.cnf" - mysql_note "Adding startup configuration:" - my_print_defaults --defaults-file="$DATADIR/.my.cnf" --mariadbd - fi - rm -rf "$DATADIR"/.init "$DATADIR"/.restore - if [ "$(id -u)" = "0" ]; then - # this will cause less disk access than `chown -R` - find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) - fi - done - if _check_if_upgrade_is_needed; then - docker_mariadb_upgrade "$@" - fi - return - fi - docker_init_database_dir "$@" - - mysql_note "Starting temporary server" - docker_temp_server_start "$@" - mysql_note "Temporary server started." - - docker_setup_db - docker_process_init_files /docker-entrypoint-initdb.d/* - # Wait until after /docker-entrypoint-initdb.d is performed before setting - # root@localhost password to a hash we don't know the password for. - if [ -n "${MARIADB_ROOT_PASSWORD_HASH}" ]; then - mysql_note "Setting root@localhost password hash" - docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL - SET @@SESSION.SQL_LOG_BIN=0; - SET PASSWORD FOR 'root'@'localhost'= '${MARIADB_ROOT_PASSWORD_HASH}'; - EOSQL - fi - - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" - - echo - mysql_note "MariaDB init process done. Ready for start up." - echo -} - -# backup the mysql database -docker_mariadb_backup_system() -{ - if [ -n "$MARIADB_DISABLE_UPGRADE_BACKUP" ] \ - && [ "$MARIADB_DISABLE_UPGRADE_BACKUP" = 1 ]; then - mysql_note "MariaDB upgrade backup disabled due to \$MARIADB_DISABLE_UPGRADE_BACKUP=1 setting" - return - fi - local backup_db="system_mysql_backup_unknown_version.sql.zst" - local oldfullversion="unknown_version" - if [ -r "$DATADIR"/mariadb_upgrade_info ]; then - read -r -d '' oldfullversion < "$DATADIR"/mariadb_upgrade_info || true - if [ -n "$oldfullversion" ]; then - backup_db="system_mysql_backup_${oldfullversion}.sql.zst" - fi - fi - - mysql_note "Backing up system database to $backup_db" - if ! mariadb-dump --skip-lock-tables --replace --databases mysql --socket="${SOCKET}" | zstd > "${DATADIR}/${backup_db}"; then - mysql_error "Unable backup system database for upgrade from $oldfullversion." - fi - mysql_note "Backing up complete" -} - -# perform mariadb-upgrade -# backup the mysql database if this is a major upgrade -docker_mariadb_upgrade() { - if [ -z "$MARIADB_AUTO_UPGRADE" ] \ - || [ "$MARIADB_AUTO_UPGRADE" = 0 ]; then - mysql_note "MariaDB upgrade (mariadb-upgrade or creating healthcheck users) required, but skipped due to \$MARIADB_AUTO_UPGRADE setting" - return - fi - mysql_note "Starting temporary server" - docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start - mysql_note "Temporary server started." - - docker_mariadb_backup_system - - if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then - mysql_note "Creating healthcheck users" - local createHealthCheckUsers - createHealthCheckUsers=$(create_healthcheck_users) - docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL - -- Healthcheck users shouldn't be replicated - SET @@SESSION.SQL_LOG_BIN=0; - -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set - SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); - FLUSH PRIVILEGES; - $createHealthCheckUsers -EOSQL - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" - - if _check_if_upgrade_is_needed; then - # need a restart as FLUSH PRIVILEGES isn't reversable - mysql_note "Restarting temporary server for upgrade" - docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start - else - return 0 - fi - fi - - mysql_note "Starting mariadb-upgrade" - mariadb-upgrade --upgrade-system-tables - mysql_note "Finished mariadb-upgrade" - - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" -} - - -_check_if_upgrade_is_needed() { - if [ ! -f "$DATADIR"/mariadb_upgrade_info ]; then - mysql_note "MariaDB upgrade information missing, assuming required" - return 0 - fi - local mariadbVersion - mariadbVersion="$(_mariadb_version)" - IFS='.-' read -ra newversion <<<"$mariadbVersion" - IFS='.-' read -ra oldversion < "$DATADIR"/mariadb_upgrade_info || true - - if [[ ${#newversion[@]} -lt 2 ]] || [[ ${#oldversion[@]} -lt 2 ]] \ - || [[ ${oldversion[0]} -lt ${newversion[0]} ]] \ - || [[ ${oldversion[0]} -eq ${newversion[0]} && ${oldversion[1]} -lt ${newversion[1]} ]]; then - return 0 - fi - if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then - mysql_note "MariaDB heathcheck configation file missing, assuming desirable" - return 0 - fi - mysql_note "MariaDB upgrade not required" - return 1 -} - -# check arguments for an option that would cause mariadbd to stop -# return true if there is one -_mysql_want_help() { - local arg - for arg; do - case "$arg" in - -'?'|--help|--print-defaults|-V|--version) - return 0 - ;; - esac - done - return 1 -} - -_main() { - # if command starts with an option, prepend mariadbd - if [ "${1:0:1}" = '-' ]; then - set -- mariadbd "$@" - fi - - #ENDOFSUBSTITUTIONS - # skip setup if they aren't running mysqld or want an option that stops mysqld - if [ "$1" = 'mariadbd' ] || [ "$1" = 'mysqld' ] && ! _mysql_want_help "$@"; then - mysql_note "Entrypoint script for MariaDB Server ${MARIADB_VERSION} started." - - mysql_check_config "$@" - # Load various environment variables - docker_setup_env "$@" - docker_create_db_directories - - # If container is started as root user, restart as dedicated mysql user - if [ "$(id -u)" = "0" ]; then - mysql_note "Switching to dedicated user 'mysql'" - exec gosu mysql "${BASH_SOURCE[0]}" "$@" - fi - - # there's no database, so it needs to be initialized - if [ -z "$DATABASE_ALREADY_EXISTS" ]; then - docker_verify_minimum_env - - docker_mariadb_init "$@" - # MDEV-27636 mariadb_upgrade --check-if-upgrade-is-needed cannot be run offline - #elif mariadb-upgrade --check-if-upgrade-is-needed; then - elif _check_if_upgrade_is_needed; then - docker_mariadb_upgrade "$@" - fi - fi - exec "$@" -} - -# If we are sourced from elsewhere, don't perform any further actions -if ! _is_sourced; then - _main "$@" -fi diff --git a/11.5-ubi/docker.cnf b/11.5-ubi/docker.cnf deleted file mode 100644 index 844c2cf..0000000 --- a/11.5-ubi/docker.cnf +++ /dev/null @@ -1,15 +0,0 @@ -# Ubuntu container compatibility - -[mariadb] -host-cache-size=0 -skip-name-resolve - -expire_logs_days=10 -character-set-server=utf8mb4 - - -[client-server] -socket=/run/mariadb/mariadb.sock - -!includedir /etc/mysql/mariadb.conf.d -!includedir /etc/mysql/conf.d diff --git a/11.5-ubi/healthcheck.sh b/11.5-ubi/healthcheck.sh deleted file mode 100755 index ad0b17f..0000000 --- a/11.5-ubi/healthcheck.sh +++ /dev/null @@ -1,390 +0,0 @@ -#!/bin/bash -# -# Healthcheck script for MariaDB -# -# Runs various tests on the MariaDB server to check its health. Pass the tests -# to run as arguments. If all tests succeed, the server is considered healthy, -# otherwise it's not. -# -# Arguments are processed in strict order. Set replication_* options before -# the --replication option. This allows a different set of replication checks -# on different connections. -# -# --su{=|-mysql} is option to run the healthcheck as a different unix user. -# Useful if mysql@localhost user exists with unix socket authentication -# Using this option disregards previous options set, so should usually be the -# first option. -# -# Some tests require SQL privileges. -# -# TEST MINIMUM GRANTS REQUIRED -# connect none* -# innodb_initialized USAGE -# innodb_buffer_pool_loaded USAGE -# galera_online USAGE -# galera_ready USAGE -# replication REPLICATION_CLIENT (<10.5)or REPLICA MONITOR (10.5+) -# mariadbupgrade none, however unix user permissions on datadir -# -# The SQL user used is the default for the mariadb client. This can be the unix user -# if no user(or password) is set in the [mariadb-client] section of a configuration -# file. --defaults-{file,extra-file,group-suffix} can specify a file/configuration -# different from elsewhere. -# -# Note * though denied error message will result in error log without -# any permissions. USAGE recommend to avoid this. - -set -eo pipefail - -_process_sql() -{ - mariadb ${nodefaults:+--no-defaults} \ - ${def['file']:+--defaults-file=${def['file']}} \ - ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ - ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ - --skip-ssl --skip-ssl-verify-server-cert \ - --protocol socket \ - -B "$@" -} - -# TESTS - - -# CONNECT -# -# Tests that a connection can be made over TCP, the final state -# of the entrypoint and is listening. The authentication used -# isn't tested. -connect() -{ - local s - # short cut mechanism, to work with --require-secure-transport - s=$(_process_sql --skip-column-names -e 'select @@skip_networking') - case "$s" in - 0|1) - connect_s=$s - return "$s"; - ;; - esac - # falling back to tcp if there wasn't a connection answer. - s=$(mariadb ${nodefaults:+--no-defaults} \ - ${def['file']:+--defaults-file=${def['file']}} \ - ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ - ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ - --skip-ssl --skip-ssl-verify-server-cert \ - -h localhost --protocol tcp \ - --skip-column-names --batch --skip-print-query-on-error \ - -e 'select @@skip_networking' 2>&1) - - case "$s" in - 1) # skip-networking=1 (no network) - ;& - ERROR\ 2002\ \(HY000\):*) - # cannot connect - connect_s=1 - ;; - 0) # skip-networking=0 - ;& - ERROR\ 1820\ \(HY000\)*) # password expire - ;& - ERROR\ 4151\ \(HY000\):*) # account locked - ;& - ERROR\ 1226\ \(42000\)*) # resource limit exceeded - ;& - ERROR\ 1[0-9][0-9][0-9]\ \(28000\):*) - # grep access denied and other 28000 client errors - we did connect - connect_s=0 - ;; - *) - >&2 echo "Unknown error $s" - connect_s=1 - ;; - esac - return $connect_s -} - -# INNODB_INITIALIZED -# -# This tests that the crash recovery of InnoDB has completed -# along with all the other things required to make it to a healthy -# operational state. Note this may return true in the early -# states of initialization. Use with a connect test to avoid -# these false positives. -innodb_initialized() -{ - local s - s=$(_process_sql --skip-column-names -e "select 1 from information_schema.ENGINES WHERE engine='innodb' AND support in ('YES', 'DEFAULT', 'ENABLED')") - [ "$s" == 1 ] -} - -# INNODB_BUFFER_POOL_LOADED -# -# Tests the load of the innodb buffer pool as been complete -# implies innodb_buffer_pool_load_at_startup=1 (default), or if -# manually SET innodb_buffer_pool_load_now=1 -innodb_buffer_pool_loaded() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='Innodb_buffer_pool_load_status'") - if [[ $s =~ 'load completed' ]]; then - return 0 - fi - return 1 -} - -# GALERA_ONLINE -# -# Tests that the galera node is in the SYNCed state -galera_online() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_LOCAL_STATE'") - # 4 from https://galeracluster.com/library/documentation/node-states.html#node-state-changes - # not https://xkcd.com/221/ - if [[ $s -eq 4 ]]; then - return 0 - fi - return 1 -} - -# GALERA_READY -# -# Tests that the Galera provider is ready. -galera_ready() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_READY'") - if [ "$s" = "ON" ]; then - return 0 - fi - return 1 -} - -# REPLICATION -# -# Tests the replication has the required set of functions: -# --replication_all -> Checks all replication sources -# --replication_name=n -> sets the multisource connection name tested -# --replication_io -> IO thread is running -# --replication_sql -> SQL thread is running -# --replication_seconds_behind_master=n -> less than or equal this seconds of delay -# --replication_sql_remaining_delay=n -> less than or equal this seconds of remaining delay -# (ref: https://mariadb.com/kb/en/delayed-replication/) -replication() -{ - # SHOW REPLICA available 10.5+ - # https://github.com/koalaman/shellcheck/issues/2383 - # shellcheck disable=SC2016,SC2026 - _process_sql -e "SHOW ${repl['all']:+all} REPLICA${repl['all']:+S} ${repl['name']:+'${repl['name']}'} STATUS\G" | \ - { - # required for trim of leading space. - shopt -s extglob - # Row header - read -t 5 -r - # read timeout - [ $? -gt 128 ] && return 1 - while IFS=":" read -t 1 -r n v; do - # Trim leading space - n=${n##+([[:space:]])} - # Leading space on all values by the \G format needs to be trimmed. - v=${v:1} - case "$n" in - Slave_IO_Running) - if [ -n "${repl['io']}" ] && [ "$v" = 'No' ]; then - return 1 - fi - ;; - Slave_SQL_Running) - if [ -n "${repl['sql']}" ] && [ "$v" = 'No' ]; then - return 1 - fi - ;; - Seconds_Behind_Master) - # A NULL value is the IO thread not running: - if [ -n "${repl['seconds_behind_master']}" ] && - { [ "$v" = NULL ] || - (( "${repl['seconds_behind_master']}" < "$v" )); }; then - return 1 - fi - ;; - SQL_Remaining_Delay) - # Unlike Seconds_Behind_Master, sql_remaining_delay will hit NULL - # once replication is caught up - https://mariadb.com/kb/en/delayed-replication/ - if [ -n "${repl['sql_remaining_delay']}" ] && - [ "$v" != NULL ] && - (( "${repl['sql_remaining_delay']}" < "$v" )); then - return 1 - fi - ;; - esac - done - # read timeout - [ $? -gt 128 ] && return 1 - return 0 - } - # reachable in command not found(?) - # shellcheck disable=SC2317 - return $? -} - -# mariadbupgrade -# -# Test the lock on the file $datadir/mariadb_upgrade_info -# https://jira.mariadb.org/browse/MDEV-27068 -mariadbupgrade() -{ - local f="$datadir/mariadb_upgrade_info" - if [ -r "$f" ]; then - flock --exclusive --nonblock -n 9 9<"$f" - return $? - fi - return 0 -} - - -# MAIN - -if [ $# -eq 0 ]; then - echo "At least one argument required" >&2 - exit 1 -fi - -#ENDOFSUBSTITUTIONS -# Marks the end of mysql -> mariadb name changes in 10.6+ -# Global variables used by tests -declare -A repl -declare -A def -nodefaults= -connect_s= -datadir=/var/lib/mysql -if [ -f $datadir/.my-healthcheck.cnf ]; then - def['extra_file']=$datadir/.my-healthcheck.cnf -fi - -_repl_param_check() -{ - case "$1" in - seconds_behind_master) ;& - sql_remaining_delay) - if [ -z "${repl['io']}" ]; then - repl['io']=1 - echo "Forcing --replication_io=1, $1 requires IO thread to be running" >&2 - fi - ;; - all) - if [ -n "${repl['name']}" ]; then - unset 'repl[name]' - echo "Option --replication_all incompatible with specified source --replication_name, clearing replication_name" >&2 - fi - ;; - name) - if [ -n "${repl['all']}" ]; then - unset 'repl[all]' - echo "Option --replication_name incompatible with --replication_all, clearing replication_all" >&2 - fi - ;; - esac -} - -_test_exists() { - declare -F "$1" > /dev/null - return $? -} - -while [ $# -gt 0 ]; do - case "$1" in - --su=*) - u="${1#*=}" - shift - exec gosu "${u}" "${BASH_SOURCE[0]}" "$@" - ;; - --su) - shift - u=$1 - shift - exec gosu "$u" "${BASH_SOURCE[0]}" "$@" - ;; - --su-mysql) - shift - exec gosu mysql "${BASH_SOURCE[0]}" "$@" - ;; - --replication_*=*) - # Change the n to what is between _ and = and make lower case - n=${1#*_} - n=${n%%=*} - n=${n,,*} - # v is after the = - v=${1#*=} - repl[$n]=$v - _repl_param_check "$n" - ;; - --replication_*) - # Without =, look for a non --option next as the value, - # otherwise treat it as an "enable", just equate to 1. - # Clearing option is possible with "--replication_X=" - n=${1#*_} - n=${n,,*} - if [ "${2:0:2}" == '--' ]; then - repl[$n]=1 - else - repl[$n]=$2 - shift - fi - _repl_param_check "$n" - ;; - --datadir=*) - datadir=${1#*=} - ;; - --datadir) - shift - datadir=${1} - ;; - --no-defaults) - def=() - nodefaults=1 - ;; - --defaults-file=*|--defaults-extra-file=*|--defaults-group-suffix=*) - n=${1:11} # length --defaults- - n=${n%%=*} - n=${n//-/_} - # v is after the = - v=${1#*=} - def[$n]=$v - nodefaults= - ;; - --defaults-file|--defaults-extra-file|--defaults-group-suffix) - n=${1:11} # length --defaults- - n=${n//-/_} - if [ "${2:0:2}" == '--' ]; then - def[$n]="" - else - def[$n]=$2 - shift - fi - nodefaults= - ;; - --*) - test=${1#--} - ;; - *) - echo "Unknown healthcheck option $1" >&2 - exit 1 - esac - if [ -n "$test" ]; then - if ! _test_exists "$test" ; then - echo "healthcheck unknown option or test '$test'" >&2 - exit 1 - elif ! "$test"; then - echo "healthcheck $test failed" >&2 - exit 1 - fi - test= - fi - shift -done -if [ "$connect_s" != "0" ]; then - # we didn't pass a connnect test, so the current success status is suspicious - # return what connect thinks. - connect - exit $? -fi diff --git a/11.5/Dockerfile b/11.5/Dockerfile deleted file mode 100644 index a394eb8..0000000 --- a/11.5/Dockerfile +++ /dev/null @@ -1,142 +0,0 @@ -# vim:set ft=dockerfile: -FROM ubuntu:noble - -# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added -RUN groupadd -r mysql && useradd -r -g mysql mysql --home-dir /var/lib/mysql && userdel --remove ubuntu - -# add gosu for easy step-down from root -# https://github.com/tianon/gosu/releases -# gosu key is B42F6819007F00F88E364FD4036A9C25BF357DD4 -ENV GOSU_VERSION 1.17 - -ARG GPG_KEYS=177F4010FE56CA3336300305F1656F24C74CD1D8 -# pub rsa4096 2016-03-30 [SC] -# 177F 4010 FE56 CA33 3630 0305 F165 6F24 C74C D1D8 -# uid [ unknown] MariaDB Signing Key -# sub rsa4096 2016-03-30 [E] -# install "libjemalloc2" as it offers better performance in some cases. Use with LD_PRELOAD -# install "pwgen" for randomizing passwords -# install "tzdata" for /usr/share/zoneinfo/ -# install "xz-utils" for .sql.xz docker-entrypoint-initdb.d files -# install "zstd" for .sql.zst docker-entrypoint-initdb.d files -# hadolint ignore=SC2086 -RUN set -eux; \ - apt-get update; \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - ca-certificates \ - gpg \ - gpgv \ - libjemalloc2 \ - pwgen \ - tzdata \ - xz-utils \ - zstd ; \ - savedAptMark="$(apt-mark showmanual)"; \ - apt-get install -y --no-install-recommends \ - dirmngr \ - gpg-agent \ - wget; \ - rm -rf /var/lib/apt/lists/*; \ - dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ - wget -q -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ - wget -q -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ - GNUPGHOME="$(mktemp -d)"; \ - export GNUPGHOME; \ - gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ - for key in $GPG_KEYS; do \ - gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key"; \ - done; \ - gpg --batch --export "$GPG_KEYS" > /etc/apt/trusted.gpg.d/mariadb.gpg; \ - if command -v gpgconf >/dev/null; then \ - gpgconf --kill all; \ - fi; \ - gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ - gpgconf --kill all; \ - rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ - apt-mark auto '.*' > /dev/null; \ - [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark >/dev/null; \ - apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ - chmod +x /usr/local/bin/gosu; \ - gosu --version; \ - gosu nobody true - -RUN mkdir /docker-entrypoint-initdb.d - -# Ensure the container exec commands handle range of utf8 characters based of -# default locales in base image (https://github.com/docker-library/docs/blob/135b79cc8093ab02e55debb61fdb079ab2dbce87/ubuntu/README.md#locales) -ENV LANG C.UTF-8 - -# OCI annotations to image -LABEL org.opencontainers.image.authors="MariaDB Community" \ - org.opencontainers.image.title="MariaDB Database" \ - org.opencontainers.image.description="MariaDB Database for relational SQL" \ - org.opencontainers.image.documentation="https://hub.docker.com/_/mariadb/" \ - org.opencontainers.image.base.name="docker.io/library/ubuntu:noble" \ - org.opencontainers.image.licenses="GPL-2.0" \ - org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ - org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="11.5.2" \ - org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" - -# bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=1:11.5.2+maria~ubu2404 -ENV MARIADB_VERSION $MARIADB_VERSION -# release-status:Stable -# release-support-type:Short Term Support -# (https://downloads.mariadb.org/rest-api/mariadb/) - -# Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions -ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.5.2/repo/ubuntu/ noble main main/debug" - -RUN set -e;\ - echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ - { \ - echo 'Package: *'; \ - echo 'Pin: release o=MariaDB'; \ - echo 'Pin-Priority: 999'; \ - } > /etc/apt/preferences.d/mariadb -# add repository pinning to make sure dependencies from this MariaDB repo are preferred over Debian dependencies -# libmariadbclient18 : Depends: libmysqlclient18 (= 5.5.42+maria-1~wheezy) but 5.5.43-0+deb7u1 is to be installed - -# the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) -# also, we set debconf keys to make APT a little quieter -# hadolint ignore=DL3015 -RUN set -ex; \ - { \ - echo "mariadb-server" mysql-server/root_password password 'unused'; \ - echo "mariadb-server" mysql-server/root_password_again password 'unused'; \ - } | debconf-set-selections; \ - apt-get update; \ -# postinst script creates a datadir, so avoid creating it by faking its existance. - mkdir -p /var/lib/mysql/mysql ; touch /var/lib/mysql/mysql/user.frm ; \ -# mariadb-backup is installed at the same time so that `mysql-common` is only installed once from just mariadb repos - apt-get install -y --no-install-recommends mariadb-server="$MARIADB_VERSION" mariadb-backup socat \ - ; \ - rm -rf /var/lib/apt/lists/*; \ -# purge and re-create /var/lib/mysql with appropriate ownership - rm -rf /var/lib/mysql; \ - mkdir -p /var/lib/mysql /run/mysqld; \ - chown -R mysql:mysql /var/lib/mysql /run/mysqld; \ -# ensure that /run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime - chmod 1777 /run/mysqld; \ -# comment out a few problematic configuration values - find /etc/mysql/ -name '*.cnf' -print0 \ - | xargs -0 grep -lZE '^(bind-address|log|user\s)' \ - | xargs -rt -0 sed -Ei 's/^(bind-address|log|user\s)/#&/'; \ -# don't reverse lookup hostnames, they are usually another container - printf "[mariadb]\nhost-cache-size=0\nskip-name-resolve\n" > /etc/mysql/mariadb.conf.d/05-skipcache.cnf; \ -# Issue #327 Correct order of reading directories /etc/mysql/mariadb.conf.d before /etc/mysql/conf.d (mount-point per documentation) - if [ -L /etc/mysql/my.cnf ]; then \ -# 10.5+ - sed -i -e '/includedir/ {N;s/\(.*\)\n\(.*\)/\n\2\n\1/}' /etc/mysql/mariadb.cnf; \ - fi - - -VOLUME /var/lib/mysql - -COPY healthcheck.sh /usr/local/bin/healthcheck.sh -COPY docker-entrypoint.sh /usr/local/bin/ -ENTRYPOINT ["docker-entrypoint.sh"] - -EXPOSE 3306 -CMD ["mariadbd"] diff --git a/11.5/docker-entrypoint.sh b/11.5/docker-entrypoint.sh deleted file mode 100755 index 5e54494..0000000 --- a/11.5/docker-entrypoint.sh +++ /dev/null @@ -1,722 +0,0 @@ -#!/bin/bash -set -eo pipefail -shopt -s nullglob - -# logging functions -mysql_log() { - local type="$1"; shift - printf '%s [%s] [Entrypoint]: %s\n' "$(date --rfc-3339=seconds)" "$type" "$*" -} -mysql_note() { - mysql_log Note "$@" -} -mysql_warn() { - mysql_log Warn "$@" >&2 -} -mysql_error() { - mysql_log ERROR "$@" >&2 - exit 1 -} - -# usage: file_env VAR [DEFAULT] -# ie: file_env 'XYZ_DB_PASSWORD' 'example' -# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of -# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) -file_env() { - local var="$1" - local fileVar="${var}_FILE" - local def="${2:-}" - if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then - mysql_error "Both $var and $fileVar are set (but are exclusive)" - fi - local val="$def" - if [ "${!var:-}" ]; then - val="${!var}" - elif [ "${!fileVar:-}" ]; then - val="$(< "${!fileVar}")" - fi - export "$var"="$val" - unset "$fileVar" -} - -# set MARIADB_xyz from MYSQL_xyz when MARIADB_xyz is unset -# and make them the same value (so user scripts can use either) -_mariadb_file_env() { - local var="$1"; shift - local maria="MARIADB_${var#MYSQL_}" - file_env "$var" "$@" - file_env "$maria" "${!var}" - if [ "${!maria:-}" ]; then - export "$var"="${!maria}" - fi -} - -# check to see if this file is being run or sourced from another script -_is_sourced() { - # https://unix.stackexchange.com/a/215279 - [ "${#FUNCNAME[@]}" -ge 2 ] \ - && [ "${FUNCNAME[0]}" = '_is_sourced' ] \ - && [ "${FUNCNAME[1]}" = 'source' ] -} - -# usage: docker_process_init_files [file [file [...]]] -# ie: docker_process_init_files /always-initdb.d/* -# process initializer files, based on file extensions -docker_process_init_files() { - # mysql here for backwards compatibility "${mysql[@]}" - # ShellCheck: mysql appears unused. Verify use (or export if used externally) - # shellcheck disable=SC2034 - mysql=( docker_process_sql ) - - echo - local f - for f; do - case "$f" in - *.sh) - # https://github.com/docker-library/postgres/issues/450#issuecomment-393167936 - # https://github.com/docker-library/postgres/pull/452 - if [ -x "$f" ]; then - mysql_note "$0: running $f" - "$f" - else - mysql_note "$0: sourcing $f" - # ShellCheck can't follow non-constant source. Use a directive to specify location. - # shellcheck disable=SC1090 - . "$f" - fi - ;; - *.sql) mysql_note "$0: running $f"; docker_process_sql < "$f"; echo ;; - *.sql.gz) mysql_note "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;; - *.sql.xz) mysql_note "$0: running $f"; xzcat "$f" | docker_process_sql; echo ;; - *.sql.zst) mysql_note "$0: running $f"; zstd -dc "$f" | docker_process_sql; echo ;; - *) mysql_warn "$0: ignoring $f" ;; - esac - echo - done -} - -# arguments necessary to run "mariadbd --verbose --help" successfully (used for testing configuration validity and for extracting default/configured values) -_verboseHelpArgs=( - --verbose --help -) - -mysql_check_config() { - local toRun=( "$@" "${_verboseHelpArgs[@]}" ) errors - if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then - mysql_error $'mariadbd failed while attempting to check config\n\tcommand was: '"${toRun[*]}"$'\n\t'"$errors" - fi -} - -# Fetch value from server config -# We use mariadbd --verbose --help instead of my_print_defaults because the -# latter only show values present in config files, and not server defaults -mysql_get_config() { - local conf="$1"; shift - "$@" "${_verboseHelpArgs[@]}" 2>/dev/null \ - | awk -v conf="$conf" '$1 == conf && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }' - # match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)" -} - -# Do a temporary startup of the MariaDB server, for init purposes -docker_temp_server_start() { - "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ - --expire-logs-days=0 \ - --loose-innodb_buffer_pool_load_at_startup=0 \ - --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ - & - declare -g MARIADB_PID - MARIADB_PID=$! - mysql_note "Waiting for server startup" - # only use the root password if the database has already been initialized - # so that it won't try to fill in a password file when it hasn't been set yet - extraArgs=() - if [ -z "$DATABASE_ALREADY_EXISTS" ]; then - extraArgs+=( '--dont-use-mysql-root-password' ) - fi - local i - for i in {30..0}; do - if docker_process_sql "${extraArgs[@]}" --database=mysql \ - --skip-ssl --skip-ssl-verify-server-cert \ - <<<'SELECT 1' &> /dev/null; then - break - fi - sleep 1 - done - if [ "$i" = 0 ]; then - mysql_error "Unable to start server." - fi -} - -# Stop the server. When using a local socket file mariadb-admin will block until -# the shutdown is complete. -docker_temp_server_stop() { - kill "$MARIADB_PID" - wait "$MARIADB_PID" -} - -# Verify that the minimally required password settings are set for new databases. -docker_verify_minimum_env() { - # Restoring from backup requires no environment variables - declare -g DATABASE_INIT_FROM_BACKUP - for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do - if [ -f "${file}" ]; then - DATABASE_INIT_FROM_BACKUP='true' - return - fi - done - if [ -z "$MARIADB_ROOT_PASSWORD" ] && [ -z "$MARIADB_ROOT_PASSWORD_HASH" ] && [ -z "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] && [ -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then - mysql_error $'Database is uninitialized and password option is not specified\n\tYou need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ROOT_PASSWORD_HASH, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' - fi - # More preemptive exclusions of combinations should have been made before *PASSWORD_HASH was added, but for now we don't enforce due to compatibility. - if [ -n "$MARIADB_ROOT_PASSWORD" ] || [ -n "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] || [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ] && [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then - mysql_error "Cannot specify MARIADB_ROOT_PASSWORD_HASH and another MARIADB_ROOT_PASSWORD* option." - fi - if [ -n "$MARIADB_PASSWORD" ] && [ -n "$MARIADB_PASSWORD_HASH" ]; then - mysql_error "Cannot specify MARIADB_PASSWORD_HASH and MARIADB_PASSWORD option." - fi - if [ -n "$MARIADB_REPLICATION_USER" ]; then - if [ -z "$MARIADB_MASTER_HOST" ]; then - # its a master, we're creating a user - if [ -z "$MARIADB_REPLICATION_PASSWORD" ] && [ -z "$MARIADB_REPLICATION_PASSWORD_HASH" ]; then - mysql_error "MARIADB_REPLICATION_PASSWORD or MARIADB_REPLICATION_PASSWORD_HASH not found to create replication user for master" - fi - else - # its a replica - if [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; then - mysql_error "MARIADB_REPLICATION_PASSWORD is mandatory to specify the replication on the replica image." - fi - if [ -n "$MARIADB_REPLICATION_PASSWORD_HASH" ] ; then - mysql_warn "MARIADB_REPLICATION_PASSWORD_HASH cannot be specified on a replica" - fi - fi - fi - if [ -n "$MARIADB_MASTER_HOST" ] && { [ -z "$MARIADB_REPLICATION_USER" ] || [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; }; then - mysql_error "For a replica, MARIADB_REPLICATION_USER and MARIADB_REPLICATION is mandatory." - fi -} - -# creates folders for the database -# also ensures permission for user mysql of run as root -docker_create_db_directories() { - local user; user="$(id -u)" - - # TODO other directories that are used by default? like /var/lib/mysql-files - # see https://github.com/docker-library/mysql/issues/562 - mkdir -p "$DATADIR" - - if [ "$user" = "0" ]; then - # this will cause less disk access than `chown -R` - find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) - # See https://github.com/MariaDB/mariadb-docker/issues/363 - if [ "${SOCKET:0:1}" != '@' ]; then # not abstract sockets - find "${SOCKET%/*}" -maxdepth 0 \! -user mysql \( -exec chown mysql: '{}' \; -o -true \) - fi - - # memory.pressure - local cgroup; cgroup=$( "$DATADIR"/.my-healthcheck.cnf - $maskPreserve -} - -# Initializes database with timezone info and root password, plus optional extra db/user -docker_setup_db() { - # Load timezone info into database - if [ -z "$MARIADB_INITDB_SKIP_TZINFO" ]; then - # --skip-write-binlog usefully disables binary logging - # but also outputs LOCK TABLES to improve the IO of - # Aria (MDEV-23326) for 10.4+. - mariadb-tzinfo-to-sql --skip-write-binlog /usr/share/zoneinfo \ - | docker_process_sql --dont-use-mysql-root-password --database=mysql - # tell docker_process_sql to not use MYSQL_ROOT_PASSWORD since it is not set yet - fi - # Generate random root password - if [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then - MARIADB_ROOT_PASSWORD="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" - export MARIADB_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=$MARIADB_ROOT_PASSWORD - mysql_note "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD" - fi - - # Creates root users for non-localhost hosts - local rootCreate= - local rootPasswordEscaped= - if [ -n "$MARIADB_ROOT_PASSWORD" ]; then - # Sets root password and creates root users for non-localhost hosts - rootPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}") - fi - - # default root to listen for connections from anywhere - if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then - # ref "read -d ''", no, we don't care if read finds a terminating character in this heredoc - # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 - if [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then - read -r -d '' rootCreate <<-EOSQL || true - CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY PASSWORD '${MARIADB_ROOT_PASSWORD_HASH}' ; - GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; - GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; - EOSQL - else - read -r -d '' rootCreate <<-EOSQL || true - CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ; - GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; - GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; - EOSQL - fi - fi - - local mysqlAtLocalhost= - local mysqlAtLocalhostGrants= - # Install mysql@localhost user - if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ]; then - read -r -d '' mysqlAtLocalhost <<-EOSQL || true - CREATE USER mysql@localhost IDENTIFIED VIA unix_socket; - EOSQL - if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then - if [ "$MARIADB_MYSQL_LOCALHOST_GRANTS" != USAGE ]; then - mysql_warn "Excessive privileges ON *.* TO mysql@localhost facilitates risks to the confidentiality, integrity and availability of data stored" - fi - mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; - fi - fi - - local createHealthCheckUsers - createHealthCheckUsers=$(create_healthcheck_users) - - local rootLocalhostPass= - if [ -z "$MARIADB_ROOT_PASSWORD_HASH" ]; then - # handle MARIADB_ROOT_PASSWORD_HASH for root@localhost after /docker-entrypoint-initdb.d - rootLocalhostPass="SET PASSWORD FOR 'root'@'localhost'= PASSWORD('${rootPasswordEscaped}');" - fi - - local createDatabase= - # Creates a custom database and user if specified - if [ -n "$MARIADB_DATABASE" ]; then - mysql_note "Creating database ${MARIADB_DATABASE}" - createDatabase="CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\`;" - fi - - local createUser= - local userGrants= - if [ -n "$MARIADB_PASSWORD" ] || [ -n "$MARIADB_PASSWORD_HASH" ] && [ -n "$MARIADB_USER" ]; then - mysql_note "Creating user ${MARIADB_USER}" - if [ -n "$MARIADB_PASSWORD_HASH" ]; then - createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY PASSWORD '$MARIADB_PASSWORD_HASH';" - else - # SQL escape the user password, \ followed by ' - local userPasswordEscaped - userPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_PASSWORD}") - createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$userPasswordEscaped';" - fi - - if [ -n "$MARIADB_DATABASE" ]; then - mysql_note "Giving user ${MARIADB_USER} access to schema ${MARIADB_DATABASE}" - userGrants="GRANT ALL ON \`${MARIADB_DATABASE//_/\\_}\`.* TO '$MARIADB_USER'@'%';" - fi - fi - - # To create replica user - local createReplicaUser= - local changeMasterTo= - local startReplica= - if [ -n "$MARIADB_REPLICATION_USER" ] ; then - if [ -z "$MARIADB_MASTER_HOST" ]; then - # on master - mysql_note "Creating user ${MARIADB_REPLICATION_USER}" - createReplicaUser=$(create_replica_user) - else - # on replica - local rplPasswordEscaped - rplPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_REPLICATION_PASSWORD}") - # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. - # shellcheck disable=SC2153 - changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" - fi - fi - - mysql_note "Securing system users (equivalent to running mysql_secure_installation)" - # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set - # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. - docker_process_sql --dont-use-mysql-root-password --database=mysql --binary-mode <<-EOSQL - -- Securing system users shouldn't be replicated - SET @orig_sql_log_bin= @@SESSION.SQL_LOG_BIN; - SET @@SESSION.SQL_LOG_BIN=0; - -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set - SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); - - DROP USER IF EXISTS root@'127.0.0.1', root@'::1'; - EXECUTE IMMEDIATE CONCAT('DROP USER IF EXISTS root@\'', @@hostname,'\''); - - ${rootLocalhostPass} - ${rootCreate} - ${mysqlAtLocalhost} - ${mysqlAtLocalhostGrants} - ${createHealthCheckUsers} - -- end of securing system users, rest of init now... - SET @@SESSION.SQL_LOG_BIN=@orig_sql_log_bin; - -- create users/databases - ${createDatabase} - ${createUser} - ${createReplicaUser} - ${userGrants} - - ${changeMasterTo} - ${startReplica} - EOSQL -} - -# create a new installation -docker_mariadb_init() -{ - - # check dir permissions to reduce likelihood of half-initialized database - ls /docker-entrypoint-initdb.d/ > /dev/null - - if [ -n "$DATABASE_INIT_FROM_BACKUP" ]; then - shopt -s dotglob - for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do - mkdir -p "$DATADIR"/.init - tar --auto-compress --extract --file "$file" --directory="$DATADIR"/.init - mariadb-backup --target-dir="$DATADIR"/.init --datadir="$DATADIR"/.restore --move-back - - mv "$DATADIR"/.restore/** "$DATADIR"/ - if [ -f "$DATADIR/.init/backup-my.cnf" ]; then - mv "$DATADIR/.init/backup-my.cnf" "$DATADIR/.my.cnf" - mysql_note "Adding startup configuration:" - my_print_defaults --defaults-file="$DATADIR/.my.cnf" --mariadbd - fi - rm -rf "$DATADIR"/.init "$DATADIR"/.restore - if [ "$(id -u)" = "0" ]; then - # this will cause less disk access than `chown -R` - find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) - fi - done - if _check_if_upgrade_is_needed; then - docker_mariadb_upgrade "$@" - fi - return - fi - docker_init_database_dir "$@" - - mysql_note "Starting temporary server" - docker_temp_server_start "$@" - mysql_note "Temporary server started." - - docker_setup_db - docker_process_init_files /docker-entrypoint-initdb.d/* - # Wait until after /docker-entrypoint-initdb.d is performed before setting - # root@localhost password to a hash we don't know the password for. - if [ -n "${MARIADB_ROOT_PASSWORD_HASH}" ]; then - mysql_note "Setting root@localhost password hash" - docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL - SET @@SESSION.SQL_LOG_BIN=0; - SET PASSWORD FOR 'root'@'localhost'= '${MARIADB_ROOT_PASSWORD_HASH}'; - EOSQL - fi - - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" - - echo - mysql_note "MariaDB init process done. Ready for start up." - echo -} - -# backup the mysql database -docker_mariadb_backup_system() -{ - if [ -n "$MARIADB_DISABLE_UPGRADE_BACKUP" ] \ - && [ "$MARIADB_DISABLE_UPGRADE_BACKUP" = 1 ]; then - mysql_note "MariaDB upgrade backup disabled due to \$MARIADB_DISABLE_UPGRADE_BACKUP=1 setting" - return - fi - local backup_db="system_mysql_backup_unknown_version.sql.zst" - local oldfullversion="unknown_version" - if [ -r "$DATADIR"/mariadb_upgrade_info ]; then - read -r -d '' oldfullversion < "$DATADIR"/mariadb_upgrade_info || true - if [ -n "$oldfullversion" ]; then - backup_db="system_mysql_backup_${oldfullversion}.sql.zst" - fi - fi - - mysql_note "Backing up system database to $backup_db" - if ! mariadb-dump --skip-lock-tables --replace --databases mysql --socket="${SOCKET}" | zstd > "${DATADIR}/${backup_db}"; then - mysql_error "Unable backup system database for upgrade from $oldfullversion." - fi - mysql_note "Backing up complete" -} - -# perform mariadb-upgrade -# backup the mysql database if this is a major upgrade -docker_mariadb_upgrade() { - if [ -z "$MARIADB_AUTO_UPGRADE" ] \ - || [ "$MARIADB_AUTO_UPGRADE" = 0 ]; then - mysql_note "MariaDB upgrade (mariadb-upgrade or creating healthcheck users) required, but skipped due to \$MARIADB_AUTO_UPGRADE setting" - return - fi - mysql_note "Starting temporary server" - docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start - mysql_note "Temporary server started." - - docker_mariadb_backup_system - - if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then - mysql_note "Creating healthcheck users" - local createHealthCheckUsers - createHealthCheckUsers=$(create_healthcheck_users) - docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL - -- Healthcheck users shouldn't be replicated - SET @@SESSION.SQL_LOG_BIN=0; - -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set - SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); - FLUSH PRIVILEGES; - $createHealthCheckUsers -EOSQL - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" - - if _check_if_upgrade_is_needed; then - # need a restart as FLUSH PRIVILEGES isn't reversable - mysql_note "Restarting temporary server for upgrade" - docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start - else - return 0 - fi - fi - - mysql_note "Starting mariadb-upgrade" - mariadb-upgrade --upgrade-system-tables - mysql_note "Finished mariadb-upgrade" - - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" -} - - -_check_if_upgrade_is_needed() { - if [ ! -f "$DATADIR"/mariadb_upgrade_info ]; then - mysql_note "MariaDB upgrade information missing, assuming required" - return 0 - fi - local mariadbVersion - mariadbVersion="$(_mariadb_version)" - IFS='.-' read -ra newversion <<<"$mariadbVersion" - IFS='.-' read -ra oldversion < "$DATADIR"/mariadb_upgrade_info || true - - if [[ ${#newversion[@]} -lt 2 ]] || [[ ${#oldversion[@]} -lt 2 ]] \ - || [[ ${oldversion[0]} -lt ${newversion[0]} ]] \ - || [[ ${oldversion[0]} -eq ${newversion[0]} && ${oldversion[1]} -lt ${newversion[1]} ]]; then - return 0 - fi - if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then - mysql_note "MariaDB heathcheck configation file missing, assuming desirable" - return 0 - fi - mysql_note "MariaDB upgrade not required" - return 1 -} - -# check arguments for an option that would cause mariadbd to stop -# return true if there is one -_mysql_want_help() { - local arg - for arg; do - case "$arg" in - -'?'|--help|--print-defaults|-V|--version) - return 0 - ;; - esac - done - return 1 -} - -_main() { - # if command starts with an option, prepend mariadbd - if [ "${1:0:1}" = '-' ]; then - set -- mariadbd "$@" - fi - - #ENDOFSUBSTITUTIONS - # skip setup if they aren't running mysqld or want an option that stops mysqld - if [ "$1" = 'mariadbd' ] || [ "$1" = 'mysqld' ] && ! _mysql_want_help "$@"; then - mysql_note "Entrypoint script for MariaDB Server ${MARIADB_VERSION} started." - - mysql_check_config "$@" - # Load various environment variables - docker_setup_env "$@" - docker_create_db_directories - - # If container is started as root user, restart as dedicated mysql user - if [ "$(id -u)" = "0" ]; then - mysql_note "Switching to dedicated user 'mysql'" - exec gosu mysql "${BASH_SOURCE[0]}" "$@" - fi - - # there's no database, so it needs to be initialized - if [ -z "$DATABASE_ALREADY_EXISTS" ]; then - docker_verify_minimum_env - - docker_mariadb_init "$@" - # MDEV-27636 mariadb_upgrade --check-if-upgrade-is-needed cannot be run offline - #elif mariadb-upgrade --check-if-upgrade-is-needed; then - elif _check_if_upgrade_is_needed; then - docker_mariadb_upgrade "$@" - fi - fi - exec "$@" -} - -# If we are sourced from elsewhere, don't perform any further actions -if ! _is_sourced; then - _main "$@" -fi diff --git a/11.5/healthcheck.sh b/11.5/healthcheck.sh deleted file mode 100755 index ad0b17f..0000000 --- a/11.5/healthcheck.sh +++ /dev/null @@ -1,390 +0,0 @@ -#!/bin/bash -# -# Healthcheck script for MariaDB -# -# Runs various tests on the MariaDB server to check its health. Pass the tests -# to run as arguments. If all tests succeed, the server is considered healthy, -# otherwise it's not. -# -# Arguments are processed in strict order. Set replication_* options before -# the --replication option. This allows a different set of replication checks -# on different connections. -# -# --su{=|-mysql} is option to run the healthcheck as a different unix user. -# Useful if mysql@localhost user exists with unix socket authentication -# Using this option disregards previous options set, so should usually be the -# first option. -# -# Some tests require SQL privileges. -# -# TEST MINIMUM GRANTS REQUIRED -# connect none* -# innodb_initialized USAGE -# innodb_buffer_pool_loaded USAGE -# galera_online USAGE -# galera_ready USAGE -# replication REPLICATION_CLIENT (<10.5)or REPLICA MONITOR (10.5+) -# mariadbupgrade none, however unix user permissions on datadir -# -# The SQL user used is the default for the mariadb client. This can be the unix user -# if no user(or password) is set in the [mariadb-client] section of a configuration -# file. --defaults-{file,extra-file,group-suffix} can specify a file/configuration -# different from elsewhere. -# -# Note * though denied error message will result in error log without -# any permissions. USAGE recommend to avoid this. - -set -eo pipefail - -_process_sql() -{ - mariadb ${nodefaults:+--no-defaults} \ - ${def['file']:+--defaults-file=${def['file']}} \ - ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ - ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ - --skip-ssl --skip-ssl-verify-server-cert \ - --protocol socket \ - -B "$@" -} - -# TESTS - - -# CONNECT -# -# Tests that a connection can be made over TCP, the final state -# of the entrypoint and is listening. The authentication used -# isn't tested. -connect() -{ - local s - # short cut mechanism, to work with --require-secure-transport - s=$(_process_sql --skip-column-names -e 'select @@skip_networking') - case "$s" in - 0|1) - connect_s=$s - return "$s"; - ;; - esac - # falling back to tcp if there wasn't a connection answer. - s=$(mariadb ${nodefaults:+--no-defaults} \ - ${def['file']:+--defaults-file=${def['file']}} \ - ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ - ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ - --skip-ssl --skip-ssl-verify-server-cert \ - -h localhost --protocol tcp \ - --skip-column-names --batch --skip-print-query-on-error \ - -e 'select @@skip_networking' 2>&1) - - case "$s" in - 1) # skip-networking=1 (no network) - ;& - ERROR\ 2002\ \(HY000\):*) - # cannot connect - connect_s=1 - ;; - 0) # skip-networking=0 - ;& - ERROR\ 1820\ \(HY000\)*) # password expire - ;& - ERROR\ 4151\ \(HY000\):*) # account locked - ;& - ERROR\ 1226\ \(42000\)*) # resource limit exceeded - ;& - ERROR\ 1[0-9][0-9][0-9]\ \(28000\):*) - # grep access denied and other 28000 client errors - we did connect - connect_s=0 - ;; - *) - >&2 echo "Unknown error $s" - connect_s=1 - ;; - esac - return $connect_s -} - -# INNODB_INITIALIZED -# -# This tests that the crash recovery of InnoDB has completed -# along with all the other things required to make it to a healthy -# operational state. Note this may return true in the early -# states of initialization. Use with a connect test to avoid -# these false positives. -innodb_initialized() -{ - local s - s=$(_process_sql --skip-column-names -e "select 1 from information_schema.ENGINES WHERE engine='innodb' AND support in ('YES', 'DEFAULT', 'ENABLED')") - [ "$s" == 1 ] -} - -# INNODB_BUFFER_POOL_LOADED -# -# Tests the load of the innodb buffer pool as been complete -# implies innodb_buffer_pool_load_at_startup=1 (default), or if -# manually SET innodb_buffer_pool_load_now=1 -innodb_buffer_pool_loaded() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='Innodb_buffer_pool_load_status'") - if [[ $s =~ 'load completed' ]]; then - return 0 - fi - return 1 -} - -# GALERA_ONLINE -# -# Tests that the galera node is in the SYNCed state -galera_online() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_LOCAL_STATE'") - # 4 from https://galeracluster.com/library/documentation/node-states.html#node-state-changes - # not https://xkcd.com/221/ - if [[ $s -eq 4 ]]; then - return 0 - fi - return 1 -} - -# GALERA_READY -# -# Tests that the Galera provider is ready. -galera_ready() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_READY'") - if [ "$s" = "ON" ]; then - return 0 - fi - return 1 -} - -# REPLICATION -# -# Tests the replication has the required set of functions: -# --replication_all -> Checks all replication sources -# --replication_name=n -> sets the multisource connection name tested -# --replication_io -> IO thread is running -# --replication_sql -> SQL thread is running -# --replication_seconds_behind_master=n -> less than or equal this seconds of delay -# --replication_sql_remaining_delay=n -> less than or equal this seconds of remaining delay -# (ref: https://mariadb.com/kb/en/delayed-replication/) -replication() -{ - # SHOW REPLICA available 10.5+ - # https://github.com/koalaman/shellcheck/issues/2383 - # shellcheck disable=SC2016,SC2026 - _process_sql -e "SHOW ${repl['all']:+all} REPLICA${repl['all']:+S} ${repl['name']:+'${repl['name']}'} STATUS\G" | \ - { - # required for trim of leading space. - shopt -s extglob - # Row header - read -t 5 -r - # read timeout - [ $? -gt 128 ] && return 1 - while IFS=":" read -t 1 -r n v; do - # Trim leading space - n=${n##+([[:space:]])} - # Leading space on all values by the \G format needs to be trimmed. - v=${v:1} - case "$n" in - Slave_IO_Running) - if [ -n "${repl['io']}" ] && [ "$v" = 'No' ]; then - return 1 - fi - ;; - Slave_SQL_Running) - if [ -n "${repl['sql']}" ] && [ "$v" = 'No' ]; then - return 1 - fi - ;; - Seconds_Behind_Master) - # A NULL value is the IO thread not running: - if [ -n "${repl['seconds_behind_master']}" ] && - { [ "$v" = NULL ] || - (( "${repl['seconds_behind_master']}" < "$v" )); }; then - return 1 - fi - ;; - SQL_Remaining_Delay) - # Unlike Seconds_Behind_Master, sql_remaining_delay will hit NULL - # once replication is caught up - https://mariadb.com/kb/en/delayed-replication/ - if [ -n "${repl['sql_remaining_delay']}" ] && - [ "$v" != NULL ] && - (( "${repl['sql_remaining_delay']}" < "$v" )); then - return 1 - fi - ;; - esac - done - # read timeout - [ $? -gt 128 ] && return 1 - return 0 - } - # reachable in command not found(?) - # shellcheck disable=SC2317 - return $? -} - -# mariadbupgrade -# -# Test the lock on the file $datadir/mariadb_upgrade_info -# https://jira.mariadb.org/browse/MDEV-27068 -mariadbupgrade() -{ - local f="$datadir/mariadb_upgrade_info" - if [ -r "$f" ]; then - flock --exclusive --nonblock -n 9 9<"$f" - return $? - fi - return 0 -} - - -# MAIN - -if [ $# -eq 0 ]; then - echo "At least one argument required" >&2 - exit 1 -fi - -#ENDOFSUBSTITUTIONS -# Marks the end of mysql -> mariadb name changes in 10.6+ -# Global variables used by tests -declare -A repl -declare -A def -nodefaults= -connect_s= -datadir=/var/lib/mysql -if [ -f $datadir/.my-healthcheck.cnf ]; then - def['extra_file']=$datadir/.my-healthcheck.cnf -fi - -_repl_param_check() -{ - case "$1" in - seconds_behind_master) ;& - sql_remaining_delay) - if [ -z "${repl['io']}" ]; then - repl['io']=1 - echo "Forcing --replication_io=1, $1 requires IO thread to be running" >&2 - fi - ;; - all) - if [ -n "${repl['name']}" ]; then - unset 'repl[name]' - echo "Option --replication_all incompatible with specified source --replication_name, clearing replication_name" >&2 - fi - ;; - name) - if [ -n "${repl['all']}" ]; then - unset 'repl[all]' - echo "Option --replication_name incompatible with --replication_all, clearing replication_all" >&2 - fi - ;; - esac -} - -_test_exists() { - declare -F "$1" > /dev/null - return $? -} - -while [ $# -gt 0 ]; do - case "$1" in - --su=*) - u="${1#*=}" - shift - exec gosu "${u}" "${BASH_SOURCE[0]}" "$@" - ;; - --su) - shift - u=$1 - shift - exec gosu "$u" "${BASH_SOURCE[0]}" "$@" - ;; - --su-mysql) - shift - exec gosu mysql "${BASH_SOURCE[0]}" "$@" - ;; - --replication_*=*) - # Change the n to what is between _ and = and make lower case - n=${1#*_} - n=${n%%=*} - n=${n,,*} - # v is after the = - v=${1#*=} - repl[$n]=$v - _repl_param_check "$n" - ;; - --replication_*) - # Without =, look for a non --option next as the value, - # otherwise treat it as an "enable", just equate to 1. - # Clearing option is possible with "--replication_X=" - n=${1#*_} - n=${n,,*} - if [ "${2:0:2}" == '--' ]; then - repl[$n]=1 - else - repl[$n]=$2 - shift - fi - _repl_param_check "$n" - ;; - --datadir=*) - datadir=${1#*=} - ;; - --datadir) - shift - datadir=${1} - ;; - --no-defaults) - def=() - nodefaults=1 - ;; - --defaults-file=*|--defaults-extra-file=*|--defaults-group-suffix=*) - n=${1:11} # length --defaults- - n=${n%%=*} - n=${n//-/_} - # v is after the = - v=${1#*=} - def[$n]=$v - nodefaults= - ;; - --defaults-file|--defaults-extra-file|--defaults-group-suffix) - n=${1:11} # length --defaults- - n=${n//-/_} - if [ "${2:0:2}" == '--' ]; then - def[$n]="" - else - def[$n]=$2 - shift - fi - nodefaults= - ;; - --*) - test=${1#--} - ;; - *) - echo "Unknown healthcheck option $1" >&2 - exit 1 - esac - if [ -n "$test" ]; then - if ! _test_exists "$test" ; then - echo "healthcheck unknown option or test '$test'" >&2 - exit 1 - elif ! "$test"; then - echo "healthcheck $test failed" >&2 - exit 1 - fi - test= - fi - shift -done -if [ "$connect_s" != "0" ]; then - # we didn't pass a connnect test, so the current success status is suspicious - # return what connect thinks. - connect - exit $? -fi diff --git a/11.6-ubi/docker-entrypoint.sh b/11.6-ubi/docker-entrypoint.sh index b654516..9539eb8 100755 --- a/11.6-ubi/docker-entrypoint.sh +++ b/11.6-ubi/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ & @@ -460,7 +461,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -473,7 +473,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -504,7 +503,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -600,8 +598,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -626,8 +623,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi diff --git a/11.6-ubi/healthcheck.sh b/11.6-ubi/healthcheck.sh index ad0b17f..62be345 100755 --- a/11.6-ubi/healthcheck.sh +++ b/11.6-ubi/healthcheck.sh @@ -363,6 +363,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; diff --git a/11.6/docker-entrypoint.sh b/11.6/docker-entrypoint.sh index b654516..9539eb8 100755 --- a/11.6/docker-entrypoint.sh +++ b/11.6/docker-entrypoint.sh @@ -121,6 +121,7 @@ mysql_get_config() { docker_temp_server_start() { "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ --expire-logs-days=0 \ + --skip-slave-start \ --loose-innodb_buffer_pool_load_at_startup=0 \ --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ & @@ -460,7 +461,6 @@ docker_setup_db() { # To create replica user local createReplicaUser= local changeMasterTo= - local startReplica= if [ -n "$MARIADB_REPLICATION_USER" ] ; then if [ -z "$MARIADB_MASTER_HOST" ]; then # on master @@ -473,7 +473,6 @@ docker_setup_db() { # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. # shellcheck disable=SC2153 changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - startReplica="START REPLICA;" fi fi @@ -504,7 +503,6 @@ docker_setup_db() { ${userGrants} ${changeMasterTo} - ${startReplica} EOSQL } @@ -600,8 +598,7 @@ docker_mariadb_upgrade() { fi mysql_note "Starting temporary server" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 mysql_note "Temporary server started." docker_mariadb_backup_system @@ -626,8 +623,7 @@ EOSQL # need a restart as FLUSH PRIVILEGES isn't reversable mysql_note "Restarting temporary server for upgrade" docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 \ - --skip-slave-start + --loose-innodb_buffer_pool_dump_at_shutdown=0 else return 0 fi diff --git a/11.6/healthcheck.sh b/11.6/healthcheck.sh index ad0b17f..62be345 100755 --- a/11.6/healthcheck.sh +++ b/11.6/healthcheck.sh @@ -363,6 +363,11 @@ while [ $# -gt 0 ]; do fi nodefaults= ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; --*) test=${1#--} ;; From e4156145dd549a1d100734a13d3db8960fe7905b Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 19 Sep 2024 16:44:23 +1000 Subject: [PATCH 09/21] 11.5 EOL --- update.sh | 2 -- versions.json | 28 +++++++--------------------- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/update.sh b/update.sh index 2ca1477..cc732cb 100755 --- a/update.sh +++ b/update.sh @@ -55,8 +55,6 @@ update_version() sed -e '/collation-server/d' docker.cnf > "$dir/docker.cnf" if [[ $version != 11.4 ]]; then sed -i -e '/character-set-collations/d' "$dir/docker.cnf" - fi - if [[ $version != 11.[45] ]]; then sed -i -e '/character-set/d' "$dir/docker.cnf" fi fi diff --git a/versions.json b/versions.json index 30d3540..1413724 100644 --- a/versions.json +++ b/versions.json @@ -111,12 +111,12 @@ "s390x" ] }, - "11.5": { - "milestone": "11.5", - "version": "11.5.2", - "fullVersion": "1:11.5.2+maria~ubu2404", + "11.4-ubi/": { + "milestone": "11.4-ubi/", + "version": "11.4.3", + "fullVersion": "1:11.4.3+maria~ubu2404", "releaseStatus": "Stable", - "supportType": "Short Term Support", + "supportType": "Long Term Support", "base": "ubuntu:noble", "arches": [ "amd64", @@ -125,26 +125,12 @@ "s390x" ] }, - "11.5-ubi": { - "milestone": "11.5", - "version": "11.5.2", - "fullVersion": "11.5.2", - "releaseStatus": "Stable", - "supportType": "Short Term Support", - "base": "ubi9", - "arches": [ - "amd64", - "arm64v8", - "ppc64le", - "s390x" - ] - }, "11.6": { "milestone": "11.6", "version": "11.6.1", "fullVersion": "1:11.6.1+maria~ubu2404", - "releaseStatus": "RC", - "supportType": "Short Term Support", + "releaseStatus": "Unknown", + "supportType": "Unknown", "base": "ubuntu:noble", "arches": [ "amd64", From c1fd2c419f468e59d4dc9443890f01ecf28adc00 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 4 Nov 2024 10:13:20 +1100 Subject: [PATCH 10/21] update.sh - handle trailing / in path --- update.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/update.sh b/update.sh index cc732cb..331bda8 100755 --- a/update.sh +++ b/update.sh @@ -219,6 +219,7 @@ fi versions=( "$@" ) for version in "${versions[@]}"; do + version="${version%/}" if [ "${version#*-}" = "ubi" ]; then ubi=-ubi version=${version%-ubi} From 64252135052f269ed2bb57134ad73537e93b7ab6 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 5 Nov 2024 07:49:10 +1100 Subject: [PATCH 11/21] 2024Q4 part 1 release --- 10.11-ubi/Dockerfile | 6 +-- 10.11-ubi/docker-entrypoint.sh | 2 +- 10.11/Dockerfile | 6 +-- 10.11/docker-entrypoint.sh | 2 +- 10.5/Dockerfile | 6 +-- 10.5/docker-entrypoint.sh | 2 +- 10.6-ubi/Dockerfile | 6 +-- 10.6-ubi/docker-entrypoint.sh | 2 +- 10.6/Dockerfile | 6 +-- 10.6/docker-entrypoint.sh | 2 +- 11.2/Dockerfile | 6 +-- 11.2/docker-entrypoint.sh | 2 +- 11.4-ubi/Dockerfile | 6 +-- 11.4-ubi/docker-entrypoint.sh | 2 +- 11.4/Dockerfile | 6 +-- 11.4/docker-entrypoint.sh | 2 +- versions.json | 74 ++++++++-------------------------- 17 files changed, 48 insertions(+), 90 deletions(-) diff --git a/10.11-ubi/Dockerfile b/10.11-ubi/Dockerfile index 61c7abd..9aea844 100644 --- a/10.11-ubi/Dockerfile +++ b/10.11-ubi/Dockerfile @@ -36,7 +36,7 @@ COPY MariaDB.repo /etc/yum.repos.d/ # https://access.redhat.com/documentation/en-us/red_hat_software_certification/2024/html/red_hat_openshift_software_certification_policy_guide/assembly-requirements-for-container-images_openshift-sw-cert-policy-introduction#con-image-metadata-requirements_openshift-sw-cert-policy-container-images LABEL name="MariaDB Server" \ vendor="MariaDB Community" \ - version="10.11.9" \ + version="10.11.10" \ release="Refer to Annotations org.opencontainers.image.{revision,source}" \ summary="MariaDB Database" \ description="MariaDB Database for relational SQL" @@ -50,11 +50,11 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="10.11.9" \ + org.opencontainers.image.version="10.11.10" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=10.11.9 +ARG MARIADB_VERSION=10.11.10 ENV MARIADB_VERSION=$MARIADB_VERSION # release-status:Stable # release-support-type:Long Term Support diff --git a/10.11-ubi/docker-entrypoint.sh b/10.11-ubi/docker-entrypoint.sh index 7f77ab4..6e9a224 100755 --- a/10.11-ubi/docker-entrypoint.sh +++ b/10.11-ubi/docker-entrypoint.sh @@ -223,7 +223,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "10.11.9-MariaDB" + echo -n "10.11.10-MariaDB" } # initializes the database directory diff --git a/10.11/Dockerfile b/10.11/Dockerfile index ded310b..a96e008 100644 --- a/10.11/Dockerfile +++ b/10.11/Dockerfile @@ -75,18 +75,18 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="10.11.9" \ + org.opencontainers.image.version="10.11.10" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=1:10.11.9+maria~ubu2204 +ARG MARIADB_VERSION=1:10.11.10+maria~ubu2204 ENV MARIADB_VERSION $MARIADB_VERSION # release-status:Stable # release-support-type:Long Term Support # (https://downloads.mariadb.org/rest-api/mariadb/) # Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions -ARG REPOSITORY="http://archive.mariadb.org/mariadb-10.11.9/repo/ubuntu/ jammy main main/debug" +ARG REPOSITORY="http://archive.mariadb.org/mariadb-10.11.10/repo/ubuntu/ jammy main main/debug" RUN set -e;\ echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ diff --git a/10.11/docker-entrypoint.sh b/10.11/docker-entrypoint.sh index 7f77ab4..6e9a224 100755 --- a/10.11/docker-entrypoint.sh +++ b/10.11/docker-entrypoint.sh @@ -223,7 +223,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "10.11.9-MariaDB" + echo -n "10.11.10-MariaDB" } # initializes the database directory diff --git a/10.5/Dockerfile b/10.5/Dockerfile index a69c6e5..e0d96e7 100644 --- a/10.5/Dockerfile +++ b/10.5/Dockerfile @@ -75,20 +75,20 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="10.5.26" \ + org.opencontainers.image.version="10.5.27" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x ARG MARIADB_MAJOR=10.5 ENV MARIADB_MAJOR $MARIADB_MAJOR -ARG MARIADB_VERSION=1:10.5.26+maria~ubu2004 +ARG MARIADB_VERSION=1:10.5.27+maria~ubu2004 ENV MARIADB_VERSION $MARIADB_VERSION # release-status:Stable # release-support-type:Long Term Support # (https://downloads.mariadb.org/rest-api/mariadb/) # Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions -ARG REPOSITORY="http://archive.mariadb.org/mariadb-10.5.26/repo/ubuntu/ focal main main/debug" +ARG REPOSITORY="http://archive.mariadb.org/mariadb-10.5.27/repo/ubuntu/ focal main main/debug" RUN set -e;\ echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ diff --git a/10.5/docker-entrypoint.sh b/10.5/docker-entrypoint.sh index ea26650..df9f11c 100755 --- a/10.5/docker-entrypoint.sh +++ b/10.5/docker-entrypoint.sh @@ -215,7 +215,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "10.5.26-MariaDB" + echo -n "10.5.27-MariaDB" } # initializes the database directory diff --git a/10.6-ubi/Dockerfile b/10.6-ubi/Dockerfile index 89b6d20..3b3017c 100644 --- a/10.6-ubi/Dockerfile +++ b/10.6-ubi/Dockerfile @@ -36,7 +36,7 @@ COPY MariaDB.repo /etc/yum.repos.d/ # https://access.redhat.com/documentation/en-us/red_hat_software_certification/2024/html/red_hat_openshift_software_certification_policy_guide/assembly-requirements-for-container-images_openshift-sw-cert-policy-introduction#con-image-metadata-requirements_openshift-sw-cert-policy-container-images LABEL name="MariaDB Server" \ vendor="MariaDB Community" \ - version="10.6.19" \ + version="10.6.20" \ release="Refer to Annotations org.opencontainers.image.{revision,source}" \ summary="MariaDB Database" \ description="MariaDB Database for relational SQL" @@ -50,12 +50,12 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="10.6.19" \ + org.opencontainers.image.version="10.6.20" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x ARG MARIADB_MAJOR=10.6 -ARG MARIADB_VERSION=10.6.19 +ARG MARIADB_VERSION=10.6.20 ENV MARIADB_VERSION=$MARIADB_VERSION # release-status:Stable # release-support-type:Long Term Support diff --git a/10.6-ubi/docker-entrypoint.sh b/10.6-ubi/docker-entrypoint.sh index 4ff446e..d4a3c2f 100755 --- a/10.6-ubi/docker-entrypoint.sh +++ b/10.6-ubi/docker-entrypoint.sh @@ -215,7 +215,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "10.6.19-MariaDB" + echo -n "10.6.20-MariaDB" } # initializes the database directory diff --git a/10.6/Dockerfile b/10.6/Dockerfile index 819b19d..583bed2 100644 --- a/10.6/Dockerfile +++ b/10.6/Dockerfile @@ -75,20 +75,20 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="10.6.19" \ + org.opencontainers.image.version="10.6.20" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x ARG MARIADB_MAJOR=10.6 ENV MARIADB_MAJOR $MARIADB_MAJOR -ARG MARIADB_VERSION=1:10.6.19+maria~ubu2004 +ARG MARIADB_VERSION=1:10.6.20+maria~ubu2004 ENV MARIADB_VERSION $MARIADB_VERSION # release-status:Stable # release-support-type:Long Term Support # (https://downloads.mariadb.org/rest-api/mariadb/) # Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions -ARG REPOSITORY="http://archive.mariadb.org/mariadb-10.6.19/repo/ubuntu/ focal main main/debug" +ARG REPOSITORY="http://archive.mariadb.org/mariadb-10.6.20/repo/ubuntu/ focal main main/debug" RUN set -e;\ echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ diff --git a/10.6/docker-entrypoint.sh b/10.6/docker-entrypoint.sh index 4ff446e..d4a3c2f 100755 --- a/10.6/docker-entrypoint.sh +++ b/10.6/docker-entrypoint.sh @@ -215,7 +215,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "10.6.19-MariaDB" + echo -n "10.6.20-MariaDB" } # initializes the database directory diff --git a/11.2/Dockerfile b/11.2/Dockerfile index 43c01cf..5775b63 100644 --- a/11.2/Dockerfile +++ b/11.2/Dockerfile @@ -75,18 +75,18 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="11.2.5" \ + org.opencontainers.image.version="11.2.6" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=1:11.2.5+maria~ubu2204 +ARG MARIADB_VERSION=1:11.2.6+maria~ubu2204 ENV MARIADB_VERSION $MARIADB_VERSION # release-status:Stable # release-support-type:Short Term Support # (https://downloads.mariadb.org/rest-api/mariadb/) # Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions -ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.2.5/repo/ubuntu/ jammy main main/debug" +ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.2.6/repo/ubuntu/ jammy main main/debug" RUN set -e;\ echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ diff --git a/11.2/docker-entrypoint.sh b/11.2/docker-entrypoint.sh index ea7eb70..5d0e26a 100755 --- a/11.2/docker-entrypoint.sh +++ b/11.2/docker-entrypoint.sh @@ -223,7 +223,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "11.2.5-MariaDB" + echo -n "11.2.6-MariaDB" } # initializes the database directory diff --git a/11.4-ubi/Dockerfile b/11.4-ubi/Dockerfile index fa324dc..6d5670c 100644 --- a/11.4-ubi/Dockerfile +++ b/11.4-ubi/Dockerfile @@ -36,7 +36,7 @@ COPY MariaDB.repo /etc/yum.repos.d/ # https://access.redhat.com/documentation/en-us/red_hat_software_certification/2024/html/red_hat_openshift_software_certification_policy_guide/assembly-requirements-for-container-images_openshift-sw-cert-policy-introduction#con-image-metadata-requirements_openshift-sw-cert-policy-container-images LABEL name="MariaDB Server" \ vendor="MariaDB Community" \ - version="11.4.3" \ + version="11.4.4" \ release="Refer to Annotations org.opencontainers.image.{revision,source}" \ summary="MariaDB Database" \ description="MariaDB Database for relational SQL" @@ -50,11 +50,11 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="11.4.3" \ + org.opencontainers.image.version="11.4.4" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=11.4.3 +ARG MARIADB_VERSION=11.4.4 ENV MARIADB_VERSION=$MARIADB_VERSION # release-status:Stable # release-support-type:Long Term Support diff --git a/11.4-ubi/docker-entrypoint.sh b/11.4-ubi/docker-entrypoint.sh index 1192a4a..d61453d 100755 --- a/11.4-ubi/docker-entrypoint.sh +++ b/11.4-ubi/docker-entrypoint.sh @@ -225,7 +225,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "11.4.3-MariaDB" + echo -n "11.4.4-MariaDB" } # initializes the database directory diff --git a/11.4/Dockerfile b/11.4/Dockerfile index 7fa81d5..c7a6acb 100644 --- a/11.4/Dockerfile +++ b/11.4/Dockerfile @@ -75,18 +75,18 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="11.4.3" \ + org.opencontainers.image.version="11.4.4" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=1:11.4.3+maria~ubu2404 +ARG MARIADB_VERSION=1:11.4.4+maria~ubu2404 ENV MARIADB_VERSION $MARIADB_VERSION # release-status:Stable # release-support-type:Long Term Support # (https://downloads.mariadb.org/rest-api/mariadb/) # Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions -ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.4.3/repo/ubuntu/ noble main main/debug" +ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.4.4/repo/ubuntu/ noble main main/debug" RUN set -e;\ echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ diff --git a/11.4/docker-entrypoint.sh b/11.4/docker-entrypoint.sh index 1192a4a..d61453d 100755 --- a/11.4/docker-entrypoint.sh +++ b/11.4/docker-entrypoint.sh @@ -225,7 +225,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "11.4.3-MariaDB" + echo -n "11.4.4-MariaDB" } # initializes the database directory diff --git a/versions.json b/versions.json index 1413724..5facecf 100644 --- a/versions.json +++ b/versions.json @@ -1,8 +1,8 @@ { "11.4": { "milestone": "11.4", - "version": "11.4.3", - "fullVersion": "1:11.4.3+maria~ubu2404", + "version": "11.4.4", + "fullVersion": "1:11.4.4+maria~ubu2404", "releaseStatus": "Stable", "supportType": "Long Term Support", "base": "ubuntu:noble", @@ -15,8 +15,8 @@ }, "11.4-ubi": { "milestone": "11.4", - "version": "11.4.3", - "fullVersion": "11.4.3", + "version": "11.4.4", + "fullVersion": "11.4.4", "releaseStatus": "Stable", "supportType": "Long Term Support", "base": "ubi9", @@ -29,8 +29,8 @@ }, "11.2": { "milestone": "11.2", - "version": "11.2.5", - "fullVersion": "1:11.2.5+maria~ubu2204", + "version": "11.2.6", + "fullVersion": "1:11.2.6+maria~ubu2204", "releaseStatus": "Stable", "supportType": "Short Term Support", "base": "ubuntu:jammy", @@ -43,8 +43,8 @@ }, "10.11": { "milestone": "10.11", - "version": "10.11.9", - "fullVersion": "1:10.11.9+maria~ubu2204", + "version": "10.11.10", + "fullVersion": "1:10.11.10+maria~ubu2204", "releaseStatus": "Stable", "supportType": "Long Term Support", "base": "ubuntu:jammy", @@ -57,8 +57,8 @@ }, "10.11-ubi": { "milestone": "10.11", - "version": "10.11.9", - "fullVersion": "10.11.9", + "version": "10.11.10", + "fullVersion": "10.11.10", "releaseStatus": "Stable", "supportType": "Long Term Support", "base": "ubi9", @@ -71,8 +71,8 @@ }, "10.6": { "milestone": "10.6", - "version": "10.6.19", - "fullVersion": "1:10.6.19+maria~ubu2004", + "version": "10.6.20", + "fullVersion": "1:10.6.20+maria~ubu2004", "releaseStatus": "Stable", "supportType": "Long Term Support", "base": "ubuntu:focal", @@ -85,8 +85,8 @@ }, "10.6-ubi": { "milestone": "10.6", - "version": "10.6.19", - "fullVersion": "10.6.19", + "version": "10.6.20", + "fullVersion": "10.6.20", "releaseStatus": "Stable", "supportType": "Long Term Support", "base": "ubi9", @@ -99,8 +99,8 @@ }, "10.5": { "milestone": "10.5", - "version": "10.5.26", - "fullVersion": "1:10.5.26+maria~ubu2004", + "version": "10.5.27", + "fullVersion": "1:10.5.27+maria~ubu2004", "releaseStatus": "Stable", "supportType": "Long Term Support", "base": "ubuntu:focal", @@ -110,47 +110,5 @@ "ppc64le", "s390x" ] - }, - "11.4-ubi/": { - "milestone": "11.4-ubi/", - "version": "11.4.3", - "fullVersion": "1:11.4.3+maria~ubu2404", - "releaseStatus": "Stable", - "supportType": "Long Term Support", - "base": "ubuntu:noble", - "arches": [ - "amd64", - "arm64v8", - "ppc64le", - "s390x" - ] - }, - "11.6": { - "milestone": "11.6", - "version": "11.6.1", - "fullVersion": "1:11.6.1+maria~ubu2404", - "releaseStatus": "Unknown", - "supportType": "Unknown", - "base": "ubuntu:noble", - "arches": [ - "amd64", - "arm64v8", - "ppc64le", - "s390x" - ] - }, - "11.6-ubi": { - "milestone": "11.6", - "version": "11.6.1", - "fullVersion": "11.6.1", - "releaseStatus": "RC", - "supportType": "Short Term Support", - "base": "ubi9", - "arches": [ - "amd64", - "arm64v8", - "ppc64le", - "s390x" - ] } } From 48de289b90fdd82166dda66e0fa616b7acce8dac Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 15 Nov 2024 09:29:01 +1100 Subject: [PATCH 12/21] Revert "11.5 EOL" This reverts commit e4156145dd549a1d100734a13d3db8960fe7905b. --- update.sh | 2 ++ versions.json | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/update.sh b/update.sh index 331bda8..9706f78 100755 --- a/update.sh +++ b/update.sh @@ -55,6 +55,8 @@ update_version() sed -e '/collation-server/d' docker.cnf > "$dir/docker.cnf" if [[ $version != 11.4 ]]; then sed -i -e '/character-set-collations/d' "$dir/docker.cnf" + fi + if [[ $version != 11.[45] ]]; then sed -i -e '/character-set/d' "$dir/docker.cnf" fi fi diff --git a/versions.json b/versions.json index 5facecf..c25e533 100644 --- a/versions.json +++ b/versions.json @@ -110,5 +110,61 @@ "ppc64le", "s390x" ] + }, + "11.5": { + "milestone": "11.5", + "version": "11.5.2", + "fullVersion": "1:11.5.2+maria~ubu2404", + "releaseStatus": "Stable", + "supportType": "Short Term Support", + "base": "ubuntu:noble", + "arches": [ + "amd64", + "arm64v8", + "ppc64le", + "s390x" + ] + }, + "11.5-ubi": { + "milestone": "11.5", + "version": "11.5.2", + "fullVersion": "11.5.2", + "releaseStatus": "Stable", + "supportType": "Short Term Support", + "base": "ubi9", + "arches": [ + "amd64", + "arm64v8", + "ppc64le", + "s390x" + ] + }, + "11.6": { + "milestone": "11.6", + "version": "11.6.1", + "fullVersion": "1:11.6.1+maria~ubu2404", + "releaseStatus": "RC", + "supportType": "Short Term Support", + "base": "ubuntu:noble", + "arches": [ + "amd64", + "arm64v8", + "ppc64le", + "s390x" + ] + }, + "11.6-ubi": { + "milestone": "11.6", + "version": "11.6.1", + "fullVersion": "11.6.1", + "releaseStatus": "RC", + "supportType": "Short Term Support", + "base": "ubi9", + "arches": [ + "amd64", + "arm64v8", + "ppc64le", + "s390x" + ] } } From 85df6a9f3d781bb94a88d506eca5c3fcc55d8125 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 15 Nov 2024 09:30:36 +1100 Subject: [PATCH 13/21] Add 11.5 back temporarly --- 11.5-ubi/Dockerfile | 113 ++++++ 11.5-ubi/MariaDB.repo | 7 + 11.5-ubi/docker-entrypoint.sh | 718 ++++++++++++++++++++++++++++++++++ 11.5-ubi/docker.cnf | 15 + 11.5-ubi/healthcheck.sh | 395 +++++++++++++++++++ 11.5/Dockerfile | 142 +++++++ 11.5/docker-entrypoint.sh | 718 ++++++++++++++++++++++++++++++++++ 11.5/healthcheck.sh | 395 +++++++++++++++++++ versions.json | 8 +- 9 files changed, 2507 insertions(+), 4 deletions(-) create mode 100644 11.5-ubi/Dockerfile create mode 100644 11.5-ubi/MariaDB.repo create mode 100755 11.5-ubi/docker-entrypoint.sh create mode 100644 11.5-ubi/docker.cnf create mode 100755 11.5-ubi/healthcheck.sh create mode 100644 11.5/Dockerfile create mode 100755 11.5/docker-entrypoint.sh create mode 100755 11.5/healthcheck.sh diff --git a/11.5-ubi/Dockerfile b/11.5-ubi/Dockerfile new file mode 100644 index 0000000..7c09361 --- /dev/null +++ b/11.5-ubi/Dockerfile @@ -0,0 +1,113 @@ +FROM redhat/ubi9-minimal + +# user 999/ group 999, that we want to use for compatibility with the ubuntu image. +RUN groupadd --gid 999 -r mysql && \ + useradd -r -g mysql mysql --home-dir /var/lib/mysql --uid 999 + +ENV GOSU_VERSION 1.17 +RUN set -eux; \ + rpmArch="$(rpm --query --queryformat='%{ARCH}' rpm)"; \ + case "$rpmArch" in \ + aarch64) dpkgArch='arm64' ;; \ + armv7*) dpkgArch='armhf' ;; \ + i686) dpkgArch='i386' ;; \ + ppc64le) dpkgArch='ppc64el' ;; \ + s390x|riscv64) dpkgArch=$rpmArch ;; \ + x86_64) dpkgArch='amd64' ;; \ + *) echo >&2 "error: unknown/unsupported architecture '$rpmArch'"; exit 1 ;; \ + esac; \ + curl --fail --location --output /usr/local/bin/gosu https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${dpkgArch} ; \ + curl --fail --location --output /usr/local/bin/gosu.asc https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${dpkgArch}.asc; \ + GNUPGHOME="$(mktemp -d)"; \ + export GNUPGHOME; \ + gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ + chmod a+x /usr/local/bin/gosu; \ + gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ + gpgconf --kill all; \ + rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ + gosu --version; \ + gosu nobody true + +COPY --chmod=0644 docker.cnf /etc/my.cnf.d/ + +COPY MariaDB.repo /etc/yum.repos.d/ + +# HasRequiredLabel requirement from Red Hat OpenShift Software Certification +# https://access.redhat.com/documentation/en-us/red_hat_software_certification/2024/html/red_hat_openshift_software_certification_policy_guide/assembly-requirements-for-container-images_openshift-sw-cert-policy-introduction#con-image-metadata-requirements_openshift-sw-cert-policy-container-images +LABEL name="MariaDB Server" \ + vendor="MariaDB Community" \ + version="11.5.2" \ + release="Refer to Annotations org.opencontainers.image.{revision,source}" \ + summary="MariaDB Database" \ + description="MariaDB Database for relational SQL" + +# OCI annotations to image +LABEL org.opencontainers.image.authors="MariaDB Community" \ + org.opencontainers.image.title="MariaDB Database" \ + org.opencontainers.image.description="MariaDB Database for relational SQL" \ + org.opencontainers.image.documentation="https://hub.docker.com/_/mariadb/" \ + org.opencontainers.image.base.name="docker.io/redhat/ubi9-minimal" \ + org.opencontainers.image.licenses="GPL-2.0" \ + org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ + org.opencontainers.image.vendor="MariaDB Community" \ + org.opencontainers.image.version="11.5.2" \ + org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" + +# bashbrew-architectures: amd64 arm64v8 ppc64le s390x +ARG MARIADB_VERSION=11.5.2 +ENV MARIADB_VERSION=$MARIADB_VERSION +# release-status:Unknown +# release-support-type:Unknown +# (https://downloads.mariadb.org/rest-api/mariadb/) + +# missing pwgen(epel), jemalloc(epel) (as entrypoint/user extensions) +# procps, pv(epel) - missing dependencies of galera sst script +# tzdata re-installed as only a fake version is part of the ubi-minimal base image. +# FF8AD1344597106ECE813B918A3872BF3228467C is the Fedora RPM key +# 177F4010FE56CA3336300305F1656F24C74CD1D8 is the MariaDB Server RPM key +RUN set -eux ; \ + curl --fail https://pagure.io/fedora-web/websites/raw/master/f/sites/getfedora.org/static/keys/FF8AD1344597106ECE813B918A3872BF3228467C.txt --output /tmp/epelkey.txt ; \ + GNUPGHOME="$(mktemp -d)"; export GNUPGHOME ; \ + gpg --batch --import /tmp/epelkey.txt ; \ + gpg --batch --armor --export FF8AD1344597106ECE813B918A3872BF3228467C > /tmp/epelkey.txt ; \ + rpmkeys --import /tmp/epelkey.txt ; \ + curl --fail https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm --output /tmp/epel-release-latest-9.noarch.rpm ; \ + rpm -K /tmp/epel-release-latest-9.noarch.rpm ; \ + rpm -ivh /tmp/epel-release-latest-9.noarch.rpm ; \ + rm /tmp/epelkey.txt /tmp/epel-release-latest-9.noarch.rpm ; \ + curl --fail https://supplychain.mariadb.com/MariaDB-Server-GPG-KEY --output /tmp/MariaDB-Server-GPG-KEY ; \ + gpg --batch --import /tmp/MariaDB-Server-GPG-KEY; \ + gpg --batch --armor --export 177F4010FE56CA3336300305F1656F24C74CD1D8 > /tmp/MariaDB-Server-GPG-KEY ; \ + rpmkeys --import /tmp/MariaDB-Server-GPG-KEY ; \ + rm -rf "$GNUPGHOME" /tmp/MariaDB-Server-GPG-KEY ; \ + unset GNUPGHOME ; \ + microdnf update -y ; \ + microdnf reinstall -y tzdata ; \ + microdnf install -y procps-ng zstd xz jemalloc pwgen pv ; \ + mkdir -p /etc/mysql/conf.d /etc/mysql/mariadb.conf.d/ /var/lib/mysql/mysql /run/mariadb /usr/lib64/galera ; \ + chmod ugo+rwx,o+t /run/mariadb ; \ + microdnf install -y MariaDB-backup-${MARIADB_VERSION} MariaDB-server-${MARIADB_VERSION} ; \ + # compatibility with DEB Galera packaging + ln -s /usr/lib64/galera-4/libgalera_smm.so /usr/lib/libgalera_smm.so ; \ + # compatibility with RPM Galera packaging + ln -s /usr/lib64/galera-4/libgalera_smm.so /usr/lib64/galera/libgalera_smm.so ; \ + microdnf clean all ; \ + rmdir /var/lib/mysql/mysql ; \ + chown -R mysql:mysql /var/lib/mysql /run/mariadb ; \ + mkdir /licenses ; \ + ln -s /usr/share/doc/MariaDB-server-${MARIADB_VERSION}/COPYING /licenses/GPL-2 ; \ + ln -s /usr/share/licenses /licenses/package-licenses ; \ + ln -s Apache-2.0-license /licenses/gosu + +VOLUME /var/lib/mysql + +RUN mkdir /docker-entrypoint-initdb.d + +COPY healthcheck.sh /usr/local/bin/healthcheck.sh +COPY docker-entrypoint.sh /usr/local/bin/ + +ENTRYPOINT ["docker-entrypoint.sh"] + +USER mysql +EXPOSE 3306 +CMD ["mariadbd"] diff --git a/11.5-ubi/MariaDB.repo b/11.5-ubi/MariaDB.repo new file mode 100644 index 0000000..777b623 --- /dev/null +++ b/11.5-ubi/MariaDB.repo @@ -0,0 +1,7 @@ +[mariadb] +name = MariaDB +#baseurl = https://rpm.mariadb.org/11.5/rhel/$releasever/$basearch +baseurl = https://archive.mariadb.org/mariadb-11.5/yum/rhel/$releasever/$basearch +#microdnf cannot read to the second key here. +#gpgkey=https://archive.mariadb.org/PublicKey +gpgcheck=1 diff --git a/11.5-ubi/docker-entrypoint.sh b/11.5-ubi/docker-entrypoint.sh new file mode 100755 index 0000000..b562bfa --- /dev/null +++ b/11.5-ubi/docker-entrypoint.sh @@ -0,0 +1,718 @@ +#!/bin/bash +set -eo pipefail +shopt -s nullglob + +# logging functions +mysql_log() { + local type="$1"; shift + printf '%s [%s] [Entrypoint]: %s\n' "$(date --rfc-3339=seconds)" "$type" "$*" +} +mysql_note() { + mysql_log Note "$@" +} +mysql_warn() { + mysql_log Warn "$@" >&2 +} +mysql_error() { + mysql_log ERROR "$@" >&2 + exit 1 +} + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + mysql_error "Both $var and $fileVar are set (but are exclusive)" + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +# set MARIADB_xyz from MYSQL_xyz when MARIADB_xyz is unset +# and make them the same value (so user scripts can use either) +_mariadb_file_env() { + local var="$1"; shift + local maria="MARIADB_${var#MYSQL_}" + file_env "$var" "$@" + file_env "$maria" "${!var}" + if [ "${!maria:-}" ]; then + export "$var"="${!maria}" + fi +} + +# check to see if this file is being run or sourced from another script +_is_sourced() { + # https://unix.stackexchange.com/a/215279 + [ "${#FUNCNAME[@]}" -ge 2 ] \ + && [ "${FUNCNAME[0]}" = '_is_sourced' ] \ + && [ "${FUNCNAME[1]}" = 'source' ] +} + +# usage: docker_process_init_files [file [file [...]]] +# ie: docker_process_init_files /always-initdb.d/* +# process initializer files, based on file extensions +docker_process_init_files() { + # mysql here for backwards compatibility "${mysql[@]}" + # ShellCheck: mysql appears unused. Verify use (or export if used externally) + # shellcheck disable=SC2034 + mysql=( docker_process_sql ) + + echo + local f + for f; do + case "$f" in + *.sh) + # https://github.com/docker-library/postgres/issues/450#issuecomment-393167936 + # https://github.com/docker-library/postgres/pull/452 + if [ -x "$f" ]; then + mysql_note "$0: running $f" + "$f" + else + mysql_note "$0: sourcing $f" + # ShellCheck can't follow non-constant source. Use a directive to specify location. + # shellcheck disable=SC1090 + . "$f" + fi + ;; + *.sql) mysql_note "$0: running $f"; docker_process_sql < "$f"; echo ;; + *.sql.gz) mysql_note "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;; + *.sql.xz) mysql_note "$0: running $f"; xzcat "$f" | docker_process_sql; echo ;; + *.sql.zst) mysql_note "$0: running $f"; zstd -dc "$f" | docker_process_sql; echo ;; + *) mysql_warn "$0: ignoring $f" ;; + esac + echo + done +} + +# arguments necessary to run "mariadbd --verbose --help" successfully (used for testing configuration validity and for extracting default/configured values) +_verboseHelpArgs=( + --verbose --help +) + +mysql_check_config() { + local toRun=( "$@" "${_verboseHelpArgs[@]}" ) errors + if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then + mysql_error $'mariadbd failed while attempting to check config\n\tcommand was: '"${toRun[*]}"$'\n\t'"$errors" + fi +} + +# Fetch value from server config +# We use mariadbd --verbose --help instead of my_print_defaults because the +# latter only show values present in config files, and not server defaults +mysql_get_config() { + local conf="$1"; shift + "$@" "${_verboseHelpArgs[@]}" 2>/dev/null \ + | awk -v conf="$conf" '$1 == conf && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }' + # match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)" +} + +# Do a temporary startup of the MariaDB server, for init purposes +docker_temp_server_start() { + "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ + --expire-logs-days=0 \ + --skip-slave-start \ + --loose-innodb_buffer_pool_load_at_startup=0 \ + --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ + & + declare -g MARIADB_PID + MARIADB_PID=$! + mysql_note "Waiting for server startup" + # only use the root password if the database has already been initialized + # so that it won't try to fill in a password file when it hasn't been set yet + extraArgs=() + if [ -z "$DATABASE_ALREADY_EXISTS" ]; then + extraArgs+=( '--dont-use-mysql-root-password' ) + fi + local i + for i in {30..0}; do + if docker_process_sql "${extraArgs[@]}" --database=mysql \ + --skip-ssl --skip-ssl-verify-server-cert \ + <<<'SELECT 1' &> /dev/null; then + break + fi + sleep 1 + done + if [ "$i" = 0 ]; then + mysql_error "Unable to start server." + fi +} + +# Stop the server. When using a local socket file mariadb-admin will block until +# the shutdown is complete. +docker_temp_server_stop() { + kill "$MARIADB_PID" + wait "$MARIADB_PID" +} + +# Verify that the minimally required password settings are set for new databases. +docker_verify_minimum_env() { + # Restoring from backup requires no environment variables + declare -g DATABASE_INIT_FROM_BACKUP + for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do + if [ -f "${file}" ]; then + DATABASE_INIT_FROM_BACKUP='true' + return + fi + done + if [ -z "$MARIADB_ROOT_PASSWORD" ] && [ -z "$MARIADB_ROOT_PASSWORD_HASH" ] && [ -z "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] && [ -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then + mysql_error $'Database is uninitialized and password option is not specified\n\tYou need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ROOT_PASSWORD_HASH, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' + fi + # More preemptive exclusions of combinations should have been made before *PASSWORD_HASH was added, but for now we don't enforce due to compatibility. + if [ -n "$MARIADB_ROOT_PASSWORD" ] || [ -n "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] || [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ] && [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then + mysql_error "Cannot specify MARIADB_ROOT_PASSWORD_HASH and another MARIADB_ROOT_PASSWORD* option." + fi + if [ -n "$MARIADB_PASSWORD" ] && [ -n "$MARIADB_PASSWORD_HASH" ]; then + mysql_error "Cannot specify MARIADB_PASSWORD_HASH and MARIADB_PASSWORD option." + fi + if [ -n "$MARIADB_REPLICATION_USER" ]; then + if [ -z "$MARIADB_MASTER_HOST" ]; then + # its a master, we're creating a user + if [ -z "$MARIADB_REPLICATION_PASSWORD" ] && [ -z "$MARIADB_REPLICATION_PASSWORD_HASH" ]; then + mysql_error "MARIADB_REPLICATION_PASSWORD or MARIADB_REPLICATION_PASSWORD_HASH not found to create replication user for master" + fi + else + # its a replica + if [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; then + mysql_error "MARIADB_REPLICATION_PASSWORD is mandatory to specify the replication on the replica image." + fi + if [ -n "$MARIADB_REPLICATION_PASSWORD_HASH" ] ; then + mysql_warn "MARIADB_REPLICATION_PASSWORD_HASH cannot be specified on a replica" + fi + fi + fi + if [ -n "$MARIADB_MASTER_HOST" ] && { [ -z "$MARIADB_REPLICATION_USER" ] || [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; }; then + mysql_error "For a replica, MARIADB_REPLICATION_USER and MARIADB_REPLICATION is mandatory." + fi +} + +# creates folders for the database +# also ensures permission for user mysql of run as root +docker_create_db_directories() { + local user; user="$(id -u)" + + # TODO other directories that are used by default? like /var/lib/mysql-files + # see https://github.com/docker-library/mysql/issues/562 + mkdir -p "$DATADIR" + + if [ "$user" = "0" ]; then + # this will cause less disk access than `chown -R` + find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) + # See https://github.com/MariaDB/mariadb-docker/issues/363 + if [ "${SOCKET:0:1}" != '@' ]; then # not abstract sockets + find "${SOCKET%/*}" -maxdepth 0 \! -user mysql \( -exec chown mysql: '{}' \; -o -true \) + fi + + # memory.pressure + local cgroup; cgroup=$( "$DATADIR"/.my-healthcheck.cnf + $maskPreserve +} + +# Initializes database with timezone info and root password, plus optional extra db/user +docker_setup_db() { + # Load timezone info into database + if [ -z "$MARIADB_INITDB_SKIP_TZINFO" ]; then + # --skip-write-binlog usefully disables binary logging + # but also outputs LOCK TABLES to improve the IO of + # Aria (MDEV-23326) for 10.4+. + mariadb-tzinfo-to-sql --skip-write-binlog /usr/share/zoneinfo \ + | docker_process_sql --dont-use-mysql-root-password --database=mysql + # tell docker_process_sql to not use MYSQL_ROOT_PASSWORD since it is not set yet + fi + # Generate random root password + if [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then + MARIADB_ROOT_PASSWORD="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" + export MARIADB_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=$MARIADB_ROOT_PASSWORD + mysql_note "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD" + fi + + # Creates root users for non-localhost hosts + local rootCreate= + local rootPasswordEscaped= + if [ -n "$MARIADB_ROOT_PASSWORD" ]; then + # Sets root password and creates root users for non-localhost hosts + rootPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}") + fi + + # default root to listen for connections from anywhere + if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then + # ref "read -d ''", no, we don't care if read finds a terminating character in this heredoc + # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 + if [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then + read -r -d '' rootCreate <<-EOSQL || true + CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY PASSWORD '${MARIADB_ROOT_PASSWORD_HASH}' ; + GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; + GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; + EOSQL + else + read -r -d '' rootCreate <<-EOSQL || true + CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ; + GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; + GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; + EOSQL + fi + fi + + local mysqlAtLocalhost= + local mysqlAtLocalhostGrants= + # Install mysql@localhost user + if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ]; then + read -r -d '' mysqlAtLocalhost <<-EOSQL || true + CREATE USER mysql@localhost IDENTIFIED VIA unix_socket; + EOSQL + if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + if [ "$MARIADB_MYSQL_LOCALHOST_GRANTS" != USAGE ]; then + mysql_warn "Excessive privileges ON *.* TO mysql@localhost facilitates risks to the confidentiality, integrity and availability of data stored" + fi + mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; + fi + fi + + local createHealthCheckUsers + createHealthCheckUsers=$(create_healthcheck_users) + + local rootLocalhostPass= + if [ -z "$MARIADB_ROOT_PASSWORD_HASH" ]; then + # handle MARIADB_ROOT_PASSWORD_HASH for root@localhost after /docker-entrypoint-initdb.d + rootLocalhostPass="SET PASSWORD FOR 'root'@'localhost'= PASSWORD('${rootPasswordEscaped}');" + fi + + local createDatabase= + # Creates a custom database and user if specified + if [ -n "$MARIADB_DATABASE" ]; then + mysql_note "Creating database ${MARIADB_DATABASE}" + createDatabase="CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\`;" + fi + + local createUser= + local userGrants= + if [ -n "$MARIADB_PASSWORD" ] || [ -n "$MARIADB_PASSWORD_HASH" ] && [ -n "$MARIADB_USER" ]; then + mysql_note "Creating user ${MARIADB_USER}" + if [ -n "$MARIADB_PASSWORD_HASH" ]; then + createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY PASSWORD '$MARIADB_PASSWORD_HASH';" + else + # SQL escape the user password, \ followed by ' + local userPasswordEscaped + userPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_PASSWORD}") + createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$userPasswordEscaped';" + fi + + if [ -n "$MARIADB_DATABASE" ]; then + mysql_note "Giving user ${MARIADB_USER} access to schema ${MARIADB_DATABASE}" + userGrants="GRANT ALL ON \`${MARIADB_DATABASE//_/\\_}\`.* TO '$MARIADB_USER'@'%';" + fi + fi + + # To create replica user + local createReplicaUser= + local changeMasterTo= + if [ -n "$MARIADB_REPLICATION_USER" ] ; then + if [ -z "$MARIADB_MASTER_HOST" ]; then + # on master + mysql_note "Creating user ${MARIADB_REPLICATION_USER}" + createReplicaUser=$(create_replica_user) + else + # on replica + local rplPasswordEscaped + rplPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_REPLICATION_PASSWORD}") + # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. + # shellcheck disable=SC2153 + changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" + fi + fi + + mysql_note "Securing system users (equivalent to running mysql_secure_installation)" + # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set + # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. + docker_process_sql --dont-use-mysql-root-password --database=mysql --binary-mode <<-EOSQL + -- Securing system users shouldn't be replicated + SET @orig_sql_log_bin= @@SESSION.SQL_LOG_BIN; + SET @@SESSION.SQL_LOG_BIN=0; + -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set + SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); + + DROP USER IF EXISTS root@'127.0.0.1', root@'::1'; + EXECUTE IMMEDIATE CONCAT('DROP USER IF EXISTS root@\'', @@hostname,'\''); + + ${rootLocalhostPass} + ${rootCreate} + ${mysqlAtLocalhost} + ${mysqlAtLocalhostGrants} + ${createHealthCheckUsers} + -- end of securing system users, rest of init now... + SET @@SESSION.SQL_LOG_BIN=@orig_sql_log_bin; + -- create users/databases + ${createDatabase} + ${createUser} + ${createReplicaUser} + ${userGrants} + + ${changeMasterTo} + EOSQL +} + +# create a new installation +docker_mariadb_init() +{ + + # check dir permissions to reduce likelihood of half-initialized database + ls /docker-entrypoint-initdb.d/ > /dev/null + + if [ -n "$DATABASE_INIT_FROM_BACKUP" ]; then + shopt -s dotglob + for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do + mkdir -p "$DATADIR"/.init + tar --auto-compress --extract --file "$file" --directory="$DATADIR"/.init + mariadb-backup --target-dir="$DATADIR"/.init --datadir="$DATADIR"/.restore --move-back + + mv "$DATADIR"/.restore/** "$DATADIR"/ + if [ -f "$DATADIR/.init/backup-my.cnf" ]; then + mv "$DATADIR/.init/backup-my.cnf" "$DATADIR/.my.cnf" + mysql_note "Adding startup configuration:" + my_print_defaults --defaults-file="$DATADIR/.my.cnf" --mariadbd + fi + rm -rf "$DATADIR"/.init "$DATADIR"/.restore + if [ "$(id -u)" = "0" ]; then + # this will cause less disk access than `chown -R` + find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) + fi + done + if _check_if_upgrade_is_needed; then + docker_mariadb_upgrade "$@" + fi + return + fi + docker_init_database_dir "$@" + + mysql_note "Starting temporary server" + docker_temp_server_start "$@" + mysql_note "Temporary server started." + + docker_setup_db + docker_process_init_files /docker-entrypoint-initdb.d/* + # Wait until after /docker-entrypoint-initdb.d is performed before setting + # root@localhost password to a hash we don't know the password for. + if [ -n "${MARIADB_ROOT_PASSWORD_HASH}" ]; then + mysql_note "Setting root@localhost password hash" + docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL + SET @@SESSION.SQL_LOG_BIN=0; + SET PASSWORD FOR 'root'@'localhost'= '${MARIADB_ROOT_PASSWORD_HASH}'; + EOSQL + fi + + mysql_note "Stopping temporary server" + docker_temp_server_stop + mysql_note "Temporary server stopped" + + echo + mysql_note "MariaDB init process done. Ready for start up." + echo +} + +# backup the mysql database +docker_mariadb_backup_system() +{ + if [ -n "$MARIADB_DISABLE_UPGRADE_BACKUP" ] \ + && [ "$MARIADB_DISABLE_UPGRADE_BACKUP" = 1 ]; then + mysql_note "MariaDB upgrade backup disabled due to \$MARIADB_DISABLE_UPGRADE_BACKUP=1 setting" + return + fi + local backup_db="system_mysql_backup_unknown_version.sql.zst" + local oldfullversion="unknown_version" + if [ -r "$DATADIR"/mariadb_upgrade_info ]; then + read -r -d '' oldfullversion < "$DATADIR"/mariadb_upgrade_info || true + if [ -n "$oldfullversion" ]; then + backup_db="system_mysql_backup_${oldfullversion}.sql.zst" + fi + fi + + mysql_note "Backing up system database to $backup_db" + if ! mariadb-dump --skip-lock-tables --replace --databases mysql --socket="${SOCKET}" | zstd > "${DATADIR}/${backup_db}"; then + mysql_error "Unable backup system database for upgrade from $oldfullversion." + fi + mysql_note "Backing up complete" +} + +# perform mariadb-upgrade +# backup the mysql database if this is a major upgrade +docker_mariadb_upgrade() { + if [ -z "$MARIADB_AUTO_UPGRADE" ] \ + || [ "$MARIADB_AUTO_UPGRADE" = 0 ]; then + mysql_note "MariaDB upgrade (mariadb-upgrade or creating healthcheck users) required, but skipped due to \$MARIADB_AUTO_UPGRADE setting" + return + fi + mysql_note "Starting temporary server" + docker_temp_server_start "$@" --skip-grant-tables \ + --loose-innodb_buffer_pool_dump_at_shutdown=0 + mysql_note "Temporary server started." + + docker_mariadb_backup_system + + if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then + mysql_note "Creating healthcheck users" + local createHealthCheckUsers + createHealthCheckUsers=$(create_healthcheck_users) + docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL + -- Healthcheck users shouldn't be replicated + SET @@SESSION.SQL_LOG_BIN=0; + -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set + SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); + FLUSH PRIVILEGES; + $createHealthCheckUsers +EOSQL + mysql_note "Stopping temporary server" + docker_temp_server_stop + mysql_note "Temporary server stopped" + + if _check_if_upgrade_is_needed; then + # need a restart as FLUSH PRIVILEGES isn't reversable + mysql_note "Restarting temporary server for upgrade" + docker_temp_server_start "$@" --skip-grant-tables \ + --loose-innodb_buffer_pool_dump_at_shutdown=0 + else + return 0 + fi + fi + + mysql_note "Starting mariadb-upgrade" + mariadb-upgrade --upgrade-system-tables + mysql_note "Finished mariadb-upgrade" + + mysql_note "Stopping temporary server" + docker_temp_server_stop + mysql_note "Temporary server stopped" +} + + +_check_if_upgrade_is_needed() { + if [ ! -f "$DATADIR"/mariadb_upgrade_info ]; then + mysql_note "MariaDB upgrade information missing, assuming required" + return 0 + fi + local mariadbVersion + mariadbVersion="$(_mariadb_version)" + IFS='.-' read -ra newversion <<<"$mariadbVersion" + IFS='.-' read -ra oldversion < "$DATADIR"/mariadb_upgrade_info || true + + if [[ ${#newversion[@]} -lt 2 ]] || [[ ${#oldversion[@]} -lt 2 ]] \ + || [[ ${oldversion[0]} -lt ${newversion[0]} ]] \ + || [[ ${oldversion[0]} -eq ${newversion[0]} && ${oldversion[1]} -lt ${newversion[1]} ]]; then + return 0 + fi + if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then + mysql_note "MariaDB heathcheck configation file missing, assuming desirable" + return 0 + fi + mysql_note "MariaDB upgrade not required" + return 1 +} + +# check arguments for an option that would cause mariadbd to stop +# return true if there is one +_mysql_want_help() { + local arg + for arg; do + case "$arg" in + -'?'|--help|--print-defaults|-V|--version) + return 0 + ;; + esac + done + return 1 +} + +_main() { + # if command starts with an option, prepend mariadbd + if [ "${1:0:1}" = '-' ]; then + set -- mariadbd "$@" + fi + + #ENDOFSUBSTITUTIONS + # skip setup if they aren't running mysqld or want an option that stops mysqld + if [ "$1" = 'mariadbd' ] || [ "$1" = 'mysqld' ] && ! _mysql_want_help "$@"; then + mysql_note "Entrypoint script for MariaDB Server ${MARIADB_VERSION} started." + + mysql_check_config "$@" + # Load various environment variables + docker_setup_env "$@" + docker_create_db_directories + + # If container is started as root user, restart as dedicated mysql user + if [ "$(id -u)" = "0" ]; then + mysql_note "Switching to dedicated user 'mysql'" + exec gosu mysql "${BASH_SOURCE[0]}" "$@" + fi + + # there's no database, so it needs to be initialized + if [ -z "$DATABASE_ALREADY_EXISTS" ]; then + docker_verify_minimum_env + + docker_mariadb_init "$@" + # MDEV-27636 mariadb_upgrade --check-if-upgrade-is-needed cannot be run offline + #elif mariadb-upgrade --check-if-upgrade-is-needed; then + elif _check_if_upgrade_is_needed; then + docker_mariadb_upgrade "$@" + fi + fi + exec "$@" +} + +# If we are sourced from elsewhere, don't perform any further actions +if ! _is_sourced; then + _main "$@" +fi diff --git a/11.5-ubi/docker.cnf b/11.5-ubi/docker.cnf new file mode 100644 index 0000000..844c2cf --- /dev/null +++ b/11.5-ubi/docker.cnf @@ -0,0 +1,15 @@ +# Ubuntu container compatibility + +[mariadb] +host-cache-size=0 +skip-name-resolve + +expire_logs_days=10 +character-set-server=utf8mb4 + + +[client-server] +socket=/run/mariadb/mariadb.sock + +!includedir /etc/mysql/mariadb.conf.d +!includedir /etc/mysql/conf.d diff --git a/11.5-ubi/healthcheck.sh b/11.5-ubi/healthcheck.sh new file mode 100755 index 0000000..62be345 --- /dev/null +++ b/11.5-ubi/healthcheck.sh @@ -0,0 +1,395 @@ +#!/bin/bash +# +# Healthcheck script for MariaDB +# +# Runs various tests on the MariaDB server to check its health. Pass the tests +# to run as arguments. If all tests succeed, the server is considered healthy, +# otherwise it's not. +# +# Arguments are processed in strict order. Set replication_* options before +# the --replication option. This allows a different set of replication checks +# on different connections. +# +# --su{=|-mysql} is option to run the healthcheck as a different unix user. +# Useful if mysql@localhost user exists with unix socket authentication +# Using this option disregards previous options set, so should usually be the +# first option. +# +# Some tests require SQL privileges. +# +# TEST MINIMUM GRANTS REQUIRED +# connect none* +# innodb_initialized USAGE +# innodb_buffer_pool_loaded USAGE +# galera_online USAGE +# galera_ready USAGE +# replication REPLICATION_CLIENT (<10.5)or REPLICA MONITOR (10.5+) +# mariadbupgrade none, however unix user permissions on datadir +# +# The SQL user used is the default for the mariadb client. This can be the unix user +# if no user(or password) is set in the [mariadb-client] section of a configuration +# file. --defaults-{file,extra-file,group-suffix} can specify a file/configuration +# different from elsewhere. +# +# Note * though denied error message will result in error log without +# any permissions. USAGE recommend to avoid this. + +set -eo pipefail + +_process_sql() +{ + mariadb ${nodefaults:+--no-defaults} \ + ${def['file']:+--defaults-file=${def['file']}} \ + ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ + ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ + --skip-ssl --skip-ssl-verify-server-cert \ + --protocol socket \ + -B "$@" +} + +# TESTS + + +# CONNECT +# +# Tests that a connection can be made over TCP, the final state +# of the entrypoint and is listening. The authentication used +# isn't tested. +connect() +{ + local s + # short cut mechanism, to work with --require-secure-transport + s=$(_process_sql --skip-column-names -e 'select @@skip_networking') + case "$s" in + 0|1) + connect_s=$s + return "$s"; + ;; + esac + # falling back to tcp if there wasn't a connection answer. + s=$(mariadb ${nodefaults:+--no-defaults} \ + ${def['file']:+--defaults-file=${def['file']}} \ + ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ + ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ + --skip-ssl --skip-ssl-verify-server-cert \ + -h localhost --protocol tcp \ + --skip-column-names --batch --skip-print-query-on-error \ + -e 'select @@skip_networking' 2>&1) + + case "$s" in + 1) # skip-networking=1 (no network) + ;& + ERROR\ 2002\ \(HY000\):*) + # cannot connect + connect_s=1 + ;; + 0) # skip-networking=0 + ;& + ERROR\ 1820\ \(HY000\)*) # password expire + ;& + ERROR\ 4151\ \(HY000\):*) # account locked + ;& + ERROR\ 1226\ \(42000\)*) # resource limit exceeded + ;& + ERROR\ 1[0-9][0-9][0-9]\ \(28000\):*) + # grep access denied and other 28000 client errors - we did connect + connect_s=0 + ;; + *) + >&2 echo "Unknown error $s" + connect_s=1 + ;; + esac + return $connect_s +} + +# INNODB_INITIALIZED +# +# This tests that the crash recovery of InnoDB has completed +# along with all the other things required to make it to a healthy +# operational state. Note this may return true in the early +# states of initialization. Use with a connect test to avoid +# these false positives. +innodb_initialized() +{ + local s + s=$(_process_sql --skip-column-names -e "select 1 from information_schema.ENGINES WHERE engine='innodb' AND support in ('YES', 'DEFAULT', 'ENABLED')") + [ "$s" == 1 ] +} + +# INNODB_BUFFER_POOL_LOADED +# +# Tests the load of the innodb buffer pool as been complete +# implies innodb_buffer_pool_load_at_startup=1 (default), or if +# manually SET innodb_buffer_pool_load_now=1 +innodb_buffer_pool_loaded() +{ + local s + s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='Innodb_buffer_pool_load_status'") + if [[ $s =~ 'load completed' ]]; then + return 0 + fi + return 1 +} + +# GALERA_ONLINE +# +# Tests that the galera node is in the SYNCed state +galera_online() +{ + local s + s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_LOCAL_STATE'") + # 4 from https://galeracluster.com/library/documentation/node-states.html#node-state-changes + # not https://xkcd.com/221/ + if [[ $s -eq 4 ]]; then + return 0 + fi + return 1 +} + +# GALERA_READY +# +# Tests that the Galera provider is ready. +galera_ready() +{ + local s + s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_READY'") + if [ "$s" = "ON" ]; then + return 0 + fi + return 1 +} + +# REPLICATION +# +# Tests the replication has the required set of functions: +# --replication_all -> Checks all replication sources +# --replication_name=n -> sets the multisource connection name tested +# --replication_io -> IO thread is running +# --replication_sql -> SQL thread is running +# --replication_seconds_behind_master=n -> less than or equal this seconds of delay +# --replication_sql_remaining_delay=n -> less than or equal this seconds of remaining delay +# (ref: https://mariadb.com/kb/en/delayed-replication/) +replication() +{ + # SHOW REPLICA available 10.5+ + # https://github.com/koalaman/shellcheck/issues/2383 + # shellcheck disable=SC2016,SC2026 + _process_sql -e "SHOW ${repl['all']:+all} REPLICA${repl['all']:+S} ${repl['name']:+'${repl['name']}'} STATUS\G" | \ + { + # required for trim of leading space. + shopt -s extglob + # Row header + read -t 5 -r + # read timeout + [ $? -gt 128 ] && return 1 + while IFS=":" read -t 1 -r n v; do + # Trim leading space + n=${n##+([[:space:]])} + # Leading space on all values by the \G format needs to be trimmed. + v=${v:1} + case "$n" in + Slave_IO_Running) + if [ -n "${repl['io']}" ] && [ "$v" = 'No' ]; then + return 1 + fi + ;; + Slave_SQL_Running) + if [ -n "${repl['sql']}" ] && [ "$v" = 'No' ]; then + return 1 + fi + ;; + Seconds_Behind_Master) + # A NULL value is the IO thread not running: + if [ -n "${repl['seconds_behind_master']}" ] && + { [ "$v" = NULL ] || + (( "${repl['seconds_behind_master']}" < "$v" )); }; then + return 1 + fi + ;; + SQL_Remaining_Delay) + # Unlike Seconds_Behind_Master, sql_remaining_delay will hit NULL + # once replication is caught up - https://mariadb.com/kb/en/delayed-replication/ + if [ -n "${repl['sql_remaining_delay']}" ] && + [ "$v" != NULL ] && + (( "${repl['sql_remaining_delay']}" < "$v" )); then + return 1 + fi + ;; + esac + done + # read timeout + [ $? -gt 128 ] && return 1 + return 0 + } + # reachable in command not found(?) + # shellcheck disable=SC2317 + return $? +} + +# mariadbupgrade +# +# Test the lock on the file $datadir/mariadb_upgrade_info +# https://jira.mariadb.org/browse/MDEV-27068 +mariadbupgrade() +{ + local f="$datadir/mariadb_upgrade_info" + if [ -r "$f" ]; then + flock --exclusive --nonblock -n 9 9<"$f" + return $? + fi + return 0 +} + + +# MAIN + +if [ $# -eq 0 ]; then + echo "At least one argument required" >&2 + exit 1 +fi + +#ENDOFSUBSTITUTIONS +# Marks the end of mysql -> mariadb name changes in 10.6+ +# Global variables used by tests +declare -A repl +declare -A def +nodefaults= +connect_s= +datadir=/var/lib/mysql +if [ -f $datadir/.my-healthcheck.cnf ]; then + def['extra_file']=$datadir/.my-healthcheck.cnf +fi + +_repl_param_check() +{ + case "$1" in + seconds_behind_master) ;& + sql_remaining_delay) + if [ -z "${repl['io']}" ]; then + repl['io']=1 + echo "Forcing --replication_io=1, $1 requires IO thread to be running" >&2 + fi + ;; + all) + if [ -n "${repl['name']}" ]; then + unset 'repl[name]' + echo "Option --replication_all incompatible with specified source --replication_name, clearing replication_name" >&2 + fi + ;; + name) + if [ -n "${repl['all']}" ]; then + unset 'repl[all]' + echo "Option --replication_name incompatible with --replication_all, clearing replication_all" >&2 + fi + ;; + esac +} + +_test_exists() { + declare -F "$1" > /dev/null + return $? +} + +while [ $# -gt 0 ]; do + case "$1" in + --su=*) + u="${1#*=}" + shift + exec gosu "${u}" "${BASH_SOURCE[0]}" "$@" + ;; + --su) + shift + u=$1 + shift + exec gosu "$u" "${BASH_SOURCE[0]}" "$@" + ;; + --su-mysql) + shift + exec gosu mysql "${BASH_SOURCE[0]}" "$@" + ;; + --replication_*=*) + # Change the n to what is between _ and = and make lower case + n=${1#*_} + n=${n%%=*} + n=${n,,*} + # v is after the = + v=${1#*=} + repl[$n]=$v + _repl_param_check "$n" + ;; + --replication_*) + # Without =, look for a non --option next as the value, + # otherwise treat it as an "enable", just equate to 1. + # Clearing option is possible with "--replication_X=" + n=${1#*_} + n=${n,,*} + if [ "${2:0:2}" == '--' ]; then + repl[$n]=1 + else + repl[$n]=$2 + shift + fi + _repl_param_check "$n" + ;; + --datadir=*) + datadir=${1#*=} + ;; + --datadir) + shift + datadir=${1} + ;; + --no-defaults) + def=() + nodefaults=1 + ;; + --defaults-file=*|--defaults-extra-file=*|--defaults-group-suffix=*) + n=${1:11} # length --defaults- + n=${n%%=*} + n=${n//-/_} + # v is after the = + v=${1#*=} + def[$n]=$v + nodefaults= + ;; + --defaults-file|--defaults-extra-file|--defaults-group-suffix) + n=${1:11} # length --defaults- + n=${n//-/_} + if [ "${2:0:2}" == '--' ]; then + def[$n]="" + else + def[$n]=$2 + shift + fi + nodefaults= + ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; + --*) + test=${1#--} + ;; + *) + echo "Unknown healthcheck option $1" >&2 + exit 1 + esac + if [ -n "$test" ]; then + if ! _test_exists "$test" ; then + echo "healthcheck unknown option or test '$test'" >&2 + exit 1 + elif ! "$test"; then + echo "healthcheck $test failed" >&2 + exit 1 + fi + test= + fi + shift +done +if [ "$connect_s" != "0" ]; then + # we didn't pass a connnect test, so the current success status is suspicious + # return what connect thinks. + connect + exit $? +fi diff --git a/11.5/Dockerfile b/11.5/Dockerfile new file mode 100644 index 0000000..a7f1aa0 --- /dev/null +++ b/11.5/Dockerfile @@ -0,0 +1,142 @@ +# vim:set ft=dockerfile: +FROM ubuntu:noble + +# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added +RUN groupadd -r mysql && useradd -r -g mysql mysql --home-dir /var/lib/mysql && userdel --remove ubuntu + +# add gosu for easy step-down from root +# https://github.com/tianon/gosu/releases +# gosu key is B42F6819007F00F88E364FD4036A9C25BF357DD4 +ENV GOSU_VERSION 1.17 + +ARG GPG_KEYS=177F4010FE56CA3336300305F1656F24C74CD1D8 +# pub rsa4096 2016-03-30 [SC] +# 177F 4010 FE56 CA33 3630 0305 F165 6F24 C74C D1D8 +# uid [ unknown] MariaDB Signing Key +# sub rsa4096 2016-03-30 [E] +# install "libjemalloc2" as it offers better performance in some cases. Use with LD_PRELOAD +# install "pwgen" for randomizing passwords +# install "tzdata" for /usr/share/zoneinfo/ +# install "xz-utils" for .sql.xz docker-entrypoint-initdb.d files +# install "zstd" for .sql.zst docker-entrypoint-initdb.d files +# hadolint ignore=SC2086 +RUN set -eux; \ + apt-get update; \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + ca-certificates \ + gpg \ + gpgv \ + libjemalloc2 \ + pwgen \ + tzdata \ + xz-utils \ + zstd ; \ + savedAptMark="$(apt-mark showmanual)"; \ + apt-get install -y --no-install-recommends \ + dirmngr \ + gpg-agent \ + wget; \ + rm -rf /var/lib/apt/lists/*; \ + dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ + wget -q -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ + wget -q -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ + GNUPGHOME="$(mktemp -d)"; \ + export GNUPGHOME; \ + gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ + for key in $GPG_KEYS; do \ + gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key"; \ + done; \ + gpg --batch --export "$GPG_KEYS" > /etc/apt/trusted.gpg.d/mariadb.gpg; \ + if command -v gpgconf >/dev/null; then \ + gpgconf --kill all; \ + fi; \ + gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ + gpgconf --kill all; \ + rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ + apt-mark auto '.*' > /dev/null; \ + [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark >/dev/null; \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ + chmod +x /usr/local/bin/gosu; \ + gosu --version; \ + gosu nobody true + +RUN mkdir /docker-entrypoint-initdb.d + +# Ensure the container exec commands handle range of utf8 characters based of +# default locales in base image (https://github.com/docker-library/docs/blob/135b79cc8093ab02e55debb61fdb079ab2dbce87/ubuntu/README.md#locales) +ENV LANG C.UTF-8 + +# OCI annotations to image +LABEL org.opencontainers.image.authors="MariaDB Community" \ + org.opencontainers.image.title="MariaDB Database" \ + org.opencontainers.image.description="MariaDB Database for relational SQL" \ + org.opencontainers.image.documentation="https://hub.docker.com/_/mariadb/" \ + org.opencontainers.image.base.name="docker.io/library/ubuntu:noble" \ + org.opencontainers.image.licenses="GPL-2.0" \ + org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ + org.opencontainers.image.vendor="MariaDB Community" \ + org.opencontainers.image.version="11.5.2" \ + org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" + +# bashbrew-architectures: amd64 arm64v8 ppc64le s390x +ARG MARIADB_VERSION=1:11.5.2+maria~ubu2404 +ENV MARIADB_VERSION $MARIADB_VERSION +# release-status:Unknown +# release-support-type:Unknown +# (https://downloads.mariadb.org/rest-api/mariadb/) + +# Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions +ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.5.2/repo/ubuntu/ noble main main/debug" + +RUN set -e;\ + echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ + { \ + echo 'Package: *'; \ + echo 'Pin: release o=MariaDB'; \ + echo 'Pin-Priority: 999'; \ + } > /etc/apt/preferences.d/mariadb +# add repository pinning to make sure dependencies from this MariaDB repo are preferred over Debian dependencies +# libmariadbclient18 : Depends: libmysqlclient18 (= 5.5.42+maria-1~wheezy) but 5.5.43-0+deb7u1 is to be installed + +# the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) +# also, we set debconf keys to make APT a little quieter +# hadolint ignore=DL3015 +RUN set -ex; \ + { \ + echo "mariadb-server" mysql-server/root_password password 'unused'; \ + echo "mariadb-server" mysql-server/root_password_again password 'unused'; \ + } | debconf-set-selections; \ + apt-get update; \ +# postinst script creates a datadir, so avoid creating it by faking its existance. + mkdir -p /var/lib/mysql/mysql ; touch /var/lib/mysql/mysql/user.frm ; \ +# mariadb-backup is installed at the same time so that `mysql-common` is only installed once from just mariadb repos + apt-get install -y --no-install-recommends mariadb-server="$MARIADB_VERSION" mariadb-backup socat \ + ; \ + rm -rf /var/lib/apt/lists/*; \ +# purge and re-create /var/lib/mysql with appropriate ownership + rm -rf /var/lib/mysql; \ + mkdir -p /var/lib/mysql /run/mysqld; \ + chown -R mysql:mysql /var/lib/mysql /run/mysqld; \ +# ensure that /run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime + chmod 1777 /run/mysqld; \ +# comment out a few problematic configuration values + find /etc/mysql/ -name '*.cnf' -print0 \ + | xargs -0 grep -lZE '^(bind-address|log|user\s)' \ + | xargs -rt -0 sed -Ei 's/^(bind-address|log|user\s)/#&/'; \ +# don't reverse lookup hostnames, they are usually another container + printf "[mariadb]\nhost-cache-size=0\nskip-name-resolve\n" > /etc/mysql/mariadb.conf.d/05-skipcache.cnf; \ +# Issue #327 Correct order of reading directories /etc/mysql/mariadb.conf.d before /etc/mysql/conf.d (mount-point per documentation) + if [ -L /etc/mysql/my.cnf ]; then \ +# 10.5+ + sed -i -e '/includedir/ {N;s/\(.*\)\n\(.*\)/\n\2\n\1/}' /etc/mysql/mariadb.cnf; \ + fi + + +VOLUME /var/lib/mysql + +COPY healthcheck.sh /usr/local/bin/healthcheck.sh +COPY docker-entrypoint.sh /usr/local/bin/ +ENTRYPOINT ["docker-entrypoint.sh"] + +EXPOSE 3306 +CMD ["mariadbd"] diff --git a/11.5/docker-entrypoint.sh b/11.5/docker-entrypoint.sh new file mode 100755 index 0000000..b562bfa --- /dev/null +++ b/11.5/docker-entrypoint.sh @@ -0,0 +1,718 @@ +#!/bin/bash +set -eo pipefail +shopt -s nullglob + +# logging functions +mysql_log() { + local type="$1"; shift + printf '%s [%s] [Entrypoint]: %s\n' "$(date --rfc-3339=seconds)" "$type" "$*" +} +mysql_note() { + mysql_log Note "$@" +} +mysql_warn() { + mysql_log Warn "$@" >&2 +} +mysql_error() { + mysql_log ERROR "$@" >&2 + exit 1 +} + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + mysql_error "Both $var and $fileVar are set (but are exclusive)" + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +# set MARIADB_xyz from MYSQL_xyz when MARIADB_xyz is unset +# and make them the same value (so user scripts can use either) +_mariadb_file_env() { + local var="$1"; shift + local maria="MARIADB_${var#MYSQL_}" + file_env "$var" "$@" + file_env "$maria" "${!var}" + if [ "${!maria:-}" ]; then + export "$var"="${!maria}" + fi +} + +# check to see if this file is being run or sourced from another script +_is_sourced() { + # https://unix.stackexchange.com/a/215279 + [ "${#FUNCNAME[@]}" -ge 2 ] \ + && [ "${FUNCNAME[0]}" = '_is_sourced' ] \ + && [ "${FUNCNAME[1]}" = 'source' ] +} + +# usage: docker_process_init_files [file [file [...]]] +# ie: docker_process_init_files /always-initdb.d/* +# process initializer files, based on file extensions +docker_process_init_files() { + # mysql here for backwards compatibility "${mysql[@]}" + # ShellCheck: mysql appears unused. Verify use (or export if used externally) + # shellcheck disable=SC2034 + mysql=( docker_process_sql ) + + echo + local f + for f; do + case "$f" in + *.sh) + # https://github.com/docker-library/postgres/issues/450#issuecomment-393167936 + # https://github.com/docker-library/postgres/pull/452 + if [ -x "$f" ]; then + mysql_note "$0: running $f" + "$f" + else + mysql_note "$0: sourcing $f" + # ShellCheck can't follow non-constant source. Use a directive to specify location. + # shellcheck disable=SC1090 + . "$f" + fi + ;; + *.sql) mysql_note "$0: running $f"; docker_process_sql < "$f"; echo ;; + *.sql.gz) mysql_note "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;; + *.sql.xz) mysql_note "$0: running $f"; xzcat "$f" | docker_process_sql; echo ;; + *.sql.zst) mysql_note "$0: running $f"; zstd -dc "$f" | docker_process_sql; echo ;; + *) mysql_warn "$0: ignoring $f" ;; + esac + echo + done +} + +# arguments necessary to run "mariadbd --verbose --help" successfully (used for testing configuration validity and for extracting default/configured values) +_verboseHelpArgs=( + --verbose --help +) + +mysql_check_config() { + local toRun=( "$@" "${_verboseHelpArgs[@]}" ) errors + if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then + mysql_error $'mariadbd failed while attempting to check config\n\tcommand was: '"${toRun[*]}"$'\n\t'"$errors" + fi +} + +# Fetch value from server config +# We use mariadbd --verbose --help instead of my_print_defaults because the +# latter only show values present in config files, and not server defaults +mysql_get_config() { + local conf="$1"; shift + "$@" "${_verboseHelpArgs[@]}" 2>/dev/null \ + | awk -v conf="$conf" '$1 == conf && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }' + # match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)" +} + +# Do a temporary startup of the MariaDB server, for init purposes +docker_temp_server_start() { + "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ + --expire-logs-days=0 \ + --skip-slave-start \ + --loose-innodb_buffer_pool_load_at_startup=0 \ + --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ + & + declare -g MARIADB_PID + MARIADB_PID=$! + mysql_note "Waiting for server startup" + # only use the root password if the database has already been initialized + # so that it won't try to fill in a password file when it hasn't been set yet + extraArgs=() + if [ -z "$DATABASE_ALREADY_EXISTS" ]; then + extraArgs+=( '--dont-use-mysql-root-password' ) + fi + local i + for i in {30..0}; do + if docker_process_sql "${extraArgs[@]}" --database=mysql \ + --skip-ssl --skip-ssl-verify-server-cert \ + <<<'SELECT 1' &> /dev/null; then + break + fi + sleep 1 + done + if [ "$i" = 0 ]; then + mysql_error "Unable to start server." + fi +} + +# Stop the server. When using a local socket file mariadb-admin will block until +# the shutdown is complete. +docker_temp_server_stop() { + kill "$MARIADB_PID" + wait "$MARIADB_PID" +} + +# Verify that the minimally required password settings are set for new databases. +docker_verify_minimum_env() { + # Restoring from backup requires no environment variables + declare -g DATABASE_INIT_FROM_BACKUP + for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do + if [ -f "${file}" ]; then + DATABASE_INIT_FROM_BACKUP='true' + return + fi + done + if [ -z "$MARIADB_ROOT_PASSWORD" ] && [ -z "$MARIADB_ROOT_PASSWORD_HASH" ] && [ -z "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] && [ -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then + mysql_error $'Database is uninitialized and password option is not specified\n\tYou need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ROOT_PASSWORD_HASH, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' + fi + # More preemptive exclusions of combinations should have been made before *PASSWORD_HASH was added, but for now we don't enforce due to compatibility. + if [ -n "$MARIADB_ROOT_PASSWORD" ] || [ -n "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] || [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ] && [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then + mysql_error "Cannot specify MARIADB_ROOT_PASSWORD_HASH and another MARIADB_ROOT_PASSWORD* option." + fi + if [ -n "$MARIADB_PASSWORD" ] && [ -n "$MARIADB_PASSWORD_HASH" ]; then + mysql_error "Cannot specify MARIADB_PASSWORD_HASH and MARIADB_PASSWORD option." + fi + if [ -n "$MARIADB_REPLICATION_USER" ]; then + if [ -z "$MARIADB_MASTER_HOST" ]; then + # its a master, we're creating a user + if [ -z "$MARIADB_REPLICATION_PASSWORD" ] && [ -z "$MARIADB_REPLICATION_PASSWORD_HASH" ]; then + mysql_error "MARIADB_REPLICATION_PASSWORD or MARIADB_REPLICATION_PASSWORD_HASH not found to create replication user for master" + fi + else + # its a replica + if [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; then + mysql_error "MARIADB_REPLICATION_PASSWORD is mandatory to specify the replication on the replica image." + fi + if [ -n "$MARIADB_REPLICATION_PASSWORD_HASH" ] ; then + mysql_warn "MARIADB_REPLICATION_PASSWORD_HASH cannot be specified on a replica" + fi + fi + fi + if [ -n "$MARIADB_MASTER_HOST" ] && { [ -z "$MARIADB_REPLICATION_USER" ] || [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; }; then + mysql_error "For a replica, MARIADB_REPLICATION_USER and MARIADB_REPLICATION is mandatory." + fi +} + +# creates folders for the database +# also ensures permission for user mysql of run as root +docker_create_db_directories() { + local user; user="$(id -u)" + + # TODO other directories that are used by default? like /var/lib/mysql-files + # see https://github.com/docker-library/mysql/issues/562 + mkdir -p "$DATADIR" + + if [ "$user" = "0" ]; then + # this will cause less disk access than `chown -R` + find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) + # See https://github.com/MariaDB/mariadb-docker/issues/363 + if [ "${SOCKET:0:1}" != '@' ]; then # not abstract sockets + find "${SOCKET%/*}" -maxdepth 0 \! -user mysql \( -exec chown mysql: '{}' \; -o -true \) + fi + + # memory.pressure + local cgroup; cgroup=$( "$DATADIR"/.my-healthcheck.cnf + $maskPreserve +} + +# Initializes database with timezone info and root password, plus optional extra db/user +docker_setup_db() { + # Load timezone info into database + if [ -z "$MARIADB_INITDB_SKIP_TZINFO" ]; then + # --skip-write-binlog usefully disables binary logging + # but also outputs LOCK TABLES to improve the IO of + # Aria (MDEV-23326) for 10.4+. + mariadb-tzinfo-to-sql --skip-write-binlog /usr/share/zoneinfo \ + | docker_process_sql --dont-use-mysql-root-password --database=mysql + # tell docker_process_sql to not use MYSQL_ROOT_PASSWORD since it is not set yet + fi + # Generate random root password + if [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then + MARIADB_ROOT_PASSWORD="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" + export MARIADB_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=$MARIADB_ROOT_PASSWORD + mysql_note "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD" + fi + + # Creates root users for non-localhost hosts + local rootCreate= + local rootPasswordEscaped= + if [ -n "$MARIADB_ROOT_PASSWORD" ]; then + # Sets root password and creates root users for non-localhost hosts + rootPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}") + fi + + # default root to listen for connections from anywhere + if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then + # ref "read -d ''", no, we don't care if read finds a terminating character in this heredoc + # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 + if [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then + read -r -d '' rootCreate <<-EOSQL || true + CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY PASSWORD '${MARIADB_ROOT_PASSWORD_HASH}' ; + GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; + GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; + EOSQL + else + read -r -d '' rootCreate <<-EOSQL || true + CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ; + GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; + GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; + EOSQL + fi + fi + + local mysqlAtLocalhost= + local mysqlAtLocalhostGrants= + # Install mysql@localhost user + if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ]; then + read -r -d '' mysqlAtLocalhost <<-EOSQL || true + CREATE USER mysql@localhost IDENTIFIED VIA unix_socket; + EOSQL + if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + if [ "$MARIADB_MYSQL_LOCALHOST_GRANTS" != USAGE ]; then + mysql_warn "Excessive privileges ON *.* TO mysql@localhost facilitates risks to the confidentiality, integrity and availability of data stored" + fi + mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; + fi + fi + + local createHealthCheckUsers + createHealthCheckUsers=$(create_healthcheck_users) + + local rootLocalhostPass= + if [ -z "$MARIADB_ROOT_PASSWORD_HASH" ]; then + # handle MARIADB_ROOT_PASSWORD_HASH for root@localhost after /docker-entrypoint-initdb.d + rootLocalhostPass="SET PASSWORD FOR 'root'@'localhost'= PASSWORD('${rootPasswordEscaped}');" + fi + + local createDatabase= + # Creates a custom database and user if specified + if [ -n "$MARIADB_DATABASE" ]; then + mysql_note "Creating database ${MARIADB_DATABASE}" + createDatabase="CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\`;" + fi + + local createUser= + local userGrants= + if [ -n "$MARIADB_PASSWORD" ] || [ -n "$MARIADB_PASSWORD_HASH" ] && [ -n "$MARIADB_USER" ]; then + mysql_note "Creating user ${MARIADB_USER}" + if [ -n "$MARIADB_PASSWORD_HASH" ]; then + createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY PASSWORD '$MARIADB_PASSWORD_HASH';" + else + # SQL escape the user password, \ followed by ' + local userPasswordEscaped + userPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_PASSWORD}") + createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$userPasswordEscaped';" + fi + + if [ -n "$MARIADB_DATABASE" ]; then + mysql_note "Giving user ${MARIADB_USER} access to schema ${MARIADB_DATABASE}" + userGrants="GRANT ALL ON \`${MARIADB_DATABASE//_/\\_}\`.* TO '$MARIADB_USER'@'%';" + fi + fi + + # To create replica user + local createReplicaUser= + local changeMasterTo= + if [ -n "$MARIADB_REPLICATION_USER" ] ; then + if [ -z "$MARIADB_MASTER_HOST" ]; then + # on master + mysql_note "Creating user ${MARIADB_REPLICATION_USER}" + createReplicaUser=$(create_replica_user) + else + # on replica + local rplPasswordEscaped + rplPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_REPLICATION_PASSWORD}") + # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. + # shellcheck disable=SC2153 + changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" + fi + fi + + mysql_note "Securing system users (equivalent to running mysql_secure_installation)" + # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set + # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. + docker_process_sql --dont-use-mysql-root-password --database=mysql --binary-mode <<-EOSQL + -- Securing system users shouldn't be replicated + SET @orig_sql_log_bin= @@SESSION.SQL_LOG_BIN; + SET @@SESSION.SQL_LOG_BIN=0; + -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set + SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); + + DROP USER IF EXISTS root@'127.0.0.1', root@'::1'; + EXECUTE IMMEDIATE CONCAT('DROP USER IF EXISTS root@\'', @@hostname,'\''); + + ${rootLocalhostPass} + ${rootCreate} + ${mysqlAtLocalhost} + ${mysqlAtLocalhostGrants} + ${createHealthCheckUsers} + -- end of securing system users, rest of init now... + SET @@SESSION.SQL_LOG_BIN=@orig_sql_log_bin; + -- create users/databases + ${createDatabase} + ${createUser} + ${createReplicaUser} + ${userGrants} + + ${changeMasterTo} + EOSQL +} + +# create a new installation +docker_mariadb_init() +{ + + # check dir permissions to reduce likelihood of half-initialized database + ls /docker-entrypoint-initdb.d/ > /dev/null + + if [ -n "$DATABASE_INIT_FROM_BACKUP" ]; then + shopt -s dotglob + for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do + mkdir -p "$DATADIR"/.init + tar --auto-compress --extract --file "$file" --directory="$DATADIR"/.init + mariadb-backup --target-dir="$DATADIR"/.init --datadir="$DATADIR"/.restore --move-back + + mv "$DATADIR"/.restore/** "$DATADIR"/ + if [ -f "$DATADIR/.init/backup-my.cnf" ]; then + mv "$DATADIR/.init/backup-my.cnf" "$DATADIR/.my.cnf" + mysql_note "Adding startup configuration:" + my_print_defaults --defaults-file="$DATADIR/.my.cnf" --mariadbd + fi + rm -rf "$DATADIR"/.init "$DATADIR"/.restore + if [ "$(id -u)" = "0" ]; then + # this will cause less disk access than `chown -R` + find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) + fi + done + if _check_if_upgrade_is_needed; then + docker_mariadb_upgrade "$@" + fi + return + fi + docker_init_database_dir "$@" + + mysql_note "Starting temporary server" + docker_temp_server_start "$@" + mysql_note "Temporary server started." + + docker_setup_db + docker_process_init_files /docker-entrypoint-initdb.d/* + # Wait until after /docker-entrypoint-initdb.d is performed before setting + # root@localhost password to a hash we don't know the password for. + if [ -n "${MARIADB_ROOT_PASSWORD_HASH}" ]; then + mysql_note "Setting root@localhost password hash" + docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL + SET @@SESSION.SQL_LOG_BIN=0; + SET PASSWORD FOR 'root'@'localhost'= '${MARIADB_ROOT_PASSWORD_HASH}'; + EOSQL + fi + + mysql_note "Stopping temporary server" + docker_temp_server_stop + mysql_note "Temporary server stopped" + + echo + mysql_note "MariaDB init process done. Ready for start up." + echo +} + +# backup the mysql database +docker_mariadb_backup_system() +{ + if [ -n "$MARIADB_DISABLE_UPGRADE_BACKUP" ] \ + && [ "$MARIADB_DISABLE_UPGRADE_BACKUP" = 1 ]; then + mysql_note "MariaDB upgrade backup disabled due to \$MARIADB_DISABLE_UPGRADE_BACKUP=1 setting" + return + fi + local backup_db="system_mysql_backup_unknown_version.sql.zst" + local oldfullversion="unknown_version" + if [ -r "$DATADIR"/mariadb_upgrade_info ]; then + read -r -d '' oldfullversion < "$DATADIR"/mariadb_upgrade_info || true + if [ -n "$oldfullversion" ]; then + backup_db="system_mysql_backup_${oldfullversion}.sql.zst" + fi + fi + + mysql_note "Backing up system database to $backup_db" + if ! mariadb-dump --skip-lock-tables --replace --databases mysql --socket="${SOCKET}" | zstd > "${DATADIR}/${backup_db}"; then + mysql_error "Unable backup system database for upgrade from $oldfullversion." + fi + mysql_note "Backing up complete" +} + +# perform mariadb-upgrade +# backup the mysql database if this is a major upgrade +docker_mariadb_upgrade() { + if [ -z "$MARIADB_AUTO_UPGRADE" ] \ + || [ "$MARIADB_AUTO_UPGRADE" = 0 ]; then + mysql_note "MariaDB upgrade (mariadb-upgrade or creating healthcheck users) required, but skipped due to \$MARIADB_AUTO_UPGRADE setting" + return + fi + mysql_note "Starting temporary server" + docker_temp_server_start "$@" --skip-grant-tables \ + --loose-innodb_buffer_pool_dump_at_shutdown=0 + mysql_note "Temporary server started." + + docker_mariadb_backup_system + + if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then + mysql_note "Creating healthcheck users" + local createHealthCheckUsers + createHealthCheckUsers=$(create_healthcheck_users) + docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL + -- Healthcheck users shouldn't be replicated + SET @@SESSION.SQL_LOG_BIN=0; + -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set + SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); + FLUSH PRIVILEGES; + $createHealthCheckUsers +EOSQL + mysql_note "Stopping temporary server" + docker_temp_server_stop + mysql_note "Temporary server stopped" + + if _check_if_upgrade_is_needed; then + # need a restart as FLUSH PRIVILEGES isn't reversable + mysql_note "Restarting temporary server for upgrade" + docker_temp_server_start "$@" --skip-grant-tables \ + --loose-innodb_buffer_pool_dump_at_shutdown=0 + else + return 0 + fi + fi + + mysql_note "Starting mariadb-upgrade" + mariadb-upgrade --upgrade-system-tables + mysql_note "Finished mariadb-upgrade" + + mysql_note "Stopping temporary server" + docker_temp_server_stop + mysql_note "Temporary server stopped" +} + + +_check_if_upgrade_is_needed() { + if [ ! -f "$DATADIR"/mariadb_upgrade_info ]; then + mysql_note "MariaDB upgrade information missing, assuming required" + return 0 + fi + local mariadbVersion + mariadbVersion="$(_mariadb_version)" + IFS='.-' read -ra newversion <<<"$mariadbVersion" + IFS='.-' read -ra oldversion < "$DATADIR"/mariadb_upgrade_info || true + + if [[ ${#newversion[@]} -lt 2 ]] || [[ ${#oldversion[@]} -lt 2 ]] \ + || [[ ${oldversion[0]} -lt ${newversion[0]} ]] \ + || [[ ${oldversion[0]} -eq ${newversion[0]} && ${oldversion[1]} -lt ${newversion[1]} ]]; then + return 0 + fi + if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then + mysql_note "MariaDB heathcheck configation file missing, assuming desirable" + return 0 + fi + mysql_note "MariaDB upgrade not required" + return 1 +} + +# check arguments for an option that would cause mariadbd to stop +# return true if there is one +_mysql_want_help() { + local arg + for arg; do + case "$arg" in + -'?'|--help|--print-defaults|-V|--version) + return 0 + ;; + esac + done + return 1 +} + +_main() { + # if command starts with an option, prepend mariadbd + if [ "${1:0:1}" = '-' ]; then + set -- mariadbd "$@" + fi + + #ENDOFSUBSTITUTIONS + # skip setup if they aren't running mysqld or want an option that stops mysqld + if [ "$1" = 'mariadbd' ] || [ "$1" = 'mysqld' ] && ! _mysql_want_help "$@"; then + mysql_note "Entrypoint script for MariaDB Server ${MARIADB_VERSION} started." + + mysql_check_config "$@" + # Load various environment variables + docker_setup_env "$@" + docker_create_db_directories + + # If container is started as root user, restart as dedicated mysql user + if [ "$(id -u)" = "0" ]; then + mysql_note "Switching to dedicated user 'mysql'" + exec gosu mysql "${BASH_SOURCE[0]}" "$@" + fi + + # there's no database, so it needs to be initialized + if [ -z "$DATABASE_ALREADY_EXISTS" ]; then + docker_verify_minimum_env + + docker_mariadb_init "$@" + # MDEV-27636 mariadb_upgrade --check-if-upgrade-is-needed cannot be run offline + #elif mariadb-upgrade --check-if-upgrade-is-needed; then + elif _check_if_upgrade_is_needed; then + docker_mariadb_upgrade "$@" + fi + fi + exec "$@" +} + +# If we are sourced from elsewhere, don't perform any further actions +if ! _is_sourced; then + _main "$@" +fi diff --git a/11.5/healthcheck.sh b/11.5/healthcheck.sh new file mode 100755 index 0000000..62be345 --- /dev/null +++ b/11.5/healthcheck.sh @@ -0,0 +1,395 @@ +#!/bin/bash +# +# Healthcheck script for MariaDB +# +# Runs various tests on the MariaDB server to check its health. Pass the tests +# to run as arguments. If all tests succeed, the server is considered healthy, +# otherwise it's not. +# +# Arguments are processed in strict order. Set replication_* options before +# the --replication option. This allows a different set of replication checks +# on different connections. +# +# --su{=|-mysql} is option to run the healthcheck as a different unix user. +# Useful if mysql@localhost user exists with unix socket authentication +# Using this option disregards previous options set, so should usually be the +# first option. +# +# Some tests require SQL privileges. +# +# TEST MINIMUM GRANTS REQUIRED +# connect none* +# innodb_initialized USAGE +# innodb_buffer_pool_loaded USAGE +# galera_online USAGE +# galera_ready USAGE +# replication REPLICATION_CLIENT (<10.5)or REPLICA MONITOR (10.5+) +# mariadbupgrade none, however unix user permissions on datadir +# +# The SQL user used is the default for the mariadb client. This can be the unix user +# if no user(or password) is set in the [mariadb-client] section of a configuration +# file. --defaults-{file,extra-file,group-suffix} can specify a file/configuration +# different from elsewhere. +# +# Note * though denied error message will result in error log without +# any permissions. USAGE recommend to avoid this. + +set -eo pipefail + +_process_sql() +{ + mariadb ${nodefaults:+--no-defaults} \ + ${def['file']:+--defaults-file=${def['file']}} \ + ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ + ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ + --skip-ssl --skip-ssl-verify-server-cert \ + --protocol socket \ + -B "$@" +} + +# TESTS + + +# CONNECT +# +# Tests that a connection can be made over TCP, the final state +# of the entrypoint and is listening. The authentication used +# isn't tested. +connect() +{ + local s + # short cut mechanism, to work with --require-secure-transport + s=$(_process_sql --skip-column-names -e 'select @@skip_networking') + case "$s" in + 0|1) + connect_s=$s + return "$s"; + ;; + esac + # falling back to tcp if there wasn't a connection answer. + s=$(mariadb ${nodefaults:+--no-defaults} \ + ${def['file']:+--defaults-file=${def['file']}} \ + ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ + ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ + --skip-ssl --skip-ssl-verify-server-cert \ + -h localhost --protocol tcp \ + --skip-column-names --batch --skip-print-query-on-error \ + -e 'select @@skip_networking' 2>&1) + + case "$s" in + 1) # skip-networking=1 (no network) + ;& + ERROR\ 2002\ \(HY000\):*) + # cannot connect + connect_s=1 + ;; + 0) # skip-networking=0 + ;& + ERROR\ 1820\ \(HY000\)*) # password expire + ;& + ERROR\ 4151\ \(HY000\):*) # account locked + ;& + ERROR\ 1226\ \(42000\)*) # resource limit exceeded + ;& + ERROR\ 1[0-9][0-9][0-9]\ \(28000\):*) + # grep access denied and other 28000 client errors - we did connect + connect_s=0 + ;; + *) + >&2 echo "Unknown error $s" + connect_s=1 + ;; + esac + return $connect_s +} + +# INNODB_INITIALIZED +# +# This tests that the crash recovery of InnoDB has completed +# along with all the other things required to make it to a healthy +# operational state. Note this may return true in the early +# states of initialization. Use with a connect test to avoid +# these false positives. +innodb_initialized() +{ + local s + s=$(_process_sql --skip-column-names -e "select 1 from information_schema.ENGINES WHERE engine='innodb' AND support in ('YES', 'DEFAULT', 'ENABLED')") + [ "$s" == 1 ] +} + +# INNODB_BUFFER_POOL_LOADED +# +# Tests the load of the innodb buffer pool as been complete +# implies innodb_buffer_pool_load_at_startup=1 (default), or if +# manually SET innodb_buffer_pool_load_now=1 +innodb_buffer_pool_loaded() +{ + local s + s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='Innodb_buffer_pool_load_status'") + if [[ $s =~ 'load completed' ]]; then + return 0 + fi + return 1 +} + +# GALERA_ONLINE +# +# Tests that the galera node is in the SYNCed state +galera_online() +{ + local s + s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_LOCAL_STATE'") + # 4 from https://galeracluster.com/library/documentation/node-states.html#node-state-changes + # not https://xkcd.com/221/ + if [[ $s -eq 4 ]]; then + return 0 + fi + return 1 +} + +# GALERA_READY +# +# Tests that the Galera provider is ready. +galera_ready() +{ + local s + s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_READY'") + if [ "$s" = "ON" ]; then + return 0 + fi + return 1 +} + +# REPLICATION +# +# Tests the replication has the required set of functions: +# --replication_all -> Checks all replication sources +# --replication_name=n -> sets the multisource connection name tested +# --replication_io -> IO thread is running +# --replication_sql -> SQL thread is running +# --replication_seconds_behind_master=n -> less than or equal this seconds of delay +# --replication_sql_remaining_delay=n -> less than or equal this seconds of remaining delay +# (ref: https://mariadb.com/kb/en/delayed-replication/) +replication() +{ + # SHOW REPLICA available 10.5+ + # https://github.com/koalaman/shellcheck/issues/2383 + # shellcheck disable=SC2016,SC2026 + _process_sql -e "SHOW ${repl['all']:+all} REPLICA${repl['all']:+S} ${repl['name']:+'${repl['name']}'} STATUS\G" | \ + { + # required for trim of leading space. + shopt -s extglob + # Row header + read -t 5 -r + # read timeout + [ $? -gt 128 ] && return 1 + while IFS=":" read -t 1 -r n v; do + # Trim leading space + n=${n##+([[:space:]])} + # Leading space on all values by the \G format needs to be trimmed. + v=${v:1} + case "$n" in + Slave_IO_Running) + if [ -n "${repl['io']}" ] && [ "$v" = 'No' ]; then + return 1 + fi + ;; + Slave_SQL_Running) + if [ -n "${repl['sql']}" ] && [ "$v" = 'No' ]; then + return 1 + fi + ;; + Seconds_Behind_Master) + # A NULL value is the IO thread not running: + if [ -n "${repl['seconds_behind_master']}" ] && + { [ "$v" = NULL ] || + (( "${repl['seconds_behind_master']}" < "$v" )); }; then + return 1 + fi + ;; + SQL_Remaining_Delay) + # Unlike Seconds_Behind_Master, sql_remaining_delay will hit NULL + # once replication is caught up - https://mariadb.com/kb/en/delayed-replication/ + if [ -n "${repl['sql_remaining_delay']}" ] && + [ "$v" != NULL ] && + (( "${repl['sql_remaining_delay']}" < "$v" )); then + return 1 + fi + ;; + esac + done + # read timeout + [ $? -gt 128 ] && return 1 + return 0 + } + # reachable in command not found(?) + # shellcheck disable=SC2317 + return $? +} + +# mariadbupgrade +# +# Test the lock on the file $datadir/mariadb_upgrade_info +# https://jira.mariadb.org/browse/MDEV-27068 +mariadbupgrade() +{ + local f="$datadir/mariadb_upgrade_info" + if [ -r "$f" ]; then + flock --exclusive --nonblock -n 9 9<"$f" + return $? + fi + return 0 +} + + +# MAIN + +if [ $# -eq 0 ]; then + echo "At least one argument required" >&2 + exit 1 +fi + +#ENDOFSUBSTITUTIONS +# Marks the end of mysql -> mariadb name changes in 10.6+ +# Global variables used by tests +declare -A repl +declare -A def +nodefaults= +connect_s= +datadir=/var/lib/mysql +if [ -f $datadir/.my-healthcheck.cnf ]; then + def['extra_file']=$datadir/.my-healthcheck.cnf +fi + +_repl_param_check() +{ + case "$1" in + seconds_behind_master) ;& + sql_remaining_delay) + if [ -z "${repl['io']}" ]; then + repl['io']=1 + echo "Forcing --replication_io=1, $1 requires IO thread to be running" >&2 + fi + ;; + all) + if [ -n "${repl['name']}" ]; then + unset 'repl[name]' + echo "Option --replication_all incompatible with specified source --replication_name, clearing replication_name" >&2 + fi + ;; + name) + if [ -n "${repl['all']}" ]; then + unset 'repl[all]' + echo "Option --replication_name incompatible with --replication_all, clearing replication_all" >&2 + fi + ;; + esac +} + +_test_exists() { + declare -F "$1" > /dev/null + return $? +} + +while [ $# -gt 0 ]; do + case "$1" in + --su=*) + u="${1#*=}" + shift + exec gosu "${u}" "${BASH_SOURCE[0]}" "$@" + ;; + --su) + shift + u=$1 + shift + exec gosu "$u" "${BASH_SOURCE[0]}" "$@" + ;; + --su-mysql) + shift + exec gosu mysql "${BASH_SOURCE[0]}" "$@" + ;; + --replication_*=*) + # Change the n to what is between _ and = and make lower case + n=${1#*_} + n=${n%%=*} + n=${n,,*} + # v is after the = + v=${1#*=} + repl[$n]=$v + _repl_param_check "$n" + ;; + --replication_*) + # Without =, look for a non --option next as the value, + # otherwise treat it as an "enable", just equate to 1. + # Clearing option is possible with "--replication_X=" + n=${1#*_} + n=${n,,*} + if [ "${2:0:2}" == '--' ]; then + repl[$n]=1 + else + repl[$n]=$2 + shift + fi + _repl_param_check "$n" + ;; + --datadir=*) + datadir=${1#*=} + ;; + --datadir) + shift + datadir=${1} + ;; + --no-defaults) + def=() + nodefaults=1 + ;; + --defaults-file=*|--defaults-extra-file=*|--defaults-group-suffix=*) + n=${1:11} # length --defaults- + n=${n%%=*} + n=${n//-/_} + # v is after the = + v=${1#*=} + def[$n]=$v + nodefaults= + ;; + --defaults-file|--defaults-extra-file|--defaults-group-suffix) + n=${1:11} # length --defaults- + n=${n//-/_} + if [ "${2:0:2}" == '--' ]; then + def[$n]="" + else + def[$n]=$2 + shift + fi + nodefaults= + ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; + --*) + test=${1#--} + ;; + *) + echo "Unknown healthcheck option $1" >&2 + exit 1 + esac + if [ -n "$test" ]; then + if ! _test_exists "$test" ; then + echo "healthcheck unknown option or test '$test'" >&2 + exit 1 + elif ! "$test"; then + echo "healthcheck $test failed" >&2 + exit 1 + fi + test= + fi + shift +done +if [ "$connect_s" != "0" ]; then + # we didn't pass a connnect test, so the current success status is suspicious + # return what connect thinks. + connect + exit $? +fi diff --git a/versions.json b/versions.json index c25e533..c21c3ec 100644 --- a/versions.json +++ b/versions.json @@ -115,8 +115,8 @@ "milestone": "11.5", "version": "11.5.2", "fullVersion": "1:11.5.2+maria~ubu2404", - "releaseStatus": "Stable", - "supportType": "Short Term Support", + "releaseStatus": "Unknown", + "supportType": "Unknown", "base": "ubuntu:noble", "arches": [ "amd64", @@ -129,8 +129,8 @@ "milestone": "11.5", "version": "11.5.2", "fullVersion": "11.5.2", - "releaseStatus": "Stable", - "supportType": "Short Term Support", + "releaseStatus": "Unknown", + "supportType": "Unknown", "base": "ubi9", "arches": [ "amd64", From 58570c6f1988c033d052ea1442675f637d881706 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 15 Nov 2024 09:39:32 +1100 Subject: [PATCH 14/21] TEMP hack to make supportType/ReleaseStatus=Unknown as stable for 11.5 This is because its removed in download, but we still need to have latest as 11.5 otherwise users will go back a version. --- generate-stackbrew-library.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/generate-stackbrew-library.sh b/generate-stackbrew-library.sh index 75b6964..1171a44 100755 --- a/generate-stackbrew-library.sh +++ b/generate-stackbrew-library.sh @@ -80,6 +80,9 @@ for version in "${versions[@]}"; do supportType="$(grep -m1 'support-type:' "$version/Dockerfile" | cut -d':' -f2)" case $releaseStatus in + Unknown) + releaseStatus=Stable + ;& Stable) suffix= ;; @@ -103,6 +106,7 @@ for version in "${versions[@]}"; do ;; *) supportType=Unknown + supportType=STS esac if [ "$version" != "$fullVersion" ]; then From 07e42ed9b5daa4f4fc8dc74f8d61a823fc6e583d Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 15 Nov 2024 09:44:09 +1100 Subject: [PATCH 15/21] version.json - hack to Stable/STS for 11.5 --- versions.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/versions.json b/versions.json index c21c3ec..c25e533 100644 --- a/versions.json +++ b/versions.json @@ -115,8 +115,8 @@ "milestone": "11.5", "version": "11.5.2", "fullVersion": "1:11.5.2+maria~ubu2404", - "releaseStatus": "Unknown", - "supportType": "Unknown", + "releaseStatus": "Stable", + "supportType": "Short Term Support", "base": "ubuntu:noble", "arches": [ "amd64", @@ -129,8 +129,8 @@ "milestone": "11.5", "version": "11.5.2", "fullVersion": "11.5.2", - "releaseStatus": "Unknown", - "supportType": "Unknown", + "releaseStatus": "Stable", + "supportType": "Short Term Support", "base": "ubi9", "arches": [ "amd64", From f9c5ee5a9f674f7287ebbc4787f5aec5ebf06555 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 22 Nov 2024 08:20:17 +1100 Subject: [PATCH 16/21] Reapply "11.5 EOL" This reverts commit 48de289b90fdd82166dda66e0fa616b7acce8dac. --- update.sh | 2 -- versions.json | 56 --------------------------------------------------- 2 files changed, 58 deletions(-) diff --git a/update.sh b/update.sh index 9706f78..331bda8 100755 --- a/update.sh +++ b/update.sh @@ -55,8 +55,6 @@ update_version() sed -e '/collation-server/d' docker.cnf > "$dir/docker.cnf" if [[ $version != 11.4 ]]; then sed -i -e '/character-set-collations/d' "$dir/docker.cnf" - fi - if [[ $version != 11.[45] ]]; then sed -i -e '/character-set/d' "$dir/docker.cnf" fi fi diff --git a/versions.json b/versions.json index c25e533..5facecf 100644 --- a/versions.json +++ b/versions.json @@ -110,61 +110,5 @@ "ppc64le", "s390x" ] - }, - "11.5": { - "milestone": "11.5", - "version": "11.5.2", - "fullVersion": "1:11.5.2+maria~ubu2404", - "releaseStatus": "Stable", - "supportType": "Short Term Support", - "base": "ubuntu:noble", - "arches": [ - "amd64", - "arm64v8", - "ppc64le", - "s390x" - ] - }, - "11.5-ubi": { - "milestone": "11.5", - "version": "11.5.2", - "fullVersion": "11.5.2", - "releaseStatus": "Stable", - "supportType": "Short Term Support", - "base": "ubi9", - "arches": [ - "amd64", - "arm64v8", - "ppc64le", - "s390x" - ] - }, - "11.6": { - "milestone": "11.6", - "version": "11.6.1", - "fullVersion": "1:11.6.1+maria~ubu2404", - "releaseStatus": "RC", - "supportType": "Short Term Support", - "base": "ubuntu:noble", - "arches": [ - "amd64", - "arm64v8", - "ppc64le", - "s390x" - ] - }, - "11.6-ubi": { - "milestone": "11.6", - "version": "11.6.1", - "fullVersion": "11.6.1", - "releaseStatus": "RC", - "supportType": "Short Term Support", - "base": "ubi9", - "arches": [ - "amd64", - "arm64v8", - "ppc64le", - "s390x" - ] } } From 08333b900b4a4f372c28ae4c21e737419fa0cbb9 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 22 Nov 2024 08:21:46 +1100 Subject: [PATCH 17/21] Revert "Add 11.5 back temporarly" This reverts commit 85df6a9f3d781bb94a88d506eca5c3fcc55d8125. --- 11.5-ubi/Dockerfile | 113 ------ 11.5-ubi/MariaDB.repo | 7 - 11.5-ubi/docker-entrypoint.sh | 718 ---------------------------------- 11.5-ubi/docker.cnf | 15 - 11.5-ubi/healthcheck.sh | 395 ------------------- 11.5/Dockerfile | 142 ------- 11.5/docker-entrypoint.sh | 718 ---------------------------------- 11.5/healthcheck.sh | 395 ------------------- versions.json | 28 ++ 9 files changed, 28 insertions(+), 2503 deletions(-) delete mode 100644 11.5-ubi/Dockerfile delete mode 100644 11.5-ubi/MariaDB.repo delete mode 100755 11.5-ubi/docker-entrypoint.sh delete mode 100644 11.5-ubi/docker.cnf delete mode 100755 11.5-ubi/healthcheck.sh delete mode 100644 11.5/Dockerfile delete mode 100755 11.5/docker-entrypoint.sh delete mode 100755 11.5/healthcheck.sh diff --git a/11.5-ubi/Dockerfile b/11.5-ubi/Dockerfile deleted file mode 100644 index 7c09361..0000000 --- a/11.5-ubi/Dockerfile +++ /dev/null @@ -1,113 +0,0 @@ -FROM redhat/ubi9-minimal - -# user 999/ group 999, that we want to use for compatibility with the ubuntu image. -RUN groupadd --gid 999 -r mysql && \ - useradd -r -g mysql mysql --home-dir /var/lib/mysql --uid 999 - -ENV GOSU_VERSION 1.17 -RUN set -eux; \ - rpmArch="$(rpm --query --queryformat='%{ARCH}' rpm)"; \ - case "$rpmArch" in \ - aarch64) dpkgArch='arm64' ;; \ - armv7*) dpkgArch='armhf' ;; \ - i686) dpkgArch='i386' ;; \ - ppc64le) dpkgArch='ppc64el' ;; \ - s390x|riscv64) dpkgArch=$rpmArch ;; \ - x86_64) dpkgArch='amd64' ;; \ - *) echo >&2 "error: unknown/unsupported architecture '$rpmArch'"; exit 1 ;; \ - esac; \ - curl --fail --location --output /usr/local/bin/gosu https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${dpkgArch} ; \ - curl --fail --location --output /usr/local/bin/gosu.asc https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${dpkgArch}.asc; \ - GNUPGHOME="$(mktemp -d)"; \ - export GNUPGHOME; \ - gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ - chmod a+x /usr/local/bin/gosu; \ - gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ - gpgconf --kill all; \ - rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ - gosu --version; \ - gosu nobody true - -COPY --chmod=0644 docker.cnf /etc/my.cnf.d/ - -COPY MariaDB.repo /etc/yum.repos.d/ - -# HasRequiredLabel requirement from Red Hat OpenShift Software Certification -# https://access.redhat.com/documentation/en-us/red_hat_software_certification/2024/html/red_hat_openshift_software_certification_policy_guide/assembly-requirements-for-container-images_openshift-sw-cert-policy-introduction#con-image-metadata-requirements_openshift-sw-cert-policy-container-images -LABEL name="MariaDB Server" \ - vendor="MariaDB Community" \ - version="11.5.2" \ - release="Refer to Annotations org.opencontainers.image.{revision,source}" \ - summary="MariaDB Database" \ - description="MariaDB Database for relational SQL" - -# OCI annotations to image -LABEL org.opencontainers.image.authors="MariaDB Community" \ - org.opencontainers.image.title="MariaDB Database" \ - org.opencontainers.image.description="MariaDB Database for relational SQL" \ - org.opencontainers.image.documentation="https://hub.docker.com/_/mariadb/" \ - org.opencontainers.image.base.name="docker.io/redhat/ubi9-minimal" \ - org.opencontainers.image.licenses="GPL-2.0" \ - org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ - org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="11.5.2" \ - org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" - -# bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=11.5.2 -ENV MARIADB_VERSION=$MARIADB_VERSION -# release-status:Unknown -# release-support-type:Unknown -# (https://downloads.mariadb.org/rest-api/mariadb/) - -# missing pwgen(epel), jemalloc(epel) (as entrypoint/user extensions) -# procps, pv(epel) - missing dependencies of galera sst script -# tzdata re-installed as only a fake version is part of the ubi-minimal base image. -# FF8AD1344597106ECE813B918A3872BF3228467C is the Fedora RPM key -# 177F4010FE56CA3336300305F1656F24C74CD1D8 is the MariaDB Server RPM key -RUN set -eux ; \ - curl --fail https://pagure.io/fedora-web/websites/raw/master/f/sites/getfedora.org/static/keys/FF8AD1344597106ECE813B918A3872BF3228467C.txt --output /tmp/epelkey.txt ; \ - GNUPGHOME="$(mktemp -d)"; export GNUPGHOME ; \ - gpg --batch --import /tmp/epelkey.txt ; \ - gpg --batch --armor --export FF8AD1344597106ECE813B918A3872BF3228467C > /tmp/epelkey.txt ; \ - rpmkeys --import /tmp/epelkey.txt ; \ - curl --fail https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm --output /tmp/epel-release-latest-9.noarch.rpm ; \ - rpm -K /tmp/epel-release-latest-9.noarch.rpm ; \ - rpm -ivh /tmp/epel-release-latest-9.noarch.rpm ; \ - rm /tmp/epelkey.txt /tmp/epel-release-latest-9.noarch.rpm ; \ - curl --fail https://supplychain.mariadb.com/MariaDB-Server-GPG-KEY --output /tmp/MariaDB-Server-GPG-KEY ; \ - gpg --batch --import /tmp/MariaDB-Server-GPG-KEY; \ - gpg --batch --armor --export 177F4010FE56CA3336300305F1656F24C74CD1D8 > /tmp/MariaDB-Server-GPG-KEY ; \ - rpmkeys --import /tmp/MariaDB-Server-GPG-KEY ; \ - rm -rf "$GNUPGHOME" /tmp/MariaDB-Server-GPG-KEY ; \ - unset GNUPGHOME ; \ - microdnf update -y ; \ - microdnf reinstall -y tzdata ; \ - microdnf install -y procps-ng zstd xz jemalloc pwgen pv ; \ - mkdir -p /etc/mysql/conf.d /etc/mysql/mariadb.conf.d/ /var/lib/mysql/mysql /run/mariadb /usr/lib64/galera ; \ - chmod ugo+rwx,o+t /run/mariadb ; \ - microdnf install -y MariaDB-backup-${MARIADB_VERSION} MariaDB-server-${MARIADB_VERSION} ; \ - # compatibility with DEB Galera packaging - ln -s /usr/lib64/galera-4/libgalera_smm.so /usr/lib/libgalera_smm.so ; \ - # compatibility with RPM Galera packaging - ln -s /usr/lib64/galera-4/libgalera_smm.so /usr/lib64/galera/libgalera_smm.so ; \ - microdnf clean all ; \ - rmdir /var/lib/mysql/mysql ; \ - chown -R mysql:mysql /var/lib/mysql /run/mariadb ; \ - mkdir /licenses ; \ - ln -s /usr/share/doc/MariaDB-server-${MARIADB_VERSION}/COPYING /licenses/GPL-2 ; \ - ln -s /usr/share/licenses /licenses/package-licenses ; \ - ln -s Apache-2.0-license /licenses/gosu - -VOLUME /var/lib/mysql - -RUN mkdir /docker-entrypoint-initdb.d - -COPY healthcheck.sh /usr/local/bin/healthcheck.sh -COPY docker-entrypoint.sh /usr/local/bin/ - -ENTRYPOINT ["docker-entrypoint.sh"] - -USER mysql -EXPOSE 3306 -CMD ["mariadbd"] diff --git a/11.5-ubi/MariaDB.repo b/11.5-ubi/MariaDB.repo deleted file mode 100644 index 777b623..0000000 --- a/11.5-ubi/MariaDB.repo +++ /dev/null @@ -1,7 +0,0 @@ -[mariadb] -name = MariaDB -#baseurl = https://rpm.mariadb.org/11.5/rhel/$releasever/$basearch -baseurl = https://archive.mariadb.org/mariadb-11.5/yum/rhel/$releasever/$basearch -#microdnf cannot read to the second key here. -#gpgkey=https://archive.mariadb.org/PublicKey -gpgcheck=1 diff --git a/11.5-ubi/docker-entrypoint.sh b/11.5-ubi/docker-entrypoint.sh deleted file mode 100755 index b562bfa..0000000 --- a/11.5-ubi/docker-entrypoint.sh +++ /dev/null @@ -1,718 +0,0 @@ -#!/bin/bash -set -eo pipefail -shopt -s nullglob - -# logging functions -mysql_log() { - local type="$1"; shift - printf '%s [%s] [Entrypoint]: %s\n' "$(date --rfc-3339=seconds)" "$type" "$*" -} -mysql_note() { - mysql_log Note "$@" -} -mysql_warn() { - mysql_log Warn "$@" >&2 -} -mysql_error() { - mysql_log ERROR "$@" >&2 - exit 1 -} - -# usage: file_env VAR [DEFAULT] -# ie: file_env 'XYZ_DB_PASSWORD' 'example' -# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of -# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) -file_env() { - local var="$1" - local fileVar="${var}_FILE" - local def="${2:-}" - if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then - mysql_error "Both $var and $fileVar are set (but are exclusive)" - fi - local val="$def" - if [ "${!var:-}" ]; then - val="${!var}" - elif [ "${!fileVar:-}" ]; then - val="$(< "${!fileVar}")" - fi - export "$var"="$val" - unset "$fileVar" -} - -# set MARIADB_xyz from MYSQL_xyz when MARIADB_xyz is unset -# and make them the same value (so user scripts can use either) -_mariadb_file_env() { - local var="$1"; shift - local maria="MARIADB_${var#MYSQL_}" - file_env "$var" "$@" - file_env "$maria" "${!var}" - if [ "${!maria:-}" ]; then - export "$var"="${!maria}" - fi -} - -# check to see if this file is being run or sourced from another script -_is_sourced() { - # https://unix.stackexchange.com/a/215279 - [ "${#FUNCNAME[@]}" -ge 2 ] \ - && [ "${FUNCNAME[0]}" = '_is_sourced' ] \ - && [ "${FUNCNAME[1]}" = 'source' ] -} - -# usage: docker_process_init_files [file [file [...]]] -# ie: docker_process_init_files /always-initdb.d/* -# process initializer files, based on file extensions -docker_process_init_files() { - # mysql here for backwards compatibility "${mysql[@]}" - # ShellCheck: mysql appears unused. Verify use (or export if used externally) - # shellcheck disable=SC2034 - mysql=( docker_process_sql ) - - echo - local f - for f; do - case "$f" in - *.sh) - # https://github.com/docker-library/postgres/issues/450#issuecomment-393167936 - # https://github.com/docker-library/postgres/pull/452 - if [ -x "$f" ]; then - mysql_note "$0: running $f" - "$f" - else - mysql_note "$0: sourcing $f" - # ShellCheck can't follow non-constant source. Use a directive to specify location. - # shellcheck disable=SC1090 - . "$f" - fi - ;; - *.sql) mysql_note "$0: running $f"; docker_process_sql < "$f"; echo ;; - *.sql.gz) mysql_note "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;; - *.sql.xz) mysql_note "$0: running $f"; xzcat "$f" | docker_process_sql; echo ;; - *.sql.zst) mysql_note "$0: running $f"; zstd -dc "$f" | docker_process_sql; echo ;; - *) mysql_warn "$0: ignoring $f" ;; - esac - echo - done -} - -# arguments necessary to run "mariadbd --verbose --help" successfully (used for testing configuration validity and for extracting default/configured values) -_verboseHelpArgs=( - --verbose --help -) - -mysql_check_config() { - local toRun=( "$@" "${_verboseHelpArgs[@]}" ) errors - if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then - mysql_error $'mariadbd failed while attempting to check config\n\tcommand was: '"${toRun[*]}"$'\n\t'"$errors" - fi -} - -# Fetch value from server config -# We use mariadbd --verbose --help instead of my_print_defaults because the -# latter only show values present in config files, and not server defaults -mysql_get_config() { - local conf="$1"; shift - "$@" "${_verboseHelpArgs[@]}" 2>/dev/null \ - | awk -v conf="$conf" '$1 == conf && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }' - # match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)" -} - -# Do a temporary startup of the MariaDB server, for init purposes -docker_temp_server_start() { - "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ - --expire-logs-days=0 \ - --skip-slave-start \ - --loose-innodb_buffer_pool_load_at_startup=0 \ - --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ - & - declare -g MARIADB_PID - MARIADB_PID=$! - mysql_note "Waiting for server startup" - # only use the root password if the database has already been initialized - # so that it won't try to fill in a password file when it hasn't been set yet - extraArgs=() - if [ -z "$DATABASE_ALREADY_EXISTS" ]; then - extraArgs+=( '--dont-use-mysql-root-password' ) - fi - local i - for i in {30..0}; do - if docker_process_sql "${extraArgs[@]}" --database=mysql \ - --skip-ssl --skip-ssl-verify-server-cert \ - <<<'SELECT 1' &> /dev/null; then - break - fi - sleep 1 - done - if [ "$i" = 0 ]; then - mysql_error "Unable to start server." - fi -} - -# Stop the server. When using a local socket file mariadb-admin will block until -# the shutdown is complete. -docker_temp_server_stop() { - kill "$MARIADB_PID" - wait "$MARIADB_PID" -} - -# Verify that the minimally required password settings are set for new databases. -docker_verify_minimum_env() { - # Restoring from backup requires no environment variables - declare -g DATABASE_INIT_FROM_BACKUP - for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do - if [ -f "${file}" ]; then - DATABASE_INIT_FROM_BACKUP='true' - return - fi - done - if [ -z "$MARIADB_ROOT_PASSWORD" ] && [ -z "$MARIADB_ROOT_PASSWORD_HASH" ] && [ -z "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] && [ -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then - mysql_error $'Database is uninitialized and password option is not specified\n\tYou need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ROOT_PASSWORD_HASH, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' - fi - # More preemptive exclusions of combinations should have been made before *PASSWORD_HASH was added, but for now we don't enforce due to compatibility. - if [ -n "$MARIADB_ROOT_PASSWORD" ] || [ -n "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] || [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ] && [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then - mysql_error "Cannot specify MARIADB_ROOT_PASSWORD_HASH and another MARIADB_ROOT_PASSWORD* option." - fi - if [ -n "$MARIADB_PASSWORD" ] && [ -n "$MARIADB_PASSWORD_HASH" ]; then - mysql_error "Cannot specify MARIADB_PASSWORD_HASH and MARIADB_PASSWORD option." - fi - if [ -n "$MARIADB_REPLICATION_USER" ]; then - if [ -z "$MARIADB_MASTER_HOST" ]; then - # its a master, we're creating a user - if [ -z "$MARIADB_REPLICATION_PASSWORD" ] && [ -z "$MARIADB_REPLICATION_PASSWORD_HASH" ]; then - mysql_error "MARIADB_REPLICATION_PASSWORD or MARIADB_REPLICATION_PASSWORD_HASH not found to create replication user for master" - fi - else - # its a replica - if [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; then - mysql_error "MARIADB_REPLICATION_PASSWORD is mandatory to specify the replication on the replica image." - fi - if [ -n "$MARIADB_REPLICATION_PASSWORD_HASH" ] ; then - mysql_warn "MARIADB_REPLICATION_PASSWORD_HASH cannot be specified on a replica" - fi - fi - fi - if [ -n "$MARIADB_MASTER_HOST" ] && { [ -z "$MARIADB_REPLICATION_USER" ] || [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; }; then - mysql_error "For a replica, MARIADB_REPLICATION_USER and MARIADB_REPLICATION is mandatory." - fi -} - -# creates folders for the database -# also ensures permission for user mysql of run as root -docker_create_db_directories() { - local user; user="$(id -u)" - - # TODO other directories that are used by default? like /var/lib/mysql-files - # see https://github.com/docker-library/mysql/issues/562 - mkdir -p "$DATADIR" - - if [ "$user" = "0" ]; then - # this will cause less disk access than `chown -R` - find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) - # See https://github.com/MariaDB/mariadb-docker/issues/363 - if [ "${SOCKET:0:1}" != '@' ]; then # not abstract sockets - find "${SOCKET%/*}" -maxdepth 0 \! -user mysql \( -exec chown mysql: '{}' \; -o -true \) - fi - - # memory.pressure - local cgroup; cgroup=$( "$DATADIR"/.my-healthcheck.cnf - $maskPreserve -} - -# Initializes database with timezone info and root password, plus optional extra db/user -docker_setup_db() { - # Load timezone info into database - if [ -z "$MARIADB_INITDB_SKIP_TZINFO" ]; then - # --skip-write-binlog usefully disables binary logging - # but also outputs LOCK TABLES to improve the IO of - # Aria (MDEV-23326) for 10.4+. - mariadb-tzinfo-to-sql --skip-write-binlog /usr/share/zoneinfo \ - | docker_process_sql --dont-use-mysql-root-password --database=mysql - # tell docker_process_sql to not use MYSQL_ROOT_PASSWORD since it is not set yet - fi - # Generate random root password - if [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then - MARIADB_ROOT_PASSWORD="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" - export MARIADB_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=$MARIADB_ROOT_PASSWORD - mysql_note "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD" - fi - - # Creates root users for non-localhost hosts - local rootCreate= - local rootPasswordEscaped= - if [ -n "$MARIADB_ROOT_PASSWORD" ]; then - # Sets root password and creates root users for non-localhost hosts - rootPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}") - fi - - # default root to listen for connections from anywhere - if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then - # ref "read -d ''", no, we don't care if read finds a terminating character in this heredoc - # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 - if [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then - read -r -d '' rootCreate <<-EOSQL || true - CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY PASSWORD '${MARIADB_ROOT_PASSWORD_HASH}' ; - GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; - GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; - EOSQL - else - read -r -d '' rootCreate <<-EOSQL || true - CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ; - GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; - GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; - EOSQL - fi - fi - - local mysqlAtLocalhost= - local mysqlAtLocalhostGrants= - # Install mysql@localhost user - if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ]; then - read -r -d '' mysqlAtLocalhost <<-EOSQL || true - CREATE USER mysql@localhost IDENTIFIED VIA unix_socket; - EOSQL - if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then - if [ "$MARIADB_MYSQL_LOCALHOST_GRANTS" != USAGE ]; then - mysql_warn "Excessive privileges ON *.* TO mysql@localhost facilitates risks to the confidentiality, integrity and availability of data stored" - fi - mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; - fi - fi - - local createHealthCheckUsers - createHealthCheckUsers=$(create_healthcheck_users) - - local rootLocalhostPass= - if [ -z "$MARIADB_ROOT_PASSWORD_HASH" ]; then - # handle MARIADB_ROOT_PASSWORD_HASH for root@localhost after /docker-entrypoint-initdb.d - rootLocalhostPass="SET PASSWORD FOR 'root'@'localhost'= PASSWORD('${rootPasswordEscaped}');" - fi - - local createDatabase= - # Creates a custom database and user if specified - if [ -n "$MARIADB_DATABASE" ]; then - mysql_note "Creating database ${MARIADB_DATABASE}" - createDatabase="CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\`;" - fi - - local createUser= - local userGrants= - if [ -n "$MARIADB_PASSWORD" ] || [ -n "$MARIADB_PASSWORD_HASH" ] && [ -n "$MARIADB_USER" ]; then - mysql_note "Creating user ${MARIADB_USER}" - if [ -n "$MARIADB_PASSWORD_HASH" ]; then - createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY PASSWORD '$MARIADB_PASSWORD_HASH';" - else - # SQL escape the user password, \ followed by ' - local userPasswordEscaped - userPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_PASSWORD}") - createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$userPasswordEscaped';" - fi - - if [ -n "$MARIADB_DATABASE" ]; then - mysql_note "Giving user ${MARIADB_USER} access to schema ${MARIADB_DATABASE}" - userGrants="GRANT ALL ON \`${MARIADB_DATABASE//_/\\_}\`.* TO '$MARIADB_USER'@'%';" - fi - fi - - # To create replica user - local createReplicaUser= - local changeMasterTo= - if [ -n "$MARIADB_REPLICATION_USER" ] ; then - if [ -z "$MARIADB_MASTER_HOST" ]; then - # on master - mysql_note "Creating user ${MARIADB_REPLICATION_USER}" - createReplicaUser=$(create_replica_user) - else - # on replica - local rplPasswordEscaped - rplPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_REPLICATION_PASSWORD}") - # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. - # shellcheck disable=SC2153 - changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - fi - fi - - mysql_note "Securing system users (equivalent to running mysql_secure_installation)" - # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set - # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. - docker_process_sql --dont-use-mysql-root-password --database=mysql --binary-mode <<-EOSQL - -- Securing system users shouldn't be replicated - SET @orig_sql_log_bin= @@SESSION.SQL_LOG_BIN; - SET @@SESSION.SQL_LOG_BIN=0; - -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set - SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); - - DROP USER IF EXISTS root@'127.0.0.1', root@'::1'; - EXECUTE IMMEDIATE CONCAT('DROP USER IF EXISTS root@\'', @@hostname,'\''); - - ${rootLocalhostPass} - ${rootCreate} - ${mysqlAtLocalhost} - ${mysqlAtLocalhostGrants} - ${createHealthCheckUsers} - -- end of securing system users, rest of init now... - SET @@SESSION.SQL_LOG_BIN=@orig_sql_log_bin; - -- create users/databases - ${createDatabase} - ${createUser} - ${createReplicaUser} - ${userGrants} - - ${changeMasterTo} - EOSQL -} - -# create a new installation -docker_mariadb_init() -{ - - # check dir permissions to reduce likelihood of half-initialized database - ls /docker-entrypoint-initdb.d/ > /dev/null - - if [ -n "$DATABASE_INIT_FROM_BACKUP" ]; then - shopt -s dotglob - for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do - mkdir -p "$DATADIR"/.init - tar --auto-compress --extract --file "$file" --directory="$DATADIR"/.init - mariadb-backup --target-dir="$DATADIR"/.init --datadir="$DATADIR"/.restore --move-back - - mv "$DATADIR"/.restore/** "$DATADIR"/ - if [ -f "$DATADIR/.init/backup-my.cnf" ]; then - mv "$DATADIR/.init/backup-my.cnf" "$DATADIR/.my.cnf" - mysql_note "Adding startup configuration:" - my_print_defaults --defaults-file="$DATADIR/.my.cnf" --mariadbd - fi - rm -rf "$DATADIR"/.init "$DATADIR"/.restore - if [ "$(id -u)" = "0" ]; then - # this will cause less disk access than `chown -R` - find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) - fi - done - if _check_if_upgrade_is_needed; then - docker_mariadb_upgrade "$@" - fi - return - fi - docker_init_database_dir "$@" - - mysql_note "Starting temporary server" - docker_temp_server_start "$@" - mysql_note "Temporary server started." - - docker_setup_db - docker_process_init_files /docker-entrypoint-initdb.d/* - # Wait until after /docker-entrypoint-initdb.d is performed before setting - # root@localhost password to a hash we don't know the password for. - if [ -n "${MARIADB_ROOT_PASSWORD_HASH}" ]; then - mysql_note "Setting root@localhost password hash" - docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL - SET @@SESSION.SQL_LOG_BIN=0; - SET PASSWORD FOR 'root'@'localhost'= '${MARIADB_ROOT_PASSWORD_HASH}'; - EOSQL - fi - - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" - - echo - mysql_note "MariaDB init process done. Ready for start up." - echo -} - -# backup the mysql database -docker_mariadb_backup_system() -{ - if [ -n "$MARIADB_DISABLE_UPGRADE_BACKUP" ] \ - && [ "$MARIADB_DISABLE_UPGRADE_BACKUP" = 1 ]; then - mysql_note "MariaDB upgrade backup disabled due to \$MARIADB_DISABLE_UPGRADE_BACKUP=1 setting" - return - fi - local backup_db="system_mysql_backup_unknown_version.sql.zst" - local oldfullversion="unknown_version" - if [ -r "$DATADIR"/mariadb_upgrade_info ]; then - read -r -d '' oldfullversion < "$DATADIR"/mariadb_upgrade_info || true - if [ -n "$oldfullversion" ]; then - backup_db="system_mysql_backup_${oldfullversion}.sql.zst" - fi - fi - - mysql_note "Backing up system database to $backup_db" - if ! mariadb-dump --skip-lock-tables --replace --databases mysql --socket="${SOCKET}" | zstd > "${DATADIR}/${backup_db}"; then - mysql_error "Unable backup system database for upgrade from $oldfullversion." - fi - mysql_note "Backing up complete" -} - -# perform mariadb-upgrade -# backup the mysql database if this is a major upgrade -docker_mariadb_upgrade() { - if [ -z "$MARIADB_AUTO_UPGRADE" ] \ - || [ "$MARIADB_AUTO_UPGRADE" = 0 ]; then - mysql_note "MariaDB upgrade (mariadb-upgrade or creating healthcheck users) required, but skipped due to \$MARIADB_AUTO_UPGRADE setting" - return - fi - mysql_note "Starting temporary server" - docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 - mysql_note "Temporary server started." - - docker_mariadb_backup_system - - if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then - mysql_note "Creating healthcheck users" - local createHealthCheckUsers - createHealthCheckUsers=$(create_healthcheck_users) - docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL - -- Healthcheck users shouldn't be replicated - SET @@SESSION.SQL_LOG_BIN=0; - -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set - SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); - FLUSH PRIVILEGES; - $createHealthCheckUsers -EOSQL - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" - - if _check_if_upgrade_is_needed; then - # need a restart as FLUSH PRIVILEGES isn't reversable - mysql_note "Restarting temporary server for upgrade" - docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 - else - return 0 - fi - fi - - mysql_note "Starting mariadb-upgrade" - mariadb-upgrade --upgrade-system-tables - mysql_note "Finished mariadb-upgrade" - - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" -} - - -_check_if_upgrade_is_needed() { - if [ ! -f "$DATADIR"/mariadb_upgrade_info ]; then - mysql_note "MariaDB upgrade information missing, assuming required" - return 0 - fi - local mariadbVersion - mariadbVersion="$(_mariadb_version)" - IFS='.-' read -ra newversion <<<"$mariadbVersion" - IFS='.-' read -ra oldversion < "$DATADIR"/mariadb_upgrade_info || true - - if [[ ${#newversion[@]} -lt 2 ]] || [[ ${#oldversion[@]} -lt 2 ]] \ - || [[ ${oldversion[0]} -lt ${newversion[0]} ]] \ - || [[ ${oldversion[0]} -eq ${newversion[0]} && ${oldversion[1]} -lt ${newversion[1]} ]]; then - return 0 - fi - if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then - mysql_note "MariaDB heathcheck configation file missing, assuming desirable" - return 0 - fi - mysql_note "MariaDB upgrade not required" - return 1 -} - -# check arguments for an option that would cause mariadbd to stop -# return true if there is one -_mysql_want_help() { - local arg - for arg; do - case "$arg" in - -'?'|--help|--print-defaults|-V|--version) - return 0 - ;; - esac - done - return 1 -} - -_main() { - # if command starts with an option, prepend mariadbd - if [ "${1:0:1}" = '-' ]; then - set -- mariadbd "$@" - fi - - #ENDOFSUBSTITUTIONS - # skip setup if they aren't running mysqld or want an option that stops mysqld - if [ "$1" = 'mariadbd' ] || [ "$1" = 'mysqld' ] && ! _mysql_want_help "$@"; then - mysql_note "Entrypoint script for MariaDB Server ${MARIADB_VERSION} started." - - mysql_check_config "$@" - # Load various environment variables - docker_setup_env "$@" - docker_create_db_directories - - # If container is started as root user, restart as dedicated mysql user - if [ "$(id -u)" = "0" ]; then - mysql_note "Switching to dedicated user 'mysql'" - exec gosu mysql "${BASH_SOURCE[0]}" "$@" - fi - - # there's no database, so it needs to be initialized - if [ -z "$DATABASE_ALREADY_EXISTS" ]; then - docker_verify_minimum_env - - docker_mariadb_init "$@" - # MDEV-27636 mariadb_upgrade --check-if-upgrade-is-needed cannot be run offline - #elif mariadb-upgrade --check-if-upgrade-is-needed; then - elif _check_if_upgrade_is_needed; then - docker_mariadb_upgrade "$@" - fi - fi - exec "$@" -} - -# If we are sourced from elsewhere, don't perform any further actions -if ! _is_sourced; then - _main "$@" -fi diff --git a/11.5-ubi/docker.cnf b/11.5-ubi/docker.cnf deleted file mode 100644 index 844c2cf..0000000 --- a/11.5-ubi/docker.cnf +++ /dev/null @@ -1,15 +0,0 @@ -# Ubuntu container compatibility - -[mariadb] -host-cache-size=0 -skip-name-resolve - -expire_logs_days=10 -character-set-server=utf8mb4 - - -[client-server] -socket=/run/mariadb/mariadb.sock - -!includedir /etc/mysql/mariadb.conf.d -!includedir /etc/mysql/conf.d diff --git a/11.5-ubi/healthcheck.sh b/11.5-ubi/healthcheck.sh deleted file mode 100755 index 62be345..0000000 --- a/11.5-ubi/healthcheck.sh +++ /dev/null @@ -1,395 +0,0 @@ -#!/bin/bash -# -# Healthcheck script for MariaDB -# -# Runs various tests on the MariaDB server to check its health. Pass the tests -# to run as arguments. If all tests succeed, the server is considered healthy, -# otherwise it's not. -# -# Arguments are processed in strict order. Set replication_* options before -# the --replication option. This allows a different set of replication checks -# on different connections. -# -# --su{=|-mysql} is option to run the healthcheck as a different unix user. -# Useful if mysql@localhost user exists with unix socket authentication -# Using this option disregards previous options set, so should usually be the -# first option. -# -# Some tests require SQL privileges. -# -# TEST MINIMUM GRANTS REQUIRED -# connect none* -# innodb_initialized USAGE -# innodb_buffer_pool_loaded USAGE -# galera_online USAGE -# galera_ready USAGE -# replication REPLICATION_CLIENT (<10.5)or REPLICA MONITOR (10.5+) -# mariadbupgrade none, however unix user permissions on datadir -# -# The SQL user used is the default for the mariadb client. This can be the unix user -# if no user(or password) is set in the [mariadb-client] section of a configuration -# file. --defaults-{file,extra-file,group-suffix} can specify a file/configuration -# different from elsewhere. -# -# Note * though denied error message will result in error log without -# any permissions. USAGE recommend to avoid this. - -set -eo pipefail - -_process_sql() -{ - mariadb ${nodefaults:+--no-defaults} \ - ${def['file']:+--defaults-file=${def['file']}} \ - ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ - ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ - --skip-ssl --skip-ssl-verify-server-cert \ - --protocol socket \ - -B "$@" -} - -# TESTS - - -# CONNECT -# -# Tests that a connection can be made over TCP, the final state -# of the entrypoint and is listening. The authentication used -# isn't tested. -connect() -{ - local s - # short cut mechanism, to work with --require-secure-transport - s=$(_process_sql --skip-column-names -e 'select @@skip_networking') - case "$s" in - 0|1) - connect_s=$s - return "$s"; - ;; - esac - # falling back to tcp if there wasn't a connection answer. - s=$(mariadb ${nodefaults:+--no-defaults} \ - ${def['file']:+--defaults-file=${def['file']}} \ - ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ - ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ - --skip-ssl --skip-ssl-verify-server-cert \ - -h localhost --protocol tcp \ - --skip-column-names --batch --skip-print-query-on-error \ - -e 'select @@skip_networking' 2>&1) - - case "$s" in - 1) # skip-networking=1 (no network) - ;& - ERROR\ 2002\ \(HY000\):*) - # cannot connect - connect_s=1 - ;; - 0) # skip-networking=0 - ;& - ERROR\ 1820\ \(HY000\)*) # password expire - ;& - ERROR\ 4151\ \(HY000\):*) # account locked - ;& - ERROR\ 1226\ \(42000\)*) # resource limit exceeded - ;& - ERROR\ 1[0-9][0-9][0-9]\ \(28000\):*) - # grep access denied and other 28000 client errors - we did connect - connect_s=0 - ;; - *) - >&2 echo "Unknown error $s" - connect_s=1 - ;; - esac - return $connect_s -} - -# INNODB_INITIALIZED -# -# This tests that the crash recovery of InnoDB has completed -# along with all the other things required to make it to a healthy -# operational state. Note this may return true in the early -# states of initialization. Use with a connect test to avoid -# these false positives. -innodb_initialized() -{ - local s - s=$(_process_sql --skip-column-names -e "select 1 from information_schema.ENGINES WHERE engine='innodb' AND support in ('YES', 'DEFAULT', 'ENABLED')") - [ "$s" == 1 ] -} - -# INNODB_BUFFER_POOL_LOADED -# -# Tests the load of the innodb buffer pool as been complete -# implies innodb_buffer_pool_load_at_startup=1 (default), or if -# manually SET innodb_buffer_pool_load_now=1 -innodb_buffer_pool_loaded() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='Innodb_buffer_pool_load_status'") - if [[ $s =~ 'load completed' ]]; then - return 0 - fi - return 1 -} - -# GALERA_ONLINE -# -# Tests that the galera node is in the SYNCed state -galera_online() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_LOCAL_STATE'") - # 4 from https://galeracluster.com/library/documentation/node-states.html#node-state-changes - # not https://xkcd.com/221/ - if [[ $s -eq 4 ]]; then - return 0 - fi - return 1 -} - -# GALERA_READY -# -# Tests that the Galera provider is ready. -galera_ready() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_READY'") - if [ "$s" = "ON" ]; then - return 0 - fi - return 1 -} - -# REPLICATION -# -# Tests the replication has the required set of functions: -# --replication_all -> Checks all replication sources -# --replication_name=n -> sets the multisource connection name tested -# --replication_io -> IO thread is running -# --replication_sql -> SQL thread is running -# --replication_seconds_behind_master=n -> less than or equal this seconds of delay -# --replication_sql_remaining_delay=n -> less than or equal this seconds of remaining delay -# (ref: https://mariadb.com/kb/en/delayed-replication/) -replication() -{ - # SHOW REPLICA available 10.5+ - # https://github.com/koalaman/shellcheck/issues/2383 - # shellcheck disable=SC2016,SC2026 - _process_sql -e "SHOW ${repl['all']:+all} REPLICA${repl['all']:+S} ${repl['name']:+'${repl['name']}'} STATUS\G" | \ - { - # required for trim of leading space. - shopt -s extglob - # Row header - read -t 5 -r - # read timeout - [ $? -gt 128 ] && return 1 - while IFS=":" read -t 1 -r n v; do - # Trim leading space - n=${n##+([[:space:]])} - # Leading space on all values by the \G format needs to be trimmed. - v=${v:1} - case "$n" in - Slave_IO_Running) - if [ -n "${repl['io']}" ] && [ "$v" = 'No' ]; then - return 1 - fi - ;; - Slave_SQL_Running) - if [ -n "${repl['sql']}" ] && [ "$v" = 'No' ]; then - return 1 - fi - ;; - Seconds_Behind_Master) - # A NULL value is the IO thread not running: - if [ -n "${repl['seconds_behind_master']}" ] && - { [ "$v" = NULL ] || - (( "${repl['seconds_behind_master']}" < "$v" )); }; then - return 1 - fi - ;; - SQL_Remaining_Delay) - # Unlike Seconds_Behind_Master, sql_remaining_delay will hit NULL - # once replication is caught up - https://mariadb.com/kb/en/delayed-replication/ - if [ -n "${repl['sql_remaining_delay']}" ] && - [ "$v" != NULL ] && - (( "${repl['sql_remaining_delay']}" < "$v" )); then - return 1 - fi - ;; - esac - done - # read timeout - [ $? -gt 128 ] && return 1 - return 0 - } - # reachable in command not found(?) - # shellcheck disable=SC2317 - return $? -} - -# mariadbupgrade -# -# Test the lock on the file $datadir/mariadb_upgrade_info -# https://jira.mariadb.org/browse/MDEV-27068 -mariadbupgrade() -{ - local f="$datadir/mariadb_upgrade_info" - if [ -r "$f" ]; then - flock --exclusive --nonblock -n 9 9<"$f" - return $? - fi - return 0 -} - - -# MAIN - -if [ $# -eq 0 ]; then - echo "At least one argument required" >&2 - exit 1 -fi - -#ENDOFSUBSTITUTIONS -# Marks the end of mysql -> mariadb name changes in 10.6+ -# Global variables used by tests -declare -A repl -declare -A def -nodefaults= -connect_s= -datadir=/var/lib/mysql -if [ -f $datadir/.my-healthcheck.cnf ]; then - def['extra_file']=$datadir/.my-healthcheck.cnf -fi - -_repl_param_check() -{ - case "$1" in - seconds_behind_master) ;& - sql_remaining_delay) - if [ -z "${repl['io']}" ]; then - repl['io']=1 - echo "Forcing --replication_io=1, $1 requires IO thread to be running" >&2 - fi - ;; - all) - if [ -n "${repl['name']}" ]; then - unset 'repl[name]' - echo "Option --replication_all incompatible with specified source --replication_name, clearing replication_name" >&2 - fi - ;; - name) - if [ -n "${repl['all']}" ]; then - unset 'repl[all]' - echo "Option --replication_name incompatible with --replication_all, clearing replication_all" >&2 - fi - ;; - esac -} - -_test_exists() { - declare -F "$1" > /dev/null - return $? -} - -while [ $# -gt 0 ]; do - case "$1" in - --su=*) - u="${1#*=}" - shift - exec gosu "${u}" "${BASH_SOURCE[0]}" "$@" - ;; - --su) - shift - u=$1 - shift - exec gosu "$u" "${BASH_SOURCE[0]}" "$@" - ;; - --su-mysql) - shift - exec gosu mysql "${BASH_SOURCE[0]}" "$@" - ;; - --replication_*=*) - # Change the n to what is between _ and = and make lower case - n=${1#*_} - n=${n%%=*} - n=${n,,*} - # v is after the = - v=${1#*=} - repl[$n]=$v - _repl_param_check "$n" - ;; - --replication_*) - # Without =, look for a non --option next as the value, - # otherwise treat it as an "enable", just equate to 1. - # Clearing option is possible with "--replication_X=" - n=${1#*_} - n=${n,,*} - if [ "${2:0:2}" == '--' ]; then - repl[$n]=1 - else - repl[$n]=$2 - shift - fi - _repl_param_check "$n" - ;; - --datadir=*) - datadir=${1#*=} - ;; - --datadir) - shift - datadir=${1} - ;; - --no-defaults) - def=() - nodefaults=1 - ;; - --defaults-file=*|--defaults-extra-file=*|--defaults-group-suffix=*) - n=${1:11} # length --defaults- - n=${n%%=*} - n=${n//-/_} - # v is after the = - v=${1#*=} - def[$n]=$v - nodefaults= - ;; - --defaults-file|--defaults-extra-file|--defaults-group-suffix) - n=${1:11} # length --defaults- - n=${n//-/_} - if [ "${2:0:2}" == '--' ]; then - def[$n]="" - else - def[$n]=$2 - shift - fi - nodefaults= - ;; - --no-connect) - # used for /docker-entrypoint-initdb.d scripts - # where you definately don't want a connection test - connect_s=0 - ;; - --*) - test=${1#--} - ;; - *) - echo "Unknown healthcheck option $1" >&2 - exit 1 - esac - if [ -n "$test" ]; then - if ! _test_exists "$test" ; then - echo "healthcheck unknown option or test '$test'" >&2 - exit 1 - elif ! "$test"; then - echo "healthcheck $test failed" >&2 - exit 1 - fi - test= - fi - shift -done -if [ "$connect_s" != "0" ]; then - # we didn't pass a connnect test, so the current success status is suspicious - # return what connect thinks. - connect - exit $? -fi diff --git a/11.5/Dockerfile b/11.5/Dockerfile deleted file mode 100644 index a7f1aa0..0000000 --- a/11.5/Dockerfile +++ /dev/null @@ -1,142 +0,0 @@ -# vim:set ft=dockerfile: -FROM ubuntu:noble - -# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added -RUN groupadd -r mysql && useradd -r -g mysql mysql --home-dir /var/lib/mysql && userdel --remove ubuntu - -# add gosu for easy step-down from root -# https://github.com/tianon/gosu/releases -# gosu key is B42F6819007F00F88E364FD4036A9C25BF357DD4 -ENV GOSU_VERSION 1.17 - -ARG GPG_KEYS=177F4010FE56CA3336300305F1656F24C74CD1D8 -# pub rsa4096 2016-03-30 [SC] -# 177F 4010 FE56 CA33 3630 0305 F165 6F24 C74C D1D8 -# uid [ unknown] MariaDB Signing Key -# sub rsa4096 2016-03-30 [E] -# install "libjemalloc2" as it offers better performance in some cases. Use with LD_PRELOAD -# install "pwgen" for randomizing passwords -# install "tzdata" for /usr/share/zoneinfo/ -# install "xz-utils" for .sql.xz docker-entrypoint-initdb.d files -# install "zstd" for .sql.zst docker-entrypoint-initdb.d files -# hadolint ignore=SC2086 -RUN set -eux; \ - apt-get update; \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - ca-certificates \ - gpg \ - gpgv \ - libjemalloc2 \ - pwgen \ - tzdata \ - xz-utils \ - zstd ; \ - savedAptMark="$(apt-mark showmanual)"; \ - apt-get install -y --no-install-recommends \ - dirmngr \ - gpg-agent \ - wget; \ - rm -rf /var/lib/apt/lists/*; \ - dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ - wget -q -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ - wget -q -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ - GNUPGHOME="$(mktemp -d)"; \ - export GNUPGHOME; \ - gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ - for key in $GPG_KEYS; do \ - gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key"; \ - done; \ - gpg --batch --export "$GPG_KEYS" > /etc/apt/trusted.gpg.d/mariadb.gpg; \ - if command -v gpgconf >/dev/null; then \ - gpgconf --kill all; \ - fi; \ - gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ - gpgconf --kill all; \ - rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ - apt-mark auto '.*' > /dev/null; \ - [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark >/dev/null; \ - apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ - chmod +x /usr/local/bin/gosu; \ - gosu --version; \ - gosu nobody true - -RUN mkdir /docker-entrypoint-initdb.d - -# Ensure the container exec commands handle range of utf8 characters based of -# default locales in base image (https://github.com/docker-library/docs/blob/135b79cc8093ab02e55debb61fdb079ab2dbce87/ubuntu/README.md#locales) -ENV LANG C.UTF-8 - -# OCI annotations to image -LABEL org.opencontainers.image.authors="MariaDB Community" \ - org.opencontainers.image.title="MariaDB Database" \ - org.opencontainers.image.description="MariaDB Database for relational SQL" \ - org.opencontainers.image.documentation="https://hub.docker.com/_/mariadb/" \ - org.opencontainers.image.base.name="docker.io/library/ubuntu:noble" \ - org.opencontainers.image.licenses="GPL-2.0" \ - org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ - org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="11.5.2" \ - org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" - -# bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=1:11.5.2+maria~ubu2404 -ENV MARIADB_VERSION $MARIADB_VERSION -# release-status:Unknown -# release-support-type:Unknown -# (https://downloads.mariadb.org/rest-api/mariadb/) - -# Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions -ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.5.2/repo/ubuntu/ noble main main/debug" - -RUN set -e;\ - echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ - { \ - echo 'Package: *'; \ - echo 'Pin: release o=MariaDB'; \ - echo 'Pin-Priority: 999'; \ - } > /etc/apt/preferences.d/mariadb -# add repository pinning to make sure dependencies from this MariaDB repo are preferred over Debian dependencies -# libmariadbclient18 : Depends: libmysqlclient18 (= 5.5.42+maria-1~wheezy) but 5.5.43-0+deb7u1 is to be installed - -# the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) -# also, we set debconf keys to make APT a little quieter -# hadolint ignore=DL3015 -RUN set -ex; \ - { \ - echo "mariadb-server" mysql-server/root_password password 'unused'; \ - echo "mariadb-server" mysql-server/root_password_again password 'unused'; \ - } | debconf-set-selections; \ - apt-get update; \ -# postinst script creates a datadir, so avoid creating it by faking its existance. - mkdir -p /var/lib/mysql/mysql ; touch /var/lib/mysql/mysql/user.frm ; \ -# mariadb-backup is installed at the same time so that `mysql-common` is only installed once from just mariadb repos - apt-get install -y --no-install-recommends mariadb-server="$MARIADB_VERSION" mariadb-backup socat \ - ; \ - rm -rf /var/lib/apt/lists/*; \ -# purge and re-create /var/lib/mysql with appropriate ownership - rm -rf /var/lib/mysql; \ - mkdir -p /var/lib/mysql /run/mysqld; \ - chown -R mysql:mysql /var/lib/mysql /run/mysqld; \ -# ensure that /run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime - chmod 1777 /run/mysqld; \ -# comment out a few problematic configuration values - find /etc/mysql/ -name '*.cnf' -print0 \ - | xargs -0 grep -lZE '^(bind-address|log|user\s)' \ - | xargs -rt -0 sed -Ei 's/^(bind-address|log|user\s)/#&/'; \ -# don't reverse lookup hostnames, they are usually another container - printf "[mariadb]\nhost-cache-size=0\nskip-name-resolve\n" > /etc/mysql/mariadb.conf.d/05-skipcache.cnf; \ -# Issue #327 Correct order of reading directories /etc/mysql/mariadb.conf.d before /etc/mysql/conf.d (mount-point per documentation) - if [ -L /etc/mysql/my.cnf ]; then \ -# 10.5+ - sed -i -e '/includedir/ {N;s/\(.*\)\n\(.*\)/\n\2\n\1/}' /etc/mysql/mariadb.cnf; \ - fi - - -VOLUME /var/lib/mysql - -COPY healthcheck.sh /usr/local/bin/healthcheck.sh -COPY docker-entrypoint.sh /usr/local/bin/ -ENTRYPOINT ["docker-entrypoint.sh"] - -EXPOSE 3306 -CMD ["mariadbd"] diff --git a/11.5/docker-entrypoint.sh b/11.5/docker-entrypoint.sh deleted file mode 100755 index b562bfa..0000000 --- a/11.5/docker-entrypoint.sh +++ /dev/null @@ -1,718 +0,0 @@ -#!/bin/bash -set -eo pipefail -shopt -s nullglob - -# logging functions -mysql_log() { - local type="$1"; shift - printf '%s [%s] [Entrypoint]: %s\n' "$(date --rfc-3339=seconds)" "$type" "$*" -} -mysql_note() { - mysql_log Note "$@" -} -mysql_warn() { - mysql_log Warn "$@" >&2 -} -mysql_error() { - mysql_log ERROR "$@" >&2 - exit 1 -} - -# usage: file_env VAR [DEFAULT] -# ie: file_env 'XYZ_DB_PASSWORD' 'example' -# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of -# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) -file_env() { - local var="$1" - local fileVar="${var}_FILE" - local def="${2:-}" - if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then - mysql_error "Both $var and $fileVar are set (but are exclusive)" - fi - local val="$def" - if [ "${!var:-}" ]; then - val="${!var}" - elif [ "${!fileVar:-}" ]; then - val="$(< "${!fileVar}")" - fi - export "$var"="$val" - unset "$fileVar" -} - -# set MARIADB_xyz from MYSQL_xyz when MARIADB_xyz is unset -# and make them the same value (so user scripts can use either) -_mariadb_file_env() { - local var="$1"; shift - local maria="MARIADB_${var#MYSQL_}" - file_env "$var" "$@" - file_env "$maria" "${!var}" - if [ "${!maria:-}" ]; then - export "$var"="${!maria}" - fi -} - -# check to see if this file is being run or sourced from another script -_is_sourced() { - # https://unix.stackexchange.com/a/215279 - [ "${#FUNCNAME[@]}" -ge 2 ] \ - && [ "${FUNCNAME[0]}" = '_is_sourced' ] \ - && [ "${FUNCNAME[1]}" = 'source' ] -} - -# usage: docker_process_init_files [file [file [...]]] -# ie: docker_process_init_files /always-initdb.d/* -# process initializer files, based on file extensions -docker_process_init_files() { - # mysql here for backwards compatibility "${mysql[@]}" - # ShellCheck: mysql appears unused. Verify use (or export if used externally) - # shellcheck disable=SC2034 - mysql=( docker_process_sql ) - - echo - local f - for f; do - case "$f" in - *.sh) - # https://github.com/docker-library/postgres/issues/450#issuecomment-393167936 - # https://github.com/docker-library/postgres/pull/452 - if [ -x "$f" ]; then - mysql_note "$0: running $f" - "$f" - else - mysql_note "$0: sourcing $f" - # ShellCheck can't follow non-constant source. Use a directive to specify location. - # shellcheck disable=SC1090 - . "$f" - fi - ;; - *.sql) mysql_note "$0: running $f"; docker_process_sql < "$f"; echo ;; - *.sql.gz) mysql_note "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;; - *.sql.xz) mysql_note "$0: running $f"; xzcat "$f" | docker_process_sql; echo ;; - *.sql.zst) mysql_note "$0: running $f"; zstd -dc "$f" | docker_process_sql; echo ;; - *) mysql_warn "$0: ignoring $f" ;; - esac - echo - done -} - -# arguments necessary to run "mariadbd --verbose --help" successfully (used for testing configuration validity and for extracting default/configured values) -_verboseHelpArgs=( - --verbose --help -) - -mysql_check_config() { - local toRun=( "$@" "${_verboseHelpArgs[@]}" ) errors - if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then - mysql_error $'mariadbd failed while attempting to check config\n\tcommand was: '"${toRun[*]}"$'\n\t'"$errors" - fi -} - -# Fetch value from server config -# We use mariadbd --verbose --help instead of my_print_defaults because the -# latter only show values present in config files, and not server defaults -mysql_get_config() { - local conf="$1"; shift - "$@" "${_verboseHelpArgs[@]}" 2>/dev/null \ - | awk -v conf="$conf" '$1 == conf && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }' - # match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)" -} - -# Do a temporary startup of the MariaDB server, for init purposes -docker_temp_server_start() { - "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ - --expire-logs-days=0 \ - --skip-slave-start \ - --loose-innodb_buffer_pool_load_at_startup=0 \ - --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ - & - declare -g MARIADB_PID - MARIADB_PID=$! - mysql_note "Waiting for server startup" - # only use the root password if the database has already been initialized - # so that it won't try to fill in a password file when it hasn't been set yet - extraArgs=() - if [ -z "$DATABASE_ALREADY_EXISTS" ]; then - extraArgs+=( '--dont-use-mysql-root-password' ) - fi - local i - for i in {30..0}; do - if docker_process_sql "${extraArgs[@]}" --database=mysql \ - --skip-ssl --skip-ssl-verify-server-cert \ - <<<'SELECT 1' &> /dev/null; then - break - fi - sleep 1 - done - if [ "$i" = 0 ]; then - mysql_error "Unable to start server." - fi -} - -# Stop the server. When using a local socket file mariadb-admin will block until -# the shutdown is complete. -docker_temp_server_stop() { - kill "$MARIADB_PID" - wait "$MARIADB_PID" -} - -# Verify that the minimally required password settings are set for new databases. -docker_verify_minimum_env() { - # Restoring from backup requires no environment variables - declare -g DATABASE_INIT_FROM_BACKUP - for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do - if [ -f "${file}" ]; then - DATABASE_INIT_FROM_BACKUP='true' - return - fi - done - if [ -z "$MARIADB_ROOT_PASSWORD" ] && [ -z "$MARIADB_ROOT_PASSWORD_HASH" ] && [ -z "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] && [ -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then - mysql_error $'Database is uninitialized and password option is not specified\n\tYou need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ROOT_PASSWORD_HASH, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' - fi - # More preemptive exclusions of combinations should have been made before *PASSWORD_HASH was added, but for now we don't enforce due to compatibility. - if [ -n "$MARIADB_ROOT_PASSWORD" ] || [ -n "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] || [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ] && [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then - mysql_error "Cannot specify MARIADB_ROOT_PASSWORD_HASH and another MARIADB_ROOT_PASSWORD* option." - fi - if [ -n "$MARIADB_PASSWORD" ] && [ -n "$MARIADB_PASSWORD_HASH" ]; then - mysql_error "Cannot specify MARIADB_PASSWORD_HASH and MARIADB_PASSWORD option." - fi - if [ -n "$MARIADB_REPLICATION_USER" ]; then - if [ -z "$MARIADB_MASTER_HOST" ]; then - # its a master, we're creating a user - if [ -z "$MARIADB_REPLICATION_PASSWORD" ] && [ -z "$MARIADB_REPLICATION_PASSWORD_HASH" ]; then - mysql_error "MARIADB_REPLICATION_PASSWORD or MARIADB_REPLICATION_PASSWORD_HASH not found to create replication user for master" - fi - else - # its a replica - if [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; then - mysql_error "MARIADB_REPLICATION_PASSWORD is mandatory to specify the replication on the replica image." - fi - if [ -n "$MARIADB_REPLICATION_PASSWORD_HASH" ] ; then - mysql_warn "MARIADB_REPLICATION_PASSWORD_HASH cannot be specified on a replica" - fi - fi - fi - if [ -n "$MARIADB_MASTER_HOST" ] && { [ -z "$MARIADB_REPLICATION_USER" ] || [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; }; then - mysql_error "For a replica, MARIADB_REPLICATION_USER and MARIADB_REPLICATION is mandatory." - fi -} - -# creates folders for the database -# also ensures permission for user mysql of run as root -docker_create_db_directories() { - local user; user="$(id -u)" - - # TODO other directories that are used by default? like /var/lib/mysql-files - # see https://github.com/docker-library/mysql/issues/562 - mkdir -p "$DATADIR" - - if [ "$user" = "0" ]; then - # this will cause less disk access than `chown -R` - find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) - # See https://github.com/MariaDB/mariadb-docker/issues/363 - if [ "${SOCKET:0:1}" != '@' ]; then # not abstract sockets - find "${SOCKET%/*}" -maxdepth 0 \! -user mysql \( -exec chown mysql: '{}' \; -o -true \) - fi - - # memory.pressure - local cgroup; cgroup=$( "$DATADIR"/.my-healthcheck.cnf - $maskPreserve -} - -# Initializes database with timezone info and root password, plus optional extra db/user -docker_setup_db() { - # Load timezone info into database - if [ -z "$MARIADB_INITDB_SKIP_TZINFO" ]; then - # --skip-write-binlog usefully disables binary logging - # but also outputs LOCK TABLES to improve the IO of - # Aria (MDEV-23326) for 10.4+. - mariadb-tzinfo-to-sql --skip-write-binlog /usr/share/zoneinfo \ - | docker_process_sql --dont-use-mysql-root-password --database=mysql - # tell docker_process_sql to not use MYSQL_ROOT_PASSWORD since it is not set yet - fi - # Generate random root password - if [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then - MARIADB_ROOT_PASSWORD="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" - export MARIADB_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=$MARIADB_ROOT_PASSWORD - mysql_note "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD" - fi - - # Creates root users for non-localhost hosts - local rootCreate= - local rootPasswordEscaped= - if [ -n "$MARIADB_ROOT_PASSWORD" ]; then - # Sets root password and creates root users for non-localhost hosts - rootPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}") - fi - - # default root to listen for connections from anywhere - if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then - # ref "read -d ''", no, we don't care if read finds a terminating character in this heredoc - # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 - if [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then - read -r -d '' rootCreate <<-EOSQL || true - CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY PASSWORD '${MARIADB_ROOT_PASSWORD_HASH}' ; - GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; - GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; - EOSQL - else - read -r -d '' rootCreate <<-EOSQL || true - CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ; - GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; - GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; - EOSQL - fi - fi - - local mysqlAtLocalhost= - local mysqlAtLocalhostGrants= - # Install mysql@localhost user - if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ]; then - read -r -d '' mysqlAtLocalhost <<-EOSQL || true - CREATE USER mysql@localhost IDENTIFIED VIA unix_socket; - EOSQL - if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then - if [ "$MARIADB_MYSQL_LOCALHOST_GRANTS" != USAGE ]; then - mysql_warn "Excessive privileges ON *.* TO mysql@localhost facilitates risks to the confidentiality, integrity and availability of data stored" - fi - mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; - fi - fi - - local createHealthCheckUsers - createHealthCheckUsers=$(create_healthcheck_users) - - local rootLocalhostPass= - if [ -z "$MARIADB_ROOT_PASSWORD_HASH" ]; then - # handle MARIADB_ROOT_PASSWORD_HASH for root@localhost after /docker-entrypoint-initdb.d - rootLocalhostPass="SET PASSWORD FOR 'root'@'localhost'= PASSWORD('${rootPasswordEscaped}');" - fi - - local createDatabase= - # Creates a custom database and user if specified - if [ -n "$MARIADB_DATABASE" ]; then - mysql_note "Creating database ${MARIADB_DATABASE}" - createDatabase="CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\`;" - fi - - local createUser= - local userGrants= - if [ -n "$MARIADB_PASSWORD" ] || [ -n "$MARIADB_PASSWORD_HASH" ] && [ -n "$MARIADB_USER" ]; then - mysql_note "Creating user ${MARIADB_USER}" - if [ -n "$MARIADB_PASSWORD_HASH" ]; then - createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY PASSWORD '$MARIADB_PASSWORD_HASH';" - else - # SQL escape the user password, \ followed by ' - local userPasswordEscaped - userPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_PASSWORD}") - createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$userPasswordEscaped';" - fi - - if [ -n "$MARIADB_DATABASE" ]; then - mysql_note "Giving user ${MARIADB_USER} access to schema ${MARIADB_DATABASE}" - userGrants="GRANT ALL ON \`${MARIADB_DATABASE//_/\\_}\`.* TO '$MARIADB_USER'@'%';" - fi - fi - - # To create replica user - local createReplicaUser= - local changeMasterTo= - if [ -n "$MARIADB_REPLICATION_USER" ] ; then - if [ -z "$MARIADB_MASTER_HOST" ]; then - # on master - mysql_note "Creating user ${MARIADB_REPLICATION_USER}" - createReplicaUser=$(create_replica_user) - else - # on replica - local rplPasswordEscaped - rplPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_REPLICATION_PASSWORD}") - # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. - # shellcheck disable=SC2153 - changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" - fi - fi - - mysql_note "Securing system users (equivalent to running mysql_secure_installation)" - # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set - # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. - docker_process_sql --dont-use-mysql-root-password --database=mysql --binary-mode <<-EOSQL - -- Securing system users shouldn't be replicated - SET @orig_sql_log_bin= @@SESSION.SQL_LOG_BIN; - SET @@SESSION.SQL_LOG_BIN=0; - -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set - SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); - - DROP USER IF EXISTS root@'127.0.0.1', root@'::1'; - EXECUTE IMMEDIATE CONCAT('DROP USER IF EXISTS root@\'', @@hostname,'\''); - - ${rootLocalhostPass} - ${rootCreate} - ${mysqlAtLocalhost} - ${mysqlAtLocalhostGrants} - ${createHealthCheckUsers} - -- end of securing system users, rest of init now... - SET @@SESSION.SQL_LOG_BIN=@orig_sql_log_bin; - -- create users/databases - ${createDatabase} - ${createUser} - ${createReplicaUser} - ${userGrants} - - ${changeMasterTo} - EOSQL -} - -# create a new installation -docker_mariadb_init() -{ - - # check dir permissions to reduce likelihood of half-initialized database - ls /docker-entrypoint-initdb.d/ > /dev/null - - if [ -n "$DATABASE_INIT_FROM_BACKUP" ]; then - shopt -s dotglob - for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do - mkdir -p "$DATADIR"/.init - tar --auto-compress --extract --file "$file" --directory="$DATADIR"/.init - mariadb-backup --target-dir="$DATADIR"/.init --datadir="$DATADIR"/.restore --move-back - - mv "$DATADIR"/.restore/** "$DATADIR"/ - if [ -f "$DATADIR/.init/backup-my.cnf" ]; then - mv "$DATADIR/.init/backup-my.cnf" "$DATADIR/.my.cnf" - mysql_note "Adding startup configuration:" - my_print_defaults --defaults-file="$DATADIR/.my.cnf" --mariadbd - fi - rm -rf "$DATADIR"/.init "$DATADIR"/.restore - if [ "$(id -u)" = "0" ]; then - # this will cause less disk access than `chown -R` - find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) - fi - done - if _check_if_upgrade_is_needed; then - docker_mariadb_upgrade "$@" - fi - return - fi - docker_init_database_dir "$@" - - mysql_note "Starting temporary server" - docker_temp_server_start "$@" - mysql_note "Temporary server started." - - docker_setup_db - docker_process_init_files /docker-entrypoint-initdb.d/* - # Wait until after /docker-entrypoint-initdb.d is performed before setting - # root@localhost password to a hash we don't know the password for. - if [ -n "${MARIADB_ROOT_PASSWORD_HASH}" ]; then - mysql_note "Setting root@localhost password hash" - docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL - SET @@SESSION.SQL_LOG_BIN=0; - SET PASSWORD FOR 'root'@'localhost'= '${MARIADB_ROOT_PASSWORD_HASH}'; - EOSQL - fi - - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" - - echo - mysql_note "MariaDB init process done. Ready for start up." - echo -} - -# backup the mysql database -docker_mariadb_backup_system() -{ - if [ -n "$MARIADB_DISABLE_UPGRADE_BACKUP" ] \ - && [ "$MARIADB_DISABLE_UPGRADE_BACKUP" = 1 ]; then - mysql_note "MariaDB upgrade backup disabled due to \$MARIADB_DISABLE_UPGRADE_BACKUP=1 setting" - return - fi - local backup_db="system_mysql_backup_unknown_version.sql.zst" - local oldfullversion="unknown_version" - if [ -r "$DATADIR"/mariadb_upgrade_info ]; then - read -r -d '' oldfullversion < "$DATADIR"/mariadb_upgrade_info || true - if [ -n "$oldfullversion" ]; then - backup_db="system_mysql_backup_${oldfullversion}.sql.zst" - fi - fi - - mysql_note "Backing up system database to $backup_db" - if ! mariadb-dump --skip-lock-tables --replace --databases mysql --socket="${SOCKET}" | zstd > "${DATADIR}/${backup_db}"; then - mysql_error "Unable backup system database for upgrade from $oldfullversion." - fi - mysql_note "Backing up complete" -} - -# perform mariadb-upgrade -# backup the mysql database if this is a major upgrade -docker_mariadb_upgrade() { - if [ -z "$MARIADB_AUTO_UPGRADE" ] \ - || [ "$MARIADB_AUTO_UPGRADE" = 0 ]; then - mysql_note "MariaDB upgrade (mariadb-upgrade or creating healthcheck users) required, but skipped due to \$MARIADB_AUTO_UPGRADE setting" - return - fi - mysql_note "Starting temporary server" - docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 - mysql_note "Temporary server started." - - docker_mariadb_backup_system - - if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then - mysql_note "Creating healthcheck users" - local createHealthCheckUsers - createHealthCheckUsers=$(create_healthcheck_users) - docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL - -- Healthcheck users shouldn't be replicated - SET @@SESSION.SQL_LOG_BIN=0; - -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set - SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); - FLUSH PRIVILEGES; - $createHealthCheckUsers -EOSQL - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" - - if _check_if_upgrade_is_needed; then - # need a restart as FLUSH PRIVILEGES isn't reversable - mysql_note "Restarting temporary server for upgrade" - docker_temp_server_start "$@" --skip-grant-tables \ - --loose-innodb_buffer_pool_dump_at_shutdown=0 - else - return 0 - fi - fi - - mysql_note "Starting mariadb-upgrade" - mariadb-upgrade --upgrade-system-tables - mysql_note "Finished mariadb-upgrade" - - mysql_note "Stopping temporary server" - docker_temp_server_stop - mysql_note "Temporary server stopped" -} - - -_check_if_upgrade_is_needed() { - if [ ! -f "$DATADIR"/mariadb_upgrade_info ]; then - mysql_note "MariaDB upgrade information missing, assuming required" - return 0 - fi - local mariadbVersion - mariadbVersion="$(_mariadb_version)" - IFS='.-' read -ra newversion <<<"$mariadbVersion" - IFS='.-' read -ra oldversion < "$DATADIR"/mariadb_upgrade_info || true - - if [[ ${#newversion[@]} -lt 2 ]] || [[ ${#oldversion[@]} -lt 2 ]] \ - || [[ ${oldversion[0]} -lt ${newversion[0]} ]] \ - || [[ ${oldversion[0]} -eq ${newversion[0]} && ${oldversion[1]} -lt ${newversion[1]} ]]; then - return 0 - fi - if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then - mysql_note "MariaDB heathcheck configation file missing, assuming desirable" - return 0 - fi - mysql_note "MariaDB upgrade not required" - return 1 -} - -# check arguments for an option that would cause mariadbd to stop -# return true if there is one -_mysql_want_help() { - local arg - for arg; do - case "$arg" in - -'?'|--help|--print-defaults|-V|--version) - return 0 - ;; - esac - done - return 1 -} - -_main() { - # if command starts with an option, prepend mariadbd - if [ "${1:0:1}" = '-' ]; then - set -- mariadbd "$@" - fi - - #ENDOFSUBSTITUTIONS - # skip setup if they aren't running mysqld or want an option that stops mysqld - if [ "$1" = 'mariadbd' ] || [ "$1" = 'mysqld' ] && ! _mysql_want_help "$@"; then - mysql_note "Entrypoint script for MariaDB Server ${MARIADB_VERSION} started." - - mysql_check_config "$@" - # Load various environment variables - docker_setup_env "$@" - docker_create_db_directories - - # If container is started as root user, restart as dedicated mysql user - if [ "$(id -u)" = "0" ]; then - mysql_note "Switching to dedicated user 'mysql'" - exec gosu mysql "${BASH_SOURCE[0]}" "$@" - fi - - # there's no database, so it needs to be initialized - if [ -z "$DATABASE_ALREADY_EXISTS" ]; then - docker_verify_minimum_env - - docker_mariadb_init "$@" - # MDEV-27636 mariadb_upgrade --check-if-upgrade-is-needed cannot be run offline - #elif mariadb-upgrade --check-if-upgrade-is-needed; then - elif _check_if_upgrade_is_needed; then - docker_mariadb_upgrade "$@" - fi - fi - exec "$@" -} - -# If we are sourced from elsewhere, don't perform any further actions -if ! _is_sourced; then - _main "$@" -fi diff --git a/11.5/healthcheck.sh b/11.5/healthcheck.sh deleted file mode 100755 index 62be345..0000000 --- a/11.5/healthcheck.sh +++ /dev/null @@ -1,395 +0,0 @@ -#!/bin/bash -# -# Healthcheck script for MariaDB -# -# Runs various tests on the MariaDB server to check its health. Pass the tests -# to run as arguments. If all tests succeed, the server is considered healthy, -# otherwise it's not. -# -# Arguments are processed in strict order. Set replication_* options before -# the --replication option. This allows a different set of replication checks -# on different connections. -# -# --su{=|-mysql} is option to run the healthcheck as a different unix user. -# Useful if mysql@localhost user exists with unix socket authentication -# Using this option disregards previous options set, so should usually be the -# first option. -# -# Some tests require SQL privileges. -# -# TEST MINIMUM GRANTS REQUIRED -# connect none* -# innodb_initialized USAGE -# innodb_buffer_pool_loaded USAGE -# galera_online USAGE -# galera_ready USAGE -# replication REPLICATION_CLIENT (<10.5)or REPLICA MONITOR (10.5+) -# mariadbupgrade none, however unix user permissions on datadir -# -# The SQL user used is the default for the mariadb client. This can be the unix user -# if no user(or password) is set in the [mariadb-client] section of a configuration -# file. --defaults-{file,extra-file,group-suffix} can specify a file/configuration -# different from elsewhere. -# -# Note * though denied error message will result in error log without -# any permissions. USAGE recommend to avoid this. - -set -eo pipefail - -_process_sql() -{ - mariadb ${nodefaults:+--no-defaults} \ - ${def['file']:+--defaults-file=${def['file']}} \ - ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ - ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ - --skip-ssl --skip-ssl-verify-server-cert \ - --protocol socket \ - -B "$@" -} - -# TESTS - - -# CONNECT -# -# Tests that a connection can be made over TCP, the final state -# of the entrypoint and is listening. The authentication used -# isn't tested. -connect() -{ - local s - # short cut mechanism, to work with --require-secure-transport - s=$(_process_sql --skip-column-names -e 'select @@skip_networking') - case "$s" in - 0|1) - connect_s=$s - return "$s"; - ;; - esac - # falling back to tcp if there wasn't a connection answer. - s=$(mariadb ${nodefaults:+--no-defaults} \ - ${def['file']:+--defaults-file=${def['file']}} \ - ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ - ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ - --skip-ssl --skip-ssl-verify-server-cert \ - -h localhost --protocol tcp \ - --skip-column-names --batch --skip-print-query-on-error \ - -e 'select @@skip_networking' 2>&1) - - case "$s" in - 1) # skip-networking=1 (no network) - ;& - ERROR\ 2002\ \(HY000\):*) - # cannot connect - connect_s=1 - ;; - 0) # skip-networking=0 - ;& - ERROR\ 1820\ \(HY000\)*) # password expire - ;& - ERROR\ 4151\ \(HY000\):*) # account locked - ;& - ERROR\ 1226\ \(42000\)*) # resource limit exceeded - ;& - ERROR\ 1[0-9][0-9][0-9]\ \(28000\):*) - # grep access denied and other 28000 client errors - we did connect - connect_s=0 - ;; - *) - >&2 echo "Unknown error $s" - connect_s=1 - ;; - esac - return $connect_s -} - -# INNODB_INITIALIZED -# -# This tests that the crash recovery of InnoDB has completed -# along with all the other things required to make it to a healthy -# operational state. Note this may return true in the early -# states of initialization. Use with a connect test to avoid -# these false positives. -innodb_initialized() -{ - local s - s=$(_process_sql --skip-column-names -e "select 1 from information_schema.ENGINES WHERE engine='innodb' AND support in ('YES', 'DEFAULT', 'ENABLED')") - [ "$s" == 1 ] -} - -# INNODB_BUFFER_POOL_LOADED -# -# Tests the load of the innodb buffer pool as been complete -# implies innodb_buffer_pool_load_at_startup=1 (default), or if -# manually SET innodb_buffer_pool_load_now=1 -innodb_buffer_pool_loaded() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='Innodb_buffer_pool_load_status'") - if [[ $s =~ 'load completed' ]]; then - return 0 - fi - return 1 -} - -# GALERA_ONLINE -# -# Tests that the galera node is in the SYNCed state -galera_online() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_LOCAL_STATE'") - # 4 from https://galeracluster.com/library/documentation/node-states.html#node-state-changes - # not https://xkcd.com/221/ - if [[ $s -eq 4 ]]; then - return 0 - fi - return 1 -} - -# GALERA_READY -# -# Tests that the Galera provider is ready. -galera_ready() -{ - local s - s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_READY'") - if [ "$s" = "ON" ]; then - return 0 - fi - return 1 -} - -# REPLICATION -# -# Tests the replication has the required set of functions: -# --replication_all -> Checks all replication sources -# --replication_name=n -> sets the multisource connection name tested -# --replication_io -> IO thread is running -# --replication_sql -> SQL thread is running -# --replication_seconds_behind_master=n -> less than or equal this seconds of delay -# --replication_sql_remaining_delay=n -> less than or equal this seconds of remaining delay -# (ref: https://mariadb.com/kb/en/delayed-replication/) -replication() -{ - # SHOW REPLICA available 10.5+ - # https://github.com/koalaman/shellcheck/issues/2383 - # shellcheck disable=SC2016,SC2026 - _process_sql -e "SHOW ${repl['all']:+all} REPLICA${repl['all']:+S} ${repl['name']:+'${repl['name']}'} STATUS\G" | \ - { - # required for trim of leading space. - shopt -s extglob - # Row header - read -t 5 -r - # read timeout - [ $? -gt 128 ] && return 1 - while IFS=":" read -t 1 -r n v; do - # Trim leading space - n=${n##+([[:space:]])} - # Leading space on all values by the \G format needs to be trimmed. - v=${v:1} - case "$n" in - Slave_IO_Running) - if [ -n "${repl['io']}" ] && [ "$v" = 'No' ]; then - return 1 - fi - ;; - Slave_SQL_Running) - if [ -n "${repl['sql']}" ] && [ "$v" = 'No' ]; then - return 1 - fi - ;; - Seconds_Behind_Master) - # A NULL value is the IO thread not running: - if [ -n "${repl['seconds_behind_master']}" ] && - { [ "$v" = NULL ] || - (( "${repl['seconds_behind_master']}" < "$v" )); }; then - return 1 - fi - ;; - SQL_Remaining_Delay) - # Unlike Seconds_Behind_Master, sql_remaining_delay will hit NULL - # once replication is caught up - https://mariadb.com/kb/en/delayed-replication/ - if [ -n "${repl['sql_remaining_delay']}" ] && - [ "$v" != NULL ] && - (( "${repl['sql_remaining_delay']}" < "$v" )); then - return 1 - fi - ;; - esac - done - # read timeout - [ $? -gt 128 ] && return 1 - return 0 - } - # reachable in command not found(?) - # shellcheck disable=SC2317 - return $? -} - -# mariadbupgrade -# -# Test the lock on the file $datadir/mariadb_upgrade_info -# https://jira.mariadb.org/browse/MDEV-27068 -mariadbupgrade() -{ - local f="$datadir/mariadb_upgrade_info" - if [ -r "$f" ]; then - flock --exclusive --nonblock -n 9 9<"$f" - return $? - fi - return 0 -} - - -# MAIN - -if [ $# -eq 0 ]; then - echo "At least one argument required" >&2 - exit 1 -fi - -#ENDOFSUBSTITUTIONS -# Marks the end of mysql -> mariadb name changes in 10.6+ -# Global variables used by tests -declare -A repl -declare -A def -nodefaults= -connect_s= -datadir=/var/lib/mysql -if [ -f $datadir/.my-healthcheck.cnf ]; then - def['extra_file']=$datadir/.my-healthcheck.cnf -fi - -_repl_param_check() -{ - case "$1" in - seconds_behind_master) ;& - sql_remaining_delay) - if [ -z "${repl['io']}" ]; then - repl['io']=1 - echo "Forcing --replication_io=1, $1 requires IO thread to be running" >&2 - fi - ;; - all) - if [ -n "${repl['name']}" ]; then - unset 'repl[name]' - echo "Option --replication_all incompatible with specified source --replication_name, clearing replication_name" >&2 - fi - ;; - name) - if [ -n "${repl['all']}" ]; then - unset 'repl[all]' - echo "Option --replication_name incompatible with --replication_all, clearing replication_all" >&2 - fi - ;; - esac -} - -_test_exists() { - declare -F "$1" > /dev/null - return $? -} - -while [ $# -gt 0 ]; do - case "$1" in - --su=*) - u="${1#*=}" - shift - exec gosu "${u}" "${BASH_SOURCE[0]}" "$@" - ;; - --su) - shift - u=$1 - shift - exec gosu "$u" "${BASH_SOURCE[0]}" "$@" - ;; - --su-mysql) - shift - exec gosu mysql "${BASH_SOURCE[0]}" "$@" - ;; - --replication_*=*) - # Change the n to what is between _ and = and make lower case - n=${1#*_} - n=${n%%=*} - n=${n,,*} - # v is after the = - v=${1#*=} - repl[$n]=$v - _repl_param_check "$n" - ;; - --replication_*) - # Without =, look for a non --option next as the value, - # otherwise treat it as an "enable", just equate to 1. - # Clearing option is possible with "--replication_X=" - n=${1#*_} - n=${n,,*} - if [ "${2:0:2}" == '--' ]; then - repl[$n]=1 - else - repl[$n]=$2 - shift - fi - _repl_param_check "$n" - ;; - --datadir=*) - datadir=${1#*=} - ;; - --datadir) - shift - datadir=${1} - ;; - --no-defaults) - def=() - nodefaults=1 - ;; - --defaults-file=*|--defaults-extra-file=*|--defaults-group-suffix=*) - n=${1:11} # length --defaults- - n=${n%%=*} - n=${n//-/_} - # v is after the = - v=${1#*=} - def[$n]=$v - nodefaults= - ;; - --defaults-file|--defaults-extra-file|--defaults-group-suffix) - n=${1:11} # length --defaults- - n=${n//-/_} - if [ "${2:0:2}" == '--' ]; then - def[$n]="" - else - def[$n]=$2 - shift - fi - nodefaults= - ;; - --no-connect) - # used for /docker-entrypoint-initdb.d scripts - # where you definately don't want a connection test - connect_s=0 - ;; - --*) - test=${1#--} - ;; - *) - echo "Unknown healthcheck option $1" >&2 - exit 1 - esac - if [ -n "$test" ]; then - if ! _test_exists "$test" ; then - echo "healthcheck unknown option or test '$test'" >&2 - exit 1 - elif ! "$test"; then - echo "healthcheck $test failed" >&2 - exit 1 - fi - test= - fi - shift -done -if [ "$connect_s" != "0" ]; then - # we didn't pass a connnect test, so the current success status is suspicious - # return what connect thinks. - connect - exit $? -fi diff --git a/versions.json b/versions.json index 5facecf..a8a154e 100644 --- a/versions.json +++ b/versions.json @@ -110,5 +110,33 @@ "ppc64le", "s390x" ] + }, + "11.6": { + "milestone": "11.6", + "version": "11.6.2", + "fullVersion": "1:11.6.2+maria~ubu2404", + "releaseStatus": "Stable", + "supportType": "Short Term Support", + "base": "ubuntu:noble", + "arches": [ + "amd64", + "arm64v8", + "ppc64le", + "s390x" + ] + }, + "11.6-ubi": { + "milestone": "11.6", + "version": "11.6.2", + "fullVersion": "11.6.2", + "releaseStatus": "Stable", + "supportType": "Short Term Support", + "base": "ubi9", + "arches": [ + "amd64", + "arm64v8", + "ppc64le", + "s390x" + ] } } From 292b81d08eaab23d8bd501171e570ea0636b0b82 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 22 Nov 2024 08:32:10 +1100 Subject: [PATCH 18/21] Update to 11.6.2 (stable) --- 11.6-ubi/Dockerfile | 8 ++++---- 11.6-ubi/docker-entrypoint.sh | 2 +- 11.6/Dockerfile | 8 ++++---- 11.6/docker-entrypoint.sh | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/11.6-ubi/Dockerfile b/11.6-ubi/Dockerfile index d205b3f..8bf1dec 100644 --- a/11.6-ubi/Dockerfile +++ b/11.6-ubi/Dockerfile @@ -36,7 +36,7 @@ COPY MariaDB.repo /etc/yum.repos.d/ # https://access.redhat.com/documentation/en-us/red_hat_software_certification/2024/html/red_hat_openshift_software_certification_policy_guide/assembly-requirements-for-container-images_openshift-sw-cert-policy-introduction#con-image-metadata-requirements_openshift-sw-cert-policy-container-images LABEL name="MariaDB Server" \ vendor="MariaDB Community" \ - version="11.6.1" \ + version="11.6.2" \ release="Refer to Annotations org.opencontainers.image.{revision,source}" \ summary="MariaDB Database" \ description="MariaDB Database for relational SQL" @@ -50,13 +50,13 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="11.6.1" \ + org.opencontainers.image.version="11.6.2" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=11.6.1 +ARG MARIADB_VERSION=11.6.2 ENV MARIADB_VERSION=$MARIADB_VERSION -# release-status:RC +# release-status:Stable # release-support-type:Short Term Support # (https://downloads.mariadb.org/rest-api/mariadb/) diff --git a/11.6-ubi/docker-entrypoint.sh b/11.6-ubi/docker-entrypoint.sh index 9539eb8..36f54d6 100755 --- a/11.6-ubi/docker-entrypoint.sh +++ b/11.6-ubi/docker-entrypoint.sh @@ -225,7 +225,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "11.6.1-MariaDB" + echo -n "11.6.2-MariaDB" } # initializes the database directory diff --git a/11.6/Dockerfile b/11.6/Dockerfile index ffc341a..4986cf7 100644 --- a/11.6/Dockerfile +++ b/11.6/Dockerfile @@ -75,18 +75,18 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="11.6.1" \ + org.opencontainers.image.version="11.6.2" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=1:11.6.1+maria~ubu2404 +ARG MARIADB_VERSION=1:11.6.2+maria~ubu2404 ENV MARIADB_VERSION $MARIADB_VERSION -# release-status:RC +# release-status:Stable # release-support-type:Short Term Support # (https://downloads.mariadb.org/rest-api/mariadb/) # Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions -ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.6.1/repo/ubuntu/ noble main main/debug" +ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.6.2/repo/ubuntu/ noble main main/debug" RUN set -e;\ echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ diff --git a/11.6/docker-entrypoint.sh b/11.6/docker-entrypoint.sh index 9539eb8..36f54d6 100755 --- a/11.6/docker-entrypoint.sh +++ b/11.6/docker-entrypoint.sh @@ -225,7 +225,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "11.6.1-MariaDB" + echo -n "11.6.2-MariaDB" } # initializes the database directory From ed58e853e16cf2a3b092afc3882d17b9861a14f2 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 22 Nov 2024 08:32:40 +1100 Subject: [PATCH 19/21] temp; update.sh bump to 11.6.2 ahead of downloads api --- update.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/update.sh b/update.sh index 331bda8..48e9348 100755 --- a/update.sh +++ b/update.sh @@ -188,6 +188,7 @@ mariaversion() mariaVersion=$(curl -fsSL "$DOWNLOADS_REST_API/mariadb/${version%-*}" \ | jq -r 'first(.releases[] | .release_id | select(. | test("[0-9]+.[0-9]+.[0-9]+$")))') mariaVersion=${mariaVersion//\"} + if [ "$mariaVersion" = 11.6.1 ]; then mariaVersion=11.6.2; fi } all() @@ -238,8 +239,8 @@ for version in "${versions[@]}"; do fi readarray -t release <<< "$(curl -fsSL "$DOWNLOADS_REST_API/mariadb/" \ | jq -r --arg version "${version%-*}" '.major_releases[] | select(.release_id == $version) | [ .release_status ] , [ .release_support_type ] | @tsv')" - releaseStatus=${release[0]:-Unknown} - supportType=${release[1]:-Unknown} + releaseStatus=${release[0]:-Stable} + supportType=${release[1]:-Short Term Support} update_version done From 59dc031f52b13c46bf0dcbc2c41b1544a5c54863 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 25 Nov 2024 08:46:31 +1100 Subject: [PATCH 20/21] 11.8 is development version --- main-ubi/Dockerfile | 6 +++--- main-ubi/docker-entrypoint.sh | 2 +- main/Dockerfile | 6 +++--- main/docker-entrypoint.sh | 2 +- update.sh | 2 +- versions.json | 27 +++++++++++++++++++++++++++ 6 files changed, 36 insertions(+), 9 deletions(-) diff --git a/main-ubi/Dockerfile b/main-ubi/Dockerfile index c4c7b7b..94e5bc9 100644 --- a/main-ubi/Dockerfile +++ b/main-ubi/Dockerfile @@ -36,7 +36,7 @@ COPY MariaDB.repo /etc/yum.repos.d/ # https://access.redhat.com/documentation/en-us/red_hat_software_certification/2024/html/red_hat_openshift_software_certification_policy_guide/assembly-requirements-for-container-images_openshift-sw-cert-policy-introduction#con-image-metadata-requirements_openshift-sw-cert-policy-container-images LABEL name="MariaDB Server" \ vendor="MariaDB Community" \ - version="11.7.0" \ + version="11.8.0" \ release="Refer to Annotations org.opencontainers.image.{revision,source}" \ summary="MariaDB Database" \ description="MariaDB Database for relational SQL" @@ -50,11 +50,11 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="11.7.0" \ + org.opencontainers.image.version="11.8.0" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=11.7.0 +ARG MARIADB_VERSION=11.8.0 ENV MARIADB_VERSION=$MARIADB_VERSION # release-status:Alpha # release-support-type:Unknown diff --git a/main-ubi/docker-entrypoint.sh b/main-ubi/docker-entrypoint.sh index d3bf557..9a64eb9 100755 --- a/main-ubi/docker-entrypoint.sh +++ b/main-ubi/docker-entrypoint.sh @@ -225,7 +225,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "11.7.0-MariaDB" + echo -n "11.8.0-MariaDB" } # initializes the database directory diff --git a/main/Dockerfile b/main/Dockerfile index 4e59706..81e4833 100644 --- a/main/Dockerfile +++ b/main/Dockerfile @@ -75,18 +75,18 @@ LABEL org.opencontainers.image.authors="MariaDB Community" \ org.opencontainers.image.licenses="GPL-2.0" \ org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ org.opencontainers.image.vendor="MariaDB Community" \ - org.opencontainers.image.version="11.7.0" \ + org.opencontainers.image.version="11.8.0" \ org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" # bashbrew-architectures: amd64 arm64v8 ppc64le s390x -ARG MARIADB_VERSION=1:11.7.0+maria~ubu2404 +ARG MARIADB_VERSION=1:11.8.0+maria~ubu2404 ENV MARIADB_VERSION $MARIADB_VERSION # release-status:Alpha # release-support-type:Unknown # (https://downloads.mariadb.org/rest-api/mariadb/) # Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions -ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.7.0/repo/ubuntu/ noble main main/debug" +ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.8.0/repo/ubuntu/ noble main main/debug" RUN set -e;\ echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ diff --git a/main/docker-entrypoint.sh b/main/docker-entrypoint.sh index d3bf557..9a64eb9 100755 --- a/main/docker-entrypoint.sh +++ b/main/docker-entrypoint.sh @@ -225,7 +225,7 @@ docker_create_db_directories() { } _mariadb_version() { - echo -n "11.7.0-MariaDB" + echo -n "11.8.0-MariaDB" } # initializes the database directory diff --git a/update.sh b/update.sh index 48e9348..4ad2d50 100755 --- a/update.sh +++ b/update.sh @@ -5,7 +5,7 @@ set -Eeuo pipefail # development_version=main -development_version_real=11.7 +development_version_real=11.8 defaultSuite='noble' declare -A suites=( diff --git a/versions.json b/versions.json index a8a154e..a483702 100644 --- a/versions.json +++ b/versions.json @@ -138,5 +138,32 @@ "ppc64le", "s390x" ] + "main": { + "milestone": "main", + "version": "11.8.0", + "fullVersion": "1:11.8.0+maria~ubu2404", + "releaseStatus": "Alpha", + "supportType": "Unknown", + "base": "ubuntu:noble", + "arches": [ + "amd64", + "arm64v8", + "ppc64le", + "s390x" + ] + }, + "main-ubi": { + "milestone": "main", + "version": "11.8.0", + "fullVersion": "11.8.0", + "releaseStatus": "Alpha", + "supportType": "Unknown", + "base": "ubi9", + "arches": [ + "amd64", + "arm64v8", + "ppc64le", + "s390x" + ] } } From a6b360fc45b1a8fcd63b87ab69d4ce43566a7c06 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 25 Nov 2024 09:03:41 +1100 Subject: [PATCH 21/21] 11.7 release --- 11.7-ubi/Dockerfile | 113 ++++++ 11.7-ubi/MariaDB.repo | 7 + 11.7-ubi/docker-entrypoint.sh | 718 ++++++++++++++++++++++++++++++++++ 11.7-ubi/docker.cnf | 14 + 11.7-ubi/healthcheck.sh | 395 +++++++++++++++++++ 11.7/Dockerfile | 142 +++++++ 11.7/docker-entrypoint.sh | 718 ++++++++++++++++++++++++++++++++++ 11.7/healthcheck.sh | 395 +++++++++++++++++++ update.sh | 22 +- versions.json | 29 ++ 10 files changed, 2551 insertions(+), 2 deletions(-) create mode 100644 11.7-ubi/Dockerfile create mode 100644 11.7-ubi/MariaDB.repo create mode 100755 11.7-ubi/docker-entrypoint.sh create mode 100644 11.7-ubi/docker.cnf create mode 100755 11.7-ubi/healthcheck.sh create mode 100644 11.7/Dockerfile create mode 100755 11.7/docker-entrypoint.sh create mode 100755 11.7/healthcheck.sh diff --git a/11.7-ubi/Dockerfile b/11.7-ubi/Dockerfile new file mode 100644 index 0000000..572ff0d --- /dev/null +++ b/11.7-ubi/Dockerfile @@ -0,0 +1,113 @@ +FROM redhat/ubi9-minimal + +# user 999/ group 999, that we want to use for compatibility with the ubuntu image. +RUN groupadd --gid 999 -r mysql && \ + useradd -r -g mysql mysql --home-dir /var/lib/mysql --uid 999 + +ENV GOSU_VERSION 1.17 +RUN set -eux; \ + rpmArch="$(rpm --query --queryformat='%{ARCH}' rpm)"; \ + case "$rpmArch" in \ + aarch64) dpkgArch='arm64' ;; \ + armv7*) dpkgArch='armhf' ;; \ + i686) dpkgArch='i386' ;; \ + ppc64le) dpkgArch='ppc64el' ;; \ + s390x|riscv64) dpkgArch=$rpmArch ;; \ + x86_64) dpkgArch='amd64' ;; \ + *) echo >&2 "error: unknown/unsupported architecture '$rpmArch'"; exit 1 ;; \ + esac; \ + curl --fail --location --output /usr/local/bin/gosu https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${dpkgArch} ; \ + curl --fail --location --output /usr/local/bin/gosu.asc https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${dpkgArch}.asc; \ + GNUPGHOME="$(mktemp -d)"; \ + export GNUPGHOME; \ + gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ + chmod a+x /usr/local/bin/gosu; \ + gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ + gpgconf --kill all; \ + rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ + gosu --version; \ + gosu nobody true + +COPY --chmod=0644 docker.cnf /etc/my.cnf.d/ + +COPY MariaDB.repo /etc/yum.repos.d/ + +# HasRequiredLabel requirement from Red Hat OpenShift Software Certification +# https://access.redhat.com/documentation/en-us/red_hat_software_certification/2024/html/red_hat_openshift_software_certification_policy_guide/assembly-requirements-for-container-images_openshift-sw-cert-policy-introduction#con-image-metadata-requirements_openshift-sw-cert-policy-container-images +LABEL name="MariaDB Server" \ + vendor="MariaDB Community" \ + version="11.7.1" \ + release="Refer to Annotations org.opencontainers.image.{revision,source}" \ + summary="MariaDB Database" \ + description="MariaDB Database for relational SQL" + +# OCI annotations to image +LABEL org.opencontainers.image.authors="MariaDB Community" \ + org.opencontainers.image.title="MariaDB Database" \ + org.opencontainers.image.description="MariaDB Database for relational SQL" \ + org.opencontainers.image.documentation="https://hub.docker.com/_/mariadb/" \ + org.opencontainers.image.base.name="docker.io/redhat/ubi9-minimal" \ + org.opencontainers.image.licenses="GPL-2.0" \ + org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ + org.opencontainers.image.vendor="MariaDB Community" \ + org.opencontainers.image.version="11.7.1" \ + org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" + +# bashbrew-architectures: amd64 arm64v8 ppc64le s390x +ARG MARIADB_VERSION=11.7.1 +ENV MARIADB_VERSION=$MARIADB_VERSION +# release-status:RC +# release-support-type:Short Term Support +# (https://downloads.mariadb.org/rest-api/mariadb/) + +# missing pwgen(epel), jemalloc(epel) (as entrypoint/user extensions) +# procps, pv(epel) - missing dependencies of galera sst script +# tzdata re-installed as only a fake version is part of the ubi-minimal base image. +# FF8AD1344597106ECE813B918A3872BF3228467C is the Fedora RPM key +# 177F4010FE56CA3336300305F1656F24C74CD1D8 is the MariaDB Server RPM key +RUN set -eux ; \ + curl --fail https://pagure.io/fedora-web/websites/raw/master/f/sites/getfedora.org/static/keys/FF8AD1344597106ECE813B918A3872BF3228467C.txt --output /tmp/epelkey.txt ; \ + GNUPGHOME="$(mktemp -d)"; export GNUPGHOME ; \ + gpg --batch --import /tmp/epelkey.txt ; \ + gpg --batch --armor --export FF8AD1344597106ECE813B918A3872BF3228467C > /tmp/epelkey.txt ; \ + rpmkeys --import /tmp/epelkey.txt ; \ + curl --fail https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm --output /tmp/epel-release-latest-9.noarch.rpm ; \ + rpm -K /tmp/epel-release-latest-9.noarch.rpm ; \ + rpm -ivh /tmp/epel-release-latest-9.noarch.rpm ; \ + rm /tmp/epelkey.txt /tmp/epel-release-latest-9.noarch.rpm ; \ + curl --fail https://supplychain.mariadb.com/MariaDB-Server-GPG-KEY --output /tmp/MariaDB-Server-GPG-KEY ; \ + gpg --batch --import /tmp/MariaDB-Server-GPG-KEY; \ + gpg --batch --armor --export 177F4010FE56CA3336300305F1656F24C74CD1D8 > /tmp/MariaDB-Server-GPG-KEY ; \ + rpmkeys --import /tmp/MariaDB-Server-GPG-KEY ; \ + rm -rf "$GNUPGHOME" /tmp/MariaDB-Server-GPG-KEY ; \ + unset GNUPGHOME ; \ + microdnf update -y ; \ + microdnf reinstall -y tzdata ; \ + microdnf install -y procps-ng zstd xz jemalloc pwgen pv ; \ + mkdir -p /etc/mysql/conf.d /etc/mysql/mariadb.conf.d/ /var/lib/mysql/mysql /run/mariadb /usr/lib64/galera ; \ + chmod ugo+rwx,o+t /run/mariadb ; \ + microdnf install -y MariaDB-backup-${MARIADB_VERSION} MariaDB-server-${MARIADB_VERSION} ; \ + # compatibility with DEB Galera packaging + ln -s /usr/lib64/galera-4/libgalera_smm.so /usr/lib/libgalera_smm.so ; \ + # compatibility with RPM Galera packaging + ln -s /usr/lib64/galera-4/libgalera_smm.so /usr/lib64/galera/libgalera_smm.so ; \ + microdnf clean all ; \ + rmdir /var/lib/mysql/mysql ; \ + chown -R mysql:mysql /var/lib/mysql /run/mariadb ; \ + mkdir /licenses ; \ + ln -s /usr/share/doc/MariaDB-server-${MARIADB_VERSION}/COPYING /licenses/GPL-2 ; \ + ln -s /usr/share/licenses /licenses/package-licenses ; \ + ln -s Apache-2.0-license /licenses/gosu + +VOLUME /var/lib/mysql + +RUN mkdir /docker-entrypoint-initdb.d + +COPY healthcheck.sh /usr/local/bin/healthcheck.sh +COPY docker-entrypoint.sh /usr/local/bin/ + +ENTRYPOINT ["docker-entrypoint.sh"] + +USER mysql +EXPOSE 3306 +CMD ["mariadbd"] diff --git a/11.7-ubi/MariaDB.repo b/11.7-ubi/MariaDB.repo new file mode 100644 index 0000000..fe521d5 --- /dev/null +++ b/11.7-ubi/MariaDB.repo @@ -0,0 +1,7 @@ +[mariadb] +name = MariaDB +#baseurl = https://rpm.mariadb.org/11.7/rhel/$releasever/$basearch +baseurl = https://archive.mariadb.org/mariadb-11.7/yum/rhel/$releasever/$basearch +#microdnf cannot read to the second key here. +#gpgkey=https://archive.mariadb.org/PublicKey +gpgcheck=1 diff --git a/11.7-ubi/docker-entrypoint.sh b/11.7-ubi/docker-entrypoint.sh new file mode 100755 index 0000000..92d280c --- /dev/null +++ b/11.7-ubi/docker-entrypoint.sh @@ -0,0 +1,718 @@ +#!/bin/bash +set -eo pipefail +shopt -s nullglob + +# logging functions +mysql_log() { + local type="$1"; shift + printf '%s [%s] [Entrypoint]: %s\n' "$(date --rfc-3339=seconds)" "$type" "$*" +} +mysql_note() { + mysql_log Note "$@" +} +mysql_warn() { + mysql_log Warn "$@" >&2 +} +mysql_error() { + mysql_log ERROR "$@" >&2 + exit 1 +} + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + mysql_error "Both $var and $fileVar are set (but are exclusive)" + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +# set MARIADB_xyz from MYSQL_xyz when MARIADB_xyz is unset +# and make them the same value (so user scripts can use either) +_mariadb_file_env() { + local var="$1"; shift + local maria="MARIADB_${var#MYSQL_}" + file_env "$var" "$@" + file_env "$maria" "${!var}" + if [ "${!maria:-}" ]; then + export "$var"="${!maria}" + fi +} + +# check to see if this file is being run or sourced from another script +_is_sourced() { + # https://unix.stackexchange.com/a/215279 + [ "${#FUNCNAME[@]}" -ge 2 ] \ + && [ "${FUNCNAME[0]}" = '_is_sourced' ] \ + && [ "${FUNCNAME[1]}" = 'source' ] +} + +# usage: docker_process_init_files [file [file [...]]] +# ie: docker_process_init_files /always-initdb.d/* +# process initializer files, based on file extensions +docker_process_init_files() { + # mysql here for backwards compatibility "${mysql[@]}" + # ShellCheck: mysql appears unused. Verify use (or export if used externally) + # shellcheck disable=SC2034 + mysql=( docker_process_sql ) + + echo + local f + for f; do + case "$f" in + *.sh) + # https://github.com/docker-library/postgres/issues/450#issuecomment-393167936 + # https://github.com/docker-library/postgres/pull/452 + if [ -x "$f" ]; then + mysql_note "$0: running $f" + "$f" + else + mysql_note "$0: sourcing $f" + # ShellCheck can't follow non-constant source. Use a directive to specify location. + # shellcheck disable=SC1090 + . "$f" + fi + ;; + *.sql) mysql_note "$0: running $f"; docker_process_sql < "$f"; echo ;; + *.sql.gz) mysql_note "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;; + *.sql.xz) mysql_note "$0: running $f"; xzcat "$f" | docker_process_sql; echo ;; + *.sql.zst) mysql_note "$0: running $f"; zstd -dc "$f" | docker_process_sql; echo ;; + *) mysql_warn "$0: ignoring $f" ;; + esac + echo + done +} + +# arguments necessary to run "mariadbd --verbose --help" successfully (used for testing configuration validity and for extracting default/configured values) +_verboseHelpArgs=( + --verbose --help +) + +mysql_check_config() { + local toRun=( "$@" "${_verboseHelpArgs[@]}" ) errors + if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then + mysql_error $'mariadbd failed while attempting to check config\n\tcommand was: '"${toRun[*]}"$'\n\t'"$errors" + fi +} + +# Fetch value from server config +# We use mariadbd --verbose --help instead of my_print_defaults because the +# latter only show values present in config files, and not server defaults +mysql_get_config() { + local conf="$1"; shift + "$@" "${_verboseHelpArgs[@]}" 2>/dev/null \ + | awk -v conf="$conf" '$1 == conf && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }' + # match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)" +} + +# Do a temporary startup of the MariaDB server, for init purposes +docker_temp_server_start() { + "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ + --expire-logs-days=0 \ + --skip-slave-start \ + --loose-innodb_buffer_pool_load_at_startup=0 \ + --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ + & + declare -g MARIADB_PID + MARIADB_PID=$! + mysql_note "Waiting for server startup" + # only use the root password if the database has already been initialized + # so that it won't try to fill in a password file when it hasn't been set yet + extraArgs=() + if [ -z "$DATABASE_ALREADY_EXISTS" ]; then + extraArgs+=( '--dont-use-mysql-root-password' ) + fi + local i + for i in {30..0}; do + if docker_process_sql "${extraArgs[@]}" --database=mysql \ + --skip-ssl --skip-ssl-verify-server-cert \ + <<<'SELECT 1' &> /dev/null; then + break + fi + sleep 1 + done + if [ "$i" = 0 ]; then + mysql_error "Unable to start server." + fi +} + +# Stop the server. When using a local socket file mariadb-admin will block until +# the shutdown is complete. +docker_temp_server_stop() { + kill "$MARIADB_PID" + wait "$MARIADB_PID" +} + +# Verify that the minimally required password settings are set for new databases. +docker_verify_minimum_env() { + # Restoring from backup requires no environment variables + declare -g DATABASE_INIT_FROM_BACKUP + for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do + if [ -f "${file}" ]; then + DATABASE_INIT_FROM_BACKUP='true' + return + fi + done + if [ -z "$MARIADB_ROOT_PASSWORD" ] && [ -z "$MARIADB_ROOT_PASSWORD_HASH" ] && [ -z "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] && [ -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then + mysql_error $'Database is uninitialized and password option is not specified\n\tYou need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ROOT_PASSWORD_HASH, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' + fi + # More preemptive exclusions of combinations should have been made before *PASSWORD_HASH was added, but for now we don't enforce due to compatibility. + if [ -n "$MARIADB_ROOT_PASSWORD" ] || [ -n "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] || [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ] && [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then + mysql_error "Cannot specify MARIADB_ROOT_PASSWORD_HASH and another MARIADB_ROOT_PASSWORD* option." + fi + if [ -n "$MARIADB_PASSWORD" ] && [ -n "$MARIADB_PASSWORD_HASH" ]; then + mysql_error "Cannot specify MARIADB_PASSWORD_HASH and MARIADB_PASSWORD option." + fi + if [ -n "$MARIADB_REPLICATION_USER" ]; then + if [ -z "$MARIADB_MASTER_HOST" ]; then + # its a master, we're creating a user + if [ -z "$MARIADB_REPLICATION_PASSWORD" ] && [ -z "$MARIADB_REPLICATION_PASSWORD_HASH" ]; then + mysql_error "MARIADB_REPLICATION_PASSWORD or MARIADB_REPLICATION_PASSWORD_HASH not found to create replication user for master" + fi + else + # its a replica + if [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; then + mysql_error "MARIADB_REPLICATION_PASSWORD is mandatory to specify the replication on the replica image." + fi + if [ -n "$MARIADB_REPLICATION_PASSWORD_HASH" ] ; then + mysql_warn "MARIADB_REPLICATION_PASSWORD_HASH cannot be specified on a replica" + fi + fi + fi + if [ -n "$MARIADB_MASTER_HOST" ] && { [ -z "$MARIADB_REPLICATION_USER" ] || [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; }; then + mysql_error "For a replica, MARIADB_REPLICATION_USER and MARIADB_REPLICATION is mandatory." + fi +} + +# creates folders for the database +# also ensures permission for user mysql of run as root +docker_create_db_directories() { + local user; user="$(id -u)" + + # TODO other directories that are used by default? like /var/lib/mysql-files + # see https://github.com/docker-library/mysql/issues/562 + mkdir -p "$DATADIR" + + if [ "$user" = "0" ]; then + # this will cause less disk access than `chown -R` + find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) + # See https://github.com/MariaDB/mariadb-docker/issues/363 + if [ "${SOCKET:0:1}" != '@' ]; then # not abstract sockets + find "${SOCKET%/*}" -maxdepth 0 \! -user mysql \( -exec chown mysql: '{}' \; -o -true \) + fi + + # memory.pressure + local cgroup; cgroup=$( "$DATADIR"/.my-healthcheck.cnf + $maskPreserve +} + +# Initializes database with timezone info and root password, plus optional extra db/user +docker_setup_db() { + # Load timezone info into database + if [ -z "$MARIADB_INITDB_SKIP_TZINFO" ]; then + # --skip-write-binlog usefully disables binary logging + # but also outputs LOCK TABLES to improve the IO of + # Aria (MDEV-23326) for 10.4+. + mariadb-tzinfo-to-sql --skip-write-binlog /usr/share/zoneinfo \ + | docker_process_sql --dont-use-mysql-root-password --database=mysql + # tell docker_process_sql to not use MYSQL_ROOT_PASSWORD since it is not set yet + fi + # Generate random root password + if [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then + MARIADB_ROOT_PASSWORD="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" + export MARIADB_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=$MARIADB_ROOT_PASSWORD + mysql_note "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD" + fi + + # Creates root users for non-localhost hosts + local rootCreate= + local rootPasswordEscaped= + if [ -n "$MARIADB_ROOT_PASSWORD" ]; then + # Sets root password and creates root users for non-localhost hosts + rootPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}") + fi + + # default root to listen for connections from anywhere + if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then + # ref "read -d ''", no, we don't care if read finds a terminating character in this heredoc + # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 + if [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then + read -r -d '' rootCreate <<-EOSQL || true + CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY PASSWORD '${MARIADB_ROOT_PASSWORD_HASH}' ; + GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; + GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; + EOSQL + else + read -r -d '' rootCreate <<-EOSQL || true + CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ; + GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; + GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; + EOSQL + fi + fi + + local mysqlAtLocalhost= + local mysqlAtLocalhostGrants= + # Install mysql@localhost user + if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ]; then + read -r -d '' mysqlAtLocalhost <<-EOSQL || true + CREATE USER mysql@localhost IDENTIFIED VIA unix_socket; + EOSQL + if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + if [ "$MARIADB_MYSQL_LOCALHOST_GRANTS" != USAGE ]; then + mysql_warn "Excessive privileges ON *.* TO mysql@localhost facilitates risks to the confidentiality, integrity and availability of data stored" + fi + mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; + fi + fi + + local createHealthCheckUsers + createHealthCheckUsers=$(create_healthcheck_users) + + local rootLocalhostPass= + if [ -z "$MARIADB_ROOT_PASSWORD_HASH" ]; then + # handle MARIADB_ROOT_PASSWORD_HASH for root@localhost after /docker-entrypoint-initdb.d + rootLocalhostPass="SET PASSWORD FOR 'root'@'localhost'= PASSWORD('${rootPasswordEscaped}');" + fi + + local createDatabase= + # Creates a custom database and user if specified + if [ -n "$MARIADB_DATABASE" ]; then + mysql_note "Creating database ${MARIADB_DATABASE}" + createDatabase="CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\`;" + fi + + local createUser= + local userGrants= + if [ -n "$MARIADB_PASSWORD" ] || [ -n "$MARIADB_PASSWORD_HASH" ] && [ -n "$MARIADB_USER" ]; then + mysql_note "Creating user ${MARIADB_USER}" + if [ -n "$MARIADB_PASSWORD_HASH" ]; then + createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY PASSWORD '$MARIADB_PASSWORD_HASH';" + else + # SQL escape the user password, \ followed by ' + local userPasswordEscaped + userPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_PASSWORD}") + createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$userPasswordEscaped';" + fi + + if [ -n "$MARIADB_DATABASE" ]; then + mysql_note "Giving user ${MARIADB_USER} access to schema ${MARIADB_DATABASE}" + userGrants="GRANT ALL ON \`${MARIADB_DATABASE//_/\\_}\`.* TO '$MARIADB_USER'@'%';" + fi + fi + + # To create replica user + local createReplicaUser= + local changeMasterTo= + if [ -n "$MARIADB_REPLICATION_USER" ] ; then + if [ -z "$MARIADB_MASTER_HOST" ]; then + # on master + mysql_note "Creating user ${MARIADB_REPLICATION_USER}" + createReplicaUser=$(create_replica_user) + else + # on replica + local rplPasswordEscaped + rplPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_REPLICATION_PASSWORD}") + # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. + # shellcheck disable=SC2153 + changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" + fi + fi + + mysql_note "Securing system users (equivalent to running mysql_secure_installation)" + # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set + # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. + docker_process_sql --dont-use-mysql-root-password --database=mysql --binary-mode <<-EOSQL + -- Securing system users shouldn't be replicated + SET @orig_sql_log_bin= @@SESSION.SQL_LOG_BIN; + SET @@SESSION.SQL_LOG_BIN=0; + -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set + SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); + + DROP USER IF EXISTS root@'127.0.0.1', root@'::1'; + EXECUTE IMMEDIATE CONCAT('DROP USER IF EXISTS root@\'', @@hostname,'\''); + + ${rootLocalhostPass} + ${rootCreate} + ${mysqlAtLocalhost} + ${mysqlAtLocalhostGrants} + ${createHealthCheckUsers} + -- end of securing system users, rest of init now... + SET @@SESSION.SQL_LOG_BIN=@orig_sql_log_bin; + -- create users/databases + ${createDatabase} + ${createUser} + ${createReplicaUser} + ${userGrants} + + ${changeMasterTo} + EOSQL +} + +# create a new installation +docker_mariadb_init() +{ + + # check dir permissions to reduce likelihood of half-initialized database + ls /docker-entrypoint-initdb.d/ > /dev/null + + if [ -n "$DATABASE_INIT_FROM_BACKUP" ]; then + shopt -s dotglob + for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do + mkdir -p "$DATADIR"/.init + tar --auto-compress --extract --file "$file" --directory="$DATADIR"/.init + mariadb-backup --target-dir="$DATADIR"/.init --datadir="$DATADIR"/.restore --move-back + + mv "$DATADIR"/.restore/** "$DATADIR"/ + if [ -f "$DATADIR/.init/backup-my.cnf" ]; then + mv "$DATADIR/.init/backup-my.cnf" "$DATADIR/.my.cnf" + mysql_note "Adding startup configuration:" + my_print_defaults --defaults-file="$DATADIR/.my.cnf" --mariadbd + fi + rm -rf "$DATADIR"/.init "$DATADIR"/.restore + if [ "$(id -u)" = "0" ]; then + # this will cause less disk access than `chown -R` + find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) + fi + done + if _check_if_upgrade_is_needed; then + docker_mariadb_upgrade "$@" + fi + return + fi + docker_init_database_dir "$@" + + mysql_note "Starting temporary server" + docker_temp_server_start "$@" + mysql_note "Temporary server started." + + docker_setup_db + docker_process_init_files /docker-entrypoint-initdb.d/* + # Wait until after /docker-entrypoint-initdb.d is performed before setting + # root@localhost password to a hash we don't know the password for. + if [ -n "${MARIADB_ROOT_PASSWORD_HASH}" ]; then + mysql_note "Setting root@localhost password hash" + docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL + SET @@SESSION.SQL_LOG_BIN=0; + SET PASSWORD FOR 'root'@'localhost'= '${MARIADB_ROOT_PASSWORD_HASH}'; + EOSQL + fi + + mysql_note "Stopping temporary server" + docker_temp_server_stop + mysql_note "Temporary server stopped" + + echo + mysql_note "MariaDB init process done. Ready for start up." + echo +} + +# backup the mysql database +docker_mariadb_backup_system() +{ + if [ -n "$MARIADB_DISABLE_UPGRADE_BACKUP" ] \ + && [ "$MARIADB_DISABLE_UPGRADE_BACKUP" = 1 ]; then + mysql_note "MariaDB upgrade backup disabled due to \$MARIADB_DISABLE_UPGRADE_BACKUP=1 setting" + return + fi + local backup_db="system_mysql_backup_unknown_version.sql.zst" + local oldfullversion="unknown_version" + if [ -r "$DATADIR"/mariadb_upgrade_info ]; then + read -r -d '' oldfullversion < "$DATADIR"/mariadb_upgrade_info || true + if [ -n "$oldfullversion" ]; then + backup_db="system_mysql_backup_${oldfullversion}.sql.zst" + fi + fi + + mysql_note "Backing up system database to $backup_db" + if ! mariadb-dump --skip-lock-tables --replace --databases mysql --socket="${SOCKET}" | zstd > "${DATADIR}/${backup_db}"; then + mysql_error "Unable backup system database for upgrade from $oldfullversion." + fi + mysql_note "Backing up complete" +} + +# perform mariadb-upgrade +# backup the mysql database if this is a major upgrade +docker_mariadb_upgrade() { + if [ -z "$MARIADB_AUTO_UPGRADE" ] \ + || [ "$MARIADB_AUTO_UPGRADE" = 0 ]; then + mysql_note "MariaDB upgrade (mariadb-upgrade or creating healthcheck users) required, but skipped due to \$MARIADB_AUTO_UPGRADE setting" + return + fi + mysql_note "Starting temporary server" + docker_temp_server_start "$@" --skip-grant-tables \ + --loose-innodb_buffer_pool_dump_at_shutdown=0 + mysql_note "Temporary server started." + + docker_mariadb_backup_system + + if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then + mysql_note "Creating healthcheck users" + local createHealthCheckUsers + createHealthCheckUsers=$(create_healthcheck_users) + docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL + -- Healthcheck users shouldn't be replicated + SET @@SESSION.SQL_LOG_BIN=0; + -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set + SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); + FLUSH PRIVILEGES; + $createHealthCheckUsers +EOSQL + mysql_note "Stopping temporary server" + docker_temp_server_stop + mysql_note "Temporary server stopped" + + if _check_if_upgrade_is_needed; then + # need a restart as FLUSH PRIVILEGES isn't reversable + mysql_note "Restarting temporary server for upgrade" + docker_temp_server_start "$@" --skip-grant-tables \ + --loose-innodb_buffer_pool_dump_at_shutdown=0 + else + return 0 + fi + fi + + mysql_note "Starting mariadb-upgrade" + mariadb-upgrade --upgrade-system-tables + mysql_note "Finished mariadb-upgrade" + + mysql_note "Stopping temporary server" + docker_temp_server_stop + mysql_note "Temporary server stopped" +} + + +_check_if_upgrade_is_needed() { + if [ ! -f "$DATADIR"/mariadb_upgrade_info ]; then + mysql_note "MariaDB upgrade information missing, assuming required" + return 0 + fi + local mariadbVersion + mariadbVersion="$(_mariadb_version)" + IFS='.-' read -ra newversion <<<"$mariadbVersion" + IFS='.-' read -ra oldversion < "$DATADIR"/mariadb_upgrade_info || true + + if [[ ${#newversion[@]} -lt 2 ]] || [[ ${#oldversion[@]} -lt 2 ]] \ + || [[ ${oldversion[0]} -lt ${newversion[0]} ]] \ + || [[ ${oldversion[0]} -eq ${newversion[0]} && ${oldversion[1]} -lt ${newversion[1]} ]]; then + return 0 + fi + if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then + mysql_note "MariaDB heathcheck configation file missing, assuming desirable" + return 0 + fi + mysql_note "MariaDB upgrade not required" + return 1 +} + +# check arguments for an option that would cause mariadbd to stop +# return true if there is one +_mysql_want_help() { + local arg + for arg; do + case "$arg" in + -'?'|--help|--print-defaults|-V|--version) + return 0 + ;; + esac + done + return 1 +} + +_main() { + # if command starts with an option, prepend mariadbd + if [ "${1:0:1}" = '-' ]; then + set -- mariadbd "$@" + fi + + #ENDOFSUBSTITUTIONS + # skip setup if they aren't running mysqld or want an option that stops mysqld + if [ "$1" = 'mariadbd' ] || [ "$1" = 'mysqld' ] && ! _mysql_want_help "$@"; then + mysql_note "Entrypoint script for MariaDB Server ${MARIADB_VERSION} started." + + mysql_check_config "$@" + # Load various environment variables + docker_setup_env "$@" + docker_create_db_directories + + # If container is started as root user, restart as dedicated mysql user + if [ "$(id -u)" = "0" ]; then + mysql_note "Switching to dedicated user 'mysql'" + exec gosu mysql "${BASH_SOURCE[0]}" "$@" + fi + + # there's no database, so it needs to be initialized + if [ -z "$DATABASE_ALREADY_EXISTS" ]; then + docker_verify_minimum_env + + docker_mariadb_init "$@" + # MDEV-27636 mariadb_upgrade --check-if-upgrade-is-needed cannot be run offline + #elif mariadb-upgrade --check-if-upgrade-is-needed; then + elif _check_if_upgrade_is_needed; then + docker_mariadb_upgrade "$@" + fi + fi + exec "$@" +} + +# If we are sourced from elsewhere, don't perform any further actions +if ! _is_sourced; then + _main "$@" +fi diff --git a/11.7-ubi/docker.cnf b/11.7-ubi/docker.cnf new file mode 100644 index 0000000..41dad70 --- /dev/null +++ b/11.7-ubi/docker.cnf @@ -0,0 +1,14 @@ +# Ubuntu container compatibility + +[mariadb] +host-cache-size=0 +skip-name-resolve + +expire_logs_days=10 + + +[client-server] +socket=/run/mariadb/mariadb.sock + +!includedir /etc/mysql/mariadb.conf.d +!includedir /etc/mysql/conf.d diff --git a/11.7-ubi/healthcheck.sh b/11.7-ubi/healthcheck.sh new file mode 100755 index 0000000..62be345 --- /dev/null +++ b/11.7-ubi/healthcheck.sh @@ -0,0 +1,395 @@ +#!/bin/bash +# +# Healthcheck script for MariaDB +# +# Runs various tests on the MariaDB server to check its health. Pass the tests +# to run as arguments. If all tests succeed, the server is considered healthy, +# otherwise it's not. +# +# Arguments are processed in strict order. Set replication_* options before +# the --replication option. This allows a different set of replication checks +# on different connections. +# +# --su{=|-mysql} is option to run the healthcheck as a different unix user. +# Useful if mysql@localhost user exists with unix socket authentication +# Using this option disregards previous options set, so should usually be the +# first option. +# +# Some tests require SQL privileges. +# +# TEST MINIMUM GRANTS REQUIRED +# connect none* +# innodb_initialized USAGE +# innodb_buffer_pool_loaded USAGE +# galera_online USAGE +# galera_ready USAGE +# replication REPLICATION_CLIENT (<10.5)or REPLICA MONITOR (10.5+) +# mariadbupgrade none, however unix user permissions on datadir +# +# The SQL user used is the default for the mariadb client. This can be the unix user +# if no user(or password) is set in the [mariadb-client] section of a configuration +# file. --defaults-{file,extra-file,group-suffix} can specify a file/configuration +# different from elsewhere. +# +# Note * though denied error message will result in error log without +# any permissions. USAGE recommend to avoid this. + +set -eo pipefail + +_process_sql() +{ + mariadb ${nodefaults:+--no-defaults} \ + ${def['file']:+--defaults-file=${def['file']}} \ + ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ + ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ + --skip-ssl --skip-ssl-verify-server-cert \ + --protocol socket \ + -B "$@" +} + +# TESTS + + +# CONNECT +# +# Tests that a connection can be made over TCP, the final state +# of the entrypoint and is listening. The authentication used +# isn't tested. +connect() +{ + local s + # short cut mechanism, to work with --require-secure-transport + s=$(_process_sql --skip-column-names -e 'select @@skip_networking') + case "$s" in + 0|1) + connect_s=$s + return "$s"; + ;; + esac + # falling back to tcp if there wasn't a connection answer. + s=$(mariadb ${nodefaults:+--no-defaults} \ + ${def['file']:+--defaults-file=${def['file']}} \ + ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ + ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ + --skip-ssl --skip-ssl-verify-server-cert \ + -h localhost --protocol tcp \ + --skip-column-names --batch --skip-print-query-on-error \ + -e 'select @@skip_networking' 2>&1) + + case "$s" in + 1) # skip-networking=1 (no network) + ;& + ERROR\ 2002\ \(HY000\):*) + # cannot connect + connect_s=1 + ;; + 0) # skip-networking=0 + ;& + ERROR\ 1820\ \(HY000\)*) # password expire + ;& + ERROR\ 4151\ \(HY000\):*) # account locked + ;& + ERROR\ 1226\ \(42000\)*) # resource limit exceeded + ;& + ERROR\ 1[0-9][0-9][0-9]\ \(28000\):*) + # grep access denied and other 28000 client errors - we did connect + connect_s=0 + ;; + *) + >&2 echo "Unknown error $s" + connect_s=1 + ;; + esac + return $connect_s +} + +# INNODB_INITIALIZED +# +# This tests that the crash recovery of InnoDB has completed +# along with all the other things required to make it to a healthy +# operational state. Note this may return true in the early +# states of initialization. Use with a connect test to avoid +# these false positives. +innodb_initialized() +{ + local s + s=$(_process_sql --skip-column-names -e "select 1 from information_schema.ENGINES WHERE engine='innodb' AND support in ('YES', 'DEFAULT', 'ENABLED')") + [ "$s" == 1 ] +} + +# INNODB_BUFFER_POOL_LOADED +# +# Tests the load of the innodb buffer pool as been complete +# implies innodb_buffer_pool_load_at_startup=1 (default), or if +# manually SET innodb_buffer_pool_load_now=1 +innodb_buffer_pool_loaded() +{ + local s + s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='Innodb_buffer_pool_load_status'") + if [[ $s =~ 'load completed' ]]; then + return 0 + fi + return 1 +} + +# GALERA_ONLINE +# +# Tests that the galera node is in the SYNCed state +galera_online() +{ + local s + s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_LOCAL_STATE'") + # 4 from https://galeracluster.com/library/documentation/node-states.html#node-state-changes + # not https://xkcd.com/221/ + if [[ $s -eq 4 ]]; then + return 0 + fi + return 1 +} + +# GALERA_READY +# +# Tests that the Galera provider is ready. +galera_ready() +{ + local s + s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_READY'") + if [ "$s" = "ON" ]; then + return 0 + fi + return 1 +} + +# REPLICATION +# +# Tests the replication has the required set of functions: +# --replication_all -> Checks all replication sources +# --replication_name=n -> sets the multisource connection name tested +# --replication_io -> IO thread is running +# --replication_sql -> SQL thread is running +# --replication_seconds_behind_master=n -> less than or equal this seconds of delay +# --replication_sql_remaining_delay=n -> less than or equal this seconds of remaining delay +# (ref: https://mariadb.com/kb/en/delayed-replication/) +replication() +{ + # SHOW REPLICA available 10.5+ + # https://github.com/koalaman/shellcheck/issues/2383 + # shellcheck disable=SC2016,SC2026 + _process_sql -e "SHOW ${repl['all']:+all} REPLICA${repl['all']:+S} ${repl['name']:+'${repl['name']}'} STATUS\G" | \ + { + # required for trim of leading space. + shopt -s extglob + # Row header + read -t 5 -r + # read timeout + [ $? -gt 128 ] && return 1 + while IFS=":" read -t 1 -r n v; do + # Trim leading space + n=${n##+([[:space:]])} + # Leading space on all values by the \G format needs to be trimmed. + v=${v:1} + case "$n" in + Slave_IO_Running) + if [ -n "${repl['io']}" ] && [ "$v" = 'No' ]; then + return 1 + fi + ;; + Slave_SQL_Running) + if [ -n "${repl['sql']}" ] && [ "$v" = 'No' ]; then + return 1 + fi + ;; + Seconds_Behind_Master) + # A NULL value is the IO thread not running: + if [ -n "${repl['seconds_behind_master']}" ] && + { [ "$v" = NULL ] || + (( "${repl['seconds_behind_master']}" < "$v" )); }; then + return 1 + fi + ;; + SQL_Remaining_Delay) + # Unlike Seconds_Behind_Master, sql_remaining_delay will hit NULL + # once replication is caught up - https://mariadb.com/kb/en/delayed-replication/ + if [ -n "${repl['sql_remaining_delay']}" ] && + [ "$v" != NULL ] && + (( "${repl['sql_remaining_delay']}" < "$v" )); then + return 1 + fi + ;; + esac + done + # read timeout + [ $? -gt 128 ] && return 1 + return 0 + } + # reachable in command not found(?) + # shellcheck disable=SC2317 + return $? +} + +# mariadbupgrade +# +# Test the lock on the file $datadir/mariadb_upgrade_info +# https://jira.mariadb.org/browse/MDEV-27068 +mariadbupgrade() +{ + local f="$datadir/mariadb_upgrade_info" + if [ -r "$f" ]; then + flock --exclusive --nonblock -n 9 9<"$f" + return $? + fi + return 0 +} + + +# MAIN + +if [ $# -eq 0 ]; then + echo "At least one argument required" >&2 + exit 1 +fi + +#ENDOFSUBSTITUTIONS +# Marks the end of mysql -> mariadb name changes in 10.6+ +# Global variables used by tests +declare -A repl +declare -A def +nodefaults= +connect_s= +datadir=/var/lib/mysql +if [ -f $datadir/.my-healthcheck.cnf ]; then + def['extra_file']=$datadir/.my-healthcheck.cnf +fi + +_repl_param_check() +{ + case "$1" in + seconds_behind_master) ;& + sql_remaining_delay) + if [ -z "${repl['io']}" ]; then + repl['io']=1 + echo "Forcing --replication_io=1, $1 requires IO thread to be running" >&2 + fi + ;; + all) + if [ -n "${repl['name']}" ]; then + unset 'repl[name]' + echo "Option --replication_all incompatible with specified source --replication_name, clearing replication_name" >&2 + fi + ;; + name) + if [ -n "${repl['all']}" ]; then + unset 'repl[all]' + echo "Option --replication_name incompatible with --replication_all, clearing replication_all" >&2 + fi + ;; + esac +} + +_test_exists() { + declare -F "$1" > /dev/null + return $? +} + +while [ $# -gt 0 ]; do + case "$1" in + --su=*) + u="${1#*=}" + shift + exec gosu "${u}" "${BASH_SOURCE[0]}" "$@" + ;; + --su) + shift + u=$1 + shift + exec gosu "$u" "${BASH_SOURCE[0]}" "$@" + ;; + --su-mysql) + shift + exec gosu mysql "${BASH_SOURCE[0]}" "$@" + ;; + --replication_*=*) + # Change the n to what is between _ and = and make lower case + n=${1#*_} + n=${n%%=*} + n=${n,,*} + # v is after the = + v=${1#*=} + repl[$n]=$v + _repl_param_check "$n" + ;; + --replication_*) + # Without =, look for a non --option next as the value, + # otherwise treat it as an "enable", just equate to 1. + # Clearing option is possible with "--replication_X=" + n=${1#*_} + n=${n,,*} + if [ "${2:0:2}" == '--' ]; then + repl[$n]=1 + else + repl[$n]=$2 + shift + fi + _repl_param_check "$n" + ;; + --datadir=*) + datadir=${1#*=} + ;; + --datadir) + shift + datadir=${1} + ;; + --no-defaults) + def=() + nodefaults=1 + ;; + --defaults-file=*|--defaults-extra-file=*|--defaults-group-suffix=*) + n=${1:11} # length --defaults- + n=${n%%=*} + n=${n//-/_} + # v is after the = + v=${1#*=} + def[$n]=$v + nodefaults= + ;; + --defaults-file|--defaults-extra-file|--defaults-group-suffix) + n=${1:11} # length --defaults- + n=${n//-/_} + if [ "${2:0:2}" == '--' ]; then + def[$n]="" + else + def[$n]=$2 + shift + fi + nodefaults= + ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; + --*) + test=${1#--} + ;; + *) + echo "Unknown healthcheck option $1" >&2 + exit 1 + esac + if [ -n "$test" ]; then + if ! _test_exists "$test" ; then + echo "healthcheck unknown option or test '$test'" >&2 + exit 1 + elif ! "$test"; then + echo "healthcheck $test failed" >&2 + exit 1 + fi + test= + fi + shift +done +if [ "$connect_s" != "0" ]; then + # we didn't pass a connnect test, so the current success status is suspicious + # return what connect thinks. + connect + exit $? +fi diff --git a/11.7/Dockerfile b/11.7/Dockerfile new file mode 100644 index 0000000..246b977 --- /dev/null +++ b/11.7/Dockerfile @@ -0,0 +1,142 @@ +# vim:set ft=dockerfile: +FROM ubuntu:noble + +# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added +RUN groupadd -r mysql && useradd -r -g mysql mysql --home-dir /var/lib/mysql && userdel --remove ubuntu + +# add gosu for easy step-down from root +# https://github.com/tianon/gosu/releases +# gosu key is B42F6819007F00F88E364FD4036A9C25BF357DD4 +ENV GOSU_VERSION 1.17 + +ARG GPG_KEYS=177F4010FE56CA3336300305F1656F24C74CD1D8 +# pub rsa4096 2016-03-30 [SC] +# 177F 4010 FE56 CA33 3630 0305 F165 6F24 C74C D1D8 +# uid [ unknown] MariaDB Signing Key +# sub rsa4096 2016-03-30 [E] +# install "libjemalloc2" as it offers better performance in some cases. Use with LD_PRELOAD +# install "pwgen" for randomizing passwords +# install "tzdata" for /usr/share/zoneinfo/ +# install "xz-utils" for .sql.xz docker-entrypoint-initdb.d files +# install "zstd" for .sql.zst docker-entrypoint-initdb.d files +# hadolint ignore=SC2086 +RUN set -eux; \ + apt-get update; \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + ca-certificates \ + gpg \ + gpgv \ + libjemalloc2 \ + pwgen \ + tzdata \ + xz-utils \ + zstd ; \ + savedAptMark="$(apt-mark showmanual)"; \ + apt-get install -y --no-install-recommends \ + dirmngr \ + gpg-agent \ + wget; \ + rm -rf /var/lib/apt/lists/*; \ + dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ + wget -q -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ + wget -q -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ + GNUPGHOME="$(mktemp -d)"; \ + export GNUPGHOME; \ + gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ + for key in $GPG_KEYS; do \ + gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key"; \ + done; \ + gpg --batch --export "$GPG_KEYS" > /etc/apt/trusted.gpg.d/mariadb.gpg; \ + if command -v gpgconf >/dev/null; then \ + gpgconf --kill all; \ + fi; \ + gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ + gpgconf --kill all; \ + rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ + apt-mark auto '.*' > /dev/null; \ + [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark >/dev/null; \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ + chmod +x /usr/local/bin/gosu; \ + gosu --version; \ + gosu nobody true + +RUN mkdir /docker-entrypoint-initdb.d + +# Ensure the container exec commands handle range of utf8 characters based of +# default locales in base image (https://github.com/docker-library/docs/blob/135b79cc8093ab02e55debb61fdb079ab2dbce87/ubuntu/README.md#locales) +ENV LANG C.UTF-8 + +# OCI annotations to image +LABEL org.opencontainers.image.authors="MariaDB Community" \ + org.opencontainers.image.title="MariaDB Database" \ + org.opencontainers.image.description="MariaDB Database for relational SQL" \ + org.opencontainers.image.documentation="https://hub.docker.com/_/mariadb/" \ + org.opencontainers.image.base.name="docker.io/library/ubuntu:noble" \ + org.opencontainers.image.licenses="GPL-2.0" \ + org.opencontainers.image.source="https://github.com/MariaDB/mariadb-docker" \ + org.opencontainers.image.vendor="MariaDB Community" \ + org.opencontainers.image.version="11.7.1" \ + org.opencontainers.image.url="https://github.com/MariaDB/mariadb-docker" + +# bashbrew-architectures: amd64 arm64v8 ppc64le s390x +ARG MARIADB_VERSION=1:11.7.1+maria~ubu2404 +ENV MARIADB_VERSION $MARIADB_VERSION +# release-status:RC +# release-support-type:Short Term Support +# (https://downloads.mariadb.org/rest-api/mariadb/) + +# Allowing overriding of REPOSITORY, a URL that includes suite and component for testing and Enterprise Versions +ARG REPOSITORY="http://archive.mariadb.org/mariadb-11.7.1/repo/ubuntu/ noble main main/debug" + +RUN set -e;\ + echo "deb ${REPOSITORY}" > /etc/apt/sources.list.d/mariadb.list; \ + { \ + echo 'Package: *'; \ + echo 'Pin: release o=MariaDB'; \ + echo 'Pin-Priority: 999'; \ + } > /etc/apt/preferences.d/mariadb +# add repository pinning to make sure dependencies from this MariaDB repo are preferred over Debian dependencies +# libmariadbclient18 : Depends: libmysqlclient18 (= 5.5.42+maria-1~wheezy) but 5.5.43-0+deb7u1 is to be installed + +# the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) +# also, we set debconf keys to make APT a little quieter +# hadolint ignore=DL3015 +RUN set -ex; \ + { \ + echo "mariadb-server" mysql-server/root_password password 'unused'; \ + echo "mariadb-server" mysql-server/root_password_again password 'unused'; \ + } | debconf-set-selections; \ + apt-get update; \ +# postinst script creates a datadir, so avoid creating it by faking its existance. + mkdir -p /var/lib/mysql/mysql ; touch /var/lib/mysql/mysql/user.frm ; \ +# mariadb-backup is installed at the same time so that `mysql-common` is only installed once from just mariadb repos + apt-get install -y --no-install-recommends mariadb-server="$MARIADB_VERSION" mariadb-backup socat \ + ; \ + rm -rf /var/lib/apt/lists/*; \ +# purge and re-create /var/lib/mysql with appropriate ownership + rm -rf /var/lib/mysql; \ + mkdir -p /var/lib/mysql /run/mysqld; \ + chown -R mysql:mysql /var/lib/mysql /run/mysqld; \ +# ensure that /run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime + chmod 1777 /run/mysqld; \ +# comment out a few problematic configuration values + find /etc/mysql/ -name '*.cnf' -print0 \ + | xargs -0 grep -lZE '^(bind-address|log|user\s)' \ + | xargs -rt -0 sed -Ei 's/^(bind-address|log|user\s)/#&/'; \ +# don't reverse lookup hostnames, they are usually another container + printf "[mariadb]\nhost-cache-size=0\nskip-name-resolve\n" > /etc/mysql/mariadb.conf.d/05-skipcache.cnf; \ +# Issue #327 Correct order of reading directories /etc/mysql/mariadb.conf.d before /etc/mysql/conf.d (mount-point per documentation) + if [ -L /etc/mysql/my.cnf ]; then \ +# 10.5+ + sed -i -e '/includedir/ {N;s/\(.*\)\n\(.*\)/\n\2\n\1/}' /etc/mysql/mariadb.cnf; \ + fi + + +VOLUME /var/lib/mysql + +COPY healthcheck.sh /usr/local/bin/healthcheck.sh +COPY docker-entrypoint.sh /usr/local/bin/ +ENTRYPOINT ["docker-entrypoint.sh"] + +EXPOSE 3306 +CMD ["mariadbd"] diff --git a/11.7/docker-entrypoint.sh b/11.7/docker-entrypoint.sh new file mode 100755 index 0000000..92d280c --- /dev/null +++ b/11.7/docker-entrypoint.sh @@ -0,0 +1,718 @@ +#!/bin/bash +set -eo pipefail +shopt -s nullglob + +# logging functions +mysql_log() { + local type="$1"; shift + printf '%s [%s] [Entrypoint]: %s\n' "$(date --rfc-3339=seconds)" "$type" "$*" +} +mysql_note() { + mysql_log Note "$@" +} +mysql_warn() { + mysql_log Warn "$@" >&2 +} +mysql_error() { + mysql_log ERROR "$@" >&2 + exit 1 +} + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + mysql_error "Both $var and $fileVar are set (but are exclusive)" + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +# set MARIADB_xyz from MYSQL_xyz when MARIADB_xyz is unset +# and make them the same value (so user scripts can use either) +_mariadb_file_env() { + local var="$1"; shift + local maria="MARIADB_${var#MYSQL_}" + file_env "$var" "$@" + file_env "$maria" "${!var}" + if [ "${!maria:-}" ]; then + export "$var"="${!maria}" + fi +} + +# check to see if this file is being run or sourced from another script +_is_sourced() { + # https://unix.stackexchange.com/a/215279 + [ "${#FUNCNAME[@]}" -ge 2 ] \ + && [ "${FUNCNAME[0]}" = '_is_sourced' ] \ + && [ "${FUNCNAME[1]}" = 'source' ] +} + +# usage: docker_process_init_files [file [file [...]]] +# ie: docker_process_init_files /always-initdb.d/* +# process initializer files, based on file extensions +docker_process_init_files() { + # mysql here for backwards compatibility "${mysql[@]}" + # ShellCheck: mysql appears unused. Verify use (or export if used externally) + # shellcheck disable=SC2034 + mysql=( docker_process_sql ) + + echo + local f + for f; do + case "$f" in + *.sh) + # https://github.com/docker-library/postgres/issues/450#issuecomment-393167936 + # https://github.com/docker-library/postgres/pull/452 + if [ -x "$f" ]; then + mysql_note "$0: running $f" + "$f" + else + mysql_note "$0: sourcing $f" + # ShellCheck can't follow non-constant source. Use a directive to specify location. + # shellcheck disable=SC1090 + . "$f" + fi + ;; + *.sql) mysql_note "$0: running $f"; docker_process_sql < "$f"; echo ;; + *.sql.gz) mysql_note "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;; + *.sql.xz) mysql_note "$0: running $f"; xzcat "$f" | docker_process_sql; echo ;; + *.sql.zst) mysql_note "$0: running $f"; zstd -dc "$f" | docker_process_sql; echo ;; + *) mysql_warn "$0: ignoring $f" ;; + esac + echo + done +} + +# arguments necessary to run "mariadbd --verbose --help" successfully (used for testing configuration validity and for extracting default/configured values) +_verboseHelpArgs=( + --verbose --help +) + +mysql_check_config() { + local toRun=( "$@" "${_verboseHelpArgs[@]}" ) errors + if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then + mysql_error $'mariadbd failed while attempting to check config\n\tcommand was: '"${toRun[*]}"$'\n\t'"$errors" + fi +} + +# Fetch value from server config +# We use mariadbd --verbose --help instead of my_print_defaults because the +# latter only show values present in config files, and not server defaults +mysql_get_config() { + local conf="$1"; shift + "$@" "${_verboseHelpArgs[@]}" 2>/dev/null \ + | awk -v conf="$conf" '$1 == conf && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }' + # match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)" +} + +# Do a temporary startup of the MariaDB server, for init purposes +docker_temp_server_start() { + "$@" --skip-networking --default-time-zone=SYSTEM --socket="${SOCKET}" --wsrep_on=OFF \ + --expire-logs-days=0 \ + --skip-slave-start \ + --loose-innodb_buffer_pool_load_at_startup=0 \ + --skip-ssl --ssl-cert='' --ssl-key='' --ssl-ca='' \ + & + declare -g MARIADB_PID + MARIADB_PID=$! + mysql_note "Waiting for server startup" + # only use the root password if the database has already been initialized + # so that it won't try to fill in a password file when it hasn't been set yet + extraArgs=() + if [ -z "$DATABASE_ALREADY_EXISTS" ]; then + extraArgs+=( '--dont-use-mysql-root-password' ) + fi + local i + for i in {30..0}; do + if docker_process_sql "${extraArgs[@]}" --database=mysql \ + --skip-ssl --skip-ssl-verify-server-cert \ + <<<'SELECT 1' &> /dev/null; then + break + fi + sleep 1 + done + if [ "$i" = 0 ]; then + mysql_error "Unable to start server." + fi +} + +# Stop the server. When using a local socket file mariadb-admin will block until +# the shutdown is complete. +docker_temp_server_stop() { + kill "$MARIADB_PID" + wait "$MARIADB_PID" +} + +# Verify that the minimally required password settings are set for new databases. +docker_verify_minimum_env() { + # Restoring from backup requires no environment variables + declare -g DATABASE_INIT_FROM_BACKUP + for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do + if [ -f "${file}" ]; then + DATABASE_INIT_FROM_BACKUP='true' + return + fi + done + if [ -z "$MARIADB_ROOT_PASSWORD" ] && [ -z "$MARIADB_ROOT_PASSWORD_HASH" ] && [ -z "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] && [ -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then + mysql_error $'Database is uninitialized and password option is not specified\n\tYou need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ROOT_PASSWORD_HASH, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD' + fi + # More preemptive exclusions of combinations should have been made before *PASSWORD_HASH was added, but for now we don't enforce due to compatibility. + if [ -n "$MARIADB_ROOT_PASSWORD" ] || [ -n "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" ] || [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ] && [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then + mysql_error "Cannot specify MARIADB_ROOT_PASSWORD_HASH and another MARIADB_ROOT_PASSWORD* option." + fi + if [ -n "$MARIADB_PASSWORD" ] && [ -n "$MARIADB_PASSWORD_HASH" ]; then + mysql_error "Cannot specify MARIADB_PASSWORD_HASH and MARIADB_PASSWORD option." + fi + if [ -n "$MARIADB_REPLICATION_USER" ]; then + if [ -z "$MARIADB_MASTER_HOST" ]; then + # its a master, we're creating a user + if [ -z "$MARIADB_REPLICATION_PASSWORD" ] && [ -z "$MARIADB_REPLICATION_PASSWORD_HASH" ]; then + mysql_error "MARIADB_REPLICATION_PASSWORD or MARIADB_REPLICATION_PASSWORD_HASH not found to create replication user for master" + fi + else + # its a replica + if [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; then + mysql_error "MARIADB_REPLICATION_PASSWORD is mandatory to specify the replication on the replica image." + fi + if [ -n "$MARIADB_REPLICATION_PASSWORD_HASH" ] ; then + mysql_warn "MARIADB_REPLICATION_PASSWORD_HASH cannot be specified on a replica" + fi + fi + fi + if [ -n "$MARIADB_MASTER_HOST" ] && { [ -z "$MARIADB_REPLICATION_USER" ] || [ -z "$MARIADB_REPLICATION_PASSWORD" ] ; }; then + mysql_error "For a replica, MARIADB_REPLICATION_USER and MARIADB_REPLICATION is mandatory." + fi +} + +# creates folders for the database +# also ensures permission for user mysql of run as root +docker_create_db_directories() { + local user; user="$(id -u)" + + # TODO other directories that are used by default? like /var/lib/mysql-files + # see https://github.com/docker-library/mysql/issues/562 + mkdir -p "$DATADIR" + + if [ "$user" = "0" ]; then + # this will cause less disk access than `chown -R` + find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) + # See https://github.com/MariaDB/mariadb-docker/issues/363 + if [ "${SOCKET:0:1}" != '@' ]; then # not abstract sockets + find "${SOCKET%/*}" -maxdepth 0 \! -user mysql \( -exec chown mysql: '{}' \; -o -true \) + fi + + # memory.pressure + local cgroup; cgroup=$( "$DATADIR"/.my-healthcheck.cnf + $maskPreserve +} + +# Initializes database with timezone info and root password, plus optional extra db/user +docker_setup_db() { + # Load timezone info into database + if [ -z "$MARIADB_INITDB_SKIP_TZINFO" ]; then + # --skip-write-binlog usefully disables binary logging + # but also outputs LOCK TABLES to improve the IO of + # Aria (MDEV-23326) for 10.4+. + mariadb-tzinfo-to-sql --skip-write-binlog /usr/share/zoneinfo \ + | docker_process_sql --dont-use-mysql-root-password --database=mysql + # tell docker_process_sql to not use MYSQL_ROOT_PASSWORD since it is not set yet + fi + # Generate random root password + if [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then + MARIADB_ROOT_PASSWORD="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" + export MARIADB_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=$MARIADB_ROOT_PASSWORD + mysql_note "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD" + fi + + # Creates root users for non-localhost hosts + local rootCreate= + local rootPasswordEscaped= + if [ -n "$MARIADB_ROOT_PASSWORD" ]; then + # Sets root password and creates root users for non-localhost hosts + rootPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}") + fi + + # default root to listen for connections from anywhere + if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then + # ref "read -d ''", no, we don't care if read finds a terminating character in this heredoc + # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151 + if [ -n "$MARIADB_ROOT_PASSWORD_HASH" ]; then + read -r -d '' rootCreate <<-EOSQL || true + CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY PASSWORD '${MARIADB_ROOT_PASSWORD_HASH}' ; + GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; + GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; + EOSQL + else + read -r -d '' rootCreate <<-EOSQL || true + CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ; + GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ; + GRANT PROXY ON ''@'%' TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION; + EOSQL + fi + fi + + local mysqlAtLocalhost= + local mysqlAtLocalhostGrants= + # Install mysql@localhost user + if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ]; then + read -r -d '' mysqlAtLocalhost <<-EOSQL || true + CREATE USER mysql@localhost IDENTIFIED VIA unix_socket; + EOSQL + if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + if [ "$MARIADB_MYSQL_LOCALHOST_GRANTS" != USAGE ]; then + mysql_warn "Excessive privileges ON *.* TO mysql@localhost facilitates risks to the confidentiality, integrity and availability of data stored" + fi + mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; + fi + fi + + local createHealthCheckUsers + createHealthCheckUsers=$(create_healthcheck_users) + + local rootLocalhostPass= + if [ -z "$MARIADB_ROOT_PASSWORD_HASH" ]; then + # handle MARIADB_ROOT_PASSWORD_HASH for root@localhost after /docker-entrypoint-initdb.d + rootLocalhostPass="SET PASSWORD FOR 'root'@'localhost'= PASSWORD('${rootPasswordEscaped}');" + fi + + local createDatabase= + # Creates a custom database and user if specified + if [ -n "$MARIADB_DATABASE" ]; then + mysql_note "Creating database ${MARIADB_DATABASE}" + createDatabase="CREATE DATABASE IF NOT EXISTS \`$MARIADB_DATABASE\`;" + fi + + local createUser= + local userGrants= + if [ -n "$MARIADB_PASSWORD" ] || [ -n "$MARIADB_PASSWORD_HASH" ] && [ -n "$MARIADB_USER" ]; then + mysql_note "Creating user ${MARIADB_USER}" + if [ -n "$MARIADB_PASSWORD_HASH" ]; then + createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY PASSWORD '$MARIADB_PASSWORD_HASH';" + else + # SQL escape the user password, \ followed by ' + local userPasswordEscaped + userPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_PASSWORD}") + createUser="CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$userPasswordEscaped';" + fi + + if [ -n "$MARIADB_DATABASE" ]; then + mysql_note "Giving user ${MARIADB_USER} access to schema ${MARIADB_DATABASE}" + userGrants="GRANT ALL ON \`${MARIADB_DATABASE//_/\\_}\`.* TO '$MARIADB_USER'@'%';" + fi + fi + + # To create replica user + local createReplicaUser= + local changeMasterTo= + if [ -n "$MARIADB_REPLICATION_USER" ] ; then + if [ -z "$MARIADB_MASTER_HOST" ]; then + # on master + mysql_note "Creating user ${MARIADB_REPLICATION_USER}" + createReplicaUser=$(create_replica_user) + else + # on replica + local rplPasswordEscaped + rplPasswordEscaped=$(docker_sql_escape_string_literal "${MARIADB_REPLICATION_PASSWORD}") + # SC cannot follow how MARIADB_MASTER_PORT is assigned a default value. + # shellcheck disable=SC2153 + changeMasterTo="CHANGE MASTER TO MASTER_HOST='$MARIADB_MASTER_HOST', MASTER_USER='$MARIADB_REPLICATION_USER', MASTER_PASSWORD='$rplPasswordEscaped', MASTER_PORT=$MARIADB_MASTER_PORT, MASTER_CONNECT_RETRY=10;" + fi + fi + + mysql_note "Securing system users (equivalent to running mysql_secure_installation)" + # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set + # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. + docker_process_sql --dont-use-mysql-root-password --database=mysql --binary-mode <<-EOSQL + -- Securing system users shouldn't be replicated + SET @orig_sql_log_bin= @@SESSION.SQL_LOG_BIN; + SET @@SESSION.SQL_LOG_BIN=0; + -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set + SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); + + DROP USER IF EXISTS root@'127.0.0.1', root@'::1'; + EXECUTE IMMEDIATE CONCAT('DROP USER IF EXISTS root@\'', @@hostname,'\''); + + ${rootLocalhostPass} + ${rootCreate} + ${mysqlAtLocalhost} + ${mysqlAtLocalhostGrants} + ${createHealthCheckUsers} + -- end of securing system users, rest of init now... + SET @@SESSION.SQL_LOG_BIN=@orig_sql_log_bin; + -- create users/databases + ${createDatabase} + ${createUser} + ${createReplicaUser} + ${userGrants} + + ${changeMasterTo} + EOSQL +} + +# create a new installation +docker_mariadb_init() +{ + + # check dir permissions to reduce likelihood of half-initialized database + ls /docker-entrypoint-initdb.d/ > /dev/null + + if [ -n "$DATABASE_INIT_FROM_BACKUP" ]; then + shopt -s dotglob + for file in /docker-entrypoint-initdb.d/*.tar{.gz,.xz,.zst}; do + mkdir -p "$DATADIR"/.init + tar --auto-compress --extract --file "$file" --directory="$DATADIR"/.init + mariadb-backup --target-dir="$DATADIR"/.init --datadir="$DATADIR"/.restore --move-back + + mv "$DATADIR"/.restore/** "$DATADIR"/ + if [ -f "$DATADIR/.init/backup-my.cnf" ]; then + mv "$DATADIR/.init/backup-my.cnf" "$DATADIR/.my.cnf" + mysql_note "Adding startup configuration:" + my_print_defaults --defaults-file="$DATADIR/.my.cnf" --mariadbd + fi + rm -rf "$DATADIR"/.init "$DATADIR"/.restore + if [ "$(id -u)" = "0" ]; then + # this will cause less disk access than `chown -R` + find "$DATADIR" \! -user mysql \( -exec chown mysql: '{}' + -o -true \) + fi + done + if _check_if_upgrade_is_needed; then + docker_mariadb_upgrade "$@" + fi + return + fi + docker_init_database_dir "$@" + + mysql_note "Starting temporary server" + docker_temp_server_start "$@" + mysql_note "Temporary server started." + + docker_setup_db + docker_process_init_files /docker-entrypoint-initdb.d/* + # Wait until after /docker-entrypoint-initdb.d is performed before setting + # root@localhost password to a hash we don't know the password for. + if [ -n "${MARIADB_ROOT_PASSWORD_HASH}" ]; then + mysql_note "Setting root@localhost password hash" + docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL + SET @@SESSION.SQL_LOG_BIN=0; + SET PASSWORD FOR 'root'@'localhost'= '${MARIADB_ROOT_PASSWORD_HASH}'; + EOSQL + fi + + mysql_note "Stopping temporary server" + docker_temp_server_stop + mysql_note "Temporary server stopped" + + echo + mysql_note "MariaDB init process done. Ready for start up." + echo +} + +# backup the mysql database +docker_mariadb_backup_system() +{ + if [ -n "$MARIADB_DISABLE_UPGRADE_BACKUP" ] \ + && [ "$MARIADB_DISABLE_UPGRADE_BACKUP" = 1 ]; then + mysql_note "MariaDB upgrade backup disabled due to \$MARIADB_DISABLE_UPGRADE_BACKUP=1 setting" + return + fi + local backup_db="system_mysql_backup_unknown_version.sql.zst" + local oldfullversion="unknown_version" + if [ -r "$DATADIR"/mariadb_upgrade_info ]; then + read -r -d '' oldfullversion < "$DATADIR"/mariadb_upgrade_info || true + if [ -n "$oldfullversion" ]; then + backup_db="system_mysql_backup_${oldfullversion}.sql.zst" + fi + fi + + mysql_note "Backing up system database to $backup_db" + if ! mariadb-dump --skip-lock-tables --replace --databases mysql --socket="${SOCKET}" | zstd > "${DATADIR}/${backup_db}"; then + mysql_error "Unable backup system database for upgrade from $oldfullversion." + fi + mysql_note "Backing up complete" +} + +# perform mariadb-upgrade +# backup the mysql database if this is a major upgrade +docker_mariadb_upgrade() { + if [ -z "$MARIADB_AUTO_UPGRADE" ] \ + || [ "$MARIADB_AUTO_UPGRADE" = 0 ]; then + mysql_note "MariaDB upgrade (mariadb-upgrade or creating healthcheck users) required, but skipped due to \$MARIADB_AUTO_UPGRADE setting" + return + fi + mysql_note "Starting temporary server" + docker_temp_server_start "$@" --skip-grant-tables \ + --loose-innodb_buffer_pool_dump_at_shutdown=0 + mysql_note "Temporary server started." + + docker_mariadb_backup_system + + if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then + mysql_note "Creating healthcheck users" + local createHealthCheckUsers + createHealthCheckUsers=$(create_healthcheck_users) + docker_process_sql --dont-use-mysql-root-password --binary-mode <<-EOSQL + -- Healthcheck users shouldn't be replicated + SET @@SESSION.SQL_LOG_BIN=0; + -- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set + SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', ''); + FLUSH PRIVILEGES; + $createHealthCheckUsers +EOSQL + mysql_note "Stopping temporary server" + docker_temp_server_stop + mysql_note "Temporary server stopped" + + if _check_if_upgrade_is_needed; then + # need a restart as FLUSH PRIVILEGES isn't reversable + mysql_note "Restarting temporary server for upgrade" + docker_temp_server_start "$@" --skip-grant-tables \ + --loose-innodb_buffer_pool_dump_at_shutdown=0 + else + return 0 + fi + fi + + mysql_note "Starting mariadb-upgrade" + mariadb-upgrade --upgrade-system-tables + mysql_note "Finished mariadb-upgrade" + + mysql_note "Stopping temporary server" + docker_temp_server_stop + mysql_note "Temporary server stopped" +} + + +_check_if_upgrade_is_needed() { + if [ ! -f "$DATADIR"/mariadb_upgrade_info ]; then + mysql_note "MariaDB upgrade information missing, assuming required" + return 0 + fi + local mariadbVersion + mariadbVersion="$(_mariadb_version)" + IFS='.-' read -ra newversion <<<"$mariadbVersion" + IFS='.-' read -ra oldversion < "$DATADIR"/mariadb_upgrade_info || true + + if [[ ${#newversion[@]} -lt 2 ]] || [[ ${#oldversion[@]} -lt 2 ]] \ + || [[ ${oldversion[0]} -lt ${newversion[0]} ]] \ + || [[ ${oldversion[0]} -eq ${newversion[0]} && ${oldversion[1]} -lt ${newversion[1]} ]]; then + return 0 + fi + if [ ! -f "$DATADIR"/.my-healthcheck.cnf ]; then + mysql_note "MariaDB heathcheck configation file missing, assuming desirable" + return 0 + fi + mysql_note "MariaDB upgrade not required" + return 1 +} + +# check arguments for an option that would cause mariadbd to stop +# return true if there is one +_mysql_want_help() { + local arg + for arg; do + case "$arg" in + -'?'|--help|--print-defaults|-V|--version) + return 0 + ;; + esac + done + return 1 +} + +_main() { + # if command starts with an option, prepend mariadbd + if [ "${1:0:1}" = '-' ]; then + set -- mariadbd "$@" + fi + + #ENDOFSUBSTITUTIONS + # skip setup if they aren't running mysqld or want an option that stops mysqld + if [ "$1" = 'mariadbd' ] || [ "$1" = 'mysqld' ] && ! _mysql_want_help "$@"; then + mysql_note "Entrypoint script for MariaDB Server ${MARIADB_VERSION} started." + + mysql_check_config "$@" + # Load various environment variables + docker_setup_env "$@" + docker_create_db_directories + + # If container is started as root user, restart as dedicated mysql user + if [ "$(id -u)" = "0" ]; then + mysql_note "Switching to dedicated user 'mysql'" + exec gosu mysql "${BASH_SOURCE[0]}" "$@" + fi + + # there's no database, so it needs to be initialized + if [ -z "$DATABASE_ALREADY_EXISTS" ]; then + docker_verify_minimum_env + + docker_mariadb_init "$@" + # MDEV-27636 mariadb_upgrade --check-if-upgrade-is-needed cannot be run offline + #elif mariadb-upgrade --check-if-upgrade-is-needed; then + elif _check_if_upgrade_is_needed; then + docker_mariadb_upgrade "$@" + fi + fi + exec "$@" +} + +# If we are sourced from elsewhere, don't perform any further actions +if ! _is_sourced; then + _main "$@" +fi diff --git a/11.7/healthcheck.sh b/11.7/healthcheck.sh new file mode 100755 index 0000000..62be345 --- /dev/null +++ b/11.7/healthcheck.sh @@ -0,0 +1,395 @@ +#!/bin/bash +# +# Healthcheck script for MariaDB +# +# Runs various tests on the MariaDB server to check its health. Pass the tests +# to run as arguments. If all tests succeed, the server is considered healthy, +# otherwise it's not. +# +# Arguments are processed in strict order. Set replication_* options before +# the --replication option. This allows a different set of replication checks +# on different connections. +# +# --su{=|-mysql} is option to run the healthcheck as a different unix user. +# Useful if mysql@localhost user exists with unix socket authentication +# Using this option disregards previous options set, so should usually be the +# first option. +# +# Some tests require SQL privileges. +# +# TEST MINIMUM GRANTS REQUIRED +# connect none* +# innodb_initialized USAGE +# innodb_buffer_pool_loaded USAGE +# galera_online USAGE +# galera_ready USAGE +# replication REPLICATION_CLIENT (<10.5)or REPLICA MONITOR (10.5+) +# mariadbupgrade none, however unix user permissions on datadir +# +# The SQL user used is the default for the mariadb client. This can be the unix user +# if no user(or password) is set in the [mariadb-client] section of a configuration +# file. --defaults-{file,extra-file,group-suffix} can specify a file/configuration +# different from elsewhere. +# +# Note * though denied error message will result in error log without +# any permissions. USAGE recommend to avoid this. + +set -eo pipefail + +_process_sql() +{ + mariadb ${nodefaults:+--no-defaults} \ + ${def['file']:+--defaults-file=${def['file']}} \ + ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ + ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ + --skip-ssl --skip-ssl-verify-server-cert \ + --protocol socket \ + -B "$@" +} + +# TESTS + + +# CONNECT +# +# Tests that a connection can be made over TCP, the final state +# of the entrypoint and is listening. The authentication used +# isn't tested. +connect() +{ + local s + # short cut mechanism, to work with --require-secure-transport + s=$(_process_sql --skip-column-names -e 'select @@skip_networking') + case "$s" in + 0|1) + connect_s=$s + return "$s"; + ;; + esac + # falling back to tcp if there wasn't a connection answer. + s=$(mariadb ${nodefaults:+--no-defaults} \ + ${def['file']:+--defaults-file=${def['file']}} \ + ${def['extra_file']:+--defaults-extra-file=${def['extra_file']}} \ + ${def['group_suffix']:+--defaults-group-suffix=${def['group_suffix']}} \ + --skip-ssl --skip-ssl-verify-server-cert \ + -h localhost --protocol tcp \ + --skip-column-names --batch --skip-print-query-on-error \ + -e 'select @@skip_networking' 2>&1) + + case "$s" in + 1) # skip-networking=1 (no network) + ;& + ERROR\ 2002\ \(HY000\):*) + # cannot connect + connect_s=1 + ;; + 0) # skip-networking=0 + ;& + ERROR\ 1820\ \(HY000\)*) # password expire + ;& + ERROR\ 4151\ \(HY000\):*) # account locked + ;& + ERROR\ 1226\ \(42000\)*) # resource limit exceeded + ;& + ERROR\ 1[0-9][0-9][0-9]\ \(28000\):*) + # grep access denied and other 28000 client errors - we did connect + connect_s=0 + ;; + *) + >&2 echo "Unknown error $s" + connect_s=1 + ;; + esac + return $connect_s +} + +# INNODB_INITIALIZED +# +# This tests that the crash recovery of InnoDB has completed +# along with all the other things required to make it to a healthy +# operational state. Note this may return true in the early +# states of initialization. Use with a connect test to avoid +# these false positives. +innodb_initialized() +{ + local s + s=$(_process_sql --skip-column-names -e "select 1 from information_schema.ENGINES WHERE engine='innodb' AND support in ('YES', 'DEFAULT', 'ENABLED')") + [ "$s" == 1 ] +} + +# INNODB_BUFFER_POOL_LOADED +# +# Tests the load of the innodb buffer pool as been complete +# implies innodb_buffer_pool_load_at_startup=1 (default), or if +# manually SET innodb_buffer_pool_load_now=1 +innodb_buffer_pool_loaded() +{ + local s + s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='Innodb_buffer_pool_load_status'") + if [[ $s =~ 'load completed' ]]; then + return 0 + fi + return 1 +} + +# GALERA_ONLINE +# +# Tests that the galera node is in the SYNCed state +galera_online() +{ + local s + s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_LOCAL_STATE'") + # 4 from https://galeracluster.com/library/documentation/node-states.html#node-state-changes + # not https://xkcd.com/221/ + if [[ $s -eq 4 ]]; then + return 0 + fi + return 1 +} + +# GALERA_READY +# +# Tests that the Galera provider is ready. +galera_ready() +{ + local s + s=$(_process_sql --skip-column-names -e "select VARIABLE_VALUE from information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='WSREP_READY'") + if [ "$s" = "ON" ]; then + return 0 + fi + return 1 +} + +# REPLICATION +# +# Tests the replication has the required set of functions: +# --replication_all -> Checks all replication sources +# --replication_name=n -> sets the multisource connection name tested +# --replication_io -> IO thread is running +# --replication_sql -> SQL thread is running +# --replication_seconds_behind_master=n -> less than or equal this seconds of delay +# --replication_sql_remaining_delay=n -> less than or equal this seconds of remaining delay +# (ref: https://mariadb.com/kb/en/delayed-replication/) +replication() +{ + # SHOW REPLICA available 10.5+ + # https://github.com/koalaman/shellcheck/issues/2383 + # shellcheck disable=SC2016,SC2026 + _process_sql -e "SHOW ${repl['all']:+all} REPLICA${repl['all']:+S} ${repl['name']:+'${repl['name']}'} STATUS\G" | \ + { + # required for trim of leading space. + shopt -s extglob + # Row header + read -t 5 -r + # read timeout + [ $? -gt 128 ] && return 1 + while IFS=":" read -t 1 -r n v; do + # Trim leading space + n=${n##+([[:space:]])} + # Leading space on all values by the \G format needs to be trimmed. + v=${v:1} + case "$n" in + Slave_IO_Running) + if [ -n "${repl['io']}" ] && [ "$v" = 'No' ]; then + return 1 + fi + ;; + Slave_SQL_Running) + if [ -n "${repl['sql']}" ] && [ "$v" = 'No' ]; then + return 1 + fi + ;; + Seconds_Behind_Master) + # A NULL value is the IO thread not running: + if [ -n "${repl['seconds_behind_master']}" ] && + { [ "$v" = NULL ] || + (( "${repl['seconds_behind_master']}" < "$v" )); }; then + return 1 + fi + ;; + SQL_Remaining_Delay) + # Unlike Seconds_Behind_Master, sql_remaining_delay will hit NULL + # once replication is caught up - https://mariadb.com/kb/en/delayed-replication/ + if [ -n "${repl['sql_remaining_delay']}" ] && + [ "$v" != NULL ] && + (( "${repl['sql_remaining_delay']}" < "$v" )); then + return 1 + fi + ;; + esac + done + # read timeout + [ $? -gt 128 ] && return 1 + return 0 + } + # reachable in command not found(?) + # shellcheck disable=SC2317 + return $? +} + +# mariadbupgrade +# +# Test the lock on the file $datadir/mariadb_upgrade_info +# https://jira.mariadb.org/browse/MDEV-27068 +mariadbupgrade() +{ + local f="$datadir/mariadb_upgrade_info" + if [ -r "$f" ]; then + flock --exclusive --nonblock -n 9 9<"$f" + return $? + fi + return 0 +} + + +# MAIN + +if [ $# -eq 0 ]; then + echo "At least one argument required" >&2 + exit 1 +fi + +#ENDOFSUBSTITUTIONS +# Marks the end of mysql -> mariadb name changes in 10.6+ +# Global variables used by tests +declare -A repl +declare -A def +nodefaults= +connect_s= +datadir=/var/lib/mysql +if [ -f $datadir/.my-healthcheck.cnf ]; then + def['extra_file']=$datadir/.my-healthcheck.cnf +fi + +_repl_param_check() +{ + case "$1" in + seconds_behind_master) ;& + sql_remaining_delay) + if [ -z "${repl['io']}" ]; then + repl['io']=1 + echo "Forcing --replication_io=1, $1 requires IO thread to be running" >&2 + fi + ;; + all) + if [ -n "${repl['name']}" ]; then + unset 'repl[name]' + echo "Option --replication_all incompatible with specified source --replication_name, clearing replication_name" >&2 + fi + ;; + name) + if [ -n "${repl['all']}" ]; then + unset 'repl[all]' + echo "Option --replication_name incompatible with --replication_all, clearing replication_all" >&2 + fi + ;; + esac +} + +_test_exists() { + declare -F "$1" > /dev/null + return $? +} + +while [ $# -gt 0 ]; do + case "$1" in + --su=*) + u="${1#*=}" + shift + exec gosu "${u}" "${BASH_SOURCE[0]}" "$@" + ;; + --su) + shift + u=$1 + shift + exec gosu "$u" "${BASH_SOURCE[0]}" "$@" + ;; + --su-mysql) + shift + exec gosu mysql "${BASH_SOURCE[0]}" "$@" + ;; + --replication_*=*) + # Change the n to what is between _ and = and make lower case + n=${1#*_} + n=${n%%=*} + n=${n,,*} + # v is after the = + v=${1#*=} + repl[$n]=$v + _repl_param_check "$n" + ;; + --replication_*) + # Without =, look for a non --option next as the value, + # otherwise treat it as an "enable", just equate to 1. + # Clearing option is possible with "--replication_X=" + n=${1#*_} + n=${n,,*} + if [ "${2:0:2}" == '--' ]; then + repl[$n]=1 + else + repl[$n]=$2 + shift + fi + _repl_param_check "$n" + ;; + --datadir=*) + datadir=${1#*=} + ;; + --datadir) + shift + datadir=${1} + ;; + --no-defaults) + def=() + nodefaults=1 + ;; + --defaults-file=*|--defaults-extra-file=*|--defaults-group-suffix=*) + n=${1:11} # length --defaults- + n=${n%%=*} + n=${n//-/_} + # v is after the = + v=${1#*=} + def[$n]=$v + nodefaults= + ;; + --defaults-file|--defaults-extra-file|--defaults-group-suffix) + n=${1:11} # length --defaults- + n=${n//-/_} + if [ "${2:0:2}" == '--' ]; then + def[$n]="" + else + def[$n]=$2 + shift + fi + nodefaults= + ;; + --no-connect) + # used for /docker-entrypoint-initdb.d scripts + # where you definately don't want a connection test + connect_s=0 + ;; + --*) + test=${1#--} + ;; + *) + echo "Unknown healthcheck option $1" >&2 + exit 1 + esac + if [ -n "$test" ]; then + if ! _test_exists "$test" ; then + echo "healthcheck unknown option or test '$test'" >&2 + exit 1 + elif ! "$test"; then + echo "healthcheck $test failed" >&2 + exit 1 + fi + test= + fi + shift +done +if [ "$connect_s" != "0" ]; then + # we didn't pass a connnect test, so the current success status is suspicious + # return what connect thinks. + connect + exit $? +fi diff --git a/update.sh b/update.sh index 4ad2d50..54291fd 100755 --- a/update.sh +++ b/update.sh @@ -185,6 +185,11 @@ update_version_array() mariaversion() { + if [ "$version" = 11.7 ]; then + #version=11.7 + mariaVersion=11.7.1; + return + fi mariaVersion=$(curl -fsSL "$DOWNLOADS_REST_API/mariadb/${version%-*}" \ | jq -r 'first(.releases[] | .release_id | select(. | test("[0-9]+.[0-9]+.[0-9]+$")))') mariaVersion=${mariaVersion//\"} @@ -239,8 +244,21 @@ for version in "${versions[@]}"; do fi readarray -t release <<< "$(curl -fsSL "$DOWNLOADS_REST_API/mariadb/" \ | jq -r --arg version "${version%-*}" '.major_releases[] | select(.release_id == $version) | [ .release_status ] , [ .release_support_type ] | @tsv')" - releaseStatus=${release[0]:-Stable} - supportType=${release[1]:-Short Term Support} + + case "$version" in + 11.7) + releaseStatus=${release[0]:-RC} + supportType=${release[1]:-Short Term Support} + ;; + 11.6) + releaseStatus=${release[0]:-Stable} + supportType=${release[1]:-Short Term Support} + ;; + *) + releaseStatus=${release[0]:-Unknown} + supportType=${release[1]:-Unknown} + ;; + esac update_version done diff --git a/versions.json b/versions.json index a483702..855ffc1 100644 --- a/versions.json +++ b/versions.json @@ -138,6 +138,35 @@ "ppc64le", "s390x" ] + }, + "11.7": { + "milestone": "11.7", + "version": "11.7.1", + "fullVersion": "1:11.7.1+maria~ubu2404", + "releaseStatus": "RC", + "supportType": "Short Term Support", + "base": "ubuntu:noble", + "arches": [ + "amd64", + "arm64v8", + "ppc64le", + "s390x" + ] + }, + "11.7-ubi": { + "milestone": "11.7", + "version": "11.7.1", + "fullVersion": "11.7.1", + "releaseStatus": "RC", + "supportType": "Short Term Support", + "base": "ubi9", + "arches": [ + "amd64", + "arm64v8", + "ppc64le", + "s390x" + ] + }, "main": { "milestone": "main", "version": "11.8.0",