fixes
This commit is contained in:
@@ -15,7 +15,8 @@ localfile="$1"
|
|||||||
remotefile="$2"
|
remotefile="$2"
|
||||||
remotetmp_base="/var/tmp/4server"
|
remotetmp_base="/var/tmp/4server"
|
||||||
|
|
||||||
while read -r host; do
|
# Read hosts from file descriptor 3 to prevent ssh from consuming stdin
|
||||||
|
while read -r host <&3; do
|
||||||
host_env_file="$host_vars_dir/$host/$host.env"
|
host_env_file="$host_vars_dir/$host/$host.env"
|
||||||
|
|
||||||
if [ ! -f "$host_env_file" ]; then
|
if [ ! -f "$host_env_file" ]; then
|
||||||
@@ -28,24 +29,19 @@ while read -r host; do
|
|||||||
source "$host_env_file"
|
source "$host_env_file"
|
||||||
set +a
|
set +a
|
||||||
|
|
||||||
|
|
||||||
NEBULA_KEY=$(<"$host_vars_dir/$host/$host.key")
|
NEBULA_KEY=$(<"$host_vars_dir/$host/$host.key")
|
||||||
NEBULA_CRT=$(<"$host_vars_dir/$host/$host.crt")
|
NEBULA_CRT=$(<"$host_vars_dir/$host/$host.crt")
|
||||||
|
|
||||||
SSH_PRIVATE=$(<"$host_vars_dir/$host/$host")
|
SSH_PRIVATE=$(<"$host_vars_dir/$host/$host")
|
||||||
SSH_PUBLIC=$(<"$host_vars_dir/$host/$host.pub")
|
SSH_PUBLIC=$(<"$host_vars_dir/$host/$host.pub")
|
||||||
|
|
||||||
content=$(<"$localfile")
|
content=$(<"$localfile")
|
||||||
|
|
||||||
for key in "${keys[@]}"; do
|
for key in "${keys[@]}"; do
|
||||||
value="${!key}" # indirect reference
|
value="${!key}" # indirect reference
|
||||||
# Replace placeholder {{KEY}} with value using Bash's parameter expansion
|
# Replace placeholder {{KEY}} with value using Bash's parameter expansion
|
||||||
content="${content//\{\{$key\}\}/$value}"
|
content="${content//\{\{$key\}\}/$value}"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Copy content to remote temporary file
|
# Copy content to remote temporary file
|
||||||
remotetmp="${remotetmp_base}_${host}"
|
remotetmp="${remotetmp_base}_${host}"
|
||||||
@@ -55,7 +51,5 @@ done
|
|||||||
# Move temporary file to final location with doas
|
# Move temporary file to final location with doas
|
||||||
ssh "$host" "doas mv '$remotetmp' '$remotefile'"
|
ssh "$host" "doas mv '$remotetmp' '$remotefile'"
|
||||||
|
|
||||||
done < /app/host_vars/hosts
|
done 3< /app/host_vars/hosts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
rex "doas sqlite3 /4server/data/contracts.db <<EOF
|
||||||
#!/bin/bash
|
UPDATE containers
|
||||||
|
SET affiliate = '{\"utm_source\":\"OD8N\",\"utm_medium\":\"direct\",\"utm_campaign\":\"none\"}';
|
||||||
rex "doas sqlite3 /4server/data/contracts.db <<'EOF'
|
|
||||||
ALTER TABLE containers
|
|
||||||
ALTER COLUMN contract DROP NOT NULL;
|
|
||||||
EOF"
|
EOF"
|
||||||
|
|||||||
16
app/sbin/api
16
app/sbin/api
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from fastapi import FastAPI, HTTPException, Depends, Response
|
from fastapi import FastAPI, HTTPException, Depends, Response
|
||||||
from fastapi.security.api_key import APIKeyHeader
|
from fastapi.security.api_key import APIKeyHeader
|
||||||
from fastapi.responses import RedirectResponse
|
from fastapi.responses import RedirectResponse, PlainTextResponse
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
import psutil
|
import psutil
|
||||||
import sqlite3
|
import sqlite3
|
||||||
@@ -14,6 +14,8 @@ import json
|
|||||||
import re
|
import re
|
||||||
from collections import deque
|
from collections import deque
|
||||||
import time
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -277,6 +279,18 @@ def list_images():
|
|||||||
images = run_command(["docker", "images", "--format", "{{.Repository}}:{{.Tag}}"])
|
images = run_command(["docker", "images", "--format", "{{.Repository}}:{{.Tag}}"])
|
||||||
return {"images": images.split("\n")}
|
return {"images": images.split("\n")}
|
||||||
|
|
||||||
|
@app.get("/system/cpu", dependencies=[Depends(verify_api_key)])
|
||||||
|
def get_cpu_log():
|
||||||
|
CPU_LOG_PATH = Path("/4server/data/log/cpu.log")
|
||||||
|
if not CPU_LOG_PATH.exists():
|
||||||
|
raise HTTPException(status_code=404, detail="CPU log file not found")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with CPU_LOG_PATH.open("r") as f:
|
||||||
|
content = f.read()
|
||||||
|
return PlainTextResponse(content)
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Error reading CPU log: {e}")
|
||||||
|
|
||||||
@app.get("/system/info", dependencies=[Depends(verify_api_key)])
|
@app.get("/system/info", dependencies=[Depends(verify_api_key)])
|
||||||
def get_system_info():
|
def get_system_info():
|
||||||
|
|||||||
39
app/sbin/cpu
Executable file
39
app/sbin/cpu
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
OUTPUT="/4server/data/log/cpu_idle.log"
|
||||||
|
|
||||||
|
# Sampling interval in seconds
|
||||||
|
INTERVAL=60
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
DATA="" # buffer to store idle samples
|
||||||
|
|
||||||
|
# Current date for the measurement period
|
||||||
|
DATE=$(date "+%Y-%m-%d")
|
||||||
|
|
||||||
|
echo "Starting measurement for $DATE"
|
||||||
|
|
||||||
|
while [ "$(date +%H:%M)" != "23:45" ]; do
|
||||||
|
# Get idle CPU percentage
|
||||||
|
IDLE=$(mpstat 1 1 | awk '/Average/ {print $12}')
|
||||||
|
|
||||||
|
# Append to buffer
|
||||||
|
DATA="$DATA$IDLE\n"
|
||||||
|
|
||||||
|
sleep $INTERVAL
|
||||||
|
done
|
||||||
|
|
||||||
|
# Write all data to log file with date
|
||||||
|
# Only one line per day: Date + space-separated idle samples
|
||||||
|
echo -n "$DATE " >> "$OUTPUT"
|
||||||
|
echo -e "$DATA" | tr '\n' ' ' >> "$OUTPUT"
|
||||||
|
echo >> "$OUTPUT" # newline at the end
|
||||||
|
echo "Measurement for $DATE written to $OUTPUT"
|
||||||
|
|
||||||
|
# Wait until 00:15 to start next day
|
||||||
|
while [ "$(date +%H:%M)" != "00:15" ]; do
|
||||||
|
sleep 30
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
# Load functions
|
# Load functions
|
||||||
source /4server/sbin/ODOO_19/ODOO_19.lib
|
source /4server/sbin/ODOO_19/ODOO_19.lib
|
||||||
|
if [[ -z "$UUID" ]]; then
|
||||||
# Config variables
|
echo "Error: UUID not set. Aborting."
|
||||||
UUID="${UUID:-default}"
|
exit 1
|
||||||
STAGING="${STAGING:-false}"
|
fi
|
||||||
|
|
||||||
POSTGRES_HOST="${POSTGRES_HOST:-beedb}"
|
POSTGRES_HOST="${POSTGRES_HOST:-beedb}"
|
||||||
POSTGRES_PORT="${POSTGRES_PORT:-5432}"
|
POSTGRES_PORT="${POSTGRES_PORT:-5432}"
|
||||||
@@ -15,13 +15,16 @@ ODOO_DB_USER="${UUID}"
|
|||||||
export ODOO_DB_PASSWORD=$(echo "$SECRET" | jq -r '.psql')
|
export ODOO_DB_PASSWORD=$(echo "$SECRET" | jq -r '.psql')
|
||||||
|
|
||||||
BASEURL="${BASEURL:-/4server/data/$UUID}"
|
BASEURL="${BASEURL:-/4server/data/$UUID}"
|
||||||
|
BACKUPURL="/4backup/$UUID"
|
||||||
|
|
||||||
doas docker stop "$UUID"
|
doas docker stop "$UUID"
|
||||||
doas docker rm "$UUID"
|
doas docker rm "$UUID"
|
||||||
|
|
||||||
if [ -n "${UUID:-}" ]; then
|
if [ -n "${UUID:-}" ]; then
|
||||||
echo "Removing directory: $BASEURL"
|
echo "Removing directory: $BASEURL"
|
||||||
doas rm -rf "$BASEURL"
|
#doas rm -rf "$BASEURL"
|
||||||
|
echo "Removing backup directory $BACKUPURL"
|
||||||
|
#doas rm -rf $BACKUPURL
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,30 @@ if [[ -z "$UUID" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
get_container_status() {
|
||||||
|
local uuid="$1"
|
||||||
|
# Get the container ID or name matching the UUID
|
||||||
|
CONTAINER_ID=$(docker ps -a --filter "name=$uuid" --format "{{.ID}}")
|
||||||
|
if [[ -z "$CONTAINER_ID" ]]; then
|
||||||
|
echo "not_found"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
STATUS=$(docker inspect -f '{{.State.Status}}' "$CONTAINER_ID")
|
||||||
|
echo "$STATUS"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if container exists
|
||||||
|
STATUS=$(get_container_status "$UUID")
|
||||||
|
if [[ "$STATUS" == "running" ]]; then
|
||||||
|
echo "Container $UUID is still running. Aborting deletion."
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
get_contract_info
|
get_contract_info
|
||||||
|
|
||||||
# Extract the second part of UUID (split by "-")
|
# Extract the second part of UUID (split by "-")
|
||||||
@@ -34,3 +58,11 @@ case "$SECOND_PART" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
sqlite3 "/4server/data/contracts.db" <<SQL
|
||||||
|
DELETE FROM containers WHERE UUID='$UUID';
|
||||||
|
SQL
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
echo "Container $UUID successfully nuked."
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ doas docker run -d --name "$UUID" \
|
|||||||
--label "traefik.http.routers.$UUID.service=$UUID" \
|
--label "traefik.http.routers.$UUID.service=$UUID" \
|
||||||
docker.odoo4projects.com/4projects/odoo_17:$BRANCH
|
docker.odoo4projects.com/4projects/odoo_17:$BRANCH
|
||||||
|
|
||||||
|
doas docker exec "$UUID" rm /var/lib/odoo/.local/share/Odoo/filestore
|
||||||
doas docker exec "$UUID" ln -s /home/odoo/.local/share/Odoo/filestore /var/lib/odoo/.local/share/Odoo/filestore
|
doas docker exec "$UUID" ln -s /home/odoo/.local/share/Odoo/filestore /var/lib/odoo/.local/share/Odoo/filestore
|
||||||
|
|
||||||
doas docker exec $UUID chown -R odoo:odoo /home/odoo/.local
|
doas docker exec $UUID chown -R odoo:odoo /home/odoo/.local
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ docker run -d \
|
|||||||
-e NODE_ENV=production \
|
-e NODE_ENV=production \
|
||||||
-e WEBHOOK_URL="https://${UUID}.odoo4projects.com/" \
|
-e WEBHOOK_URL="https://${UUID}.odoo4projects.com/" \
|
||||||
-e GENERIC_TIMEZONE="UTC-3" \
|
-e GENERIC_TIMEZONE="UTC-3" \
|
||||||
|
-e N8N_CUSTOM_EXTENSIONS="/usr/local/share/n8n/custom" \
|
||||||
-v "/4server/data/${UUID}/n8n:/home/node/.n8n" \
|
-v "/4server/data/${UUID}/n8n:/home/node/.n8n" \
|
||||||
-v "/4server/data/${UUID}/data:/data" \
|
-v "/4server/data/${UUID}/data:/data" \
|
||||||
--label "traefik.enable=true" \
|
--label "traefik.enable=true" \
|
||||||
@@ -42,7 +43,6 @@ docker run -d \
|
|||||||
--label "traefik.http.routers.${UUID}.tls.certresolver=production" \
|
--label "traefik.http.routers.${UUID}.tls.certresolver=production" \
|
||||||
--label "traefik.http.services.${UUID}.loadbalancer.server.port=5678" \
|
--label "traefik.http.services.${UUID}.loadbalancer.server.port=5678" \
|
||||||
--network 4server_4projects \
|
--network 4server_4projects \
|
||||||
n8nio/n8n:latest
|
docker.odoo4projects.com/4projects/n8n:release
|
||||||
|
|
||||||
|
|
||||||
echo "Started $1"
|
echo "Started $1"
|
||||||
|
|||||||
@@ -15,6 +15,20 @@ if [[ -z "$UUID" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
DOMAIN_FILE="/4server/data/$UUID/etc/domain"
|
||||||
|
DB_FILE="/4server/data/contracts.db"
|
||||||
|
if [ -f "$DOMAIN_FILE" ]; then
|
||||||
|
DOMAINS=$(paste -sd "," "$DOMAIN_FILE")
|
||||||
|
sqlite3 "$DB_FILE" <<SQL
|
||||||
|
UPDATE containers
|
||||||
|
SET domains='$DOMAINS'
|
||||||
|
WHERE UUID='$UUID';
|
||||||
|
SQL
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
get_contract_info
|
get_contract_info
|
||||||
|
|
||||||
# Extract the second part of UUID (split by "-")
|
# Extract the second part of UUID (split by "-")
|
||||||
|
|||||||
6
app/sbin/stopContainer
Executable file
6
app/sbin/stopContainer
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
exec > /4server/data/log/stopContainer.log 2>&1
|
||||||
|
echo "$(date '+%Y-%m-%d %H:%M') Stop container $1"
|
||||||
|
|
||||||
|
docker stop $1
|
||||||
|
|
||||||
17
app/templates/init.d/cpu
Executable file
17
app/templates/init.d/cpu
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/sbin/openrc-run
|
||||||
|
# OpenRC service for /4server/sbin/cpu
|
||||||
|
|
||||||
|
name="cpu"
|
||||||
|
description="Logs cpu usage"
|
||||||
|
|
||||||
|
command="/4server/sbin/cpu"
|
||||||
|
command_background="yes"
|
||||||
|
pidfile="/run/cpu.pid"
|
||||||
|
output_log="/4server/data/log/cpu.log"
|
||||||
|
error_log="/4server/data/log/cpu.log"
|
||||||
|
|
||||||
|
depend() {
|
||||||
|
need localmount
|
||||||
|
after bootmisc
|
||||||
|
}
|
||||||
|
|
||||||
@@ -68,6 +68,13 @@ rex doas chown root:root /etc/init.d/cleanTmp
|
|||||||
rex doas rc-update add cleanTmp default
|
rex doas rc-update add cleanTmp default
|
||||||
rex doas rc-service cleanTmp restart
|
rex doas rc-service cleanTmp restart
|
||||||
|
|
||||||
|
#INSTALL cpu service
|
||||||
|
template templates/init.d/cpu /etc/init.d/cpu
|
||||||
|
rex doas chmod 0755 /etc/init.d/cpu
|
||||||
|
rex doas chown root:root /etc/init.d/cpu
|
||||||
|
rex doas rc-update add cpu default
|
||||||
|
rex doas rc-service cpu restart
|
||||||
|
|
||||||
### Infrastructure
|
### Infrastructure
|
||||||
##### Docker
|
##### Docker
|
||||||
rex doas rc-service docker start
|
rex doas rc-service docker start
|
||||||
|
|||||||
Binary file not shown.
@@ -4,6 +4,7 @@ set -euo pipefail
|
|||||||
VAULT_FILE="/app/vault/host_vars.img"
|
VAULT_FILE="/app/vault/host_vars.img"
|
||||||
MAPPER_NAME="host_vars_crypt"
|
MAPPER_NAME="host_vars_crypt"
|
||||||
MOUNT_POINT="/app/host_vars"
|
MOUNT_POINT="/app/host_vars"
|
||||||
|
LOOP_DEVICE="/dev/loop50"
|
||||||
|
|
||||||
mkdir -p "$MOUNT_POINT"
|
mkdir -p "$MOUNT_POINT"
|
||||||
|
|
||||||
@@ -13,19 +14,36 @@ if cryptsetup status "$MAPPER_NAME" >/dev/null 2>&1; then
|
|||||||
cryptsetup close "$MAPPER_NAME"
|
cryptsetup close "$MAPPER_NAME"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Open
|
# Detach loop device if already in use
|
||||||
|
if losetup "$LOOP_DEVICE" >/dev/null 2>&1; then
|
||||||
|
echo "Detaching stale loop device $LOOP_DEVICE..."
|
||||||
|
losetup -d "$LOOP_DEVICE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create loop device if missing
|
||||||
|
if [ ! -e "$LOOP_DEVICE" ]; then
|
||||||
|
echo "Creating loop device $LOOP_DEVICE..."
|
||||||
|
mknod "$LOOP_DEVICE" b 7 50
|
||||||
|
chmod 660 "$LOOP_DEVICE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Attach vault file to loop device
|
||||||
|
echo "Attaching $VAULT_FILE to $LOOP_DEVICE..."
|
||||||
|
losetup "$LOOP_DEVICE" "$VAULT_FILE"
|
||||||
|
|
||||||
|
# Open encrypted volume
|
||||||
echo "Opening encrypted volume..."
|
echo "Opening encrypted volume..."
|
||||||
cryptsetup open "$VAULT_FILE" "$MAPPER_NAME"
|
cryptsetup open "$LOOP_DEVICE" "$MAPPER_NAME"
|
||||||
|
|
||||||
# Format if needed
|
# Format if needed
|
||||||
if ! blkid /dev/mapper/"$MAPPER_NAME" >/dev/null 2>&1; then
|
if ! blkid "/dev/mapper/$MAPPER_NAME" >/dev/null 2>&1; then
|
||||||
echo "No filesystem found, creating ext4..."
|
echo "No filesystem found, creating ext4..."
|
||||||
mkfs.ext4 /dev/mapper/"$MAPPER_NAME"
|
mkfs.ext4 "/dev/mapper/$MAPPER_NAME"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Mount
|
# Mount
|
||||||
echo "Mounting at $MOUNT_POINT..."
|
echo "Mounting at $MOUNT_POINT..."
|
||||||
mount /dev/mapper/"$MAPPER_NAME" "$MOUNT_POINT"
|
mount "/dev/mapper/$MAPPER_NAME" "$MOUNT_POINT"
|
||||||
|
|
||||||
echo "Vault is mounted at $MOUNT_POINT"
|
echo "Vault is mounted at $MOUNT_POINT"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user