This commit is contained in:
oliver committed 2026-09-27 10:39:39 -03:00
1 parent 2e9c775599
commit 9a59b2932a
10 files changed
+499

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
"$(dirname "$(realpath "${BASH_SOURCE[0]:-$0}")")/listModules" "$1"
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env python3
import csv
import sys
import zipfile
if len(sys.argv) < 2:
print("Usage: python3 check_odoo_version.py <dump.zip>")
sys.exit(1)
zip_path = sys.argv[1]
base_version = None
with zipfile.ZipFile(zip_path, 'r') as z:
# Assume there is only one .sql file in the zip
sql_files = [f for f in z.namelist() if f.endswith('.sql')]
if not sql_files:
print("No .sql file found in the zip.")
sys.exit(1)
sql_file_name = sql_files[0]
with z.open(sql_file_name, 'r') as f:
# Decode bytes to string
lines = (line.decode('utf-8') for line in f)
# Skip lines until COPY command
for line in lines:
if line.startswith("COPY public.ir_module_module"):
break
# Read the COPY data until the terminator '\.'
reader = csv.reader(lines, delimiter='\t', quotechar='"', escapechar='\\')
for row in reader:
if row == ['\\.']: # End of COPY
break
if len(row) < 12:
continue
module_name = row[7].strip() # 8th column = name
if module_name == "base":
base_version = row[11].strip() # 12th column = latest_version
break
if base_version:
print(base_version.split(".")[0])
else:
print("Base module not found in dump.")
+31
View File
@@ -0,0 +1,31 @@
#!/bin/bash
# Create the tmp directory if it doesn't exist
mkdir -p /4server/tmp/
# Save original stdout
exec 3>&1
# Redirect all other output to log
exec > /4server/data/log/importDb.log 2>&1
echo "$(date '+%Y-%m-%d %H:%M') Import file $1"
# Generate random 8-digit filename
RANDOM_FILE="/4server/tmp/import_$(date '+%Y%m%d_%H%M').zip"
# Download file from Google Drive using gdown
gdown "$1" -O "$RANDOM_FILE"
# Execute dbVersion on the downloaded file and capture output
VERSION=$("$(dirname "$(realpath "${BASH_SOURCE[0]:-$0}")")/dbVersion" "$RANDOM_FILE")
# Output JSON to original stdout
cat <<EOF >&3
{
"version":"$VERSION",
"file":"$RANDOM_FILE"
}
EOF
# Close saved stdout
exec 3>&-
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
export PATH=/4PROJECTS/bin:$PATH
CONTAINER_ID="$1"
_self="$(realpath "${BASH_SOURCE[0]:-$0}")"; SBIN_ROOT="$(dirname "$(dirname "$_self")")" # parent of ODOO/
source "$SBIN_ROOT/helpers"
[ -z "$CONTAINER_ID" ] && die "Usage: $0 <container_id>"
load_container_config "$CONTAINER_ID"
get_contract_info
DB_NAME="${DB_NAME:-$CONTAINER_ID}"
log "shell: CONTAINER_ID=$CONTAINER_ID DB_NAME=$DB_NAME"
doas docker exec -it "$CONTAINER_ID" odoo shell --db_host beedb --db_password="$ODOO_DB_PASSWORD" -d "$DB_NAME" --db_user="$DB_NAME"
+31
View File
@@ -0,0 +1,31 @@
#!/bin/bash
export PATH=/4PROJECTS/bin:$PATH
# --------------------------------------------------
# Validate parameter
# --------------------------------------------------
CONTAINER_ID="$1"
_self="$(realpath "${BASH_SOURCE[0]:-$0}")"; SBIN_ROOT="$(dirname "$(dirname "$_self")")" # parent of ODOO/
source "$SBIN_ROOT/helpers"
[ -z "$CONTAINER_ID" ] && die "Usage: $0 <container_id>"
load_container_config "$CONTAINER_ID"
get_contract_info
DB_NAME="${DB_NAME:-$CONTAINER_ID}"
doas docker ps -a --format "{{.Names}}" | grep -q "^${CONTAINER_ID}$" \
|| die "Container $CONTAINER_ID does not exist"
log "Updating all Odoo modules: DB=$DB_NAME host=$POSTGRES_HOST"
doas docker exec -u odoo "$CONTAINER_ID" odoo \
-u all \
-d "$DB_NAME" \
--stop-after-init \
--db_host="$POSTGRES_HOST" \
--db_port="$POSTGRES_PORT" \
--db_user="$POSTGRES_ADMIN_USER" \
--db_password="$POSTGRES_ADMIN_PASSWORD" \
|| die "Odoo module update failed for $CONTAINER_ID"
log "Module update complete — restarting $CONTAINER_ID"
"$SBIN_ROOT/startContainer" "$CONTAINER_ID"
+49
View File
@@ -0,0 +1,49 @@
#!/bin/bash
# Usage: initContainer <container_id> <software> [db_name]
#
# Creates /4server/data/<container_id>/config/container.env
#
# <container_id> : new codename (e.g. "banana")
# <software> : n8n | ODOO_17 | ODOO_18 | ODOO_19
# [db_name] : optional — postgres DB/user name to use.
# Defaults to <container_id>.
# Pass the OLD container_id here when migrating an existing container
# so the existing postgres database is reused.
#
# Examples:
# New container:
# initContainer banana ODOO_19
#
# Migrating existing container (old container_id kept as DB name):
# initContainer banana ODOO_19 005-003-91f3922c-8cc2-4950-aa57-808775c341ff
CONTAINER_ID="$1"
SOFTWARE="$2"
DB_NAME="${3:-$1}"
if [[ -z "$CONTAINER_ID" || -z "$SOFTWARE" ]]; then
echo "Usage: $0 <container_id> <software> [db_name]"
echo " software: n8n | ODOO_17 | ODOO_18 | ODOO_19"
exit 1
fi
case "$SOFTWARE" in
n8n|ODOO_17|ODOO_18|ODOO_19) ;;
*)
echo "ERROR: Unknown software type: $SOFTWARE"
echo " Valid values: n8n | ODOO_17 | ODOO_18 | ODOO_19"
exit 1
;;
esac
CONFIG_DIR="/4server/data/$CONTAINER_ID/config"
mkdir -p "$CONFIG_DIR"
cat > "$CONFIG_DIR/container.env" <<EOF
SOFTWARE=$SOFTWARE
DB_NAME=$DB_NAME
EOF
echo "Created $CONFIG_DIR/container.env"
echo " SOFTWARE=$SOFTWARE"
echo " DB_NAME=$DB_NAME"
+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
# Unified Odoo nuke script (all versions).
# CONTAINER_ID, DB_NAME, SOFTWARE already exported by nukeContainer.
_self="$(realpath "${BASH_SOURCE[0]:-$0}")"; SBIN_ROOT="$(dirname "$(dirname "$_self")")" # parent of nuke/
source "$SBIN_ROOT/helpers"
source "$SBIN_ROOT/odoo.lib"
[ -z "$CONTAINER_ID" ] && die "CONTAINER_ID not set"
load_container_config "$CONTAINER_ID"
POSTGRES_HOST="${POSTGRES_HOST:-beedb}"
POSTGRES_PORT="${POSTGRES_PORT:-5432}"
POSTGRES_ADMIN_USER="${POSTGRES_ADMIN_USER:-1gtT0sf8klB9lDbYZD9}"
POSTGRES_ADMIN_PASSWORD="${POSTGRES_ADMIN_PASSWORD:-ZpSwWNafyy9GhY2gzHw}"
DB_NAME="${DB_NAME:-$CONTAINER_ID}"
ODOO_DB_USER="$DB_NAME"
BASEURL="/4server/data/$CONTAINER_ID"
BACKUPURL="/BACKUP/$CONTAINER_ID"
log "Nuking container $CONTAINER_ID (DB_NAME=$DB_NAME)"
doas docker stop "$CONTAINER_ID" || warn "docker stop failed (may already be stopped)"
doas docker rm "$CONTAINER_ID" || warn "docker rm failed (may not exist)"
log "Dropping PostgreSQL database: $DB_NAME"
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -p "$POSTGRES_PORT" -d postgres \
-c "DROP DATABASE IF EXISTS \"$DB_NAME\";" \
|| die "failed to drop database $DB_NAME"
log "Dropping PostgreSQL user: $ODOO_DB_USER"
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -p "$POSTGRES_PORT" -d postgres <<EOF
DO
\$do\$
BEGIN
IF EXISTS (SELECT FROM pg_catalog.pg_user WHERE usename = '${ODOO_DB_USER}') THEN
EXECUTE 'DROP USER "' || '${ODOO_DB_USER}' || '"';
END IF;
END
\$do\$;
EOF
log "Database '$DB_NAME' and user '$ODOO_DB_USER' removed"
# Uncomment when ready to also wipe data directories:
# log "Removing data directory: $BASEURL"
# doas rm -rf "$BASEURL"
# log "Removing backup directory: $BACKUPURL"
# doas rm -rf "$BACKUPURL"
+107
View File
@@ -0,0 +1,107 @@
#!/bin/bash
# Shared library for all Odoo containers (17 / 18 / 19).
# Sourced by start/odoo, nuke/odoo, and admin tools.
# Requires: helpers already sourced (provides log/warn/die).
# ---------------------------------------------------------------------------
# dump_config — print all resolved variables for debugging
# ---------------------------------------------------------------------------
dump_config() {
log "========== Odoo Container Configuration =========="
log "CONTAINER_ID: $CONTAINER_ID"
log "DB_NAME: $DB_NAME"
log "IMAGE_TAG: $IMAGE_TAG"
log "BRANCH: $BRANCH"
log ""
log "PostgreSQL Host: $POSTGRES_HOST"
log "PostgreSQL Port: $POSTGRES_PORT"
log "ODOO DB User: $ODOO_DB_USER"
log ""
log "BASEURL: $BASEURL"
log "SERVER_IP: $SERVER_IP"
log "PORT: $PORT"
log "=================================================="
}
# ---------------------------------------------------------------------------
# build_traefik_rule
# Reads CONTAINER_ID and BASEURL from env. Resolves each candidate domain via
# nslookup and builds a Traefik Host() rule containing only domains that point
# to this server. Exports DOMAIN_LABEL.
# ---------------------------------------------------------------------------
build_traefik_rule() {
local server_ip
server_ip=$(ip -4 addr show eth0 | awk '/inet/ {print $2}' | cut -d/ -f1 | head -n1)
local domains=("$CONTAINER_ID.odoo4projects.com")
if [ -f "$BASEURL/etc/domain" ]; then
while IFS= read -r domain || [ -n "$domain" ]; do
[ -z "$domain" ] && continue
domains+=("$domain")
done < "$BASEURL/etc/domain"
fi
local rule=""
for d in "${domains[@]}"; do
local resolved_ip
resolved_ip=$(nslookup "$d" 2>/dev/null | awk '/^Address: / { print $2 }' | head -n1 || true)
if [ -z "$resolved_ip" ]; then
warn "build_traefik_rule: could not resolve $d, skipping"
continue
fi
if [ "$resolved_ip" = "$server_ip" ]; then
rule+=" || Host(\`$d\`)"
else
warn "build_traefik_rule: $d resolves to $resolved_ip, not $server_ip — skipping"
fi
done
rule="${rule# || }"
if [ -z "$rule" ]; then
die "build_traefik_rule: no valid domains resolved for $CONTAINER_ID — cannot start container"
fi
DOMAIN_LABEL="traefik.http.routers.$CONTAINER_ID.rule=$rule"
log "Traefik rule: $DOMAIN_LABEL"
}
# ---------------------------------------------------------------------------
# check_and_create_db
# Creates the postgres user and database if they don't exist yet.
# On a brand-new container this triggers a restore from default.zip.
# Requires: DB_NAME, ODOO_DB_USER, ODOO_DB_PASSWORD, POSTGRES_* from env.
# ---------------------------------------------------------------------------
check_and_create_db() {
local _dbname="${DB_NAME:-$CONTAINER_ID}"
local _dbuser="${ODOO_DB_USER:-$_dbname}"
log "check_and_create_db: user=$_dbuser db=$_dbname host=$POSTGRES_HOST"
# --- user ---
local _user_result
_user_result=$(PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -p "$POSTGRES_PORT" \
-d postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='$_dbuser';" 2>&1) \
|| die "check_and_create_db: psql connection failed: $_user_result"
if ! echo "$_user_result" | grep -q 1; then
log "Creating PostgreSQL user $_dbuser"
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -p "$POSTGRES_PORT" \
-d postgres -c "CREATE USER \"$_dbuser\" WITH PASSWORD '$ODOO_DB_PASSWORD';" \
|| die "check_and_create_db: failed to create user $_dbuser"
fi
# --- database ---
local _db_result
_db_result=$(PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -p "$POSTGRES_PORT" \
-d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='$_dbname';" 2>&1) \
|| die "check_and_create_db: psql connection failed: $_db_result"
if ! echo "$_db_result" | grep -q 1; then
log "Database $_dbname not found — restoring from default.zip"
"$SBIN_ROOT/odoo/restore" "$CONTAINER_ID" default.zip \
|| die "check_and_create_db: restore failed for $_dbname"
fi
}
+74
View File
@@ -0,0 +1,74 @@
#!/bin/bash
# Usage: odoo/restore <container_id> <file>
# Restores an Odoo database from a backup zip inside the container.
if [ -z "$2" ]; then
echo "Usage: $0 <container_id> <file>"
exit 1
fi
CONTAINER_ID="$1"
_self="$(realpath "${BASH_SOURCE[0]:-$0}")"; SBIN_ROOT="$(dirname "$(dirname "$_self")")" # parent of odoo/
source "$SBIN_ROOT/helpers"
load_container_config "$CONTAINER_ID"
get_contract_info
DB_NAME="${DB_NAME:-$CONTAINER_ID}"
log "Restoring $2 into CONTAINER_ID=$CONTAINER_ID DB_NAME=$DB_NAME"
log "Postgres host: $POSTGRES_HOST"
BACKUP="/mnt/backup/$2"
TEMPLATE="/mnt/db_images/$2"
if doas docker exec "$CONTAINER_ID" /bin/bash -c "[ -f $BACKUP ]"; then
FILENAME="$BACKUP"
elif doas docker exec "$CONTAINER_ID" /bin/bash -c "[ -f $TEMPLATE ]"; then
FILENAME="$TEMPLATE"
else
die "restore: file $2 not found at $BACKUP or $TEMPLATE inside container $CONTAINER_ID"
fi
log "Using file: $FILENAME"
# Terminate active connections then drop/recreate
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -d postgres -c "
SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE datname = '$DB_NAME' AND pid <> pg_backend_pid();" \
|| die "restore: failed to terminate connections on $DB_NAME"
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -d postgres \
-c "DROP DATABASE IF EXISTS \"$DB_NAME\";" \
|| die "restore: failed to drop database $DB_NAME"
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -p "$POSTGRES_PORT" -d postgres \
-c "ALTER ROLE \"$DB_NAME\" CREATEDB;" \
|| die "restore: failed to grant CREATEDB on $DB_NAME"
doas docker exec "$CONTAINER_ID" rm -rf /home/odoo/.local/share/Odoo/filestore
doas docker exec "$CONTAINER_ID" rm -rf /root/.local/share/Odoo/filestore
doas docker exec "$CONTAINER_ID" odoo db \
--db_host beedb \
-w "$ODOO_DB_PASSWORD" \
-r "$DB_NAME" \
load "$DB_NAME" "$FILENAME" -f \
|| die "restore: odoo db load failed for $DB_NAME"
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -p "$POSTGRES_PORT" -d postgres \
-c "ALTER ROLE \"$DB_NAME\" NOCREATEDB;" \
|| die "restore: failed to revoke CREATEDB on $DB_NAME"
doas docker exec "$CONTAINER_ID" cp -r /root/.local/share/Odoo/filestore /home/odoo/.local/share/Odoo/filestore
doas docker exec "$CONTAINER_ID" chown -R odoo:odoo /home/odoo/.local
doas docker exec "$CONTAINER_ID" mkdir -p /var/lib/odoo/.local/share/Odoo/
doas docker exec "$CONTAINER_ID" ln -s /home/odoo/.local/share/Odoo/filestore /var/lib/odoo/.local/share/Odoo/filestore
log "Restore complete, restarting container $CONTAINER_ID"
docker restart "$CONTAINER_ID"
+92
View File
@@ -0,0 +1,92 @@
#!/bin/bash
# Unified Odoo start script for all versions (17 / 18 / 19).
# Called by startContainer with IMAGE_TAG exported, e.g.:
# IMAGE_TAG=odoo_19 /4server/sbin/start/odoo
#
# Requires (exported by startContainer before this is called):
# CONTAINER_ID, IMAGE_TAG, SOFTWARE, DB_NAME
_self="$(realpath "${BASH_SOURCE[0]:-$0}")"; SBIN_ROOT="$(dirname "$(dirname "$_self")")" # parent of start/
source "$SBIN_ROOT/helpers"
source "$SBIN_ROOT/odoo.lib"
load_container_config "$CONTAINER_ID"
get_contract_info
BRANCH="${BRANCH:-release}"
DB_NAME="${DB_NAME:-$CONTAINER_ID}"
ODOO_DB_USER="$DB_NAME"
log "Starting Odoo container: CONTAINER_ID=$CONTAINER_ID IMAGE_TAG=$IMAGE_TAG DB_NAME=$DB_NAME"
BASEURL="/4server/data/$CONTAINER_ID"
DATA_DIR="$BASEURL/odoo"
CUSTOM_DIR="$BASEURL/git/$CONTAINER_ID/custom"
ENTERPRISE_DIR="$BASEURL/git/$CONTAINER_ID/enterprise"
LOGS_DIR="$BASEURL/logs"
CONFIG_DIR="$BASEURL/config"
CC_DIR="$BASEURL/cc"
BACKUP_DIR="/BACKUP/$CONTAINER_ID"
GIT_DIR="$BASEURL/git-server"
INSTALL_DIR="$BASEURL/install"
SSH_DIR="$BASEURL/.ssh"
ETC_DIR="$BASEURL/etc"
PORT=$((CONTAINERDBID + 2200))
log "SSH port: $PORT"
# --- prepare directories ---
find "$BASEURL" -type d -exec chmod 777 {} \;
mkdir -p "$ETC_DIR" "$BACKUP_DIR" "$GIT_DIR/keys" "$INSTALL_DIR" "$SSH_DIR"
chmod 777 "$ETC_DIR" "$BACKUP_DIR" "$GIT_DIR"
touch "$GIT_DIR/keys/id_rsa.pub"
echo "git clone \"ssh://git@${CONTAINER_ID}.odoo4projects.com:${PORT}/git-server/repos/odoo.git\"" > "$ETC_DIR/gitpath"
# --- build Traefik domain rule (exports DOMAIN_LABEL) ---
build_traefik_rule
# --- stop and remove any existing container ---
docker stop "$CONTAINER_ID" 2>/dev/null || true
docker rm "$CONTAINER_ID" 2>/dev/null || true
# --- run ---
docker run -d --name "$CONTAINER_ID" \
--network 4server_4projects \
--restart=always \
-v "$DATA_DIR/odoo-web-data:/home/odoo/.local/share/Odoo" \
-v "$CUSTOM_DIR:/mnt/addons/custom" \
-v "$ENTERPRISE_DIR:/mnt/addons/enterprise" \
-v "$LOGS_DIR:/mnt/logs" \
-v "$CC_DIR:/mnt/cc" \
-v "$BACKUP_DIR:/mnt/backup" \
-v "$GIT_DIR:/git-server" \
-v "$INSTALL_DIR:/mnt/install" \
-v "$SSH_DIR:/etc/sshkey" \
-v "$ETC_DIR:/mnt/etc" \
-p "$PORT:22" \
-e HOST="beedb" \
-e USER="$ODOO_DB_USER" \
-e PASSWORD="$ODOO_DB_PASSWORD" \
-e CONTAINER_ID="$CONTAINER_ID" \
-e DB_NAME="$DB_NAME" \
-e HDD="$HDD" \
-e DOMAINS_SLOTS="$DOMAINS_SLOTS" \
-e BACKUP_SLOTS="$BACKUP_SLOTS" \
-e WORKER="$WORKER" \
-e GIT="$GIT" \
--label "$DOMAIN_LABEL" \
--label "traefik.http.services.$CONTAINER_ID.loadbalancer.server.port=8069" \
--label "traefik.http.routers.$CONTAINER_ID.entrypoints=web,websecure" \
--label "traefik.http.routers.$CONTAINER_ID.tls=true" \
--label "traefik.http.routers.$CONTAINER_ID.tls.certresolver=production" \
--label "traefik.http.routers.$CONTAINER_ID.service=$CONTAINER_ID" \
"docker.odoo4projects.com/4projects/${IMAGE_TAG}:${BRANCH}" \
|| die "docker run failed for $CONTAINER_ID"
# --- fix ownership inside container ---
docker exec "$CONTAINER_ID" chown -R odoo:odoo /home/odoo/.local
docker exec "$CONTAINER_ID" chown -R odoo:odoo /mnt
docker exec "$CONTAINER_ID" chown -R git:git /git-server
chmod 777 "$CC_DIR"
# --- ensure DB/user exist, restore from default.zip if brand new ---
check_and_create_db