diff --git a/4.1.1/ubuntu/focal/Dockerfile b/4.1.1/ubuntu/focal/Dockerfile new file mode 100644 index 0000000..1619a23 --- /dev/null +++ b/4.1.1/ubuntu/focal/Dockerfile @@ -0,0 +1,183 @@ + +# +# Autogenerated files, do not edit. See README.md +# + + +FROM ubuntu:focal as base +LABEL org.opencontainers.image.authors="emanuel@ongres.com" + +ARG MAX_JOBS +ENV TAG=BABEL_4_1_1__PG_16_2 +ENV BABELFISH_VERSION=4.1.1 +ENV MAX_JOBS=${MAX_JOBS:-2} +ENV ANTLR_VERSION=4.9.3 + +ENV PREFIX=/usr/local/babelfishpg-${BABELFISH_VERSION} +ENV ANTLR_RUNTIME=/opt/antlr4 + +ENV PG_SRC=/opt/${TAG}/ +ENV PG_CONFIG=${PREFIX}/bin/pg_config +ENV ANTLR4_RUNTIME_INCLUDE_DIR=/usr/local/include/antlr4-runtime/ + +ENV ANTLR4_JAVA_BIN=/usr/bin/java + +RUN set -ex; \ + apt update + +RUN set -ex ; \ + DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \ + build-essential flex libxml2-dev libxml2-utils libc6-dev \ + libxslt-dev \ + libreadline-dev zlib1g-dev libldap2-dev libpam0g-dev gettext \ + uuid uuid-dev cmake lld apt-utils pkg-config libossp-uuid-dev gnulib bison git + +RUN set -ex ; \ + DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \ + xsltproc icu-devtools libicu66 libicu-dev gawk curl + +RUN set -ex ; \ + DEBIAN_FRONTEND=noninteractive \ + apt install -y openjdk-8-jre openssl \ + libssl-dev python-dev libpq-dev \ + pkgconf unzip libutfcpp-dev gnupg + +RUN sysArch=$(uname -m) + +# SQL Server Tooling dependencies +# Reference: https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-setup-tools?view=sql-server-ver15#ubuntu +# For non-amd64 mssql-tools isn't available, installing freetds in its place +RUN set -ex ; \ + case "$sysArch" in \ + x86_64 | amd64 | ppc64el) \ + curl -L https://packages.microsoft.com/keys/microsoft.asc | apt-key add - && \ + curl -L https://packages.microsoft.com/config/ubuntu/20.04/prod.list | tee /etc/apt/sources.list.d/msprod.list && \ + apt update && ACCEPT_EULA=Y apt install -y mssql-tools unixodbc-dev ; \ + PATH="${PREFIX}/bin:/opt/mssql-tools/bin/:${PATH}" ;; \ + * ) \ + DEBIAN_FRONTEND=noninteractive \ + apt install -y freetds-bin freetds-common ;; \ + esac ; + + + +RUN rm -rf /var/lib/apt/lists/*; \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; + + +RUN curl -L https://github.com/babelfish-for-postgresql/babelfish-for-postgresql/releases/download/${TAG}/${TAG}.zip \ + --output ${TAG}.zip && unzip -d /opt/ ${TAG}.zip + +# Compiling and installing antlr runtime +# ENV ANTLR_EXECUTABLE=/usr/local/lib/antlr-${ANTLR_VERSION}-complete.jar +ENV ANTLR_EXECUTABLE=${PG_SRC}/contrib/babelfishpg_tsql/antlr/thirdparty/antlr/antlr-${ANTLR_VERSION}-complete.jar + +# RUN curl https://www.antlr.org/download/antlr-${ANTLR_VERSION}-complete.jar \ +# --output ${ANTLR_EXECUTABLE} && chmod +x ${ANTLR_EXECUTABLE} + +RUN curl https://www.antlr.org/download/antlr4-cpp-runtime-${ANTLR_VERSION}-source.zip \ + --output /opt/antlr4-cpp-runtime-${ANTLR_VERSION}-source.zip && \ + unzip -d ${ANTLR_RUNTIME} /opt/antlr4-cpp-runtime-${ANTLR_VERSION}-source.zip + +WORKDIR ${ANTLR_RUNTIME} + +RUN mkdir build && cd build && \ + cmake .. -D ANTLR_JAR_LOCATION=${ANTLR_EXECUTABLE} \ + -DCMAKE_INSTALL_PREFIX=/usr/local -DWITH_DEMO=True && \ + make && make install + + +WORKDIR ${PG_SRC} + +RUN set -ex ; \ + case "$sysArch" in \ + x86_64 | amd64 | ppc64el) \ + CFLAGS_ARG='${CFLAGS:--Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic}' ; \ + CONFIGURE_FLAGS="" ;; \ + * ) \ + CFLAGS_ARG="-ggdb " CONFIGURE_FLAGS=' --build=arm-linux-gnueabihf ';; \ + esac ; \ + ./configure CFLAGS="${CFLAGS_ARG}" \ + --prefix=${PREFIX} \ + --enable-debug \ + --with-ldap \ + --with-libxml \ + --with-pam \ + --with-uuid=ossp \ + --enable-nls \ + --with-libxslt \ + --with-icu ${CONFIGURE_FLAGS} + + # --with-openssl + +# Engine Compilation +RUN make clean && make DESTDIR=${PREFIX}/tmp_install -j ${MAX_JOBS} world-bin && make install + +WORKDIR ${PG_SRC}/contrib +# Built-in contrib installation +RUN make +RUN make install + +## Regression Tests +# RUN make DESTDIR=${PREFIX}/tmp_install EXTRA_REGRESS_OPTS=--debug -j ${MAX_JOBS} check + +RUN cp /usr/local/lib/libantlr4-runtime.so.${ANTLR_VERSION} ${PREFIX}/lib + +ENV USE_PGXS=1 + +RUN ["/usr/bin/bash", "-c", "cd ${PG_SRC}/contrib/babelfishpg_tsql/antlr ; cmake . "] + +RUN PG_CONFIG=${PG_CONFIG} PG_SRC=${PG_SRC} cmake=$(which cmake) ANTLR4_RUNTIME_LIBRARIES=/usr/include/antlr4-runtime ; \ + for EXT in babelfishpg_common babelfishpg_money babelfishpg_tds babelfishpg_tsql ; \ + do \ + cd ${PG_SRC}/contrib/${EXT} ; \ + make clean && make && make install ; \ + done + +FROM base AS babelfishpg +COPY --from=base ${PREFIX}/ /usr/local/ /opt/mssql-tools/bin/ + +ENV DEBIAN_FRONTEND=noninteractive +ENV PATH="${PREFIX}/bin:${PATH}" +ENV PGDATA="/var/lib/postgresql/data" +ENV DOCKER_ENTRYPOINT="/usr/local/bin/entrypoint.sh" + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + libssl1.1 openssl libxml2 libreadline8 tzdata libldap-2.4-2 libpython2.7 libxslt1.1 libossp-uuid16 && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Create postgres user +RUN useradd postgres && usermod -a -G postgres postgres + +# Sample default ready for Babelfish to run +RUN set -eux; \ + sed -ri "s!^#?(listen_addresses)\s*=\s*\S+.*!\1 = '*'!" "${PREFIX}/share/postgresql/postgresql.conf.sample"; \ + sed -ri "s+#?shared_preload_libraries.*+shared_preload_libraries = 'babelfishpg_tds'+g" "${PREFIX}/share/postgresql/postgresql.conf.sample"; \ + sed -i -e "\$ababelfishpg_tds.listen_addresses = '*'" "${PREFIX}/share/postgresql/postgresql.conf.sample"; \ + grep -F "listen_addresses = '*'" "${PREFIX}/share/postgresql/postgresql.conf.sample"; \ + grep -F "shared_preload_libraries = 'babelfishpg_tds'" "${PREFIX}/share/postgresql/postgresql.conf.sample"; \ + grep -F "babelfishpg_tds.listen_addresses = '*'" "${PREFIX}/share/postgresql/postgresql.conf.sample"; + +RUN mkdir -p "$PGDATA" && chown -R postgres:postgres "$PGDATA" && chmod 777 "$PGDATA" + +COPY entrypoint.sh ${DOCKER_ENTRYPOINT} + +RUN chmod -R 0750 "${PREFIX}/share" && \ + chown postgres: ${DOCKER_ENTRYPOINT} && \ + chmod +x ${DOCKER_ENTRYPOINT} && \ + chown -R postgres: ${PREFIX} + +WORKDIR "${PREFIX}/bin/" + +USER postgres + +STOPSIGNAL SIGINT + +EXPOSE 1433 +EXPOSE 5432 + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] + +CMD ["postgres"] diff --git a/4.1.1/ubuntu/focal/docker-compose.yml b/4.1.1/ubuntu/focal/docker-compose.yml new file mode 100644 index 0000000..df8aee5 --- /dev/null +++ b/4.1.1/ubuntu/focal/docker-compose.yml @@ -0,0 +1,24 @@ + +services: + babelfishpg-4.1.1-ubuntu-focal: + container_name: babelfishpg-4.1.1-ubuntu.focal + image: babelfishpg:4.1.1-ubuntu.focal + ports: + # Port forwarding not supported by BabelfishPG + - 1433:1433 + - 5432:15432 + environment: + - POSTGRES_PASSWORD=password + - POSTGRES_DB=postgres + - POSTGRES_USER=postgres + - BABELFISH_USER=bbf + - BABELFISH_PASS=password + - BABELFISH_DB=bbf + - BABELFISH_MIGRATION_MODE=multi-db + - POSTGRES_HOST_AUTH_METHOD=trust + networks: + - babelfish + +networks: + babelfish: + diff --git a/4.1.1/ubuntu/focal/entrypoint.sh b/4.1.1/ubuntu/focal/entrypoint.sh new file mode 100644 index 0000000..d20597c --- /dev/null +++ b/4.1.1/ubuntu/focal/entrypoint.sh @@ -0,0 +1,380 @@ +#!/usr/bin/env bash +set -Eeo pipefail +# TODO swap to -Eeuo pipefail above (after handling all potentially-unset variables) + +# 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 + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +# 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' ] +} + +# used to create initial postgres directories and if run as root, ensure ownership to the "postgres" user +docker_create_db_directories() { + local user; user="$(id -u)" + + mkdir -p "$PGDATA" + # ignore failure since there are cases where we can't chmod (and PostgreSQL might fail later anyhow - it's picky about permissions of this directory) + chmod 700 "$PGDATA" || : + + # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289 + mkdir -p /var/run/postgresql || : + chmod 775 /var/run/postgresql || : + + # Create the transaction log directory before initdb is run so the directory is owned by the correct user + if [ -n "$POSTGRES_INITDB_WALDIR" ]; then + mkdir -p "$POSTGRES_INITDB_WALDIR" + if [ "$user" = '0' ]; then + find "$POSTGRES_INITDB_WALDIR" \! -user postgres -exec chown postgres '{}' + + fi + chmod 700 "$POSTGRES_INITDB_WALDIR" + fi + + # allow the container to be started with `--user` + if [ "$user" = '0' ]; then + find "$PGDATA" \! -user postgres -exec chown postgres '{}' + + find /var/run/postgresql \! -user postgres -exec chown postgres '{}' + + fi +} + +# initialize empty PGDATA directory with new database via 'initdb' +# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function +# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames +# this is also where the database user is created, specified by `POSTGRES_USER` env +docker_init_database_dir() { + # "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary + # see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html + local uid; uid="$(id -u)" + if ! getent passwd "$uid" &> /dev/null; then + # see if we can find a suitable "libnss_wrapper.so" (https://salsa.debian.org/sssd-team/nss-wrapper/-/commit/b9925a653a54e24d09d9b498a2d913729f7abb15) + local wrapper + for wrapper in {/usr,}/lib{/*,}/libnss_wrapper.so; do + if [ -s "$wrapper" ]; then + NSS_WRAPPER_PASSWD="$(mktemp)" + NSS_WRAPPER_GROUP="$(mktemp)" + export LD_PRELOAD="$wrapper" NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP + local gid; gid="$(id -g)" + echo "postgres:x:$uid:$gid:PostgreSQL:$PGDATA:/bin/false" > "$NSS_WRAPPER_PASSWD" + echo "postgres:x:$gid:" > "$NSS_WRAPPER_GROUP" + break + fi + done + fi + + if [ -n "$POSTGRES_INITDB_WALDIR" ]; then + set -- --waldir "$POSTGRES_INITDB_WALDIR" "$@" + fi + + # Babelfish supports UTF-8 only + eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") -E "UTF8" '"$POSTGRES_INITDB_ARGS"' "$@"' + + # unset/cleanup "nss_wrapper" bits + if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then + rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP" + unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP + fi +} + +# print large warning if POSTGRES_PASSWORD is long +# error if both POSTGRES_PASSWORD is empty and POSTGRES_HOST_AUTH_METHOD is not 'trust' +# print large warning if POSTGRES_HOST_AUTH_METHOD is set to 'trust' +# assumes database is not set up, ie: [ -z "$DATABASE_ALREADY_EXISTS" ] +docker_verify_minimum_env() { + # check password first so we can output the warning before postgres + # messes it up + if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then + cat >&2 <<-'EOWARN' + + WARNING: The supplied POSTGRES_PASSWORD is 100+ characters. + + This will not work if used via PGPASSWORD with "psql". + + https://www.postgresql.org/message-id/flat/E1Rqxp2-0004Qt-PL%40wrigleys.postgresql.org (BUG #6412) + https://github.com/docker-library/postgres/issues/507 + + EOWARN + fi + if [ -z "$POSTGRES_PASSWORD" ] && [ 'trust' != "$POSTGRES_HOST_AUTH_METHOD" ]; then + # The - option suppresses leading tabs but *not* spaces. :) + cat >&2 <<-'EOE' + Error: Database is uninitialized and superuser password is not specified. + You must specify POSTGRES_PASSWORD to a non-empty value for the + superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run". + + You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all + connections without a password. This is *not* recommended. + + See PostgreSQL documentation about "trust": + https://www.postgresql.org/docs/current/auth-trust.html + EOE + exit 1 + fi + if [ 'trust' = "$POSTGRES_HOST_AUTH_METHOD" ]; then + cat >&2 <<-'EOWARN' + ******************************************************************************** + WARNING: POSTGRES_HOST_AUTH_METHOD has been set to "trust". This will allow + anyone with access to the Postgres port to access your database without + a password, even if POSTGRES_PASSWORD is set. See PostgreSQL + documentation about "trust": + https://www.postgresql.org/docs/current/auth-trust.html + In Docker's default configuration, this is effectively any other + container on the same system. + + It is not recommended to use POSTGRES_HOST_AUTH_METHOD=trust. Replace + it with "-e POSTGRES_PASSWORD=password" instead to set a password in + "docker run". + ******************************************************************************** + EOWARN + fi +} + +# usage: docker_process_init_files [file [file [...]]] +# ie: docker_process_init_files /always-initdb.d/* +# process initializer files, based on file extensions and permissions +docker_process_init_files() { + # psql here for backwards compatibility "${psql[@]}" + psql=( 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 + echo "$0: running $f" + "$f" + else + echo "$0: sourcing $f" + . "$f" + fi + ;; + *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;; + *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;; + *.sql.xz) echo "$0: running $f"; xzcat "$f" | docker_process_sql; echo ;; + *) echo "$0: ignoring $f" ;; + esac + echo + done +} + +# Execute sql script, passed via stdin (or -f flag of pqsl) +# usage: docker_process_sql [psql-cli-args] +# ie: docker_process_sql --dbname=mydb <<<'INSERT ...' +# ie: docker_process_sql -f my-file.sql +# ie: docker_process_sql > $PGDATA/postgresql.conf + + docker_process_sql --dbname $POSTGRES_DB -c 'select pg_reload_conf();' +} + +# Loads various settings that are used elsewhere in the script +# This should be called before any other functions +docker_setup_env() { + file_env 'POSTGRES_PASSWORD' + + file_env 'POSTGRES_USER' 'postgres' + file_env 'POSTGRES_DB' "$POSTGRES_USER" + file_env 'BABELFISH_MIGRATION_MODE' 'single-db' + file_env 'BABELFISH_MIGRATION_MODE' "$BABELFISH_MIGRATION_MODE" + file_env 'POSTGRES_INITDB_ARGS' + : "${POSTGRES_HOST_AUTH_METHOD:=}" + + declare -g DATABASE_ALREADY_EXISTS + # look specifically for PG_VERSION, as it is expected in the DB dir + if [ -s "$PGDATA/PG_VERSION" ]; then + DATABASE_ALREADY_EXISTS='true' + fi +} + +# append POSTGRES_HOST_AUTH_METHOD to pg_hba.conf for "host" connections +# all arguments will be passed along as arguments to `postgres` for getting the value of 'password_encryption' +pg_setup_hba_conf() { + # default authentication method is md5 on versions before 14 + # https://www.postgresql.org/about/news/postgresql-14-released-2318/ + if [ "$1" = 'postgres' ]; then + shift + fi + local auth + # check the default/configured encryption and use that as the auth method + auth="$(postgres -C password_encryption "$@")" + # postgres 9 only reports "on" and not "md5" + if [ "$auth" = 'on' ]; then + auth='md5' + fi + : "${POSTGRES_HOST_AUTH_METHOD:=$auth}" + { + echo + if [ 'trust' = "$POSTGRES_HOST_AUTH_METHOD" ]; then + echo '# warning trust is enabled for all connections' + echo '# see https://www.postgresql.org/docs/12/auth-trust.html' + fi + echo "host all all all $POSTGRES_HOST_AUTH_METHOD" + } >> "$PGDATA/pg_hba.conf" +} + +# start socket-only postgresql server for setting up or running scripts +# all arguments will be passed along as arguments to `postgres` (via pg_ctl) +docker_temp_server_start() { + if [ "$1" = 'postgres' ]; then + shift + fi + + # internal start of server in order to allow setup using psql client + # does not listen on external TCP/IP and waits until start finishes + set -- "$@" -c listen_addresses='' -p "${PGPORT:-5432}" + + PGUSER="${PGUSER:-$POSTGRES_USER}" \ + pg_ctl -D "$PGDATA" \ + -o "$(printf '%q ' "$@")" \ + -w start +} + +# stop postgresql server after done setting up user and running scripts +docker_temp_server_stop() { + PGUSER="${PGUSER:-postgres}" \ + pg_ctl -D "$PGDATA" -m fast -w stop +} + +# check arguments for an option that would cause postgres to stop +# return true if there is one +_pg_want_help() { + local arg + for arg; do + case "$arg" in + # postgres --help | grep 'then exit' + # leaving out -C on purpose since it always fails and is unhelpful: + # postgres: could not access the server configuration file "/var/lib/postgresql/data/postgresql.conf": No such file or directory + -'?'|--help|--describe-config|-V|--version) + return 0 + ;; + esac + done + return 1 +} + +_main() { + # if first arg looks like a flag, assume we want to run postgres server + if [ "${1:0:1}" = '-' ]; then + set -- postgres "$@" + fi + + if [ "$1" = 'postgres' ] && ! _pg_want_help "$@"; then + docker_setup_env + # setup data directories and permissions (when run as root) + docker_create_db_directories + if [ "$(id -u)" = '0' ]; then + # then restart script as postgres user + exec gosu postgres "$BASH_SOURCE" "$@" + fi + + # only run initialization on an empty data directory + if [ -z "$DATABASE_ALREADY_EXISTS" ]; then + docker_verify_minimum_env + + # check dir permissions to reduce likelihood of half-initialized database + #ls /docker-entrypoint-initdb.d/ > /dev/null + + docker_init_database_dir + pg_setup_hba_conf "$@" + + # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless + # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS + export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}" + docker_temp_server_start "$@" + + docker_setup_db + + docker_setup_babelfish_db + + docker_process_init_files /docker-entrypoint-initdb.d/* + + docker_temp_server_stop + unset PGPASSWORD + + echo + echo 'PostgreSQL init process complete; ready for start up.' + echo + else + echo + echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization' + echo + fi + fi + + exec "$@" +} + +if ! _is_sourced; then + _main "$@" +fi \ No newline at end of file diff --git a/4.2.0/ubuntu/focal/Dockerfile b/4.2.0/ubuntu/focal/Dockerfile new file mode 100644 index 0000000..3c3b908 --- /dev/null +++ b/4.2.0/ubuntu/focal/Dockerfile @@ -0,0 +1,183 @@ + +# +# Autogenerated files, do not edit. See README.md +# + + +FROM ubuntu:focal as base +LABEL org.opencontainers.image.authors="emanuel@ongres.com" + +ARG MAX_JOBS +ENV TAG=BABEL_4_2_0__PG_16_3 +ENV BABELFISH_VERSION=4.2.0 +ENV MAX_JOBS=${MAX_JOBS:-2} +ENV ANTLR_VERSION=4.9.3 + +ENV PREFIX=/usr/local/babelfishpg-${BABELFISH_VERSION} +ENV ANTLR_RUNTIME=/opt/antlr4 + +ENV PG_SRC=/opt/${TAG}/ +ENV PG_CONFIG=${PREFIX}/bin/pg_config +ENV ANTLR4_RUNTIME_INCLUDE_DIR=/usr/local/include/antlr4-runtime/ + +ENV ANTLR4_JAVA_BIN=/usr/bin/java + +RUN set -ex; \ + apt update + +RUN set -ex ; \ + DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \ + build-essential flex libxml2-dev libxml2-utils libc6-dev \ + libxslt-dev \ + libreadline-dev zlib1g-dev libldap2-dev libpam0g-dev gettext \ + uuid uuid-dev cmake lld apt-utils pkg-config libossp-uuid-dev gnulib bison git + +RUN set -ex ; \ + DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \ + xsltproc icu-devtools libicu66 libicu-dev gawk curl + +RUN set -ex ; \ + DEBIAN_FRONTEND=noninteractive \ + apt install -y openjdk-8-jre openssl \ + libssl-dev python-dev libpq-dev \ + pkgconf unzip libutfcpp-dev gnupg + +RUN sysArch=$(uname -m) + +# SQL Server Tooling dependencies +# Reference: https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-setup-tools?view=sql-server-ver15#ubuntu +# For non-amd64 mssql-tools isn't available, installing freetds in its place +RUN set -ex ; \ + case "$sysArch" in \ + x86_64 | amd64 | ppc64el) \ + curl -L https://packages.microsoft.com/keys/microsoft.asc | apt-key add - && \ + curl -L https://packages.microsoft.com/config/ubuntu/20.04/prod.list | tee /etc/apt/sources.list.d/msprod.list && \ + apt update && ACCEPT_EULA=Y apt install -y mssql-tools unixodbc-dev ; \ + PATH="${PREFIX}/bin:/opt/mssql-tools/bin/:${PATH}" ;; \ + * ) \ + DEBIAN_FRONTEND=noninteractive \ + apt install -y freetds-bin freetds-common ;; \ + esac ; + + + +RUN rm -rf /var/lib/apt/lists/*; \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; + + +RUN curl -L https://github.com/babelfish-for-postgresql/babelfish-for-postgresql/releases/download/${TAG}/${TAG}.zip \ + --output ${TAG}.zip && unzip -d /opt/ ${TAG}.zip + +# Compiling and installing antlr runtime +# ENV ANTLR_EXECUTABLE=/usr/local/lib/antlr-${ANTLR_VERSION}-complete.jar +ENV ANTLR_EXECUTABLE=${PG_SRC}/contrib/babelfishpg_tsql/antlr/thirdparty/antlr/antlr-${ANTLR_VERSION}-complete.jar + +# RUN curl https://www.antlr.org/download/antlr-${ANTLR_VERSION}-complete.jar \ +# --output ${ANTLR_EXECUTABLE} && chmod +x ${ANTLR_EXECUTABLE} + +RUN curl https://www.antlr.org/download/antlr4-cpp-runtime-${ANTLR_VERSION}-source.zip \ + --output /opt/antlr4-cpp-runtime-${ANTLR_VERSION}-source.zip && \ + unzip -d ${ANTLR_RUNTIME} /opt/antlr4-cpp-runtime-${ANTLR_VERSION}-source.zip + +WORKDIR ${ANTLR_RUNTIME} + +RUN mkdir build && cd build && \ + cmake .. -D ANTLR_JAR_LOCATION=${ANTLR_EXECUTABLE} \ + -DCMAKE_INSTALL_PREFIX=/usr/local -DWITH_DEMO=True && \ + make && make install + + +WORKDIR ${PG_SRC} + +RUN set -ex ; \ + case "$sysArch" in \ + x86_64 | amd64 | ppc64el) \ + CFLAGS_ARG='${CFLAGS:--Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic}' ; \ + CONFIGURE_FLAGS="" ;; \ + * ) \ + CFLAGS_ARG="-ggdb " CONFIGURE_FLAGS=' --build=arm-linux-gnueabihf ';; \ + esac ; \ + ./configure CFLAGS="${CFLAGS_ARG}" \ + --prefix=${PREFIX} \ + --enable-debug \ + --with-ldap \ + --with-libxml \ + --with-pam \ + --with-uuid=ossp \ + --enable-nls \ + --with-libxslt \ + --with-icu ${CONFIGURE_FLAGS} + + # --with-openssl + +# Engine Compilation +RUN make clean && make DESTDIR=${PREFIX}/tmp_install -j ${MAX_JOBS} world-bin && make install + +WORKDIR ${PG_SRC}/contrib +# Built-in contrib installation +RUN make +RUN make install + +## Regression Tests +# RUN make DESTDIR=${PREFIX}/tmp_install EXTRA_REGRESS_OPTS=--debug -j ${MAX_JOBS} check + +RUN cp /usr/local/lib/libantlr4-runtime.so.${ANTLR_VERSION} ${PREFIX}/lib + +ENV USE_PGXS=1 + +RUN ["/usr/bin/bash", "-c", "cd ${PG_SRC}/contrib/babelfishpg_tsql/antlr ; cmake . "] + +RUN PG_CONFIG=${PG_CONFIG} PG_SRC=${PG_SRC} cmake=$(which cmake) ANTLR4_RUNTIME_LIBRARIES=/usr/include/antlr4-runtime ; \ + for EXT in babelfishpg_common babelfishpg_money babelfishpg_tds babelfishpg_tsql ; \ + do \ + cd ${PG_SRC}/contrib/${EXT} ; \ + make clean && make && make install ; \ + done + +FROM base AS babelfishpg +COPY --from=base ${PREFIX}/ /usr/local/ /opt/mssql-tools/bin/ + +ENV DEBIAN_FRONTEND=noninteractive +ENV PATH="${PREFIX}/bin:${PATH}" +ENV PGDATA="/var/lib/postgresql/data" +ENV DOCKER_ENTRYPOINT="/usr/local/bin/entrypoint.sh" + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + libssl1.1 openssl libxml2 libreadline8 tzdata libldap-2.4-2 libpython2.7 libxslt1.1 libossp-uuid16 && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Create postgres user +RUN useradd postgres && usermod -a -G postgres postgres + +# Sample default ready for Babelfish to run +RUN set -eux; \ + sed -ri "s!^#?(listen_addresses)\s*=\s*\S+.*!\1 = '*'!" "${PREFIX}/share/postgresql/postgresql.conf.sample"; \ + sed -ri "s+#?shared_preload_libraries.*+shared_preload_libraries = 'babelfishpg_tds'+g" "${PREFIX}/share/postgresql/postgresql.conf.sample"; \ + sed -i -e "\$ababelfishpg_tds.listen_addresses = '*'" "${PREFIX}/share/postgresql/postgresql.conf.sample"; \ + grep -F "listen_addresses = '*'" "${PREFIX}/share/postgresql/postgresql.conf.sample"; \ + grep -F "shared_preload_libraries = 'babelfishpg_tds'" "${PREFIX}/share/postgresql/postgresql.conf.sample"; \ + grep -F "babelfishpg_tds.listen_addresses = '*'" "${PREFIX}/share/postgresql/postgresql.conf.sample"; + +RUN mkdir -p "$PGDATA" && chown -R postgres:postgres "$PGDATA" && chmod 777 "$PGDATA" + +COPY entrypoint.sh ${DOCKER_ENTRYPOINT} + +RUN chmod -R 0750 "${PREFIX}/share" && \ + chown postgres: ${DOCKER_ENTRYPOINT} && \ + chmod +x ${DOCKER_ENTRYPOINT} && \ + chown -R postgres: ${PREFIX} + +WORKDIR "${PREFIX}/bin/" + +USER postgres + +STOPSIGNAL SIGINT + +EXPOSE 1433 +EXPOSE 5432 + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] + +CMD ["postgres"] diff --git a/4.2.0/ubuntu/focal/docker-compose.yml b/4.2.0/ubuntu/focal/docker-compose.yml new file mode 100644 index 0000000..8d6e3ad --- /dev/null +++ b/4.2.0/ubuntu/focal/docker-compose.yml @@ -0,0 +1,24 @@ + +services: + babelfishpg-4.2.0-ubuntu-focal: + container_name: babelfishpg-4.2.0-ubuntu.focal + image: babelfishpg:4.2.0-ubuntu.focal + ports: + # Port forwarding not supported by BabelfishPG + - 1433:1433 + - 5432:15432 + environment: + - POSTGRES_PASSWORD=password + - POSTGRES_DB=postgres + - POSTGRES_USER=postgres + - BABELFISH_USER=bbf + - BABELFISH_PASS=password + - BABELFISH_DB=bbf + - BABELFISH_MIGRATION_MODE=multi-db + - POSTGRES_HOST_AUTH_METHOD=trust + networks: + - babelfish + +networks: + babelfish: + diff --git a/4.2.0/ubuntu/focal/entrypoint.sh b/4.2.0/ubuntu/focal/entrypoint.sh new file mode 100644 index 0000000..d20597c --- /dev/null +++ b/4.2.0/ubuntu/focal/entrypoint.sh @@ -0,0 +1,380 @@ +#!/usr/bin/env bash +set -Eeo pipefail +# TODO swap to -Eeuo pipefail above (after handling all potentially-unset variables) + +# 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 + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +# 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' ] +} + +# used to create initial postgres directories and if run as root, ensure ownership to the "postgres" user +docker_create_db_directories() { + local user; user="$(id -u)" + + mkdir -p "$PGDATA" + # ignore failure since there are cases where we can't chmod (and PostgreSQL might fail later anyhow - it's picky about permissions of this directory) + chmod 700 "$PGDATA" || : + + # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289 + mkdir -p /var/run/postgresql || : + chmod 775 /var/run/postgresql || : + + # Create the transaction log directory before initdb is run so the directory is owned by the correct user + if [ -n "$POSTGRES_INITDB_WALDIR" ]; then + mkdir -p "$POSTGRES_INITDB_WALDIR" + if [ "$user" = '0' ]; then + find "$POSTGRES_INITDB_WALDIR" \! -user postgres -exec chown postgres '{}' + + fi + chmod 700 "$POSTGRES_INITDB_WALDIR" + fi + + # allow the container to be started with `--user` + if [ "$user" = '0' ]; then + find "$PGDATA" \! -user postgres -exec chown postgres '{}' + + find /var/run/postgresql \! -user postgres -exec chown postgres '{}' + + fi +} + +# initialize empty PGDATA directory with new database via 'initdb' +# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function +# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames +# this is also where the database user is created, specified by `POSTGRES_USER` env +docker_init_database_dir() { + # "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary + # see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html + local uid; uid="$(id -u)" + if ! getent passwd "$uid" &> /dev/null; then + # see if we can find a suitable "libnss_wrapper.so" (https://salsa.debian.org/sssd-team/nss-wrapper/-/commit/b9925a653a54e24d09d9b498a2d913729f7abb15) + local wrapper + for wrapper in {/usr,}/lib{/*,}/libnss_wrapper.so; do + if [ -s "$wrapper" ]; then + NSS_WRAPPER_PASSWD="$(mktemp)" + NSS_WRAPPER_GROUP="$(mktemp)" + export LD_PRELOAD="$wrapper" NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP + local gid; gid="$(id -g)" + echo "postgres:x:$uid:$gid:PostgreSQL:$PGDATA:/bin/false" > "$NSS_WRAPPER_PASSWD" + echo "postgres:x:$gid:" > "$NSS_WRAPPER_GROUP" + break + fi + done + fi + + if [ -n "$POSTGRES_INITDB_WALDIR" ]; then + set -- --waldir "$POSTGRES_INITDB_WALDIR" "$@" + fi + + # Babelfish supports UTF-8 only + eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") -E "UTF8" '"$POSTGRES_INITDB_ARGS"' "$@"' + + # unset/cleanup "nss_wrapper" bits + if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then + rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP" + unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP + fi +} + +# print large warning if POSTGRES_PASSWORD is long +# error if both POSTGRES_PASSWORD is empty and POSTGRES_HOST_AUTH_METHOD is not 'trust' +# print large warning if POSTGRES_HOST_AUTH_METHOD is set to 'trust' +# assumes database is not set up, ie: [ -z "$DATABASE_ALREADY_EXISTS" ] +docker_verify_minimum_env() { + # check password first so we can output the warning before postgres + # messes it up + if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then + cat >&2 <<-'EOWARN' + + WARNING: The supplied POSTGRES_PASSWORD is 100+ characters. + + This will not work if used via PGPASSWORD with "psql". + + https://www.postgresql.org/message-id/flat/E1Rqxp2-0004Qt-PL%40wrigleys.postgresql.org (BUG #6412) + https://github.com/docker-library/postgres/issues/507 + + EOWARN + fi + if [ -z "$POSTGRES_PASSWORD" ] && [ 'trust' != "$POSTGRES_HOST_AUTH_METHOD" ]; then + # The - option suppresses leading tabs but *not* spaces. :) + cat >&2 <<-'EOE' + Error: Database is uninitialized and superuser password is not specified. + You must specify POSTGRES_PASSWORD to a non-empty value for the + superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run". + + You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all + connections without a password. This is *not* recommended. + + See PostgreSQL documentation about "trust": + https://www.postgresql.org/docs/current/auth-trust.html + EOE + exit 1 + fi + if [ 'trust' = "$POSTGRES_HOST_AUTH_METHOD" ]; then + cat >&2 <<-'EOWARN' + ******************************************************************************** + WARNING: POSTGRES_HOST_AUTH_METHOD has been set to "trust". This will allow + anyone with access to the Postgres port to access your database without + a password, even if POSTGRES_PASSWORD is set. See PostgreSQL + documentation about "trust": + https://www.postgresql.org/docs/current/auth-trust.html + In Docker's default configuration, this is effectively any other + container on the same system. + + It is not recommended to use POSTGRES_HOST_AUTH_METHOD=trust. Replace + it with "-e POSTGRES_PASSWORD=password" instead to set a password in + "docker run". + ******************************************************************************** + EOWARN + fi +} + +# usage: docker_process_init_files [file [file [...]]] +# ie: docker_process_init_files /always-initdb.d/* +# process initializer files, based on file extensions and permissions +docker_process_init_files() { + # psql here for backwards compatibility "${psql[@]}" + psql=( 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 + echo "$0: running $f" + "$f" + else + echo "$0: sourcing $f" + . "$f" + fi + ;; + *.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;; + *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;; + *.sql.xz) echo "$0: running $f"; xzcat "$f" | docker_process_sql; echo ;; + *) echo "$0: ignoring $f" ;; + esac + echo + done +} + +# Execute sql script, passed via stdin (or -f flag of pqsl) +# usage: docker_process_sql [psql-cli-args] +# ie: docker_process_sql --dbname=mydb <<<'INSERT ...' +# ie: docker_process_sql -f my-file.sql +# ie: docker_process_sql > $PGDATA/postgresql.conf + + docker_process_sql --dbname $POSTGRES_DB -c 'select pg_reload_conf();' +} + +# Loads various settings that are used elsewhere in the script +# This should be called before any other functions +docker_setup_env() { + file_env 'POSTGRES_PASSWORD' + + file_env 'POSTGRES_USER' 'postgres' + file_env 'POSTGRES_DB' "$POSTGRES_USER" + file_env 'BABELFISH_MIGRATION_MODE' 'single-db' + file_env 'BABELFISH_MIGRATION_MODE' "$BABELFISH_MIGRATION_MODE" + file_env 'POSTGRES_INITDB_ARGS' + : "${POSTGRES_HOST_AUTH_METHOD:=}" + + declare -g DATABASE_ALREADY_EXISTS + # look specifically for PG_VERSION, as it is expected in the DB dir + if [ -s "$PGDATA/PG_VERSION" ]; then + DATABASE_ALREADY_EXISTS='true' + fi +} + +# append POSTGRES_HOST_AUTH_METHOD to pg_hba.conf for "host" connections +# all arguments will be passed along as arguments to `postgres` for getting the value of 'password_encryption' +pg_setup_hba_conf() { + # default authentication method is md5 on versions before 14 + # https://www.postgresql.org/about/news/postgresql-14-released-2318/ + if [ "$1" = 'postgres' ]; then + shift + fi + local auth + # check the default/configured encryption and use that as the auth method + auth="$(postgres -C password_encryption "$@")" + # postgres 9 only reports "on" and not "md5" + if [ "$auth" = 'on' ]; then + auth='md5' + fi + : "${POSTGRES_HOST_AUTH_METHOD:=$auth}" + { + echo + if [ 'trust' = "$POSTGRES_HOST_AUTH_METHOD" ]; then + echo '# warning trust is enabled for all connections' + echo '# see https://www.postgresql.org/docs/12/auth-trust.html' + fi + echo "host all all all $POSTGRES_HOST_AUTH_METHOD" + } >> "$PGDATA/pg_hba.conf" +} + +# start socket-only postgresql server for setting up or running scripts +# all arguments will be passed along as arguments to `postgres` (via pg_ctl) +docker_temp_server_start() { + if [ "$1" = 'postgres' ]; then + shift + fi + + # internal start of server in order to allow setup using psql client + # does not listen on external TCP/IP and waits until start finishes + set -- "$@" -c listen_addresses='' -p "${PGPORT:-5432}" + + PGUSER="${PGUSER:-$POSTGRES_USER}" \ + pg_ctl -D "$PGDATA" \ + -o "$(printf '%q ' "$@")" \ + -w start +} + +# stop postgresql server after done setting up user and running scripts +docker_temp_server_stop() { + PGUSER="${PGUSER:-postgres}" \ + pg_ctl -D "$PGDATA" -m fast -w stop +} + +# check arguments for an option that would cause postgres to stop +# return true if there is one +_pg_want_help() { + local arg + for arg; do + case "$arg" in + # postgres --help | grep 'then exit' + # leaving out -C on purpose since it always fails and is unhelpful: + # postgres: could not access the server configuration file "/var/lib/postgresql/data/postgresql.conf": No such file or directory + -'?'|--help|--describe-config|-V|--version) + return 0 + ;; + esac + done + return 1 +} + +_main() { + # if first arg looks like a flag, assume we want to run postgres server + if [ "${1:0:1}" = '-' ]; then + set -- postgres "$@" + fi + + if [ "$1" = 'postgres' ] && ! _pg_want_help "$@"; then + docker_setup_env + # setup data directories and permissions (when run as root) + docker_create_db_directories + if [ "$(id -u)" = '0' ]; then + # then restart script as postgres user + exec gosu postgres "$BASH_SOURCE" "$@" + fi + + # only run initialization on an empty data directory + if [ -z "$DATABASE_ALREADY_EXISTS" ]; then + docker_verify_minimum_env + + # check dir permissions to reduce likelihood of half-initialized database + #ls /docker-entrypoint-initdb.d/ > /dev/null + + docker_init_database_dir + pg_setup_hba_conf "$@" + + # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless + # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS + export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}" + docker_temp_server_start "$@" + + docker_setup_db + + docker_setup_babelfish_db + + docker_process_init_files /docker-entrypoint-initdb.d/* + + docker_temp_server_stop + unset PGPASSWORD + + echo + echo 'PostgreSQL init process complete; ready for start up.' + echo + else + echo + echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization' + echo + fi + fi + + exec "$@" +} + +if ! _is_sourced; then + _main "$@" +fi \ No newline at end of file diff --git a/templates/docker-compose.yml.j2 b/templates/docker-compose.yml.j2 index 66b6962..38643f3 100644 --- a/templates/docker-compose.yml.j2 +++ b/templates/docker-compose.yml.j2 @@ -1,4 +1,3 @@ -version: "3" services: babelfishpg-{{ BABELFISH_VERSION }}-{{DISTRO}}-{{OSVERSION}}: @@ -7,7 +6,7 @@ services: ports: # Port forwarding not supported by BabelfishPG - 1433:1433 - - 5432:15432 + - 15432:5432 environment: - POSTGRES_PASSWORD=password - POSTGRES_DB=postgres @@ -22,4 +21,4 @@ services: networks: babelfish: - \ No newline at end of file +