Add Debian packaging support and network configuration enhancements

- Introduce Debian package build script using `cargo-deb` for orchestrator releases.
- Add systemd unit file and post-installation script for automatic service setup.
- Update `compose.yml` with host-only port bindings for Postgres and RabbitMQ.
- Introduce NGINX-based log proxy for orchestrator logs with Traefik support.
- Bump orchestrator version to 0.1.1 and update related Cargo metadata for packaging.
- Add example environment file for orchestrator configuration.

Signed-off-by: Till Wegmueller <toasterson@gmail.com>
This commit is contained in:
Till Wegmueller 2025-11-17 19:57:19 +01:00
parent 9dfa9c4b95
commit fad8e60ec1
No known key found for this signature in database
8 changed files with 142 additions and 3 deletions

2
.idea/dataSources.xml generated
View file

@ -5,7 +5,7 @@
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://172.18.0.5:5432/postgres</jdbc-url>
<jdbc-url>jdbc:postgresql://127.0.0.1:5432/postgres</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>

15
.mise/tasks/build/deb Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail
# Build Debian package for the orchestrator using cargo-deb
if ! command -v cargo-deb >/dev/null 2>&1; then
cargo install cargo-deb
fi
# Build release binary first for reproducible asset path
cargo build -p orchestrator --release
# Package orchestrator
cargo deb -p orchestrator --no-build
echo "\nDebs written under target/debian/*.deb"

View file

@ -1,6 +1,6 @@
[package]
name = "orchestrator"
version = "0.1.0"
version = "0.1.1"
edition = "2024"
build = "build.rs"
@ -38,7 +38,27 @@ chrono = { version = "0.4", default-features = false, features = ["clock", "std"
dashmap = "6"
async-trait = "0.1"
uuid = { version = "1", features = ["v4", "serde"] }
futures-util = "0.3.31"
[target.'cfg(target_os = "linux")'.dependencies]
virt = { version = "0.4.3" }
[package.metadata.deb]
name = "solstice-orchestrator"
maintainer = "Solstice CI <ops@solstice-ci.org>"
section = "utils"
priority = "optional"
assets = [
["target/release/orchestrator", "/usr/bin/solstice-orchestrator", "755"],
["packaging/solstice-orchestrator.service", "/lib/systemd/system/solstice-orchestrator.service", "644"],
["../../examples/orchestrator-image-map.yaml", "/etc/solstice/orchestrator.yaml", "644"],
["../../examples/etc/solstice/orchestrator.env.sample", "/etc/solstice/orchestrator.env", "640"],
]
depends = [
"libvirt-daemon-system",
"libvirt-clients",
"ca-certificates",
"openssh-client",
]
recommends = ["qemu-kvm", "virtinst"]
conf-files = ["/etc/solstice/orchestrator.yaml", "/etc/solstice/orchestrator.env"]
maintainer-scripts = "packaging/debian/"

View file

@ -0,0 +1,20 @@
#!/bin/sh
set -e
# Create solstice system user/group if not present
if ! id -u solstice >/dev/null 2>&1; then
adduser --system --group --no-create-home --home /nonexistent --shell /usr/sbin/nologin solstice || true
fi
# Ensure config directory exists
mkdir -p /etc/solstice
chown root:root /etc/solstice
chmod 755 /etc/solstice
# Reload systemd units and enable service
if command -v systemctl >/dev/null 2>&1; then
systemctl daemon-reload || true
systemctl enable solstice-orchestrator.service || true
fi
exit 0

View file

@ -0,0 +1,23 @@
[Unit]
Description=Solstice CI Orchestrator
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
EnvironmentFile=-/etc/default/solstice-orchestrator
EnvironmentFile=-/etc/solstice/orchestrator.env
ExecStart=/usr/bin/solstice-orchestrator
Restart=on-failure
RestartSec=3s
User=solstice
Group=solstice
AmbientCapabilities=
NoNewPrivileges=yes
ProtectSystem=full
ProtectHome=true
PrivateTmp=true
RuntimeDirectory=solstice
[Install]
WantedBy=multi-user.target

View file

@ -77,6 +77,8 @@ services:
timeout: 5s
retries: 5
start_period: 10s
ports:
- "127.0.0.1:5432:5432" # expose Postgres to host only
volumes:
- postgres-data:/var/lib/postgresql/data:Z
networks:
@ -113,6 +115,8 @@ services:
timeout: 5s
retries: 5
start_period: 5s
ports:
- "127.0.0.1:5672:5672" # expose AMQP to host only
volumes:
- rabbitmq-data:/var/lib/rabbitmq:Z
networks:
@ -236,6 +240,22 @@ services:
- traefik.http.routers.api.tls.certresolver=le
- traefik.http.services.api.loadbalancer.server.port=8081
orchestrator-logs-proxy:
image: docker.io/library/nginx:alpine
container_name: solstice-orchestrator-logs
restart: unless-stopped
volumes:
- ./nginx/orchestrator-logs.conf:/etc/nginx/conf.d/default.conf:ro,Z
networks:
- core
labels:
- traefik.enable=true
# Expose orchestrator HTTP (logs) running on the host via a tiny proxy
- traefik.http.routers.logs.rule=Host(`logs.${ENV}.${DOMAIN}`)
- traefik.http.routers.logs.entrypoints=websecure
- traefik.http.routers.logs.tls.certresolver=le
- traefik.http.services.logs.loadbalancer.server.port=80
forge-integration:
build:
context: ../..

View file

@ -0,0 +1,14 @@
server {
listen 80;
server_name _;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_connect_timeout 5s;
proxy_pass http://host.containers.internal:8081;
}
}

View file

@ -0,0 +1,27 @@
# Solstice Orchestrator environment overrides
# Copy to /etc/solstice/orchestrator.env and edit values as needed.
# Anything unset falls back to compiled defaults or other env vars.
# Networking
HTTP_ADDR=0.0.0.0:8081
# Messaging (RabbitMQ)
AMQP_URL=amqp://user:pass@mq.svc.example:5672/%2f
AMQP_EXCHANGE=solstice.jobs
AMQP_QUEUE=solstice.jobs.v1
AMQP_ROUTING_KEY=jobrequest.v1
AMQP_PREFETCH=16
# Database (optional)
# Leave empty to disable persistence
DATABASE_URL=postgres://solstice:solstice@db.svc.example:5432/solstice_prod
# Libvirt
LIBVIRT_URI=qemu:///system
LIBVIRT_NETWORK=default
# Scheduler
MAX_CONCURRENCY=2
# Telemetry
# OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol.svc.example:4317