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 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 from typing import Optional
# Constants # Constants
DB_PATH = "/4server/data/contracts/contracts.db" DB_PATH = "/4server/data/contracts.db"
BIN_PATH = "/4server/sbin" BIN_PATH = "/4server/sbin"
API_KEY = os.getenv("API_KEY", "your-secret-api-key") API_KEY = os.getenv("API_KEY", "your-secret-api-key")
VERSION = "API: 0.0.5"
# FastAPI app # FastAPI app
app = FastAPI() app = FastAPI()
@@ -28,7 +29,6 @@ def verify_api_key(key: str = Depends(api_key_header)):
if key != API_KEY: if key != API_KEY:
raise HTTPException(status_code=403, detail="Unauthorized") raise HTTPException(status_code=403, detail="Unauthorized")
# ---------------------- Database ---------------------- # ---------------------- Database ----------------------
def init_db(): def init_db():
"""Initialize the database with containers table.""" """Initialize the database with containers table."""
@@ -38,12 +38,18 @@ def init_db():
cursor.execute(''' cursor.execute('''
CREATE TABLE IF NOT EXISTS containers ( CREATE TABLE IF NOT EXISTS containers (
ID INTEGER PRIMARY KEY AUTOINCREMENT, ID INTEGER PRIMARY KEY AUTOINCREMENT,
UUID CHAR(36), UUID CHAR(50),
location CHAR(100),
email CHAR(100), email CHAR(100),
expires DATE, expires DATE,
tags TEXT, 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() conn.commit()
@@ -53,11 +59,17 @@ def init_db():
# ---------------------- Models ---------------------- # ---------------------- Models ----------------------
class ContainerModel(BaseModel): class ContainerModel(BaseModel):
UUID: str UUID: str
location: str
email: str email: str
expires: str expires: str
tags: Optional[str] = None tags: Optional[str] = None
env: 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): class StartContainerRequest(BaseModel):
@@ -65,29 +77,57 @@ class StartContainerRequest(BaseModel):
email: str email: str
# ---------------------- Routes ---------------------- # ---------------------- CONTAINER Routes ----------------------
@app.get("/", include_in_schema=False) @app.get("/", include_in_schema=False)
def redirect_to_odoo(): def redirect_to_odoo():
return RedirectResponse(url="https://ODOO4PROJECTS.com") 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): def start_container(request: StartContainerRequest):
try: --> refactor, so that only the container is is given in the request. the shell script BIN_PATH/startContainer is called withtge containerid as parameter
result = subprocess.run(
[os.path.join(BIN_PATH, "startContainer"), request.uuid, request.email], @app.post("/container/stop", dependencies=[Depends(verify_api_key)])
capture_output=True, def stop_container(request: StopContainerRequest):
text=True, --> refactor, so that only the container is is given in the request. the shell script BIN_PATH/stopContainer is called withtge containerid as parameter
check=True
) @app.post("/container/nuke", dependencies=[Depends(verify_api_key)])
return {"status": "success", "output": result.stdout} def nuke_container(request: StopContainerRequest):
except subprocess.CalledProcessError as e: --> refactor, so that only the container is is given in the request.
print(f"Error in /startContainer: {e.stderr}", file=sys.stderr) when the status of the database is "nuke" then
raise HTTPException(status_code=500, detail=f"Command failed: {e.stderr}") 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(): 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: try:
with open("/etc/alpine-release") as f: with open("/etc/alpine-release") as f:
version = f.read().strip() version = f.read().strip()
@@ -98,8 +138,11 @@ def get_system_info():
raise HTTPException(status_code=500, detail=str(e)) 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(): def get_resources():
--> consolidate this API into /system/info
mem = psutil.virtual_memory() mem = psutil.virtual_memory()
disk = psutil.disk_usage("/") disk = psutil.disk_usage("/")
return { 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 ---------------------- # ---------------------- Entry Point ----------------------
if __name__ == "__main__": if __name__ == "__main__":
print("Version 0.1") print(VERSION)
init_db() init_db()
uvicorn.run(app, host="10.5.0.1", port=8888) 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 this script gets a container UUID
exec > /4server/data/startContainer.log 2>&1
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 get the second number
HOSTNAME=$(hostname)
mkdir -p /4server/data/${CONTAINER_NAME}/n8n When the number is 001 call the script BIN_PATH/start/n8n
mkdir -p /4server/data/${CONTAINER_NAME}/data 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 - 8080:8080
volumes: volumes:
- /run/docker.sock:/run/docker.sock:ro - /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/certs:/certs
- /4server/data/traefik/traefik-logs:/var/log/traefik - /4server/data/traefik/traefik-logs:/var/log/traefik
networks: 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: pki:
ca: /etc/nebula/ca.crt ca: /etc/nebula/ca.crt
cert: /etc/nebula/{{ hostname }}.crt cert: /etc/nebula/host.crt
key: /etc/nebula/{{ hostname }}.key key: /etc/nebula/host.key
static_host_map: static_host_map:
"192.168.9.1": ["167.71.79.60:4242"] "192.168.9.1": ["167.71.79.60:4242"]
lighthouse: 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 am_lighthouse: false
interval: 60 interval: 60
hosts: hosts:
@@ -50,7 +48,7 @@ firewall:
host: any host: any
inbound: inbound:
- port: any - port: any #ping
proto: icmp proto: icmp
host: any host: any
@@ -66,22 +64,6 @@ firewall:
-admin -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 rex mkdir -p /4server/data
### PACKAGES ### PACKAGES
rex doas apk update template templates/repositories /etc/apk/repositories ./host_vars
rex doas apk add rsync rex doas apk update && upgrade
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
rex doas apk add jq rsync mc vim docker docker-compose htop linux-lts sqlite bash rex doas apk add jq rsync mc vim docker docker-compose htop linux-lts sqlite bash
### own bins ### own bins
prsync -h "$hosts_file" -avz ./sbin/ /4server/sbin/ prsync -h "$hosts_file" -avz ./sbin/ /4server/sbin/
prsync -h "$hosts_file" -avz ./etc/.bashrc /home/oliver/
### API ### API
#INSTALL API KEYS #INSTALL API KEYS
template templates/4server /4server/4server ./host_vars template templates/4server /etc/4server ./host_vars
rex doas mv /4server/4server /etc/4server
#INSTALL API SERVICE #INSTALL API SERVICE
template templates/4server-api /4server/4server-api ./host_vars/ template templates/init.d/4server-api /etc/init.d/4server-api ./host_vars/
rex doas mv /4server/4server-api /etc/init.d/4server-api
rex doas chmod 0755 /etc/init.d/4server-api rex doas chmod 0755 /etc/init.d/4server-api
rex doas chown root:root /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-update add 4server-api default
rex doas rc-service 4server-api restart rex doas rc-service 4server-api restart
rex doas rc-update add 4server-api default
### Infrastructure ### Infrastructure
@@ -45,14 +31,12 @@ rex doas rc-update add 4server-api default
rex doas rc-service docker start rex doas rc-service docker start
rex doas rc-update add docker boot rex doas rc-update add docker boot
rex mkdir -p /4server/config/ rex mkdir -p /4server/data/treafik/config/
template templates/traefik.yaml /4server/config/traefik.yaml ./host_vars template templates/traefik.yaml /4server/data/traefik/config/traefik.yaml ./host_vars
rex mkdir -p /4server/data/traefik/etc/certs rex mkdir -p /4server/data/traefik/etc/certs
prsync -h "$hosts_file" -avz ./etc/certs/* /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 template templates/docker-compose.yml /4server/docker-compose.yml ./host_vars
rex doas docker-compose -f /4server/docker-compose.yml up -d rex doas docker-compose -f /4server/docker-compose.yml up -d