392 lines
11 KiB
Plaintext
392 lines
11 KiB
Plaintext
|
|
# OrbStack Integration Helpers
|
||
|
|
# Utilities for interacting with OrbStack machine "provisioning"
|
||
|
|
|
||
|
|
use std log
|
||
|
|
|
||
|
|
# Connect to OrbStack machine
|
||
|
|
export def orbstack-connect [] {
|
||
|
|
let test_config = (load-test-config)
|
||
|
|
let machine_name = $test_config.orbstack.machine_name
|
||
|
|
|
||
|
|
# Verify OrbStack machine exists
|
||
|
|
let machines = (orb list | from json)
|
||
|
|
|
||
|
|
if not ($machine_name in ($machines | get name)) {
|
||
|
|
error make {
|
||
|
|
msg: $"OrbStack machine '($machine_name)' not found"
|
||
|
|
label: {
|
||
|
|
text: "Machine not found"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Return connection info
|
||
|
|
{
|
||
|
|
machine: $machine_name
|
||
|
|
docker_socket: $test_config.orbstack.connection.socket
|
||
|
|
network: $test_config.orbstack.network
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Run command on OrbStack machine
|
||
|
|
export def orbstack-run [
|
||
|
|
command: string
|
||
|
|
--detach: bool = false
|
||
|
|
] {
|
||
|
|
let connection = (orbstack-connect)
|
||
|
|
|
||
|
|
if $detach {
|
||
|
|
docker -H $connection.docker_socket run -d $command
|
||
|
|
} else {
|
||
|
|
docker -H $connection.docker_socket run --rm $command
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Execute command in running container
|
||
|
|
export def orbstack-exec [
|
||
|
|
container_name: string
|
||
|
|
command: string
|
||
|
|
] {
|
||
|
|
let connection = (orbstack-connect)
|
||
|
|
|
||
|
|
docker -H $connection.docker_socket exec $container_name $command
|
||
|
|
}
|
||
|
|
|
||
|
|
# Deploy platform service to OrbStack
|
||
|
|
export def orbstack-deploy-service [
|
||
|
|
service_name: string
|
||
|
|
config: record
|
||
|
|
] {
|
||
|
|
let connection = (orbstack-connect)
|
||
|
|
let test_config = (load-test-config)
|
||
|
|
|
||
|
|
log info $"Deploying ($service_name) to OrbStack..."
|
||
|
|
|
||
|
|
match $service_name {
|
||
|
|
"orchestrator" => {
|
||
|
|
deploy-orchestrator $connection $config
|
||
|
|
}
|
||
|
|
"coredns" => {
|
||
|
|
deploy-coredns $connection $config
|
||
|
|
}
|
||
|
|
"oci_registry" => {
|
||
|
|
deploy-oci-registry $connection $config
|
||
|
|
}
|
||
|
|
"gitea" => {
|
||
|
|
deploy-gitea $connection $config
|
||
|
|
}
|
||
|
|
"postgres" => {
|
||
|
|
deploy-postgres $connection $config
|
||
|
|
}
|
||
|
|
"prometheus" => {
|
||
|
|
deploy-prometheus $connection $config
|
||
|
|
}
|
||
|
|
"grafana" => {
|
||
|
|
deploy-grafana $connection $config
|
||
|
|
}
|
||
|
|
_ => {
|
||
|
|
error make {
|
||
|
|
msg: $"Unknown service: ($service_name)"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Deploy orchestrator service
|
||
|
|
def deploy-orchestrator [connection: record, config: record] {
|
||
|
|
let test_config = (load-test-config)
|
||
|
|
let service_config = $test_config.services.orchestrator
|
||
|
|
|
||
|
|
# Build orchestrator image if needed
|
||
|
|
let orchestrator_path = $"($env.PWD)/provisioning/platform/orchestrator"
|
||
|
|
|
||
|
|
cd $orchestrator_path
|
||
|
|
docker -H $connection.docker_socket build -t provisioning-orchestrator:test .
|
||
|
|
|
||
|
|
# Run orchestrator container
|
||
|
|
docker -H $connection.docker_socket run -d \
|
||
|
|
--name orchestrator \
|
||
|
|
--network provisioning-net \
|
||
|
|
--ip $service_config.host \
|
||
|
|
-p $"($service_config.port):($service_config.port)" \
|
||
|
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||
|
|
provisioning-orchestrator:test
|
||
|
|
|
||
|
|
log info "Orchestrator deployed successfully"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Deploy CoreDNS service
|
||
|
|
def deploy-coredns [connection: record, config: record] {
|
||
|
|
let test_config = (load-test-config)
|
||
|
|
let service_config = $test_config.services.coredns
|
||
|
|
|
||
|
|
# Create CoreDNS configuration
|
||
|
|
let coredns_config = $"
|
||
|
|
.:53 {
|
||
|
|
forward . 8.8.8.8 8.8.4.4
|
||
|
|
log
|
||
|
|
errors
|
||
|
|
cache
|
||
|
|
}
|
||
|
|
|
||
|
|
local:53 {
|
||
|
|
file /etc/coredns/db.local
|
||
|
|
log
|
||
|
|
errors
|
||
|
|
}
|
||
|
|
"
|
||
|
|
|
||
|
|
# Write config to temp file
|
||
|
|
$coredns_config | save -f /tmp/Corefile
|
||
|
|
|
||
|
|
# Run CoreDNS container
|
||
|
|
docker -H $connection.docker_socket run -d \
|
||
|
|
--name coredns \
|
||
|
|
--network provisioning-net \
|
||
|
|
--ip $service_config.host \
|
||
|
|
-p $"($service_config.port):53/udp" \
|
||
|
|
-v /tmp/Corefile:/etc/coredns/Corefile \
|
||
|
|
coredns/coredns:latest
|
||
|
|
|
||
|
|
log info "CoreDNS deployed successfully"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Deploy OCI registry (Zot or Harbor)
|
||
|
|
def deploy-oci-registry [connection: record, config: record] {
|
||
|
|
let test_config = (load-test-config)
|
||
|
|
let use_harbor = ($config.use_harbor? | default false)
|
||
|
|
|
||
|
|
if $use_harbor {
|
||
|
|
deploy-harbor $connection $config
|
||
|
|
} else {
|
||
|
|
deploy-zot $connection $config
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Deploy Zot OCI registry
|
||
|
|
def deploy-zot [connection: record, config: record] {
|
||
|
|
let test_config = (load-test-config)
|
||
|
|
let service_config = $test_config.services.oci_registry.zot
|
||
|
|
|
||
|
|
# Zot configuration
|
||
|
|
let zot_config = {
|
||
|
|
storage: {
|
||
|
|
rootDirectory: "/var/lib/registry"
|
||
|
|
}
|
||
|
|
http: {
|
||
|
|
address: "0.0.0.0"
|
||
|
|
port: 5000
|
||
|
|
}
|
||
|
|
log: {
|
||
|
|
level: "info"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$zot_config | to json | save -f /tmp/zot-config.json
|
||
|
|
|
||
|
|
# Run Zot container
|
||
|
|
docker -H $connection.docker_socket run -d \
|
||
|
|
--name oci-registry \
|
||
|
|
--network provisioning-net \
|
||
|
|
--ip $service_config.host \
|
||
|
|
-p $"($service_config.port):5000" \
|
||
|
|
-v /tmp/zot-config.json:/etc/zot/config.json \
|
||
|
|
-v zot-data:/var/lib/registry \
|
||
|
|
ghcr.io/project-zot/zot:latest
|
||
|
|
|
||
|
|
log info "Zot OCI registry deployed successfully"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Deploy Harbor OCI registry
|
||
|
|
def deploy-harbor [connection: record, config: record] {
|
||
|
|
let test_config = (load-test-config)
|
||
|
|
let service_config = $test_config.services.oci_registry.harbor
|
||
|
|
|
||
|
|
# Harbor requires docker-compose, use Harbor installer
|
||
|
|
log info "Deploying Harbor (enterprise mode)..."
|
||
|
|
|
||
|
|
# Download Harbor offline installer
|
||
|
|
let harbor_version = "v2.9.0"
|
||
|
|
let harbor_url = $"https://github.com/goharbor/harbor/releases/download/($harbor_version)/harbor-offline-installer-($harbor_version).tgz"
|
||
|
|
|
||
|
|
# Note: Full Harbor deployment requires docker-compose and is complex
|
||
|
|
# For testing, we'll use a simplified Harbor deployment
|
||
|
|
docker -H $connection.docker_socket run -d \
|
||
|
|
--name harbor \
|
||
|
|
--network provisioning-net \
|
||
|
|
--ip $service_config.host \
|
||
|
|
-p $"($service_config.port):443" \
|
||
|
|
-p $"($service_config.ui_port):80" \
|
||
|
|
goharbor/harbor-core:$harbor_version
|
||
|
|
|
||
|
|
log info "Harbor OCI registry deployed successfully"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Deploy Gitea service
|
||
|
|
def deploy-gitea [connection: record, config: record] {
|
||
|
|
let test_config = (load-test-config)
|
||
|
|
let service_config = $test_config.services.gitea
|
||
|
|
let postgres_config = $test_config.services.postgres
|
||
|
|
|
||
|
|
# Run Gitea container
|
||
|
|
docker -H $connection.docker_socket run -d \
|
||
|
|
--name gitea \
|
||
|
|
--network provisioning-net \
|
||
|
|
--ip $service_config.host \
|
||
|
|
-p $"($service_config.port):3000" \
|
||
|
|
-p $"($service_config.ssh_port):22" \
|
||
|
|
-e USER_UID=1000 \
|
||
|
|
-e USER_GID=1000 \
|
||
|
|
-e GITEA__database__DB_TYPE=postgres \
|
||
|
|
-e $"GITEA__database__HOST=($postgres_config.host):($postgres_config.port)" \
|
||
|
|
-e GITEA__database__NAME=gitea \
|
||
|
|
-e GITEA__database__USER=$postgres_config.username \
|
||
|
|
-e GITEA__database__PASSWD=gitea \
|
||
|
|
-v gitea-data:/data \
|
||
|
|
gitea/gitea:latest
|
||
|
|
|
||
|
|
log info "Gitea deployed successfully"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Deploy PostgreSQL service
|
||
|
|
def deploy-postgres [connection: record, config: record] {
|
||
|
|
let test_config = (load-test-config)
|
||
|
|
let service_config = $test_config.services.postgres
|
||
|
|
|
||
|
|
# Run PostgreSQL container
|
||
|
|
docker -H $connection.docker_socket run -d \
|
||
|
|
--name postgres \
|
||
|
|
--network provisioning-net \
|
||
|
|
--ip $service_config.host \
|
||
|
|
-p $"($service_config.port):5432" \
|
||
|
|
-e POSTGRES_USER=$service_config.username \
|
||
|
|
-e POSTGRES_PASSWORD=postgres \
|
||
|
|
-e POSTGRES_DB=$service_config.database \
|
||
|
|
-v postgres-data:/var/lib/postgresql/data \
|
||
|
|
postgres:15-alpine
|
||
|
|
|
||
|
|
log info "PostgreSQL deployed successfully"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Deploy Prometheus service
|
||
|
|
def deploy-prometheus [connection: record, config: record] {
|
||
|
|
let test_config = (load-test-config)
|
||
|
|
let service_config = $test_config.services.prometheus
|
||
|
|
|
||
|
|
# Prometheus configuration
|
||
|
|
let prometheus_config = $"
|
||
|
|
global:
|
||
|
|
scrape_interval: 15s
|
||
|
|
evaluation_interval: 15s
|
||
|
|
|
||
|
|
scrape_configs:
|
||
|
|
- job_name: 'orchestrator'
|
||
|
|
static_configs:
|
||
|
|
- targets: ['($test_config.services.orchestrator.host):($test_config.services.orchestrator.port)']
|
||
|
|
"
|
||
|
|
|
||
|
|
$prometheus_config | save -f /tmp/prometheus.yml
|
||
|
|
|
||
|
|
# Run Prometheus container
|
||
|
|
docker -H $connection.docker_socket run -d \
|
||
|
|
--name prometheus \
|
||
|
|
--network provisioning-net \
|
||
|
|
--ip $service_config.host \
|
||
|
|
-p $"($service_config.port):9090" \
|
||
|
|
-v /tmp/prometheus.yml:/etc/prometheus/prometheus.yml \
|
||
|
|
-v prometheus-data:/prometheus \
|
||
|
|
prom/prometheus:latest
|
||
|
|
|
||
|
|
log info "Prometheus deployed successfully"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Deploy Grafana service
|
||
|
|
def deploy-grafana [connection: record, config: record] {
|
||
|
|
let test_config = (load-test-config)
|
||
|
|
let service_config = $test_config.services.grafana
|
||
|
|
|
||
|
|
# Run Grafana container
|
||
|
|
docker -H $connection.docker_socket run -d \
|
||
|
|
--name grafana \
|
||
|
|
--network provisioning-net \
|
||
|
|
--ip $service_config.host \
|
||
|
|
-p $"($service_config.port):3000" \
|
||
|
|
-e GF_SECURITY_ADMIN_PASSWORD=admin \
|
||
|
|
-v grafana-data:/var/lib/grafana \
|
||
|
|
grafana/grafana:latest
|
||
|
|
|
||
|
|
log info "Grafana deployed successfully"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Create Docker network for services
|
||
|
|
export def orbstack-create-network [] {
|
||
|
|
let connection = (orbstack-connect)
|
||
|
|
let test_config = (load-test-config)
|
||
|
|
|
||
|
|
# Create custom network
|
||
|
|
docker -H $connection.docker_socket network create \
|
||
|
|
--subnet $test_config.orbstack.network.subnet \
|
||
|
|
--gateway $test_config.orbstack.network.gateway \
|
||
|
|
provisioning-net
|
||
|
|
|
||
|
|
log info "Docker network 'provisioning-net' created"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Cleanup OrbStack resources
|
||
|
|
export def orbstack-cleanup [] {
|
||
|
|
let connection = (orbstack-connect)
|
||
|
|
|
||
|
|
log info "Cleaning up OrbStack resources..."
|
||
|
|
|
||
|
|
# Stop and remove all containers
|
||
|
|
let containers = [
|
||
|
|
"orchestrator"
|
||
|
|
"coredns"
|
||
|
|
"oci-registry"
|
||
|
|
"harbor"
|
||
|
|
"gitea"
|
||
|
|
"postgres"
|
||
|
|
"prometheus"
|
||
|
|
"grafana"
|
||
|
|
]
|
||
|
|
|
||
|
|
for container in $containers {
|
||
|
|
try {
|
||
|
|
docker -H $connection.docker_socket stop $container
|
||
|
|
docker -H $connection.docker_socket rm $container
|
||
|
|
} catch {
|
||
|
|
# Ignore errors if container doesn't exist
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Remove network
|
||
|
|
try {
|
||
|
|
docker -H $connection.docker_socket network rm provisioning-net
|
||
|
|
} catch {
|
||
|
|
# Ignore errors if network doesn't exist
|
||
|
|
}
|
||
|
|
|
||
|
|
log info "OrbStack cleanup completed"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get logs from OrbStack container
|
||
|
|
export def orbstack-logs [
|
||
|
|
container_name: string
|
||
|
|
--tail: int = 100
|
||
|
|
--follow: bool = false
|
||
|
|
] {
|
||
|
|
let connection = (orbstack-connect)
|
||
|
|
|
||
|
|
if $follow {
|
||
|
|
docker -H $connection.docker_socket logs -f --tail $tail $container_name
|
||
|
|
} else {
|
||
|
|
docker -H $connection.docker_socket logs --tail $tail $container_name
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Helper to load test config (copied from test_helpers.nu to avoid circular dependency)
|
||
|
|
def load-test-config [] {
|
||
|
|
let config_path = $"($env.PWD)/provisioning/tests/integration/test_config.yaml"
|
||
|
|
open $config_path
|
||
|
|
}
|