From 9c5f91952a41a1425c18c9605a7d612cb8091ec5 Mon Sep 17 00:00:00 2001 From: Sattvik Chakravarthy Date: Tue, 12 Aug 2025 12:26:38 +0530 Subject: [PATCH] fix: for backport release 9.3 --- .github/helpers/docker/Dockerfile | 50 +++ .github/helpers/docker/docker-entrypoint.sh | 411 ++++++++++++++++++++ CHANGELOG.md | 4 + build.gradle | 2 +- startDb.sh | 66 +++- 5 files changed, 531 insertions(+), 2 deletions(-) create mode 100644 .github/helpers/docker/Dockerfile create mode 100644 .github/helpers/docker/docker-entrypoint.sh diff --git a/.github/helpers/docker/Dockerfile b/.github/helpers/docker/Dockerfile new file mode 100644 index 00000000..fbed3104 --- /dev/null +++ b/.github/helpers/docker/Dockerfile @@ -0,0 +1,50 @@ +FROM ubuntu:bionic-20200219 AS tmp +WORKDIR /build +RUN apt-get update && apt-get install -y curl wget zip + +RUN ARCH=$(dpkg --print-architecture) && \ + if [ "$ARCH" = "amd64" ]; then \ + wget -O jre.zip https://github.com/supertokens/jre/raw/refs/heads/master/jre-15.0.1-linux.zip; \ + elif [ "$ARCH" = "arm64" ]; then \ + wget -O jre.zip https://github.com/supertokens/jre/raw/refs/heads/master/jre-15.0.1-linux-arm.zip; \ + else \ + echo "Unsupported architecture: $ARCH" && exit 1; \ + fi +RUN unzip jre.zip +RUN mv jre-15.0.1 jre || mv jre-15.0.1-linux-aarch/jre-15.0.1 jre +ADD ./cli ./cli +ADD ./core ./core +ADD ./plugin-interface ./plugin-interface +ADD ./plugin ./plugin +ADD ./ee ./ee +ADD ./config.yaml ./config.yaml +ADD ./version.yaml ./version.yaml + +RUN ls && ./jre/bin/java -classpath "./cli/*" io.supertokens.cli.Main true $@ + +FROM debian:bookworm-slim +RUN groupadd supertokens && useradd -m -s /bin/bash -g supertokens supertokens +RUN apt-get update && apt-get install -y --no-install-recommends gnupg dirmngr curl && rm -rf /var/lib/apt/lists/* +RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata +ENV GOSU_VERSION=1.7 +RUN set -x \ + && apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \ + && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture)" \ + && wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture).asc" \ + && export GNUPGHOME="$(mktemp -d)" \ + && gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \ + && gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \ + && gpgconf --kill all \ + && rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc \ + && chmod +x /usr/local/bin/gosu \ + && apt-get purge -y --auto-remove wget +COPY --from=tmp --chown=supertokens /usr/lib/supertokens /usr/lib/supertokens +COPY --from=tmp --chown=supertokens /usr/bin/supertokens /usr/bin/supertokens +COPY ./supertokens-postgresql-plugin/.github/helpers/docker/docker-entrypoint.sh /usr/local/bin/ +RUN echo "$(md5sum /usr/lib/supertokens/config.yaml | awk '{ print $1 }')" >> /CONFIG_HASH +RUN ln -s /usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat +RUN chmod +x /usr/local/bin/docker-entrypoint.sh +EXPOSE 3567 +USER "supertokens" +ENTRYPOINT ["/entrypoint.sh"] +CMD ["supertokens", "start"] \ No newline at end of file diff --git a/.github/helpers/docker/docker-entrypoint.sh b/.github/helpers/docker/docker-entrypoint.sh new file mode 100644 index 00000000..fe22ed92 --- /dev/null +++ b/.github/helpers/docker/docker-entrypoint.sh @@ -0,0 +1,411 @@ +#!/bin/bash +set -eo pipefail +# -e Exit immediately if a command exits with a non-zero status. +# -o pipefail the return value of a pipeline is the status of the last command +# to exit with a non-zero status, or zero if no command exited with a non-zero status + +CONFIG_HASH=$(head -n 1 /CONFIG_HASH) + +ERROR="\x1b[1;31m" +DEFAULT="\x1b[0m" + +# logging functions +log() { + local level="$1"; shift + local type="$1"; shift + printf "[$level$type$DEFAULT]: $*\n" +} +error_log() { + log "$ERROR" "$@" >&2 + exit 1 +} + +# if command starts with an option, prepend supertokens start +if [ "${1}" = 'dev' -o "${1}" = "production" -o "${1:0:2}" = "--" ]; then + # set -- supertokens start "$@" + set -- supertokens start "$@" + # check if --foreground option is passed or not + if [[ "$*" != *--foreground* ]] + then + set -- "$@" --foreground + fi +fi + +CONFIG_FILE=/usr/lib/supertokens/config.yaml +TEMP_LOCATION_WHEN_READONLY=/lib/supertokens/temp/ +mkdir -p $TEMP_LOCATION_WHEN_READONLY +CONFIG_MD5SUM="$(md5sum /usr/lib/supertokens/config.yaml | awk '{ print $1 }')" + +# always assuming read-only + +#changing where the config file is written +ORIGINAL_CONFIG=$CONFIG_FILE +CONFIG_FILE="${TEMP_LOCATION_WHEN_READONLY}config.yaml" +cat $ORIGINAL_CONFIG >> $CONFIG_FILE +#required by JNA +export _JAVA_OPTIONS=-Djava.io.tmpdir=$TEMP_LOCATION_WHEN_READONLY +#make sure the CLI knows which config file to pass to the core +set -- "$@" --with-config="$CONFIG_FILE" --with-temp-dir="$TEMP_LOCATION_WHEN_READONLY" --foreground + + +if [ "$CONFIG_HASH" = "$CONFIG_MD5SUM" ] +then + echo "" >> $CONFIG_FILE + echo "host: 0.0.0.0" >> $CONFIG_FILE + echo "postgresql_config_version: 0" >> $CONFIG_FILE + + # verify api keys are passed + if [ ! -z $API_KEYS ] + then + echo "api_keys: $API_KEYS" >> $CONFIG_FILE + fi + + # verify postgresql user name is passed + if [ ! -z $POSTGRESQL_USER ] + then + echo "postgresql_user: $POSTGRESQL_USER" >> $CONFIG_FILE + fi + + if [ ! -z $POSTGRESQL_PASSWORD_FILE ] + then + POSTGRESQL_PASSWORD=$(cat "$POSTGRESQL_PASSWORD_FILE") + export POSTGRESQL_PASSWORD + fi + + # verify postgresql password is passed + if [ ! -z $POSTGRESQL_PASSWORD ] + then + echo "postgresql_password: $POSTGRESQL_PASSWORD" >> $CONFIG_FILE + fi + + # check if supertokens port is passed + if [ ! -z $SUPERTOKENS_PORT ] + then + echo "port: $SUPERTOKENS_PORT" >> $CONFIG_FILE + fi + + # check if access token validity is passed + if [ ! -z $ACCESS_TOKEN_VALIDITY ] + then + echo "access_token_validity: $ACCESS_TOKEN_VALIDITY" >> $CONFIG_FILE + fi + + # check if access token blacklisting is passed + if [ ! -z $ACCESS_TOKEN_BLACKLISTING ] + then + echo "access_token_blacklisting: $ACCESS_TOKEN_BLACKLISTING" >> $CONFIG_FILE + fi + + # check if access token signing key dynamic is passed + if [ ! -z $ACCESS_TOKEN_SIGNING_KEY_DYNAMIC ] + then + echo "access_token_signing_key_dynamic: $ACCESS_TOKEN_SIGNING_KEY_DYNAMIC" >> $CONFIG_FILE + fi + + # check if access token signing key update interval is passed + if [ ! -z $ACCESS_TOKEN_DYNAMIC_SIGNING_KEY_UPDATE_INTERVAL ] + then + echo "access_token_dynamic_signing_key_update_interval: $ACCESS_TOKEN_DYNAMIC_SIGNING_KEY_UPDATE_INTERVAL" >> $CONFIG_FILE + fi + + # check if refresh token validity is passed + if [ ! -z $REFRESH_TOKEN_VALIDITY ] + then + echo "refresh_token_validity: $REFRESH_TOKEN_VALIDITY" >> $CONFIG_FILE + fi + + if [ ! -z $PASSWORD_RESET_TOKEN_LIFETIME ] + then + echo "password_reset_token_lifetime: $PASSWORD_RESET_TOKEN_LIFETIME" >> $CONFIG_FILE + fi + + if [ ! -z $EMAIL_VERIFICATION_TOKEN_LIFETIME ] + then + echo "email_verification_token_lifetime: $EMAIL_VERIFICATION_TOKEN_LIFETIME" >> $CONFIG_FILE + fi + + if [ ! -z $PASSWORDLESS_MAX_CODE_INPUT_ATTEMPTS ] + then + echo "passwordless_max_code_input_attempts: $PASSWORDLESS_MAX_CODE_INPUT_ATTEMPTS" >> $CONFIG_FILE + fi + + if [ ! -z $PASSWORDLESS_CODE_LIFETIME ] + then + echo "passwordless_code_lifetime: $PASSWORDLESS_CODE_LIFETIME" >> $CONFIG_FILE + fi + + if [ ! -z $BASE_PATH ] + then + echo "base_path: $BASE_PATH" >> $CONFIG_FILE + fi + + if [ ! -z $PASSWORD_HASHING_ALG ] + then + echo "password_hashing_alg: $PASSWORD_HASHING_ALG" >> $CONFIG_FILE + fi + + if [ ! -z $ARGON2_ITERATIONS ] + then + echo "argon2_iterations: $ARGON2_ITERATIONS" >> $CONFIG_FILE + fi + + if [ ! -z $ARGON2_MEMORY_KB ] + then + echo "argon2_memory_kb: $ARGON2_MEMORY_KB" >> $CONFIG_FILE + fi + + if [ ! -z $ARGON2_PARALLELISM ] + then + echo "argon2_parallelism: $ARGON2_PARALLELISM" >> $CONFIG_FILE + fi + + if [ ! -z $ARGON2_HASHING_POOL_SIZE ] + then + echo "argon2_hashing_pool_size: $ARGON2_HASHING_POOL_SIZE" >> $CONFIG_FILE + fi + + if [ ! -z $BCRYPT_LOG_ROUNDS ] + then + echo "bcrypt_log_rounds: $BCRYPT_LOG_ROUNDS" >> $CONFIG_FILE + fi + + if [ ! -z $FIREBASE_PASSWORD_HASHING_SIGNER_KEY ] + then + echo "firebase_password_hashing_signer_key: $FIREBASE_PASSWORD_HASHING_SIGNER_KEY" >> $CONFIG_FILE + fi + + if [ ! -z $FIREBASE_PASSWORD_HASHING_POOL_SIZE ] + then + echo "firebase_password_hashing_pool_size: $FIREBASE_PASSWORD_HASHING_POOL_SIZE" >> $CONFIG_FILE + fi + + if [ ! -z $LOG_LEVEL ] + then + echo "log_level: $LOG_LEVEL" >> $CONFIG_FILE + fi + + if [ ! -z $IP_ALLOW_REGEX ] + then + echo "ip_allow_regex: $IP_ALLOW_REGEX" >> $CONFIG_FILE + fi + + if [ ! -z $IP_DENY_REGEX ] + then + echo "ip_deny_regex: $IP_DENY_REGEX" >> $CONFIG_FILE + fi + + if [ ! -z $TOTP_MAX_ATTEMPTS ] + then + echo "totp_max_attempts: $TOTP_MAX_ATTEMPTS" >> $CONFIG_FILE + fi + + if [ ! -z $TOTP_RATE_LIMIT_COOLDOWN_SEC ] + then + echo "totp_rate_limit_cooldown_sec: $TOTP_RATE_LIMIT_COOLDOWN_SEC" >> $CONFIG_FILE + fi + + if [ ! -z $SUPERTOKENS_SAAS_SECRET ] + then + echo "supertokens_saas_secret: $SUPERTOKENS_SAAS_SECRET" >> $CONFIG_FILE + fi + + if [ ! -z $SUPERTOKENS_MAX_CDI_VERSION ] + then + echo "supertokens_max_cdi_version: $SUPERTOKENS_MAX_CDI_VERSION" >> $CONFIG_FILE + fi + + # check if info log path is not passed + if [ ! -z $INFO_LOG_PATH ] + then + if [[ ! -f $INFO_LOG_PATH ]] + then + touch $INFO_LOG_PATH + fi + echo "info_log_path: $INFO_LOG_PATH" >> $CONFIG_FILE + else + echo "info_log_path: null" >> $CONFIG_FILE + fi + + # check if error log path is passed + if [ ! -z $ERROR_LOG_PATH ] + then + if [[ ! -f $ERROR_LOG_PATH ]] + then + touch $ERROR_LOG_PATH + fi + echo "error_log_path: $ERROR_LOG_PATH" >> $CONFIG_FILE + else + echo "error_log_path: null" >> $CONFIG_FILE + fi + + # check if max server pool size is passed + if [ ! -z $MAX_SERVER_POOL_SIZE ] + then + echo "max_server_pool_size: $MAX_SERVER_POOL_SIZE" >> $CONFIG_FILE + fi + + # check if telemetry config is passed + if [ ! -z $DISABLE_TELEMETRY ] + then + echo "disable_telemetry: $DISABLE_TELEMETRY" >> $CONFIG_FILE + fi + + # check if max server pool size is passed + if [ ! -z $POSTGRESQL_CONNECTION_POOL_SIZE ] + then + echo "postgresql_connection_pool_size: $POSTGRESQL_CONNECTION_POOL_SIZE" >> $CONFIG_FILE + fi + + # check if postgresql host is passed + if [ ! -z $POSTGRESQL_HOST ] + then + echo "postgresql_host: $POSTGRESQL_HOST" >> $CONFIG_FILE + fi + + # check if postgresql port is passed + if [ ! -z $POSTGRESQL_PORT ] + then + echo "postgresql_port: $POSTGRESQL_PORT" >> $CONFIG_FILE + fi + + # check if postgresql database name is passed + if [ ! -z $POSTGRESQL_DATABASE_NAME ] + then + echo "postgresql_database_name: $POSTGRESQL_DATABASE_NAME" >> $CONFIG_FILE + fi + + # check if postgresql table schema is passed + if [ ! -z $POSTGRESQL_TABLE_SCHEMA ] + then + echo "postgresql_table_schema: $POSTGRESQL_TABLE_SCHEMA" >> $CONFIG_FILE + fi + + # check if postgresql table name prefix is passed + if [ ! -z $POSTGRESQL_TABLE_NAMES_PREFIX ] + then + echo "postgresql_table_names_prefix: $POSTGRESQL_TABLE_NAMES_PREFIX" >> $CONFIG_FILE + fi + + if [ ! -z $POSTGRESQL_CONNECTION_URI ] + then + echo "postgresql_connection_uri: $POSTGRESQL_CONNECTION_URI" >> $CONFIG_FILE + fi + + # THE CONFIGS BELOW ARE DEPRECATED---------------- + + # check if postgresql key value table name is passed + if [ ! -z $POSTGRESQL_KEY_VALUE_TABLE_NAME ] + then + echo "postgresql_key_value_table_name: $POSTGRESQL_KEY_VALUE_TABLE_NAME" >> $CONFIG_FILE + fi + + # check if postgresql session info table name is passed + if [ ! -z $POSTGRESQL_SESSION_INFO_TABLE_NAME ] + then + echo "postgresql_session_info_table_name: $POSTGRESQL_SESSION_INFO_TABLE_NAME" >> $CONFIG_FILE + fi + + # check if postgresql emailpassword user table name is passed + if [ ! -z $POSTGRESQL_EMAILPASSWORD_USERS_TABLE_NAME ] + then + echo "postgresql_emailpassword_users_table_name: $POSTGRESQL_EMAILPASSWORD_USERS_TABLE_NAME" >> $CONFIG_FILE + fi + + # check if postgresql emailpassword password reset table name is passed + if [ ! -z $POSTGRESQL_EMAILPASSWORD_PSWD_RESET_TOKENS_TABLE_NAME ] + then + echo "postgresql_emailpassword_pswd_reset_tokens_table_name: $POSTGRESQL_EMAILPASSWORD_PSWD_RESET_TOKENS_TABLE_NAME" >> $CONFIG_FILE + fi + + # check if postgresql email verification tokens table name is passed + if [ ! -z $POSTGRESQL_EMAILVERIFICATION_TOKENS_TABLE_NAME ] + then + echo "postgresql_emailverification_tokens_table_name: $POSTGRESQL_EMAILVERIFICATION_TOKENS_TABLE_NAME" >> $CONFIG_FILE + fi + + # check if postgresql verified emails table name is passed + if [ ! -z $POSTGRESQL_EMAILVERIFICATION_VERIFIED_EMAILS_TABLE_NAME ] + then + echo "postgresql_emailverification_verified_emails_table_name: $POSTGRESQL_EMAILVERIFICATION_VERIFIED_EMAILS_TABLE_NAME" >> $CONFIG_FILE + fi + + if [ ! -z $POSTGRESQL_THIRDPARTY_USERS_TABLE_NAME ] + then + echo "postgresql_thirdparty_users_table_name: $POSTGRESQL_THIRDPARTY_USERS_TABLE_NAME" >> $CONFIG_FILE + fi + + if [ ! -z $POSTGRESQL_IDLE_CONNECTION_TIMEOUT ] + then + echo "postgresql_idle_connection_timeout: $POSTGRESQL_IDLE_CONNECTION_TIMEOUT" >> $CONFIG_FILE + fi + + if [ ! -z $POSTGRESQL_MINIMUM_IDLE_CONNECTIONS ] + then + echo "postgresql_minimum_idle_connections: $POSTGRESQL_MINIMUM_IDLE_CONNECTIONS" >> $CONFIG_FILE + fi + + if [ ! -z $SUPERTOKENS_SAAS_LOAD_ONLY_CUD ] + then + echo "supertokens_saas_load_only_cud: $SUPERTOKENS_SAAS_LOAD_ONLY_CUD" >> $CONFIG_FILE + fi + + if [ ! -z $OAUTH_PROVIDER_PUBLIC_SERVICE_URL ] + then + echo "oauth_provider_public_service_url: $OAUTH_PROVIDER_PUBLIC_SERVICE_URL" >> $CONFIG_FILE + fi + + if [ ! -z $OAUTH_PROVIDER_ADMIN_SERVICE_URL ] + then + echo "oauth_provider_admin_service_url: $OAUTH_PROVIDER_ADMIN_SERVICE_URL" >> $CONFIG_FILE + fi + + if [ ! -z $OAUTH_PROVIDER_CONSENT_LOGIN_BASE_URL ] + then + echo "oauth_provider_consent_login_base_url: $OAUTH_PROVIDER_CONSENT_LOGIN_BASE_URL" >> $CONFIG_FILE + fi + + if [ ! -z $OAUTH_PROVIDER_URL_CONFIGURED_IN_OAUTH_PROVIDER ] + then + echo "oauth_provider_url_configured_in_oauth_provider: $OAUTH_PROVIDER_URL_CONFIGURED_IN_OAUTH_PROVIDER" >> $CONFIG_FILE + fi + + if [ ! -z $OAUTH_CLIENT_SECRET_ENCRYPTION_KEY ] + then + echo "oauth_client_secret_encryption_key: $OAUTH_CLIENT_SECRET_ENCRYPTION_KEY" >> $CONFIG_FILE + fi + + if [ ! -z $BULK_MIGRATION_PARALLELISM ] + then + echo "bulk_migration_parallelism: $BULK_MIGRATION_PARALLELISM" >> $CONFIG_FILE + fi + + if [ ! -z $BULK_MIGRATION_BATCH_SIZE ] + then + echo "bulk_migration_batch_size: $BULK_MIGRATION_BATCH_SIZE" >> $CONFIG_FILE + fi + + if [ ! -z $WEBAUTHN_RECOVER_ACCOUNT_TOKEN_LIFETIME ] + then + echo "webauthn_recover_account_token_lifetime: $WEBAUTHN_RECOVER_ACCOUNT_TOKEN_LIFETIME" >> $CONFIG_FILE + fi + + if [ ! -z $OTEL_COLLECTOR_CONNECTION_URI ] + then + echo "otel_collector_connection_uri: $OTEL_COLLECTOR_CONNECTION_URI" >> $CONFIG_FILE + fi + +fi + +# check if no options has been passed to docker run +if [[ "$@" == "supertokens start" ]] +then + set -- "$@" --with-config="$CONFIG_FILE" --foreground +fi + + +# If container is started as root user, restart as dedicated supertokens user +if [ "$(id -u)" = "0" ] && [ "$1" = 'supertokens' ]; then + exec gosu supertokens "$@" +else + exec "$@" +fi \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index af622075..7b58d487 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [7.2.1] + +- Helpers for docker build + ## [7.2.0] - 2024-10-03 - Compatible with plugin interface version 6.3 diff --git a/build.gradle b/build.gradle index 553a2c88..1b24a626 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java-library' } -version = "7.2.0" +version = "7.2.1" repositories { mavenCentral() diff --git a/startDb.sh b/startDb.sh index 5fa7d75e..b54dbd3c 100755 --- a/startDb.sh +++ b/startDb.sh @@ -1 +1,65 @@ -docker run --rm --name postgres -e 'POSTGRES_USER=root' -e 'POSTGRES_PASSWORD=root' -d -p 5432:5432 -v ~/Desktop/db/pstgres:/var/lib/postgresql/data postgres -c 'max_connections=10000' \ No newline at end of file +docker run --rm --name postgres \ + -e 'POSTGRES_USER=root' \ + -e 'POSTGRES_PASSWORD=root' \ + -d -p 5432:5432 \ + -v ~/Desktop/db/pstgres:/var/lib/postgresql/data \ + postgres \ + -c 'max_connections=1000' \ + -c 'autovacuum_naptime=1' \ + -c 'autovacuum_vacuum_threshold=10' \ + -c 'autovacuum_analyze_threshold=10' + +sleep 30 + +docker exec postgres psql -U root root -c 'create database supertokens;' +docker exec postgres psql -U root root -c 'create database st0;' +docker exec postgres psql -U root root -c 'create database st1;' +docker exec postgres psql -U root root -c 'create database st2;' +docker exec postgres psql -U root root -c 'create database st3;' +docker exec postgres psql -U root root -c 'create database st4;' +docker exec postgres psql -U root root -c 'create database st5;' +docker exec postgres psql -U root root -c 'create database st6;' +docker exec postgres psql -U root root -c 'create database st7;' +docker exec postgres psql -U root root -c 'create database st8;' +docker exec postgres psql -U root root -c 'create database st9;' +docker exec postgres psql -U root root -c 'create database st10;' +docker exec postgres psql -U root root -c 'create database st11;' +docker exec postgres psql -U root root -c 'create database st12;' +docker exec postgres psql -U root root -c 'create database st13;' +docker exec postgres psql -U root root -c 'create database st14;' +docker exec postgres psql -U root root -c 'create database st15;' +docker exec postgres psql -U root root -c 'create database st16;' +docker exec postgres psql -U root root -c 'create database st17;' +docker exec postgres psql -U root root -c 'create database st18;' +docker exec postgres psql -U root root -c 'create database st19;' +docker exec postgres psql -U root root -c 'create database st20;' +docker exec postgres psql -U root root -c 'create database st21;' +docker exec postgres psql -U root root -c 'create database st22;' +docker exec postgres psql -U root root -c 'create database st23;' +docker exec postgres psql -U root root -c 'create database st24;' +docker exec postgres psql -U root root -c 'create database st25;' +docker exec postgres psql -U root root -c 'create database st26;' +docker exec postgres psql -U root root -c 'create database st27;' +docker exec postgres psql -U root root -c 'create database st28;' +docker exec postgres psql -U root root -c 'create database st29;' +docker exec postgres psql -U root root -c 'create database st30;' +docker exec postgres psql -U root root -c 'create database st31;' +docker exec postgres psql -U root root -c 'create database st32;' +docker exec postgres psql -U root root -c 'create database st33;' +docker exec postgres psql -U root root -c 'create database st34;' +docker exec postgres psql -U root root -c 'create database st35;' +docker exec postgres psql -U root root -c 'create database st36;' +docker exec postgres psql -U root root -c 'create database st37;' +docker exec postgres psql -U root root -c 'create database st38;' +docker exec postgres psql -U root root -c 'create database st39;' +docker exec postgres psql -U root root -c 'create database st40;' +docker exec postgres psql -U root root -c 'create database st41;' +docker exec postgres psql -U root root -c 'create database st42;' +docker exec postgres psql -U root root -c 'create database st43;' +docker exec postgres psql -U root root -c 'create database st44;' +docker exec postgres psql -U root root -c 'create database st45;' +docker exec postgres psql -U root root -c 'create database st46;' +docker exec postgres psql -U root root -c 'create database st47;' +docker exec postgres psql -U root root -c 'create database st48;' +docker exec postgres psql -U root root -c 'create database st49;' +docker exec postgres psql -U root root -c 'create database st50;' \ No newline at end of file