feat: Semaphore UI on AZ-PRM-1 (AZ-NIX-4ux)
This commit is contained in:
@@ -63,6 +63,12 @@ in {
|
|||||||
file = ../../secrets/pgadmin-pw.age;
|
file = ../../secrets/pgadmin-pw.age;
|
||||||
owner = "pgadmin";
|
owner = "pgadmin";
|
||||||
};
|
};
|
||||||
|
semaphore-env = {
|
||||||
|
file = ../../secrets/semaphore-env.age;
|
||||||
|
owner = "postgres";
|
||||||
|
group = "postgres";
|
||||||
|
mode = "0400";
|
||||||
|
};
|
||||||
pg-cert = {
|
pg-cert = {
|
||||||
file = ../../secrets/server.crt.age;
|
file = ../../secrets/server.crt.age;
|
||||||
owner = "postgres";
|
owner = "postgres";
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
./excalidraw.nix
|
./excalidraw.nix
|
||||||
./kestra.nix
|
./kestra.nix
|
||||||
./online3dviewer.nix
|
./online3dviewer.nix
|
||||||
|
./semaphore.nix
|
||||||
./stirling-pdf.nix
|
./stirling-pdf.nix
|
||||||
];
|
];
|
||||||
system.activationScripts.createPodmanNetworkWeb = lib.mkAfter ''
|
system.activationScripts.createPodmanNetworkWeb = lib.mkAfter ''
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
serviceName = "semaphore";
|
||||||
|
servicePort = config.m3ta.ports.get serviceName;
|
||||||
|
in {
|
||||||
|
virtualisation.oci-containers.containers."${serviceName}" = {
|
||||||
|
# Image contains the Semaphore server plus ansible, terraform,
|
||||||
|
# opentofu and terragrunt runners.
|
||||||
|
image = "docker.io/semaphoreui/semaphore:latest";
|
||||||
|
environment = {
|
||||||
|
SEMAPHORE_DB_DIALECT = "postgres";
|
||||||
|
SEMAPHORE_DB_HOST = "postgres";
|
||||||
|
SEMAPHORE_DB_PORT = "5432";
|
||||||
|
SEMAPHORE_PLAYBOOK_PATH = "/tmp/semaphore/";
|
||||||
|
};
|
||||||
|
# SEMAPHORE_DB (name), SEMAPHORE_DB_USER, SEMAPHORE_DB_PASS and the
|
||||||
|
# admin bootstrap vars (SEMAPHORE_ADMIN*) come from the agenix secret
|
||||||
|
# (podman env-file).
|
||||||
|
environmentFiles = [config.age.secrets.semaphore-env.path];
|
||||||
|
ports = ["127.0.0.1:${toString servicePort}:3000"];
|
||||||
|
volumes = [
|
||||||
|
"semaphore_data:/var/lib/semaphore"
|
||||||
|
];
|
||||||
|
extraOptions = ["--network=web" "--ip=10.89.0.17" "--add-host=postgres:10.89.0.1"];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Idempotent provisioning of the semaphore role/database on the host
|
||||||
|
# PostgreSQL 17 (same pattern as atrocore-db-init: initialScript cannot
|
||||||
|
# be used, the cluster is already initialized and the password must
|
||||||
|
# never land in the Nix store).
|
||||||
|
systemd.services.semaphore-db-init = {
|
||||||
|
description = "Provision semaphore role/database from agenix secret";
|
||||||
|
after = ["postgresql.service"];
|
||||||
|
before = ["podman-${serviceName}.service"];
|
||||||
|
wants = ["postgresql.service"];
|
||||||
|
wantedBy = ["multi-user.target"];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = "postgres";
|
||||||
|
Group = "postgres";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
path = [config.services.postgresql.package];
|
||||||
|
# Env-file format: plain KEY=value lines (no quotes), same file the
|
||||||
|
# container consumes.
|
||||||
|
script = ''
|
||||||
|
set -euo pipefail
|
||||||
|
ENV_FILE="${config.age.secrets.semaphore-env.path}"
|
||||||
|
get_val() {
|
||||||
|
grep -m1 "^$1=" "$ENV_FILE" | head -n1 | cut -d= -f2- | tr -d '\r'
|
||||||
|
}
|
||||||
|
db_name="$(get_val SEMAPHORE_DB)"
|
||||||
|
db_user="$(get_val SEMAPHORE_DB_USER)"
|
||||||
|
db_pass="$(get_val SEMAPHORE_DB_PASS)"
|
||||||
|
if [ -z "$db_name" ] || [ -z "$db_user" ] || [ -z "$db_pass" ]; then
|
||||||
|
echo "semaphore-db-init: SEMAPHORE_DB/SEMAPHORE_DB_USER/SEMAPHORE_DB_PASS missing in $ENV_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
psql -v ON_ERROR_STOP=1 -d postgres \
|
||||||
|
-v db_name="$db_name" -v db_user="$db_user" -v db_pass="$db_pass" <<'SQL'
|
||||||
|
SELECT format('CREATE ROLE %I LOGIN', :'db_user')
|
||||||
|
WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = :'db_user') \gexec
|
||||||
|
ALTER ROLE :"db_user" WITH LOGIN PASSWORD :'db_pass';
|
||||||
|
SELECT format('CREATE DATABASE %I OWNER %I', :'db_name', :'db_user')
|
||||||
|
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = :'db_name') \gexec
|
||||||
|
ALTER DATABASE :"db_name" OWNER TO :"db_user";
|
||||||
|
SQL
|
||||||
|
echo "semaphore-db-init: role/database '$db_name' ready"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Traefik configuration specific to semaphore
|
||||||
|
services.traefik.dynamicConfigOptions.http = {
|
||||||
|
services.${serviceName}.loadBalancer.servers = [{url = "http://localhost:${toString servicePort}/";}];
|
||||||
|
|
||||||
|
routers.${serviceName} = {
|
||||||
|
rule = "Host(`sem.l.az-gruppe.com`)";
|
||||||
|
tls = {certResolver = "ionos";};
|
||||||
|
service = serviceName;
|
||||||
|
entrypoints = "websecure";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -39,6 +39,7 @@ in {
|
|||||||
"https://g.l.az-gruppe.com"
|
"https://g.l.az-gruppe.com"
|
||||||
"https://wf.l.az-gruppe.com"
|
"https://wf.l.az-gruppe.com"
|
||||||
"https://k.l.az-gruppe.com"
|
"https://k.l.az-gruppe.com"
|
||||||
|
"https://sem.l.az-gruppe.com"
|
||||||
"https://git.az-gruppe.com"
|
"https://git.az-gruppe.com"
|
||||||
"https://ping.az-gruppe.com"
|
"https://ping.az-gruppe.com"
|
||||||
"https://llm.az-gruppe.com"
|
"https://llm.az-gruppe.com"
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
host baserow baserow 10.89.0.0/24 scram-sha-256
|
host baserow baserow 10.89.0.0/24 scram-sha-256
|
||||||
host kestra kestra 10.89.0.0/24 scram-sha-256
|
host kestra kestra 10.89.0.0/24 scram-sha-256
|
||||||
host atrocore atrocore 10.89.0.0/24 scram-sha-256
|
host atrocore atrocore 10.89.0.0/24 scram-sha-256
|
||||||
|
host semaphore semaphore 10.89.0.0/24 scram-sha-256
|
||||||
|
|
||||||
# Grafana (local socket / localhost only)
|
# Grafana (local socket / localhost only)
|
||||||
host grafana grafana 127.0.0.1/32 scram-sha-256
|
host grafana grafana 127.0.0.1/32 scram-sha-256
|
||||||
@@ -66,7 +67,7 @@
|
|||||||
services.postgresqlBackup = {
|
services.postgresqlBackup = {
|
||||||
enable = true;
|
enable = true;
|
||||||
startAt = "03:10:00";
|
startAt = "03:10:00";
|
||||||
databases = ["atrocore" "baserow" "kestra" "n8n" "netbox"];
|
databases = ["atrocore" "baserow" "kestra" "n8n" "netbox" "semaphore"];
|
||||||
};
|
};
|
||||||
networking.firewall = {
|
networking.firewall = {
|
||||||
extraCommands = ''
|
extraCommands = ''
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
phishboard = 3055;
|
phishboard = 3055;
|
||||||
homarr = 3057;
|
homarr = 3057;
|
||||||
atrocore = 3058;
|
atrocore = 3058;
|
||||||
|
semaphore = 3059;
|
||||||
|
|
||||||
metabase = 3013;
|
metabase = 3013;
|
||||||
baserow = 3050;
|
baserow = 3050;
|
||||||
|
|||||||
@@ -67,4 +67,5 @@ in {
|
|||||||
"secrets/monitoring-loki-htpasswd.age".publicKeys = [AZ-PRM-1] ++ users;
|
"secrets/monitoring-loki-htpasswd.age".publicKeys = [AZ-PRM-1] ++ users;
|
||||||
"secrets/monitoring-loki-remote-env.age".publicKeys = [AZ-CLD-1] ++ users;
|
"secrets/monitoring-loki-remote-env.age".publicKeys = [AZ-CLD-1] ++ users;
|
||||||
"secrets/ntfy-grafana-webhook.age".publicKeys = systems ++ users;
|
"secrets/ntfy-grafana-webhook.age".publicKeys = systems ++ users;
|
||||||
|
"secrets/semaphore-env.age".publicKeys = [AZ-PRM-1] ++ users;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user