Fixes in plane

This commit is contained in:
Oliver
2025-08-11 05:16:34 -03:00
parent a84fe3f740
commit eb172a367f
22 changed files with 219 additions and 174 deletions

View File

@@ -1 +1,4 @@
API_KEY=4h6lDzAOVksuCqmhEB3
hostname="dev"
nebula_key="123"
nebula_cert="456"

Binary file not shown.

View File

@@ -1,17 +0,0 @@
#!/bin/bash
echo "prsync nebula bin"
prsync -h "$hosts_file" -avz ./nebula/nebula /4server/nebula
ass doas mv /4server/nebula /usr/bin/
ass doas mkdir -p /etc/nebula
ass doas chmod 777 /etc/nebula
template templates/nebula.yml /etc/nebula/config.yml ./host_vars
ass doas chmod 700 /etc/nebula

38
app/onboarding Executable file
View File

@@ -0,0 +1,38 @@
#!/bin/bash
template templates/hosthostname ./host_vars
t
# ------ create user 4server
# ------ disable root user and login
# ----- install nabula
echo "prsync nebula bin"
prsync -h "$hosts_file" -avz ./templates/nebula/nebula /4server/nebula
rex doas mv /4server/nebula /usr/bin/
rex doas mkdir -p /etc/nebula
rex doas chmod 700 /etc/nebula
template templates/nebula/nebula.yml /etc/nebula/config.yml ./host_vars
template templates/nebula/host.key /etc/nebula/host.key ./host_vars
template templates/nebula/host.crt /etc/nebula/host.crt ./host_vars
rex doas chmod 700 /etc/nebula
template templates/init.d/nebula /etc/init.d/nebula ./host_vars/
rex doas chmod 0755 /etc/init.d/nebula
rex doas chown root:root /etc/init.d/nebula
rex doas rc-update add nebula default
rex doas rc-service nebula restart
#! ----------- install ufe
- ssh, 8080 only on nebula
- only 80, 443 to the world

View File

@@ -13,9 +13,10 @@ import uvicorn
from typing import Optional
# Constants
DB_PATH = "/4server/data/contracts/contracts.db"
DB_PATH = "/4server/data/contracts.db"
BIN_PATH = "/4server/sbin"
API_KEY = os.getenv("API_KEY", "your-secret-api-key")
VERSION = "API: 0.0.5"
# FastAPI app
app = FastAPI()
@@ -28,7 +29,6 @@ def verify_api_key(key: str = Depends(api_key_header)):
if key != API_KEY:
raise HTTPException(status_code=403, detail="Unauthorized")
# ---------------------- Database ----------------------
def init_db():
"""Initialize the database with containers table."""
@@ -38,12 +38,18 @@ def init_db():
cursor.execute('''
CREATE TABLE IF NOT EXISTS containers (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
UUID CHAR(36),
location CHAR(100),
UUID CHAR(50),
email CHAR(100),
expires DATE,
tags TEXT,
env TEXT
env TEXT,
affiliate char(30),
image char(50),
history text,
comment text,
domains text,
status char (20).
created DATE
)
''')
conn.commit()
@@ -53,11 +59,17 @@ def init_db():
# ---------------------- Models ----------------------
class ContainerModel(BaseModel):
UUID: str
location: str
email: str
expires: str
tags: Optional[str] = None
env: Optional[str] = None
affiliate: Optional[str] = None
image: Optional[str} = None
history: Optional[str] = None
comment: Optional[str] = None
domains:Optional[str] = None
status: str
created: str
class StartContainerRequest(BaseModel):
@@ -65,29 +77,57 @@ class StartContainerRequest(BaseModel):
email: str
# ---------------------- Routes ----------------------
# ---------------------- CONTAINER Routes ----------------------
@app.get("/", include_in_schema=False)
def redirect_to_odoo():
return RedirectResponse(url="https://ODOO4PROJECTS.com")
@app.post("/container/update", dependencies=[Depends(verify_api_key)])
def update_container(request: UpdateContainerRequest):
--> Insert the new container into the database. Create, if container does not exist
@app.post("/startContainer", dependencies=[Depends(verify_api_key)])
@app.post("/container/start", dependencies=[Depends(verify_api_key)])
def start_container(request: StartContainerRequest):
try:
result = subprocess.run(
[os.path.join(BIN_PATH, "startContainer"), request.uuid, request.email],
capture_output=True,
text=True,
check=True
)
return {"status": "success", "output": result.stdout}
except subprocess.CalledProcessError as e:
print(f"Error in /startContainer: {e.stderr}", file=sys.stderr)
raise HTTPException(status_code=500, detail=f"Command failed: {e.stderr}")
--> refactor, so that only the container is is given in the request. the shell script BIN_PATH/startContainer is called withtge containerid as parameter
@app.post("/container/stop", dependencies=[Depends(verify_api_key)])
def stop_container(request: StopContainerRequest):
--> refactor, so that only the container is is given in the request. the shell script BIN_PATH/stopContainer is called withtge containerid as parameter
@app.post("/container/nuke", dependencies=[Depends(verify_api_key)])
def nuke_container(request: StopContainerRequest):
--> refactor, so that only the container is is given in the request.
when the status of the database is "nuke" then
the shell script BIN_PATH/nukeContainer is called withtge containerid as parameter
@app.post("/container/info", dependencies=[Depends(verify_api_key)])
def info_container(request: InfoContainerRequest):
--> refactor: When no container id is given, query all containers from the database. when a containeris is given, just select that one. Return the result
@app.get("/system", dependencies=[Depends(verify_api_key)])
--> add /container/quota return the disk and ram usage of this container. I think you can obtain this from docker
# ------------------------ SYSTEM Routes
@app.get("/system/containers", dependencies=[Depends(verify_api_key)])
def get_containers():
result = subprocess.run([BIN_PATH+'/getContainers'], capture_output=True, text=True)
if result.returncode != 0:
return Response(content='{"error": "Script failed"}', media_type="application/json", status_code=500)
return Response(content=result.stdout, media_type="application/json")
@app.get("/system/info", dependencies=[Depends(verify_api_key)])
def get_system_info():
return all INFOas JSON
in this function add last_update and return the content of /4server/data/update
if this file does not exist return NONE
return the VERSION as well.
try:
with open("/etc/alpine-release") as f:
version = f.read().strip()
@@ -98,8 +138,11 @@ def get_system_info():
raise HTTPException(status_code=500, detail=str(e))
@app.get("/resources", dependencies=[Depends(verify_api_key)])
@app.get("/system/resources", dependencies=[Depends(verify_api_key)])
def get_resources():
--> consolidate this API into /system/info
mem = psutil.virtual_memory()
disk = psutil.disk_usage("/")
return {
@@ -109,55 +152,10 @@ def get_resources():
}
@app.get("/containers", dependencies=[Depends(verify_api_key)])
def get_containers():
result = subprocess.run([BIN_PATH+'/getContainers'], capture_output=True, text=True)
if result.returncode != 0:
return Response(content='{"error": "Script failed"}', media_type="application/json", status_code=500)
return Response(content=result.stdout, media_type="application/json")
@app.post("/container", dependencies=[Depends(verify_api_key)])
def upsert_container(container: ContainerModel):
try:
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT 1 FROM containers WHERE UUID = ?", (container.UUID,))
exists = cursor.fetchone()
if exists:
cursor.execute("""
UPDATE containers SET
location = ?, email = ?, expires = ?, tags = ?, env = ?
WHERE UUID = ?
""", (
container.location, container.email, container.expires,
container.tags, container.env, container.UUID
))
operation = "update"
else:
cursor.execute("""
INSERT INTO containers (UUID, location, email, expires, tags, env)
VALUES (?, ?, ?, ?, ?, ?)
""", (
container.UUID, container.location, container.email,
container.expires, container.tags, container.env
))
operation = "insert"
conn.commit()
return {"status": "success", "operation": operation}
except Exception as e:
print(f"Error in /container: {e}", file=sys.stderr)
raise HTTPException(status_code=500, detail=str(e))
finally:
conn.close()
# ---------------------- Entry Point ----------------------
if __name__ == "__main__":
print("Version 0.1")
print(VERSION)
init_db()
uvicorn.run(app, host="10.5.0.1", port=8888)

52
app/sbin/start/n8n Executable file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/env bash
exec > /4server/data/startContainer.log 2>&1
echo "$(date '+%Y-%m-%d %H:%M') - startContainer $1"
CONTAINER_NAME="$1"
# Get the hostname of the machine
HOSTNAME=$(hostname)
mkdir -p /4server/data/${CONTAINER_NAME}/n8n
mkdir -p /4server/data/${CONTAINER_NAME}/data
sudo chmod 777 /4server/data/${CONTAINER_NAME}/n8n
sudo chmod 777 /4server/data/${CONTAINER_NAME}/data
# Stop the container if it exists
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
echo "$(date '+%Y-%m-%d %H:%M') - stopping existing container $CONTAINER_NAME"
docker stop "$CONTAINER_NAME"
docker rm "$CONTAINER_NAME"
fi
docker run -d \
--name "$CONTAINER_NAME" \
-p 5678 \
--cap-add=SYS_ADMIN \
--security-opt seccomp=unconfined \
--restart=always \
-e N8N_HOST="${CONTAINER_NAME}.od8n.com" \
-e N8N_PORT=5678 \
-e N8N_PROTOCOL=https \
-e NODE_ENV=production \
-e WEBHOOK_URL="https://${CONTAINER_NAME}.od8n.com/" \
-e GENERIC_TIMEZONE="UTC-3" \
-v "/4server/data/${CONTAINER_NAME}/n8n:/home/node/.n8n" \
-v "/4server/data/${CONTAINER_NAME}/data:/data" \
--label "traefik.enable=true" \
--label "traefik.http.routers.${CONTAINER_NAME}.rule=Host(\`${CONTAINER_NAME}.od8n.com\`)" \
--label "traefik.http.routers.${CONTAINER_NAME}.entrypoints=web,websecure" \
--label "traefik.http.routers.${CONTAINER_NAME}.tls=true" \
--label "traefik.http.routers.${CONTAINER_NAME}.tls.certresolver=production" \
--label "traefik.http.services.${CONTAINER_NAME}.loadbalancer.server.port=5678" \
--network docker-compose_4projects \
n8nio/n8n:latest
echo "Started $1"

54
app/sbin/startContainer Executable file → Normal file
View File

@@ -1,52 +1,14 @@
#!/usr/bin/env bash
exec > /4server/data/startContainer.log 2>&1
this script gets a container UUID
echo "$(date '+%Y-%m-%d %H:%M') - startContainer $1"
Wtrite a bash script, that gets all info out off the Sqlite3 Database usind the UUID and stores the values in environment variables
setr the BIN_BATH to /4srver/sbin/
CONTAINER_NAME="$1"
the uuid looks like xxx-xxx-xxxx-xxxx-xxxx-....
# Get the hostname of the machine
HOSTNAME=$(hostname)
get the second number
mkdir -p /4server/data/${CONTAINER_NAME}/n8n
mkdir -p /4server/data/${CONTAINER_NAME}/data
When the number is 001 call the script BIN_PATH/start/n8n
When the number is 002 call the sctipr BIN_ÜATH/start/ODOO18
WHen the number is 003 call the script BIN_PATH/start/ODOO19
sudo chmod 777 /4server/data/${CONTAINER_NAME}/n8n
sudo chmod 777 /4server/data/${CONTAINER_NAME}/data
# Stop the container if it exists
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
echo "$(date '+%Y-%m-%d %H:%M') - stopping existing container $CONTAINER_NAME"
docker stop "$CONTAINER_NAME"
docker rm "$CONTAINER_NAME"
fi
docker run -d \
--name "$CONTAINER_NAME" \
-p 5678 \
--cap-add=SYS_ADMIN \
--security-opt seccomp=unconfined \
--restart=always \
-e N8N_HOST="${CONTAINER_NAME}.od8n.com" \
-e N8N_PORT=5678 \
-e N8N_PROTOCOL=https \
-e NODE_ENV=production \
-e WEBHOOK_URL="https://${CONTAINER_NAME}.od8n.com/" \
-e GENERIC_TIMEZONE="UTC-3" \
-v "/4server/data/${CONTAINER_NAME}/n8n:/home/node/.n8n" \
-v "/4server/data/${CONTAINER_NAME}/data:/data" \
--label "traefik.enable=true" \
--label "traefik.http.routers.${CONTAINER_NAME}.rule=Host(\`${CONTAINER_NAME}.od8n.com\`)" \
--label "traefik.http.routers.${CONTAINER_NAME}.entrypoints=web,websecure" \
--label "traefik.http.routers.${CONTAINER_NAME}.tls=true" \
--label "traefik.http.routers.${CONTAINER_NAME}.tls.certresolver=production" \
--label "traefik.http.services.${CONTAINER_NAME}.loadbalancer.server.port=5678" \
--network docker-compose_4projects \
n8nio/n8n:latest
echo "Done $1"

View File

@@ -23,7 +23,7 @@ services:
- 8080:8080
volumes:
- /run/docker.sock:/run/docker.sock:ro
- /4server/config/traefik/etc:/etc/traefik
- /4server/data/traefik/config/traefik/etc:/etc/traefik
- /4server/data/traefik/certs:/certs
- /4server/data/traefik/traefik-logs:/var/log/traefik
networks:

1
app/templates/hostname Normal file
View File

@@ -0,0 +1 @@
{{hostname}}

View File

12
app/templates/init.d/nebula Executable file
View File

@@ -0,0 +1,12 @@
#!/sbin/openrc-run
command="/usr/bin/nebula"
command_args="-config /etc/nebula/config.yml"
command_background="yes"
pidfile="/run/nebula.pid"
name="nebula"
depend() {
need localmount
after networking
}

17
app/templates/init.d/ping_check Executable file
View File

@@ -0,0 +1,17 @@
#!/sbin/openrc-run
description="Ping 192.168.9.1 every minute"
pidfile="/run/ping_check.pid"
start() {
ebegin "Starting ping_check service"
start-stop-daemon --start --background --make-pidfile --pidfile $pidfile --exec /bin/sh -- -c "while true; do ping -c 1 192.168.9.1; sleep 60; done"
eend $?
}
stop() {
ebegin "Stopping ping_check service"
start-stop-daemon --stop --pidfile $pidfile
eend $?
}

View File

@@ -1,12 +1,10 @@
pki:
ca: /etc/nebula/ca.crt
cert: /etc/nebula/{{ hostname }}.crt
key: /etc/nebula/{{ hostname }}.key
cert: /etc/nebula/host.crt
key: /etc/nebula/host.key
static_host_map:
"192.168.9.1": ["167.71.79.60:4242"]
lighthouse:
# am_lighthouse is used to enable lighthouse functionality for a node. This should ONLY be true on nodes
# you have configured to be lighthouses in your network
am_lighthouse: false
interval: 60
hosts:
@@ -50,7 +48,7 @@ firewall:
host: any
inbound:
- port: any
- port: any #ping
proto: icmp
host: any
@@ -66,22 +64,6 @@ firewall:
-admin
- port: 3001
proto: tcp
groups:
-admin
- port: 8080
proto: tcp
groups:
-admin

View File

@@ -0,0 +1,8 @@
write a curl request that creatrs a container with
a uuid starting with 000-001-....
email o.arnold@projektbox.de
domain n8n.local
and the rest with sane info

5
app/test/start_container Normal file
View File

@@ -0,0 +1,5 @@
start the container
000-001-
add a random uuid

View File

@@ -6,38 +6,24 @@ rex doas chmod 777 /4server
rex mkdir -p /4server/data
### PACKAGES
rex doas apk update
rex doas apk add rsync
echo "prsync ./etc/repositories"
prsync -h "$hosts_file" -avz ./etc/repositories /4server/repositories
rex doas mv /4server/repositories /etc/apk/
rex doas apk update
rex doas apk upgrade
template templates/repositories /etc/apk/repositories ./host_vars
rex doas apk update && upgrade
rex doas apk add jq rsync mc vim docker docker-compose htop linux-lts sqlite bash
### own bins
prsync -h "$hosts_file" -avz ./sbin/ /4server/sbin/
prsync -h "$hosts_file" -avz ./etc/.bashrc /home/oliver/
### API
#INSTALL API KEYS
template templates/4server /4server/4server ./host_vars
rex doas mv /4server/4server /etc/4server
template templates/4server /etc/4server ./host_vars
#INSTALL API SERVICE
template templates/4server-api /4server/4server-api ./host_vars/
rex doas mv /4server/4server-api /etc/init.d/4server-api
template templates/init.d/4server-api /etc/init.d/4server-api ./host_vars/
rex doas chmod 0755 /etc/init.d/4server-api
rex doas chown root:root /etc/init.d/4server-api
rex doas rc-update add 4server-api default
rex doas rc-service 4server-api restart
rex doas rc-update add 4server-api default
### Infrastructure
@@ -45,14 +31,12 @@ rex doas rc-update add 4server-api default
rex doas rc-service docker start
rex doas rc-update add docker boot
rex mkdir -p /4server/config/
template templates/traefik.yaml /4server/config/traefik.yaml ./host_vars
rex mkdir -p /4server/data/treafik/config/
template templates/traefik.yaml /4server/data/traefik/config/traefik.yaml ./host_vars
rex mkdir -p /4server/data/traefik/etc/certs
prsync -h "$hosts_file" -avz ./etc/certs/* /4server/data/traefik/etc/certs/
template templates/docker-compose.yml /4server/docker-compose.yml ./host_vars
rex doas docker-compose -f /4server/docker-compose.yml up -d