Compare commits

...
12 Commits
Author SHA1 Message Date
oliver 920a7de568 db access 2026-11-08 05:08:17 -03:00
oliver 44eaced13d working 2026-10-21 17:27:33 -03:00
oliver eeabd35f8d working 2026-10-17 18:57:34 -03:00
oliver de583713da c 2026-10-15 18:52:10 -03:00
oliver 10f0422155 odoo 2026-10-15 18:33:33 -03:00
oliver 7263c859a2 fixes 2026-10-15 17:45:09 -03:00
oliver cd187b6d3d k 2026-10-15 05:05:31 -03:00
oliver 8772004ff6 working 2026-10-14 18:35:16 -03:00
oliver 4868517abb update 2026-10-14 10:27:30 -03:00
oliver a915a87ed9 works 2026-10-14 10:18:40 -03:00
oliver 722e499089 s 2026-10-14 10:00:09 -03:00
oliver d25a9a94a3 n8n + hostname 2026-10-14 07:26:16 -03:00
14 changed files with 235 additions and 33 deletions

No files matched your search

+6 -6
View File
@@ -1,8 +1,3 @@
#Host dev
# Hostname dev
# User oliver
# Port 2222
Host dev Host dev
Hostname dev Hostname dev
User 4server User 4server
@@ -30,7 +25,7 @@ Host meppel
IdentityFile /app/host_vars/meppel/meppel IdentityFile /app/host_vars/meppel/meppel
Host sydney Host sydney
Hostname 192.168.9.22 Hostname 192.168.9.14
User 4server User 4server
IdentityFile /app/host_vars/sydney/sydney IdentityFile /app/host_vars/sydney/sydney
@@ -38,3 +33,8 @@ Host saopaulo
Hostname 192.168.9.11 Hostname 192.168.9.11
User 4server User 4server
IdentityFile /app/host_vars/saopaulo/saopaulo IdentityFile /app/host_vars/saopaulo/saopaulo
Host sydney2
Hostname 192.168.9.22
User 4server
IdentityFile /app/host_vars/sydney2/sydney2
+3
View File
@@ -15,3 +15,6 @@
192.168.9.21 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDtexcutExMflSRPJOwGPuZx49c+ZUMoElNPNntXONOuVZ8jM+zzA/4s+HCj+RWdHMnarLcNJjwRZRq7JWruqmr1EN9eNmvu13cLCKZr6Ape1gt8VmMhvQ9nA7eMx3UdvnWgXjLCfJy+BKh2XVAneM5lOSPMcyQlcACrLQVkse9EKhxhV5nEjXKYxSNetIPK9PxglXznpC8IpuWlXnDH2R8vDhdvBmBFTKOjN5Wa+GrMfElWeQOjyCpNcMVYohvV87VN6FxHQTADFTm2CKy/W7pnM8rI55ZbBIMfvLyhpM+vtFh1sJlIZSFnn+ytMUImNEAgBDI3fCpwZ99zeLViGhQJlBkdCUI+JJK9XJjpcOMNydeWh142RGU6juPuSLOZPqKNc3BpZYgPY0vMDgDWgT9AcYup3rAJ/UnUnhsxiT2h/gx7+t/j9xg01BQF5S6mezaueuavHCh9MvAzXiJXR8zanhl/Hh9BKgIAFrZh71CzP/PYG33BKCe9DXA09aJrf8= 192.168.9.21 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDtexcutExMflSRPJOwGPuZx49c+ZUMoElNPNntXONOuVZ8jM+zzA/4s+HCj+RWdHMnarLcNJjwRZRq7JWruqmr1EN9eNmvu13cLCKZr6Ape1gt8VmMhvQ9nA7eMx3UdvnWgXjLCfJy+BKh2XVAneM5lOSPMcyQlcACrLQVkse9EKhxhV5nEjXKYxSNetIPK9PxglXznpC8IpuWlXnDH2R8vDhdvBmBFTKOjN5Wa+GrMfElWeQOjyCpNcMVYohvV87VN6FxHQTADFTm2CKy/W7pnM8rI55ZbBIMfvLyhpM+vtFh1sJlIZSFnn+ytMUImNEAgBDI3fCpwZ99zeLViGhQJlBkdCUI+JJK9XJjpcOMNydeWh142RGU6juPuSLOZPqKNc3BpZYgPY0vMDgDWgT9AcYup3rAJ/UnUnhsxiT2h/gx7+t/j9xg01BQF5S6mezaueuavHCh9MvAzXiJXR8zanhl/Hh9BKgIAFrZh71CzP/PYG33BKCe9DXA09aJrf8=
192.168.9.22 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMO5VhveQe76kEOdVqrdoTwW1fNzmgDzZNBznFEC4ohtXes0VMtJR02lhc+55XTIUX+EDxBtAh8U+kJpFeLetMU= 192.168.9.22 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMO5VhveQe76kEOdVqrdoTwW1fNzmgDzZNBznFEC4ohtXes0VMtJR02lhc+55XTIUX+EDxBtAh8U+kJpFeLetMU=
192.168.9.21 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGlzLZWNjSaDuDd4e66LoBizY5j+QCsifIIxkvX4CrzP/AqAgWDEEgT+pAXBFkNJlBR6TDFJ0bIdwZTbcq8/72E= 192.168.9.21 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGlzLZWNjSaDuDd4e66LoBizY5j+QCsifIIxkvX4CrzP/AqAgWDEEgT+pAXBFkNJlBR6TDFJ0bIdwZTbcq8/72E=
192.168.9.14 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBoHCfS8EQBWo2v5m/D2S3Sy97yZcVbbLJyW2sf+Rd7c
192.168.9.14 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC3LOvVI7S+/YYRpe/SxElLVn/bRg85PtH6MeYS7DMot6Uj3SnAmOxyVmU5j9dxS+039EjoLjMr+ppx+sRqVtr78q8GhKXmCKmp2EDcieEbJ9h66Drb8JoOuQJFyL3TiXwa9MNFy5qkBahwnhF+1wuV2a82/irnqYvGFFDuNuzXRpzJlZPPQddMFryj/9J3Qu2E1vlXw30Ap1EQD0+I/Zlifj5BQpJMA6ZpOnmXPY4k3qnY/tnyufqfZJQE7DOdxY2NOPOOOYt8JsG0gaydk7+Kt8/01TLBGVKgfmlbKTkKQYQUgfc87Rx1of4AaZMkBnBjTto/x+DIaFh3BvivEUSHbF/9NYL9/cj+Alb9x5qXo4bW6TFFhC/RVPnQ0XWKaH0cDFUZ7sgQ6XXapXYvojZ4TL8SZ3xzRt3cB2t10BQGgkEOKSJ7sDltxEthHhQDzy2pQg6iuFPAL1ss4oz/UiZwTRJ3lp1kto2wVU2JzIci46GfDEV63wOsw8aubQ2LXQM=
192.168.9.14 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMnz/R4sp9QPwJ4VRnsrz9EBjf1E0YuzUEC0TlptUXuyhVcUB4ZSbvd67PsXOuVxQiIIppqnZWzNL1w5dCLJoyU=
+1 -1
View File
@@ -7,7 +7,7 @@ fi
host_vars_dir="/app/host_vars" host_vars_dir="/app/host_vars"
keys=(NEBULA_CA API_KEY HOSTNAME NEBULA_CRT NEBULA_KEY SSH_PRIVATE SSH_PUBLIC) keys=(NEBULA_CA API_KEY HOSTNAME NEBULA_CRT NEBULA_KEY SSH_PRIVATE SSH_PUBLIC PROVIDER COST CONTRACT_END )
NEBULA_CA=$(<"$host_vars_dir/ca.crt") NEBULA_CA=$(<"$host_vars_dir/ca.crt")
+3 -4
View File
@@ -6,12 +6,11 @@ rex doas apk update
rex doas apk add bash doas rsync openssh linux-lts rex doas apk add bash doas rsync openssh linux-lts
### activate lts kerner ### activate lts kerner
template templates/extlinux.conf /boot/extlinux.conf #template templates/extlinux.conf /boot/extlinux.conf
rex doas chown root:root /boot/extlinux.conf #rex doas chown root:root /boot/extlinux.conf
rex doas chmod 644 /boot/extlinux.conf #rex doas chmod 644 /boot/extlinux.conf
# ass swap file ????
rex doas mkdir -p /4server rex doas mkdir -p /4server
rex doas chmod 777 /4server rex doas chmod 777 /4server
+14
View File
@@ -65,6 +65,20 @@ doas docker exec "$UUID" rm -rf /root/.local/share/Odoo/filestore
if ! doas docker exec "$UUID" odoo db --db_host beedb -w "$ODOO_DB_PASSWORD" -r "$UUID" load "$UUID" $FILENAME -f; then if ! doas docker exec "$UUID" odoo db --db_host beedb -w "$ODOO_DB_PASSWORD" -r "$UUID" load "$UUID" $FILENAME -f; then
echo "ERROR: odoo db load failed - putting the old filestore back" echo "ERROR: odoo db load failed - putting the old filestore back"
# Restrict database access to its UUID owner
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" \
-p "$POSTGRES_PORT" -d postgres \
-v ON_ERROR_STOP=1 \
-c "REVOKE CONNECT, TEMPORARY ON DATABASE \"$UUID\" FROM PUBLIC;
GRANT CONNECT ON DATABASE \"$UUID\" TO \"$UUID\";
ALTER DATABASE \"$UUID\" OWNER TO \"$UUID\";
ALTER ROLE \"$UUID\" NOCREATEDB;"
doas docker exec "$UUID" sh -c "[ -d $OLD_FS ] && rm -rf /home/odoo/.local/share/Odoo/filestore && mv $OLD_FS /home/odoo/.local/share/Odoo/filestore; true" doas docker exec "$UUID" sh -c "[ -d $OLD_FS ] && rm -rf /home/odoo/.local/share/Odoo/filestore && mv $OLD_FS /home/odoo/.local/share/Odoo/filestore; true"
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \ PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
-h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -p "$POSTGRES_PORT" -d postgres \ -h "$POSTGRES_HOST" -U "$POSTGRES_ADMIN_USER" -p "$POSTGRES_PORT" -d postgres \
+55 -19
View File
@@ -17,6 +17,14 @@ from fastapi.responses import PlainTextResponse, RedirectResponse
from fastapi.security.api_key import APIKeyHeader from fastapi.security.api_key import APIKeyHeader
from pydantic import BaseModel from pydantic import BaseModel
import logging
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s %(levelname)s [%(name)s] %(message)s",
)
log = logging.getLogger("4server.api")
# ---------------------- Constants ---------------------- # ---------------------- Constants ----------------------
DB_PATH = "/4server/data/contracts.db" DB_PATH = "/4server/data/contracts.db"
BIN_PATH = "/4server/sbin" BIN_PATH = "/4server/sbin"
@@ -89,13 +97,29 @@ def init_db():
def execute_db(query: str, params: tuple = (), fetch: bool = False): def execute_db(query: str, params: tuple = (), fetch: bool = False):
log.debug("DB open: path=%s fetch=%s", DB_PATH, fetch)
conn = sqlite3.connect(DB_PATH) conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row conn.row_factory = sqlite3.Row
cursor = conn.cursor() cursor = conn.cursor()
try:
cursor.execute(query, params) cursor.execute(query, params)
conn.commit() conn.commit()
rowcount = cursor.rowcount
data = cursor.fetchall() if fetch else None data = cursor.fetchall() if fetch else None
except Exception as exc:
log.error(
"DB error: %s | query=%s | params=%s", exc, query, params
)
raise
finally:
conn.close() conn.close()
log.debug(
"DB done: rowcount=%s rows=%s | query=%s | params=%s",
rowcount,
len(data) if data else 0,
query,
params,
)
if data and fetch: if data and fetch:
return [dict(row) for row in data] return [dict(row) for row in data]
return None return None
@@ -160,22 +184,6 @@ class ImageRequest(BaseModel):
image: str image: str
# ---------------------- Routes ----------------------
@app.get("/", include_in_schema=False)
def redirect_to_odoo():
return RedirectResponse(url="https://ODOO4PROJECTS.com")
import json
from typing import Any, Dict, Optional
from fastapi import Depends, FastAPI
from fastapi.responses import RedirectResponse
from pydantic import BaseModel
app = FastAPI()
# ---------------------- Routes ---------------------- # ---------------------- Routes ----------------------
@app.get("/", include_in_schema=False) @app.get("/", include_in_schema=False)
def redirect_to_odoo(): def redirect_to_odoo():
@@ -184,11 +192,24 @@ def redirect_to_odoo():
@app.post("/container/update", dependencies=[Depends(verify_api_key)]) @app.post("/container/update", dependencies=[Depends(verify_api_key)])
def update_container(request: ContainerModel): def update_container(request: ContainerModel):
payload = (
request.model_dump()
if hasattr(request, "model_dump")
else request.dict()
)
log.info("update_container called: UUID=%r payload=%s", request.UUID, payload)
# Fetch existing record # Fetch existing record
existing = execute_db( existing = execute_db(
"SELECT * FROM containers WHERE UUID = ?", (request.UUID,), fetch=True "SELECT * FROM containers WHERE UUID = ?", (request.UUID,), fetch=True
) )
log.info(
"update_container lookup: UUID=%r existing=%s",
request.UUID,
existing,
)
if not existing: if not existing:
log.info("update_container: no record for UUID=%r -> INSERT", request.UUID)
# If record does not exist, insert a new one with all given fields # If record does not exist, insert a new one with all given fields
execute_db( execute_db(
""" """
@@ -221,15 +242,21 @@ def update_container(request: ContainerModel):
request.env_list, request.env_list,
), ),
) )
inserted = execute_db(
"SELECT * FROM containers WHERE UUID = ?", (request.UUID,), fetch=True
)
log.info("update_container INSERT result: %s", inserted)
return {"UUID": request.UUID, "status": "created"} return {"UUID": request.UUID, "status": "created"}
# Existing record found, do partial update # Existing record found, do partial update
existing = existing[0] # Assuming fetch returns list of dicts existing = existing[0] # Assuming fetch returns list of dicts
log.info("update_container: existing row before update=%s", existing)
updates = {} updates = {}
params = [] params = []
# Only add fields that are not None in the request # Only add fields that are not None in the request
for field in ContainerModel.__fields__: model_fields = getattr(ContainerModel, "model_fields", None) or ContainerModel.__fields__
for field in model_fields:
if field == "UUID": if field == "UUID":
continue continue
value = getattr(request, field) value = getattr(request, field)
@@ -237,17 +264,26 @@ def update_container(request: ContainerModel):
updates[field] = value updates[field] = value
params.append(value) params.append(value)
log.info("update_container: computed updates=%s params=%s", updates, params)
if updates: if updates:
# Build SQL dynamically # Build SQL dynamically
set_clause = ", ".join(f"{k}=?" for k in updates.keys()) set_clause = ", ".join(f"{k}=?" for k in updates.keys())
params.append(request.UUID) # UUID for WHERE clause params.append(request.UUID) # UUID for WHERE clause
execute_db(f"UPDATE containers SET {set_clause} WHERE UUID=?", tuple(params)) sql = f"UPDATE containers SET {set_clause} WHERE UUID=?"
log.info("update_container: executing SQL=%s params=%s", sql, tuple(params))
execute_db(sql, tuple(params))
after = execute_db(
"SELECT * FROM containers WHERE UUID = ?", (request.UUID,), fetch=True
)
log.info("update_container: row after update=%s", after)
return { return {
"UUID": request.UUID, "UUID": request.UUID,
"status": "updated", "status": "updated",
"fields_updated": list(updates.keys()), "fields_updated": list(updates.keys()),
} }
log.info("update_container: no non-None fields supplied -> no_change")
return {"UUID": request.UUID, "status": "no_change"} return {"UUID": request.UUID, "status": "no_change"}
@@ -257,7 +293,7 @@ def start_container(request: UUIDRequest):
@app.post("/container/restartAllContainers", dependencies=[Depends(verify_api_key)]) @app.post("/container/restartAllContainers", dependencies=[Depends(verify_api_key)])
def start_container(request: ImageRequest): def restart_all_containers_by_image(request: ImageRequest):
return {"message": run_command([f"{BIN_PATH}/restartContainers", request.image])} return {"message": run_command([f"{BIN_PATH}/restartContainers", request.image])}
+25
View File
@@ -36,9 +36,34 @@ def read_file(path):
return None return None
def read_env_file(path, keys):
"""Read KEY=VALUE lines from path and return the requested keys."""
result = {key: None for key in keys}
try:
with open(path) as f:
for line in f:
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
if line.startswith("export "):
line = line[len("export "):].lstrip()
key, value = line.split("=", 1)
key = key.strip()
if key in result:
result[key] = value.strip().strip("\"'")
except (FileNotFoundError, PermissionError):
pass
return result
def main(): def main():
audit = {} audit = {}
# Contract info from /etc/4server
audit.update(
read_env_file("/etc/4server", ["PROVIDER", "COST", "CONTRACT_END"])
)
# Container identity # Container identity
audit["container_id"] = os.environ.get("HOSTNAME") audit["container_id"] = os.environ.get("HOSTNAME")
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
# checkFilestoreAll — check the filestore of every active container.
# Runs checkFilestore for each UUID returned by activeContainers.
# Output: "<UUID> OK" or "<UUID> NOK" per container.
SBIN_DIR="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"
active_uuids() {
"$SBIN_DIR/activeContainers" | awk 'NF && $1 != "uuid" && $1 !~ /^-/ {print $1}'
}
failed=0
while read -r UUID; do
[[ -n "$UUID" ]] || continue
if "$SBIN_DIR/checkFilestore" "$UUID" >/dev/null 2>&1; then
echo "$UUID OK"
else
echo "$UUID NOK"
failed=1
fi
done < <(active_uuids)
exit "$failed"
+1 -1
View File
@@ -73,7 +73,7 @@ chmod 777 ${GIT_DIR}
touch ${GIT_DIR}keys/id_rsa.pub touch ${GIT_DIR}keys/id_rsa.pub
echo "git clone \"ssh://git@${UUID}.odoo4projects.com:${PORT}/git-server/repos/odoo.git\"" > "${ETC_DIR}/gitpath" echo "git clone \"ssh://git@${UUID}.$HOSTNAME.odoo4projects.com:${PORT}/git-server/repos/odoo.git\"" > "${ETC_DIR}/gitpath"
echo "$(date '+%Y-%m-%d %H:%M:%S') Wrote git clone path for $UUID to ${ETC_DIR}gitpath (SSH port $PORT)" echo "$(date '+%Y-%m-%d %H:%M:%S') Wrote git clone path for $UUID to ${ETC_DIR}gitpath (SSH port $PORT)"
+2 -2
View File
@@ -4,7 +4,7 @@
# Get the hostname of the machine # Get the hostname of the machine
HOSTNAME=$(hostname) HOSTNAME=$(hostname)
echo "$(date '+%Y-%m-%d %H:%M:%S') START N8N UUID=${UUID} HOST=${HOSTNAME} DOMAIN=${UUID}.odoo4projects.com" echo "$(date '+%Y-%m-%d %H:%M:%S') START N8N UUID=${UUID} HOST=${HOSTNAME} DOMAIN=${UUID}.odoo4projects.com DOMAIN2=${UUID}.${HOSTNAME}.odoo4projects.com"
mkdir -p /4server/data/${UUID}/n8n mkdir -p /4server/data/${UUID}/n8n
mkdir -p /4server/data/${UUID}/data mkdir -p /4server/data/${UUID}/data
@@ -53,7 +53,7 @@ docker run -d \
-v "/4server/data/${UUID}/data:/data" \ -v "/4server/data/${UUID}/data:/data" \
-v "/4server/data/${UUID}/backup:/backup" \ -v "/4server/data/${UUID}/backup:/backup" \
--label "traefik.enable=true" \ --label "traefik.enable=true" \
--label "traefik.http.routers.${UUID}.rule=Host(\`${UUID}.odoo4projects.com\`)" \ --label "traefik.http.routers.${UUID}.rule=Host(\`${UUID}.odoo4projects.com\`) || Host(\`${UUID}.${HOSTNAME}.odoo4projects.com\`)" \
--label "traefik.http.routers.${UUID}.entrypoints=web,websecure" \ --label "traefik.http.routers.${UUID}.entrypoints=web,websecure" \
--label "traefik.http.routers.${UUID}.tls=true" \ --label "traefik.http.routers.${UUID}.tls=true" \
--label "traefik.http.routers.${UUID}.tls.certresolver=production" \ --label "traefik.http.routers.${UUID}.tls.certresolver=production" \
+98
View File
@@ -0,0 +1,98 @@
#!/bin/bash
#
# swapon — create, enable and persist an 8GB swap file.
#
# Runs on each managed server (Alpine/OpenRC). Deploy with ./update_sbin, then:
#
# rex doas /4server/sbin/swapon
#
# The script aborts if any swap is already active or if /swapfile already
# exists, so it is safe to run against the whole fleet.
#
# Optional first argument: swap size in MiB (default 8192 = 8GB).
set -euo pipefail
SWAPFILE="/swapfile"
SWAP_SIZE_MB="${1:-8192}"
FSTAB="/etc/fstab"
log() {
echo "[$(hostname)] $*"
}
die() {
echo "[$(hostname)] ERROR: $*" >&2
exit 1
}
case "$SWAP_SIZE_MB" in
''|*[!0-9]*) die "swap size must be a positive integer in MiB" ;;
esac
[ "$SWAP_SIZE_MB" -gt 0 ] || die "swap size must be greater than zero"
# Remove a partially created swap file if anything fails before it is enabled.
CREATED=0
cleanup() {
[ "$CREATED" -eq 1 ] || return 0
[ -e "$SWAPFILE" ] || return 0
if grep -q "^${SWAPFILE}[[:space:]]" /proc/swaps; then
return 0
fi
log "removing incomplete ${SWAPFILE}"
rm -f "$SWAPFILE"
}
trap cleanup EXIT
# --- must run as root ---------------------------------------------------
[ "$(id -u)" -eq 0 ] || die "must be run as root (use: rex doas /4server/sbin/swapon)"
# --- abort if swap is already active ------------------------------------
# /proc/swaps always has a header line; anything more means swap is in use.
if [ "$(wc -l < /proc/swaps)" -gt 1 ]; then
echo "[$(hostname)] ERROR: swap is already active:" >&2
cat /proc/swaps >&2
exit 1
fi
# --- abort if the swap file already exists ------------------------------
if [ -e "$SWAPFILE" ]; then
die "$SWAPFILE already exists; remove it manually before recreating swap"
fi
# --- persistence requires OpenRC's swap service --------------------------
[ -x /etc/init.d/swap ] || \
die "/etc/init.d/swap not found; cannot persist swap across reboots"
# --- make sure there is enough room on / ---------------------------------
AVAIL_KB=$(df -Pk / | awk 'NR==2 {print $4}')
# Leave a 100MiB margin for filesystem metadata.
REQUIRED_KB=$((SWAP_SIZE_MB * 1024 + 102400))
[ "$AVAIL_KB" -ge "$REQUIRED_KB" ] || \
die "not enough free space on / (need ${SWAP_SIZE_MB}MiB, have $((AVAIL_KB / 1024))MiB)"
# --- create the swap file -----------------------------------------------
log "creating ${SWAP_SIZE_MB}MiB swap file at ${SWAPFILE}"
CREATED=1
dd if=/dev/zero of="$SWAPFILE" bs=1M count="$SWAP_SIZE_MB"
chmod 600 "$SWAPFILE"
/sbin/mkswap "$SWAPFILE"
# --- persist across reboots ---------------------------------------------
# OpenRC's swap service runs `swapon -a`, which reads /etc/fstab.
if ! grep -qE "^[[:space:]]*${SWAPFILE}[[:space:]]" "$FSTAB"; then
# Terminate the last line first in case fstab has no trailing newline.
[ -z "$(tail -c 1 "$FSTAB")" ] || echo >> "$FSTAB"
echo "${SWAPFILE} none swap sw 0 0" >> "$FSTAB"
log "added ${SWAPFILE} to ${FSTAB}"
fi
rc-update add swap boot >/dev/null 2>&1 || \
die "could not add the swap service to the boot runlevel"
# --- enable it now -------------------------------------------------------
# Absolute path avoids recursing into this script if /4server/sbin is on PATH.
/sbin/swapon "$SWAPFILE"
log "swap enabled:"
cat /proc/swaps
+3
View File
@@ -1 +1,4 @@
API_KEY={{API_KEY}} API_KEY={{API_KEY}}
PROVIDER={{PROVIDER}}
COST={{COST}}
CONTRACT_END={{CONTRACT_END}}
+1
View File
@@ -1 +1,2 @@
permit nopass 4server as root permit nopass 4server as root
permit nopass root as root
Binary file not shown.