From e8708191f6f731ffdd55e43a8aa2a5607489d6f0 Mon Sep 17 00:00:00 2001 From: Henrik Jess Nielsen Date: Sun, 10 May 2026 12:16:38 +0200 Subject: [PATCH] First run --- ilsp.nomad | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 ilsp.nomad diff --git a/ilsp.nomad b/ilsp.nomad new file mode 100644 index 0000000..de9c8bb --- /dev/null +++ b/ilsp.nomad @@ -0,0 +1,194 @@ +variable "service_name" { + description = "Service name for consistent naming" + type = string + default = "ilsp" +} + +variable "image_tag" { + description = "Docker image tag — override in CI with commit SHA: -var=\"image_tag=$SHA\"" + type = string + default = "latest" +} + +job "ilsp" { + region = "global" + datacenters = ["dc1"] + type = "service" + + meta { + uuid = uuidv4() + deployed_at = "[[ timeNowUTC ]]" + service_name = var.service_name + } + + update { + stagger = "30s" + max_parallel = 1 + auto_revert = true + progress_deadline = "25m" + } + + group "ilsp-group" { + count = 1 + + # Deploy specifically on the 'autobox.i80.dk' node + constraint { + attribute = "${node.unique.name}" + value = "autobox.i80.dk" + } + + # Zero-downtime update strategy: canary ensures new alloc is healthy + # before old alloc is stopped. Both run briefly during transition. + update { + canary = 1 # Start 1 new alloc before stopping old + auto_promote = true # Promote automatically when healthy + min_healthy_time = "15s" + healthy_deadline = "20m" + progress_deadline = "25m" + auto_revert = true + } + + network { + port "http" { + } + } + + reschedule { + attempts = 5 + interval = "10m" + delay = "30s" + delay_function = "exponential" + max_delay = "120s" + unlimited = false + } + + # Volumes disabled for quick deployment + # volume "ssl-certs" { + # type = "host" + # source = "certs" + # read_only = true + # } + + volume "refactor-data" { + type = "host" + source = "refactor-data" + read_only = false + } + + # Register the service with Consul + service { + provider = "consul" + name = var.service_name + port = "http" + + # Traefik-specific tags for routing + tags = [ + "traefik.enable=true", + "traefik.http.routers.${var.service_name}.rule=Host(`${var.service_name}.i80.dk`)", + "traefik.http.routers.${var.service_name}.tls=true", + # Rate limiting for refactoring operations + "traefik.http.middlewares.${var.service_name}-limit.ratelimit.burst=10", + "traefik.http.middlewares.${var.service_name}-limit.ratelimit.period=1m", + "traefik.http.routers.${var.service_name}.middlewares=${var.service_name}-limit" + ] + + # Primary health check - HTTP + check { + name = "http_health_check" + type = "http" + port = "http" + path = "/health" + interval = "10s" + timeout = "5s" + } + } + + task "ilsp-task" { + driver = "docker" + + config { + image = "registry.i80.dk/gitea/ilsp:${var.image_tag}" + ports = ["http"] + force_pull = true + auth { + username = "robot$gitserver" + password = "${HARBOR_ROBOT_TOKEN}" + } + } + + restart { + attempts = 10 + interval = "10m" + delay = "15s" + mode = "fail" + } + + # Volume mounts disabled for quick deployment + # volume_mount { + # volume = "ssl-certs" + # destination = "/certs" + # read_only = true + # } + + volume_mount { + volume = "refactor-data" + destination = "/app/data" + read_only = false + } + + env { + # DevOpsMCP Configuration + # Server Configuration + PYTHONUNBUFFERED = "1" + PORT = "${NOMAD_PORT_http}" + HOST = "0.0.0.0" + + # Gitea (gea.i80.dk) API token for server-side CI/Actions queries + GITEA_TOKEN = "441b0e1f3f23d2b29984c970743ec8f7fc4081fa" + GITEA_URL = "https://gea.i80.dk" + + # LanguageTool — self-hosted grammar/spell-check (autobox.i80.dk:8010) + LANGUAGETOOL_URL = "http://192.168.15.124:8010" + # SSL certificate paths (available but not required for app) + SSL_CERT_PATH = "/certs/wildcard.i80.dk.crt_cert.crt" + SSL_KEY_PATH = "/certs/wildcard.i80.dk.key" + SSL_FULLCHAIN_PATH = "/certs/wildcard.i80.dk.crt_fullchain.crt" + + # External MCP servers — tokens loaded from Consul (see template block below) + # Servers start automatically in entrypoint.sh when tokens are present + } + + # Registry authentication template + template { + data = <