diff --git a/18.0/Dockerfile b/18.0/Dockerfile index d1882e2ef..a9af2ead8 100644 --- a/18.0/Dockerfile +++ b/18.0/Dockerfile @@ -14,6 +14,7 @@ ARG TARGETARCH RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive \ apt-get install -y --no-install-recommends \ + gettext \ ca-certificates \ curl \ dirmngr \ @@ -81,10 +82,13 @@ RUN curl -o odoo.deb -sSL http://nightly.odoo.com/${ODOO_VERSION}/nightly/deb/od # Copy entrypoint script and Odoo configuration file COPY ./entrypoint.sh / -COPY ./odoo.conf /etc/odoo/ + +# Copy the configuration file to the template. +COPY ./odoo.conf /etc/odoo/odoo.conf +RUN touch /etc/odoo/odoo_docker.conf # Set permissions and Mount /var/lib/odoo to allow restoring filestore and /mnt/extra-addons for users addons -RUN chown odoo /etc/odoo/odoo.conf \ +RUN chown odoo:odoo /etc/odoo/odoo.conf /etc/odoo/odoo_docker.conf \ && mkdir -p /mnt/extra-addons \ && chown -R odoo /mnt/extra-addons VOLUME ["/var/lib/odoo", "/mnt/extra-addons"] @@ -93,7 +97,7 @@ VOLUME ["/var/lib/odoo", "/mnt/extra-addons"] EXPOSE 8069 8071 8072 # Set the default config file -ENV ODOO_RC /etc/odoo/odoo.conf +ENV ODOO_RC /etc/odoo/odoo_docker.conf COPY wait-for-psql.py /usr/local/bin/wait-for-psql.py diff --git a/18.0/docker-compose.yml b/18.0/docker-compose.yml new file mode 100644 index 000000000..3c6e539dc --- /dev/null +++ b/18.0/docker-compose.yml @@ -0,0 +1,75 @@ +version: '3.8' + +services: + odoo: + build: + context: . + dockerfile: Dockerfile + container_name: odoo + environment: + ADDONS_PATH: ${ADDONS_PATH:-/mnt/extra-addons} + DATA_DIR: ${DATA_DIR:-/var/lib/odoo} + DB_HOST: ${DB_HOST:-db} + DB_PORT: ${DB_PORT:-5432} + DB_USER: ${DB_USER:-odoo} + DB_PASSWORD: ${DB_PASSWORD:-odoo} + DB_NAME: ${DB_NAME:-postgres} + ADMIN_PASSWD: ${ADMIN_PASSWD:-admin} + CSV_INTERNAL_SEP: ${CSV_INTERNAL_SEP:-,} + DB_MAXCONN: ${DB_MAXCONN:-64} + DB_TEMPLATE: ${DB_TEMPLATE:-template1} + DBFILTER: ${DBFILTER:-.*} + DEBUG_MODE: ${DEBUG_MODE:-False} + EMAIL_FROM: ${EMAIL_FROM:-False} + LIMIT_MEMORY_HARD: ${LIMIT_MEMORY_HARD:-2684354560} + LIMIT_MEMORY_SOFT: ${LIMIT_MEMORY_SOFT:-2147483648} + LIMIT_REQUEST: ${LIMIT_REQUEST:-8192} + LIMIT_TIME_CPU: ${LIMIT_TIME_CPU:-60} + LIMIT_TIME_REAL: ${LIMIT_TIME_REAL:-120} + LIST_DB: ${LIST_DB:-True} + LOG_DB: ${LOG_DB:-False} + LOG_HANDLER: ${LOG_HANDLER:-[:INFO]} + LOG_LEVEL: ${LOG_LEVEL:-info} + LOGFILE: ${LOGFILE:-None} + LONGPOLLING_PORT: ${LONGPOLLING_PORT:-8072} + MAX_CRON_THREADS: ${MAX_CRON_THREADS:-2} + OSV_MEMORY_AGE_LIMIT: ${OSV_MEMORY_AGE_LIMIT:-1.0} + OSV_MEMORY_COUNT_LIMIT: ${OSV_MEMORY_COUNT_LIMIT:-False} + SMTP_PASSWORD: ${SMTP_PASSWORD:-False} + SMTP_PORT: ${SMTP_PORT:-25} + SMTP_SERVER: ${SMTP_SERVER:-localhost} + SMTP_SSL: ${SMTP_SSL:-False} + SMTP_USER: ${SMTP_USER:-False} + WORKERS: ${WORKERS:-0} + XMLRPC: ${XMLRPC:-True} + XMLRPC_INTERFACE: ${XMLRPC_INTERFACE:-} + XMLRPC_PORT: ${XMLRPC_PORT:-8069} + XMLRPCS: ${XMLRPCS:-True} + XMLRPCS_INTERFACE: ${XMLRPCS_INTERFACE:-} + XMLRPCS_PORT: ${XMLRPCS_PORT:-8071} + PSQL_WAIT_TIMEOUT: ${PSQL_WAIT_TIMEOUT:-30} + ports: + - "8069:8069" + - "8071:8071" + - "8072:8072" + volumes: + - odoo_data:/var/lib/odoo + - ./addons:/mnt/extra-addons + depends_on: + - db + + db: + image: postgres:13 + container_name: odoo_db + environment: + POSTGRES_USER: ${POSTGRES_USER:-odoo} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-odoo} + POSTGRES_DB: ${POSTGRES_DATABASE:-postgres} + volumes: + - pg_data:/var/lib/postgresql/data + ports: + - "5432:5432" + +volumes: + odoo_data: + pg_data: diff --git a/18.0/entrypoint.sh b/18.0/entrypoint.sh index f802bcb25..71cd900ca 100755 --- a/18.0/entrypoint.sh +++ b/18.0/entrypoint.sh @@ -2,31 +2,57 @@ set -e +# Setup default configuration values +export ADDONS_PATH=${ADDONS_PATH:-/mnt/extra-addons} +export DATA_DIR=${DATA_DIR:-/var/lib/odoo} +export DB_HOST=${DB_HOST:=${HOST:=${DB_PORT_5432_TCP_ADDR:='db'}}} +export DB_PORT=${DB_PORT:=${PORT:=${DB_PORT_5432_TCP_PORT:=5432}}} +export DB_USER=${DB_USER:=${USER:=${DB_ENV_POSTGRES_USER:=${POSTGRES_USER:='odoo'}}}} +export DB_PASSWORD=${DB_PASSWORD:=${PASSWORD:=${DB_ENV_POSTGRES_PASSWORD:=${POSTGRES_PASSWORD:='odoo'}}}} +export DB_NAME=${DB_NAME:-'postgres'} +export ADMIN_PASSWD=${ADMIN_PASSWD:-admin} +export CSV_INTERNAL_SEP=${CSV_INTERNAL_SEP:-,} +export DB_MAXCONN=${DB_MAXCONN:-64} +export DB_TEMPLATE=${DB_TEMPLATE:-template1} +export DBFILTER=${DBFILTER:-.*} +export DEBUG_MODE=${DEBUG_MODE:-False} +export EMAIL_FROM=${EMAIL_FROM:-False} +export LIMIT_MEMORY_HARD=${LIMIT_MEMORY_HARD:-2684354560} +export LIMIT_MEMORY_SOFT=${LIMIT_MEMORY_SOFT:-2147483648} +export LIMIT_REQUEST=${LIMIT_REQUEST:-8192} +export LIMIT_TIME_CPU=${LIMIT_TIME_CPU:-60} +export LIMIT_TIME_REAL=${LIMIT_TIME_REAL:-120} +export LIST_DB=${LIST_DB:-True} +export LOG_DB=${LOG_DB:-False} +export LOG_HANDLER=${LOG_HANDLER:-[:INFO]} +export LOG_LEVEL=${LOG_LEVEL:-info} +export LOGFILE=${LOGFILE:-None} +export LONGPOLLING_PORT=${LONGPOLLING_PORT:-8072} +export MAX_CRON_THREADS=${MAX_CRON_THREADS:-2} +export TRANSIENT_AGE_LIMIT=${TRANSIENT_AGE_LIMIT:-1.0} +export OSV_MEMORY_COUNT_LIMIT=${OSV_MEMORY_COUNT_LIMIT:-False} +export SMTP_PASSWORD=${SMTP_PASSWORD:-False} +export SMTP_PORT=${SMTP_PORT:-25} +export SMTP_SERVER=${SMTP_SERVER:-localhost} +export SMTP_SSL=${SMTP_SSL:-False} +export SMTP_USER=${SMTP_USER:-False} +export WORKERS=${WORKERS:-0} +export XMLRPC=${XMLRPC:-True} +export XMLRPC_INTERFACE=${XMLRPC_INTERFACE:-} +export XMLRPC_PORT=${XMLRPC_PORT:-8069} +export XMLRPCS=${XMLRPCS:-True} +export XMLRPCS_INTERFACE=${XMLRPCS_INTERFACE:-} +export XMLRPCS_PORT=${XMLRPCS_PORT:-8071} +export PSQL_WAIT_TIMEOUT=${PSQL_WAIT_TIMEOUT:-30} + +# Set the password file environment variable if [ -v PASSWORD_FILE ]; then - PASSWORD="$(< $PASSWORD_FILE)" + DB_PASSWORD="$(< $PASSWORD_FILE)" fi -# set the postgres database host, port, user and password according to the environment -# and pass them as arguments to the odoo process if not present in the config file -: ${HOST:=${DB_PORT_5432_TCP_ADDR:='db'}} -: ${PORT:=${DB_PORT_5432_TCP_PORT:=5432}} -: ${USER:=${DB_ENV_POSTGRES_USER:=${POSTGRES_USER:='odoo'}}} -: ${PASSWORD:=${DB_ENV_POSTGRES_PASSWORD:=${POSTGRES_PASSWORD:='odoo'}}} - -DB_ARGS=() -function check_config() { - param="$1" - value="$2" - if grep -q -E "^\s*\b${param}\b\s*=" "$ODOO_RC" ; then - value=$(grep -E "^\s*\b${param}\b\s*=" "$ODOO_RC" |cut -d " " -f3|sed 's/["\n\r]//g') - fi; - DB_ARGS+=("--${param}") - DB_ARGS+=("${value}") -} -check_config "db_host" "$HOST" -check_config "db_port" "$PORT" -check_config "db_user" "$USER" -check_config "db_password" "$PASSWORD" +# Substitute environment variables into the config file +# and write them back to the Odoo config +envsubst < /etc/odoo/odoo.conf > "${ODOO_RC}" case "$1" in -- | odoo) @@ -34,13 +60,13 @@ case "$1" in if [[ "$1" == "scaffold" ]] ; then exec odoo "$@" else - wait-for-psql.py ${DB_ARGS[@]} --timeout=30 - exec odoo "$@" "${DB_ARGS[@]}" + wait-for-psql.py + exec odoo "$@" fi ;; -*) - wait-for-psql.py ${DB_ARGS[@]} --timeout=30 - exec odoo "$@" "${DB_ARGS[@]}" + wait-for-psql.py + exec odoo "$@" ;; *) exec "$@" diff --git a/18.0/odoo.conf b/18.0/odoo.conf index 28f70c105..69fbcea34 100644 --- a/18.0/odoo.conf +++ b/18.0/odoo.conf @@ -1,37 +1,42 @@ [options] -addons_path = /mnt/extra-addons -data_dir = /var/lib/odoo -; admin_passwd = admin -; csv_internal_sep = , -; db_maxconn = 64 -; db_name = False -; db_template = template1 -; dbfilter = .* -; debug_mode = False -; email_from = False -; limit_memory_hard = 2684354560 -; limit_memory_soft = 2147483648 -; limit_request = 8192 -; limit_time_cpu = 60 -; limit_time_real = 120 -; list_db = True -; log_db = False -; log_handler = [':INFO'] -; log_level = info -; logfile = None -; longpolling_port = 8072 -; max_cron_threads = 2 -; osv_memory_age_limit = 1.0 -; osv_memory_count_limit = False -; smtp_password = False -; smtp_port = 25 -; smtp_server = localhost -; smtp_ssl = False -; smtp_user = False -; workers = 0 -; xmlrpc = True -; xmlrpc_interface = -; xmlrpc_port = 8069 -; xmlrpcs = True -; xmlrpcs_interface = -; xmlrpcs_port = 8071 +addons_path = $ADDONS_PATH +data_dir = $DATA_DIR +db_host = $DB_HOST +db_port = $DB_PORT +db_user = $DB_USER +db_password = $DB_PASSWORD + +;db_name = $DB_NAME +;admin_passwd = $ADMIN_PASSWD +;csv_internal_sep = $CSV_INTERNAL_SEP +;db_maxconn = $DB_MAXCONN +;db_template = $DB_TEMPLATE +;dbfilter = $DBFILTER +;debug_mode = $DEBUG_MODE +;email_from = $EMAIL_FROM +;limit_memory_hard = $LIMIT_MEMORY_HARD +;limit_memory_soft = $LIMIT_MEMORY_SOFT +;limit_request = $LIMIT_REQUEST +;limit_time_cpu = $LIMIT_TIME_CPU +;limit_time_real = $LIMIT_TIME_REAL +;list_db = $LIST_DB +;log_db = $LOG_DB +;log_handler = $LOG_HANDLER +;log_level = $LOG_LEVEL +;logfile = $LOGFILE +;longpolling_port = $LONGPOLLING_PORT +;max_cron_threads = $MAX_CRON_THREADS +;transient_age_limit = $TRANSIENT_AGE_LIMIT +;osv_memory_count_limit = $OSV_MEMORY_COUNT_LIMIT +;smtp_password = $SMTP_PASSWORD +;smtp_port = $SMTP_PORT +;smtp_server = $SMTP_SERVER +;smtp_ssl = $SMTP_SSL +;smtp_user = $SMTP_USER +;workers = $WORKERS +;xmlrpc = $XMLRPC +;xmlrpc_interface = $XMLRPC_INTERFACE +;xmlrpc_port = $XMLRPC_PORT +;xmlrpcs = $XMLRPCS +;xmlrpcs_interface = $XMLRPCS_INTERFACE +;xmlrpcs_port = $XMLRPCS_PORT diff --git a/18.0/wait-for-psql.py b/18.0/wait-for-psql.py index a55f44098..b4b1d01cf 100755 --- a/18.0/wait-for-psql.py +++ b/18.0/wait-for-psql.py @@ -1,32 +1,70 @@ #!/usr/bin/env python3 import argparse -import psycopg2 -import sys +import configparser +import logging +import os +import subprocess import time +logging.basicConfig( + format="%(asctime)s - %(levelname)s - %(message)s", + level=logging.INFO +) + + +class DatabaseConnectionError(Exception): + pass + + +def check_postgres_status(host="localhost", port=5432, user="postgres", timeout=30): + result = subprocess.run( + ["pg_isready", "-h", host, "-p", str(port), "-U", user, "-t", str(timeout)], + capture_output=True, + text=True + ) + + return result.stdout.strip(), result.returncode + if __name__ == '__main__': + default_config_path = os.getenv('ODOO_RC', '/etc/odoo/odoo_docker.conf') + default_psql_wait_timeout = os.getenv('PSQL_WAIT_TIMEOUT', 30) + arg_parser = argparse.ArgumentParser() - arg_parser.add_argument('--db_host', required=True) - arg_parser.add_argument('--db_port', required=True) - arg_parser.add_argument('--db_user', required=True) - arg_parser.add_argument('--db_password', required=True) - arg_parser.add_argument('--timeout', type=int, default=5) + arg_parser.add_argument('--config', type=str, default=default_config_path) + arg_parser.add_argument('--timeout', type=int, default=default_psql_wait_timeout) args = arg_parser.parse_args() + config = configparser.ConfigParser() + config.read(args.config) + + db_host = config.get('options', 'db_host', fallback='localhost') + db_port = config.get('options', 'db_port', fallback=5432) + db_user = config.get('options', 'db_user', fallback='odoo') + + logging.info("Waiting for database(s) to be ready ...") + logging.info(f"Host: {db_user}@{db_host}:{db_port}") + logging.info(f"Timeout: {args.timeout} seconds") + start_time = time.time() - while (time.time() - start_time) < args.timeout: - try: - conn = psycopg2.connect(user=args.db_user, host=args.db_host, port=args.db_port, password=args.db_password, dbname='postgres') - error = '' + + status, exit_code = "", 0 + + while time.time() < start_time + args.timeout: + status, exit_code = check_postgres_status( + host=db_host, + port=db_port, + user=db_user, + timeout=args.timeout + ) + + if exit_code == 0: break - except psycopg2.OperationalError as e: - error = e - else: - conn.close() + time.sleep(1) - if error: - print("Database connection failure: %s" % error, file=sys.stderr) - sys.exit(1) + if exit_code != 0: + raise DatabaseConnectionError(f"Unable to connect to the database. Exit code: {exit_code} - Message: {status}") + + logging.info("🚀 Database(s) are ready.")