This commit is contained in:
Oliver
2025-09-26 16:27:40 -03:00
parent ac8f70d368
commit bb271b8d71
15 changed files with 199 additions and 48 deletions

View File

@@ -3,5 +3,6 @@
#!/bin/bash
rex "doas sqlite3 /4server/data/contracts.db <<'EOF'
ALTER TABLE containers RENAME COLUMN secrets TO secret;
ALTER TABLE containers
ADD COLUMN secret TEXT NOT NULL DEFAULT '';
EOF"

View File

@@ -1,5 +1,6 @@
#!/bin/bash
dump_config (){
echo "========== Odoo Container Configuration =========="
echo "UUID: $UUID"

View File

@@ -6,16 +6,23 @@ if [ ! -n "$2" ]; then
fi
UUID=$1
echo "UUID: $UUID"
source /4server/sbin/helpers
get_contract_info
export ODOO_DB_PASSWORD=$(echo "$SECRET" | jq -r '.psql')
echo "PASSWORD $ODOO_DB_PASSWORD"
echo "Restoring $FILENAME to $1"
echo "status of container"
doas docker ps -a --filter "id=$UUID"
echo "POSTGRES HOST: $POSTGRES_HOST"
BACKUP="/mnt/backup/$2"
TEMPLATE="/mnt/db_images/$2"
echo "TEMPLATE"
doas docker exec "${1%}" /bin/bash -c "[ -f $TEMPLATE ]"
if doas docker exec "${1%}" /bin/bash -c "[ -f $BACKUP ]"; then
@@ -28,32 +35,30 @@ else
fi
### DELETE DATABASE
### DELETE AND CREATE DATABASE
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 = '$UUID' AND pid <> pg_backend_pid();
"
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql -h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -d postgres -c "
DROP DATABASE IF EXISTS \"$UUID\";
"
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -p "$POSTGRES_PORT" -d postgres \
-c "DROP DATABASE IF EXISTS \"$UUID\";"
-c "ALTER ROLE \"$1\" CREATEDB;"
doas docker exec "${1%}" rm -rf /home/odoo/.local/share/Odoo/filestore
echo "deleting old restore artifacts"
doas docker exec "${1%}" rm -rf /root/.local/
doas docker exec "${1%}" odoo db --db_host beedb -w "$ODOO_DB_PASSWORD" -r "$1" load "$1" $FILENAME -f
if [[ "$1" == *"_"* ]]; then
echo "Neutralize DB"
doas docker exec "${1%_}" odoo db --db_host beedb -w "${1%_}" -r "$1" load "$1" $FILENAME -f --neutralize
else
echo "No Neutralize DB"
doas docker exec "${1%}" odoo db --db_host beedb -w "${1%_}" -r "$1" load "$1" $FILENAME -f
fi
doas docker exec "${1%}" cp -r /root/.local/. /var/lib/odoo/.local/
doas docker exec "${1%}" chown -R odoo:odoo /var/lib/odoo/.local/
### transfer ownership
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -p "$POSTGRES_PORT" -d postgres \
-c "ALTER DATABASE \"$UUID\" OWNER TO \"$UUID\";"
-c "ALTER ROLE \"$1\" NOCREATEDB;"
doas docker exec "${1%}" cp -r /root/.local/share/Odoo/filestore /home/odoo/.local/share/Odoo/filestore
doas docker exec "${1%}" chown -R odoo:odoo /home/odoo/.local/share/Odoo/filestore
docker restart "${1%}"

View File

@@ -35,7 +35,14 @@ def run_command(cmd: list[str]) -> str:
"""Run a shell command and return stdout or raise HTTPException on error."""
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise HTTPException(status_code=500, detail=result.stderr.strip() or "Unknown error")
error_msg = (
f"Command failed\n"
f"Command: {' '.join(cmd)}\n"
f"Return code: {result.returncode}\n"
f"Stdout: {result.stdout.strip()}\n"
f"Stderr: {result.stderr.strip() or 'None'}"
)
raise HTTPException(status_code=500, detail=error_msg)
return result.stdout.strip()
@@ -155,16 +162,18 @@ def nuke_container(request: UUIDRequest):
@app.post("/container/info", dependencies=[Depends(verify_api_key)])
def info_container(request: Optional[UUIDRequest] = None):
# Fields to select
fields = [
"ID", "UUID", "email", "expires", "tags", "env", "affiliate",
"image", "history", "comment", "domains", "status", "created"
]
field_str = ", ".join(fields)
# Execute query
if request:
rows = execute_db(
f"SELECT {field_str} FROM containers WHERE UUID=?",
(request.UUID,),
(str(request.UUID),),
fetch=True
)
else:
@@ -173,15 +182,21 @@ def info_container(request: Optional[UUIDRequest] = None):
fetch=True
)
# Map rows to dicts with field names
containers = [dict(zip(fields, row)) for row in rows]
# Map rows to dicts safely
containers = []
for row in rows:
if isinstance(row, dict):
# Already a dict (e.g., some DB wrappers)
containers.append(row)
else:
# Tuple/list -> map with fields
containers.append(dict(zip(fields, row)))
# Wrap in N8N JSON format
# Wrap in n8n JSON format
n8n_items = [{"json": container} for container in containers]
return n8n_items
@app.post("/container/bump", dependencies=[Depends(verify_api_key)])
def bump_container(request: UUIDRequest):
today = datetime.utcnow().strftime("%Y-%m-%d")

15
app/sbin/backup/ODOO_19 Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
source /4server/sbin/helpers
get_contract_info
export ODOO_DB_PASSWORD=$(echo "$SECRET" | jq -r '.psql')
echo "PASSWORD $ODOO_DB_PASSWORD UUID $UUID"
FILENAME=$(date +"%Y%m%d_%H:%M")".zip"
doas docker exec "$UUID" odoo db --db_host beedb -r "$UUID" -w "$ODOO_DB_PASSWORD" --data-dir /home/odoo/.local/share/Odoo/ dump "$UUID" /mnt/backup/$FILENAME
doas chmod 666 /BACKUP/$UUID/*

36
app/sbin/backupContainer Executable file
View File

@@ -0,0 +1,36 @@
#!/bin/bash
# Usage: ./start_by_uuid.sh <uuid>
# Example: ./start_by_uuid.sh abc-001-xxxx-xxxx-xxxx
exec > /4server/data/log/backupContainer.log 2>&1
echo "$(date '+%Y-%m-%d %H:%M') Backup container $1"
source /4server/sbin/helpers
BIN_PATH="/4server/sbin"
UUID="$1"
if [[ -z "$UUID" ]]; then
echo "Usage: $0 <uuid>"
exit 1
fi
get_contract_info
# Extract the second part of UUID (split by "-")
SECOND_PART=$(echo "$UUID" | cut -d'-' -f2)
# Decide which script to run
case "$SECOND_PART" in
001)
"$BIN_PATH/backup/n8n"
;;
003)
"$BIN_PATH/backup/ODOO_19"
;;
*)
echo "Unknown UUID type: $SECOND_PART"
exit 2
;;
esac

34
app/sbin/checkCalls Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/bash
cd /4server/data/
while :
do
for dir in ???-???-*; do
if [ -d "${dir}/cc" ]; then
if [ -f "${dir}/cc/backup" ]; then
echo "BACKUP for: ${dir%/}"
/4server/sbin/backupContainer ${dir%/} 2
rm "${dir}/cc/backup"
fi
if [ -f "${dir}/cc/restart" ]; then
echo "Restart for: ${dir%/}"
/4server/sbin/startContainer ${dir%/}
rm "${dir}/cc/restart"
fi
if [ -f "${dir}/cc/restore" ]; then
FILENAME=$(head -n 1 "${dir}/cc/restore")
echo "Restore for: ${dir%/} - $FILENAME"
/4server/sbin/ODOO_19/restore ${dir%/} $FILENAME
rm "${dir}/cc/restore"
fi
fi
done
sleep 60
done

View File

@@ -1,5 +1,12 @@
#!/bin/bash
POSTGRES_HOST="${POSTGRES_HOST:-beedb}"
POSTGRES_PORT="${POSTGRES_PORT:-5432}"
POSTGRES_ADMIN_USER="${POSTGRES_ADMIN_USER:-1gtT0sf8klB9lDbYZD9}"
POSTGRES_ADMIN_PASSWORD="${POSTGRES_ADMIN_PASSWORD:-ZpSwWNafyy9GhY2gzHw}"
get_contract_info() {
DB_PATH="/4server/data/contracts.db"

View File

@@ -2,19 +2,16 @@
# Load functions
source /4server/sbin/ODOO_19/ODOO_19.lib
source /4server/sbin/helpers
# Config variables
UUID="${UUID:-default}"
BRANCH="${BRANCH:-main}"
STAGING="${STAGING:-false}"
BRANCH="${BRANCH:-release}"
POSTGRES_HOST="${POSTGRES_HOST:-beedb}"
POSTGRES_PORT="${POSTGRES_PORT:-5432}"
POSTGRES_ADMIN_USER="${POSTGRES_ADMIN_USER:-1gtT0sf8klB9lDbYZD9}"
POSTGRES_ADMIN_PASSWORD="${POSTGRES_ADMIN_PASSWORD:-ZpSwWNafyy9GhY2gzHw}"
ODOO_DB_USER="${UUID}"
export ODOO_DB_PASSWORD=$(echo "$SECRET" | jq -r '.psql')
BASEURL="${BASEURL:-/4server/data/$UUID}"
DATA_DIR="$BASEURL/odoo/"
CUSTOM_DIR="$BASEURL/git/$UUID/custom/"
@@ -24,10 +21,8 @@ CONFIG_DIR="$BASEURL/config/"
CC_DIR="$BASEURL/cc/"
BACKUP_DIR="/BACKUP/$UUID"
GIT_DIR="$BASEURL/git-server/"
ETC_DIR="$BASEURL/etc/"
INSTALL_DIR="$BASEURL/install/"
SSH_DIR="$BASEURL/.ssh/"
HUGO_DIR="$BASEURL/git-server/local/hugo"
SERVER_IP=$(ip -4 addr show eth0 | awk '/inet/ {print $2}' | cut -d/ -f1)
@@ -35,36 +30,34 @@ DOMAIN_LABEL=$(check_domains "$UUID.odoo4projects.com" "$SERVER_IP")
DOMAIN_LABEL="traefik.http.routers.$UUID.rule=Host(\`$UUID.odoo4projects.com\`)"
doas find "$BASEURL" -type d -exec chmod 777 {} \;
doas chmod 777 $BACKUP_DIR
PORT=$((RANDOM%1000+2200))
doas docker stop "$UUID" 2>/dev/null
doas docker rm "$UUID" 2>/dev/null
EXTRA_DOCKER_PARAMETER=""
if [ -d "$HUGO_DIR" ]; then
EXTRA_DOCKER_PARAMETER="-v $HUGO_DIR:/mnt/hugo"
fi
doas docker run -d --name "$UUID" \
--network 4server_4projects \
--restart=always \
$EXTRA_DOCKER_PARAMETER \
-v "$DATA_DIR/odoo-web-data:/var/lib/odoo" \
-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 "$CONFIG_DIR:/etc/odoo" \
-v "$GIT_DIR:/git-server" \
-v "$ETC_DIR:/mnt/etc" \
-v "$INSTALL_DIR:/mnt/install" \
-v "$SSH_DIR:/etc/sshkey" \
-p "$PORT:22" \
-e HOST="$POSTGRES_HOST" \
-e HOST="beedb" \
-e USER="$ODOO_DB_USER" \
-e PASSWORD="$ODOO_DB_PASSWORD" \
-e STAGING="$STAGING" \
-e UUID="$UUID" \
--label "$DOMAIN_LABEL" \
--label "traefik.http.services.$UUID.loadbalancer.server.port=8069" \
--label "traefic.http.routers.$UUID.entrypoints=web, websecure" \

View File

@@ -25,7 +25,7 @@ case "$SECOND_PART" in
001)
"$BIN_PATH/start/n8n"
;;
002)
003)
"$BIN_PATH/start/ODOO_19"
;;
*)

24
app/templates/init.d/checkCalls Executable file
View File

@@ -0,0 +1,24 @@
#!/sbin/openrc-run
name="checkCalls"
description="check container service calls"
# Command uses Python inside the venv
command="/4server/sbin/checkCalls"
command_args=""
pidfile="/run/${RC_SVCNAME}.pid"
command_background="yes"
respawn_delay=5 # seconds to wait before restart
respawn_max=0 # 0 = unlimited restarts
# Load environment variables if needed
output_log="/4server/data/log/checkCalls.log"
error_log="/4server/data/log/checkCalls.log"
depend() {
need net
use logger dns
after firewall
}

View File

@@ -46,6 +46,13 @@ rex doas chown root:root /etc/init.d/api
rex doas rc-update add api default
rex doas rc-service api restart
#INSTALL checkCalls SERVICE
template templates/init.d/checkCalls /etc/init.d/checkCalls
rex doas chmod 0755 /etc/init.d/checkCalls
rex doas chown root:root /etc/init.d/checkCalls
rex doas rc-update add checkCalls default
rex doas rc-service checkCalls restart
### Infrastructure
##### Docker

Binary file not shown.