diff --git a/app/host_vars/dev b/app/host_vars/dev index 15411b6..cb3c613 100644 --- a/app/host_vars/dev +++ b/app/host_vars/dev @@ -1 +1,4 @@ API_KEY=4h6lDzAOVksuCqmhEB3 +hostname="dev" +nebula_key="123" +nebula_cert="456" diff --git a/app/host_vars/boston b/app/host_vars/vault/boston similarity index 100% rename from app/host_vars/boston rename to app/host_vars/vault/boston diff --git a/app/host_vars/london b/app/host_vars/vault/london similarity index 100% rename from app/host_vars/london rename to app/host_vars/vault/london diff --git a/app/host_vars/mumbai b/app/host_vars/vault/mumbai similarity index 100% rename from app/host_vars/mumbai rename to app/host_vars/vault/mumbai diff --git a/app/host_vars/saopaulo b/app/host_vars/vault/saopaulo similarity index 100% rename from app/host_vars/saopaulo rename to app/host_vars/vault/saopaulo diff --git a/app/nebula/nebula-cert b/app/nebula/nebula-cert deleted file mode 100755 index 78f7ad9..0000000 Binary files a/app/nebula/nebula-cert and /dev/null differ diff --git a/app/nebula_install b/app/nebula_install deleted file mode 100755 index 71dbf27..0000000 --- a/app/nebula_install +++ /dev/null @@ -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 - - diff --git a/app/onboarding b/app/onboarding new file mode 100755 index 0000000..5522050 --- /dev/null +++ b/app/onboarding @@ -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 diff --git a/app/sbin/api b/app/sbin/api index 29a6cd8..1c90ebd 100755 --- a/app/sbin/api +++ b/app/sbin/api @@ -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) diff --git a/app/nebula/nebula b/app/sbin/nebula similarity index 100% rename from app/nebula/nebula rename to app/sbin/nebula diff --git a/app/sbin/start/n8n b/app/sbin/start/n8n new file mode 100755 index 0000000..2b489f9 --- /dev/null +++ b/app/sbin/start/n8n @@ -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" diff --git a/app/sbin/startContainer b/app/sbin/startContainer old mode 100755 new mode 100644 index b15fe13..abaa384 --- a/app/sbin/startContainer +++ b/app/sbin/startContainer @@ -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" diff --git a/app/templates/docker-compose.yml b/app/templates/docker-compose.yml index ac955ad..7783d86 100644 --- a/app/templates/docker-compose.yml +++ b/app/templates/docker-compose.yml @@ -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: diff --git a/app/templates/hostname b/app/templates/hostname new file mode 100644 index 0000000..12ef44b --- /dev/null +++ b/app/templates/hostname @@ -0,0 +1 @@ +{{hostname}} diff --git a/app/templates/4server-api b/app/templates/init.d/4server-api old mode 100644 new mode 100755 similarity index 100% rename from app/templates/4server-api rename to app/templates/init.d/4server-api diff --git a/app/templates/init.d/nebula b/app/templates/init.d/nebula new file mode 100755 index 0000000..73ef02e --- /dev/null +++ b/app/templates/init.d/nebula @@ -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 +} + diff --git a/app/templates/init.d/ping_check b/app/templates/init.d/ping_check new file mode 100755 index 0000000..43672d7 --- /dev/null +++ b/app/templates/init.d/ping_check @@ -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 $? +} + diff --git a/app/nebula/config.yml b/app/templates/nebula/config.yml similarity index 69% rename from app/nebula/config.yml rename to app/templates/nebula/config.yml index 828f944..f886d82 100644 --- a/app/nebula/config.yml +++ b/app/templates/nebula/config.yml @@ -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 - - - - - - - diff --git a/app/etc/repositories b/app/templates/repositories similarity index 100% rename from app/etc/repositories rename to app/templates/repositories diff --git a/app/test/create_container b/app/test/create_container new file mode 100644 index 0000000..9c3681f --- /dev/null +++ b/app/test/create_container @@ -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 + + + diff --git a/app/test/start_container b/app/test/start_container new file mode 100644 index 0000000..059ce0c --- /dev/null +++ b/app/test/start_container @@ -0,0 +1,5 @@ +start the container + +000-001- + +add a random uuid diff --git a/app/update b/app/update index 228d22e..892fd78 100755 --- a/app/update +++ b/app/update @@ -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