From 4825ad149537a90e333e06c0beb3857442c19608 Mon Sep 17 00:00:00 2001 From: Alexandre Pires Date: Mon, 29 Jun 2026 14:31:28 +0200 Subject: [PATCH] - Added windows llama proxy - Added terraform-mcp - Added S3 storage to gitea - Changed context size for windows LLMs - Changed number of cores for VMs, added P2000 support --- ansible/host_vars/ci-01.lab.alexpires.me.yml | 24 +++- ansible/host_vars/dev-01.lab.alexpires.me.yml | 9 +- ansible/host_vars/vh-01.lab.alexpires.me.yml | 22 +-- ansible/playbook_systools.yml | 20 ++- .../roles/windows_containers/tasks/main.yml | 29 ++-- .../tasks/{ => obsolete}/ubuntu_container.yml | 0 .../tasks/{ => obsolete}/verify.yml | 0 scripts/install-opnsense.sh | 1 + terraform/apps/dev-01/apps.tf | 16 +++ terraform/apps/dev-01/config.tf | 16 +++ terraform/apps/dev-01/sectool.json | 1 + terraform/apps/prod-01/apps.tf | 22 +-- terraform/apps/prod-01/config.tf | 27 ++-- terraform/apps/prod-01/secrets.tf | 13 -- terraform/apps/prod-01/sectool.env | 2 - terraform/apps/prod-01/sectool.json | 1 + terraform/iac/scaleway/buckets.tf | 47 +++++++ terraform/iac/scaleway/iam.tf | 26 ++++ terraform/iac/scaleway/outputs.tf | 17 +++ terraform/iac/scaleway/sectool.json | 1 + terraform/modules/apps/gitea/config.tf | 1 + .../modules/apps/gitea/resources/app.ini.tpl | 8 ++ terraform/modules/apps/gitea/variables.tf | 1 + terraform/modules/apps/nextcloud/config.tf | 2 +- .../modules/apps/terraform-mcp/config.tf | 4 + .../modules/apps/terraform-mcp/ingress.tf | 24 ++++ terraform/modules/apps/terraform-mcp/main.tf | 131 ++++++++++++++++++ .../modules/apps/terraform-mcp/provider.tf | 9 ++ .../modules/apps/terraform-mcp/variables.tf | 15 ++ 29 files changed, 399 insertions(+), 90 deletions(-) rename ansible/roles/windows_containers/tasks/{ => obsolete}/ubuntu_container.yml (100%) rename ansible/roles/windows_containers/tasks/{ => obsolete}/verify.yml (100%) create mode 120000 terraform/apps/dev-01/sectool.json create mode 120000 terraform/apps/prod-01/sectool.json create mode 120000 terraform/iac/scaleway/sectool.json create mode 100644 terraform/modules/apps/terraform-mcp/config.tf create mode 100644 terraform/modules/apps/terraform-mcp/ingress.tf create mode 100644 terraform/modules/apps/terraform-mcp/main.tf create mode 100644 terraform/modules/apps/terraform-mcp/provider.tf create mode 100644 terraform/modules/apps/terraform-mcp/variables.tf diff --git a/ansible/host_vars/ci-01.lab.alexpires.me.yml b/ansible/host_vars/ci-01.lab.alexpires.me.yml index 6a95d69..b9d47ba 100644 --- a/ansible/host_vars/ci-01.lab.alexpires.me.yml +++ b/ansible/host_vars/ci-01.lab.alexpires.me.yml @@ -42,18 +42,38 @@ llama_server_models: model_id: "mradermacher/Luau-Qwen3-4B-FIM-v0.1-GGUF" quant: "IQ4_XS" revision: "main" + preset: + ctx-size: 4096 - name: "ministral-3-3b-instruct" model_id: "unsloth/Ministral-3-3B-Instruct-2512-GGUF" quant: "IQ4_XS" revision: "main" + preset: + ctx-size: 4096 - name: "qwen2.5-coder-1.5b-instruct" model_id: "Qwen/Qwen2.5-Coder-1.5B-Instruct-GGUF" quant: "Q4_K_M" revision: "main" - - name: "qwen2.5-coder-3b-instruct" - model_id: "unsloth/Qwen2.5-Coder-3B-Instruct-128K-GGUF" + preset: + ctx-size: 4096 + - name: "qwencoder-3b" + model_id: "Jojobigworld/XiYanSQL-QwenCoder-3B-2502-Q4_K_M-GGUF" quant: "Q4_K_M" revision: "main" + preset: + ctx-size: 4096 + - name: "qwen2.5-coder-1.5b-q8" + model_id: "ggml-org/Qwen2.5-Coder-1.5B-Q8_0-GGUF" + quant: "Q8_0" + revision: "main" + preset: + ctx-size: 4096 + - name: "qwen2.5-coder-3b-q8" + model_id: "ggml-org/Qwen2.5-Coder-3B-Q8_0-GGUF" + quant: "Q8_0" + revision: "main" + preset: + ctx-size: 4096 llama_server_host: "0.0.0.0" diff --git a/ansible/host_vars/dev-01.lab.alexpires.me.yml b/ansible/host_vars/dev-01.lab.alexpires.me.yml index e26758f..25c322d 100644 --- a/ansible/host_vars/dev-01.lab.alexpires.me.yml +++ b/ansible/host_vars/dev-01.lab.alexpires.me.yml @@ -38,9 +38,12 @@ fw_allowed_ports: - { rule: "allow", port: "16443", proto: "tcp", from: "10.19.4.0/24" } # Kubernetes API (local network) - { rule: "allow", port: "139", proto: "tcp", from: "10.19.4.0/24" } # Samba (local network only) - { rule: "allow", port: "445", proto: "tcp", from: "10.19.4.0/24" } # Samba (local network only) - - { rule: "allow", port: "11434", proto: "tcp", from: "10.19.4.0/24" } # Ollama (local network only) - - { rule: "allow", port: "11434", proto: "tcp", from: "10.5.5.5/32" } # Ollama (Laptop) - - { rule: "allow", port: "11434", proto: "tcp", from: "10.5.5.2/32" } # Ollama (Contabo VPN) + - { rule: "allow", port: "11434", proto: "tcp", from: "10.19.4.0/24" } # LLama.cpp (local network only) + - { rule: "allow", port: "11434", proto: "tcp", from: "10.5.5.5/32" } # LLama.cpp (Laptop) + - { rule: "allow", port: "11434", proto: "tcp", from: "10.5.5.2/32" } # LLama.cpp (Contabo VPN) + - { rule: "allow", port: "11435", proto: "tcp", from: "10.19.4.0/24" } # LLama.cpp (local network only) + - { rule: "allow", port: "11435", proto: "tcp", from: "10.5.5.5/32" } # LLama.cpp (Laptop) + - { rule: "allow", port: "11435", proto: "tcp", from: "10.5.5.2/32" } # LLama.cpp (Contabo VPN) - { rule: "allow", port: "9090", proto: "tcp", from: "10.5.5.2/32" } # Prometheus (Contabo VPN) - { rule: "allow", port: "443", proto: "tcp", from: "10.5.5.2/32" } # HTTPS (Contabo VPN) - { rule: "allow", port: "53", proto: "udp", from: "10.19.4.0/24" } # DNS (local network) diff --git a/ansible/host_vars/vh-01.lab.alexpires.me.yml b/ansible/host_vars/vh-01.lab.alexpires.me.yml index baca601..4cf68ff 100644 --- a/ansible/host_vars/vh-01.lab.alexpires.me.yml +++ b/ansible/host_vars/vh-01.lab.alexpires.me.yml @@ -128,6 +128,8 @@ virt_extra_grub_args: > virt_vfio_ids: - 10de:1430 # NVIDIA Corporation M2000 [Maxwell GM107GL] - 10de:0fba # NVIDIA Corporation M2000 High Definition Audio Controller + - 10de:1c30 # NVIDIA Corporation P2000 [NVIDIA Corporation GP106GL] + - 10de:10f1 # NVIDIA Corporation P2000 High Definition Audio Controller - 1b73:1100 # Fresco Logic FL1100 USB 3.0 Host Controller - c0a9:5415 # Micron/Crucial Technology T500 NVMe PCIe SSD @@ -143,9 +145,9 @@ virt_machines: uuid: "51d5d091-67cb-4113-bd8e-817e7317e1b4" autostart: false memory: 16 - cores: 5 + cores: 4 threads: 2 - physical_cpus: "3-11,4-12,5-13,6-14,7-15" + physical_cpus: "4-12,5-13,6-14,7-15" reserved_cpus: "0,8" enable_hyperv: true cdrom: true @@ -222,9 +224,9 @@ virt_machines: uuid: "51d5d091-67cb-4113-bd8e-817e7317e1b5" autostart: false memory: 16 - cores: 5 + cores: 4 threads: 2 - physical_cpus: "3-11,4-12,5-13,6-14,7-15" + physical_cpus: "4-12,5-13,6-14,7-15" reserved_cpus: "0,8" enable_hyperv: true cdrom: true @@ -301,9 +303,9 @@ virt_machines: uuid: "51d5d091-67cb-4113-bd8e-817e7317e1b6" autostart: false memory: 16 - cores: 5 + cores: 4 threads: 2 - physical_cpus: "3-11,4-12,5-13,6-14,7-15" + physical_cpus: "4-12,5-13,6-14,7-15" reserved_cpus: "0,8" enable_hyperv: true cdrom: true @@ -380,9 +382,9 @@ virt_machines: uuid: "51d5d091-67cb-4113-bd8e-817e7317e1b7" autostart: false memory: 16 - cores: 5 + cores: 4 threads: 2 - physical_cpus: "3-11,4-12,5-13,6-14,7-15" + physical_cpus: "4-12,5-13,6-14,7-15" reserved_cpus: "0,8" enable_hyperv: true cdrom: true @@ -463,9 +465,9 @@ virt_machines: cloud_init: true autostart: true memory: 8 - cores: 1 + cores: 2 threads: 2 - physical_cpus: "2-10" + physical_cpus: "2-10,3-11" reserved_cpus: "0,8" cdrom: true console: true diff --git a/ansible/playbook_systools.yml b/ansible/playbook_systools.yml index 612340c..b09ba39 100644 --- a/ansible/playbook_systools.yml +++ b/ansible/playbook_systools.yml @@ -3,7 +3,7 @@ hosts: ubuntu gather_facts: true -# Specific tasks for this playbook + # Specific tasks for this playbook tasks: - name: Set required facts ansible.builtin.set_fact: @@ -15,7 +15,7 @@ ansible.builtin.get_url: url: https://github.com/a13labs/systools/releases/download/v{{ systools_version }}/systools-v{{ systools_version }}-linux-amd64.zip dest: /tmp/systools-v{{ systools_version }}-linux-amd64.zip - mode: '0644' + mode: "0644" - name: Unpack systools zip file become: true @@ -24,7 +24,7 @@ src: /tmp/systools-v{{ systools_version }}-linux-amd64.zip dest: /usr/local/bin remote_src: true - mode: '0755' + mode: "0755" extra_opts: - -j @@ -37,7 +37,7 @@ become: true ansible.builtin.file: path: /usr/local/bin/{{ item }} - mode: '0700' + mode: "0700" loop: - open_volume - read_system_id @@ -48,14 +48,22 @@ ansible.builtin.file: path: /var/run/ssh_locker state: directory - mode: '0777' + mode: "0777" + + - name: Add entry on tmpfiles.d for persisting socket permissions + become: true + ansible.builtin.copy: + dest: /etc/tmpfiles.d/ssh_locker.conf + mode: "0700" + content: | + d /run/ssh_locker 0777 root root - - name: Install ssh_locker service become: true ansible.builtin.template: src: ssh_locker.service.j2 dest: /etc/systemd/system/ssh_locker.service - mode: '0644' + mode: "0644" notify: - Reload systemd daemon - Enable ssh_locker service diff --git a/ansible/roles/windows_containers/tasks/main.yml b/ansible/roles/windows_containers/tasks/main.yml index f7ffad4..c1e114f 100644 --- a/ansible/roles/windows_containers/tasks/main.yml +++ b/ansible/roles/windows_containers/tasks/main.yml @@ -19,19 +19,18 @@ tags: - roles::windows_containers - roles::windows_containers::podman_install +# # ── Phase 2: Ubuntu container ──────────────────────────────────────────── +# - name: Setup Ubuntu container +# ansible.builtin.include_tasks: ubuntu_container.yml +# tags: +# - roles::windows_containers +# - roles::windows_containers::ubuntu_container +# when: ansible_facts.os_product_type == "workstation" -# ── Phase 2: Ubuntu container ──────────────────────────────────────────── -- name: Setup Ubuntu container - ansible.builtin.include_tasks: ubuntu_container.yml - tags: - - roles::windows_containers - - roles::windows_containers::ubuntu_container - when: ansible_facts.os_product_type == "workstation" - -# ── Phase 3: Verification ──────────────────────────────────────────────── -- name: Verify installation - ansible.builtin.include_tasks: verify.yml - tags: - - roles::windows_containers - - roles::windows_containers::verify - when: ansible_facts.os_product_type == "workstation" +# # ── Phase 3: Verification ──────────────────────────────────────────────── +# - name: Verify installation +# ansible.builtin.include_tasks: verify.yml +# tags: +# - roles::windows_containers +# - roles::windows_containers::verify +# when: ansible_facts.os_product_type == "workstation" diff --git a/ansible/roles/windows_containers/tasks/ubuntu_container.yml b/ansible/roles/windows_containers/tasks/obsolete/ubuntu_container.yml similarity index 100% rename from ansible/roles/windows_containers/tasks/ubuntu_container.yml rename to ansible/roles/windows_containers/tasks/obsolete/ubuntu_container.yml diff --git a/ansible/roles/windows_containers/tasks/verify.yml b/ansible/roles/windows_containers/tasks/obsolete/verify.yml similarity index 100% rename from ansible/roles/windows_containers/tasks/verify.yml rename to ansible/roles/windows_containers/tasks/obsolete/verify.yml diff --git a/scripts/install-opnsense.sh b/scripts/install-opnsense.sh index 15e0c9a..a007967 100755 --- a/scripts/install-opnsense.sh +++ b/scripts/install-opnsense.sh @@ -152,3 +152,4 @@ rm -f /tmp/opnsense-install.img /tmp/opnsense-install.img.bz2 /tmp/config.iso rm -rf /tmp/opnsense-config echo "Done." +exit 0 \ No newline at end of file diff --git a/terraform/apps/dev-01/apps.tf b/terraform/apps/dev-01/apps.tf index 7f127c2..12686a9 100644 --- a/terraform/apps/dev-01/apps.tf +++ b/terraform/apps/dev-01/apps.tf @@ -43,6 +43,14 @@ module "nextcloud" { issuer = local.internal_issuer } +module "llama_windows_proxy" { + source = "../../modules/utils/wol_proxy" + + upstream = local.llm_proxy_1 + proxy_port = 11435 + namespace = "llamacpp" +} + # module "comfyui_proxy" { # source = "../../modules/utils/wol_proxy" @@ -122,3 +130,11 @@ module "vaultwarden" { # signup_enabled = true # signup_verify = false } + +module "terraform-mcp" { + source = "../../modules/apps/terraform-mcp" + + fqdn = local.terraform_mcp_fqdn + tag = "1.0.0" + persistent_folder = local.persistent_folder +} diff --git a/terraform/apps/dev-01/config.tf b/terraform/apps/dev-01/config.tf index 4ec25e2..f5ac8d4 100644 --- a/terraform/apps/dev-01/config.tf +++ b/terraform/apps/dev-01/config.tf @@ -126,6 +126,11 @@ locals { name = "vaultwarden" type = "CNAME" content = "dev-01.${local.lab_domain}." + }, + { + name = "terraform-mcp" + type = "CNAME" + content = "dev-01.${local.lab_domain}." } ] } @@ -179,6 +184,14 @@ locals { scheme = "http" } + llm_proxy_1 = { + enabled = true + mac = "52:54:00:CD:DD:2E" + ip = "10.19.4.207" + port = 11434 + scheme = "http" + } + # comfyui_proxy = { # mac = "04:7c:16:d6:63:66" # ip = "10.19.4.106" @@ -267,6 +280,9 @@ locals { vaultwarden_smtp_from_name = "Vaultwarden" vaultwarden_smtp_username = var.scaleway_project_id vaultwarden_smtp_password = local.mail_app_api_secret_key + + # terraform-mcp + terraform_mcp_fqdn = "terraform-mcp.${local.lab_domain}" } data "terraform_remote_state" "scaleway" { diff --git a/terraform/apps/dev-01/sectool.json b/terraform/apps/dev-01/sectool.json new file mode 120000 index 0000000..681e1f8 --- /dev/null +++ b/terraform/apps/dev-01/sectool.json @@ -0,0 +1 @@ +../../../sectool.json \ No newline at end of file diff --git a/terraform/apps/prod-01/apps.tf b/terraform/apps/prod-01/apps.tf index 9f31ea0..8faf7bf 100644 --- a/terraform/apps/prod-01/apps.tf +++ b/terraform/apps/prod-01/apps.tf @@ -89,6 +89,7 @@ module "gitea" { smtp_passwd = local.mail_app_api_secret_key secret_key = var.gitea_secret_key internal_token = var.gitea_internal_token + s3_storage = join("\n", [for k, v in local.gitea_s3_storage : "${k}=${v}"]) disable_registration = true } } @@ -157,24 +158,3 @@ module "auth_exporter" { source = "../../modules/utils/auth-exporter" persistent_folder = "${local.persistent_folder}/monitoring" } - -module "vaultwarden" { - source = "../../modules/apps/vaultwarden" - - persistent_folder = local.vaultwarden_folder - fqdn = local.vaultwarden_fqdn - issuer = local.vaultwarden_issuer - tag = local.vaultwarden_version - admin_token = var.vaultwarden_admin_token - smtp_host = local.vaultwarden_smtp_host - smtp_port = local.vaultwarden_smtp_port - smtp_security = local.vaultwarden_smtp_security - smtp_from = local.vaultwarden_smtp_from - smtp_from_name = local.vaultwarden_smtp_from_name - smtp_username = local.vaultwarden_smtp_username - smtp_password = var.vaultwarden_smtp_password - smtp_timeout = local.vaultwarden_smtp_timeout - smtp_auth_mechanism = local.vaultwarden_smtp_auth_mechanism - smtp_helo_name = local.vaultwarden_smtp_helo_name - smtp_embed_images = local.vaultwarden_smtp_embed_images -} diff --git a/terraform/apps/prod-01/config.tf b/terraform/apps/prod-01/config.tf index 38c564b..733e894 100644 --- a/terraform/apps/prod-01/config.tf +++ b/terraform/apps/prod-01/config.tf @@ -18,8 +18,17 @@ locals { } # gitea - gitea_version = "1.25-rootless" + gitea_version = "1.26-rootless" gitea_fqdn = "code.${local.primary_domain}" + gitea_s3_storage = { + STORAGE_TYPE = "minio" + MINIO_ENDPOINT = "s3.fr-par.scw.cloud" + MINIO_ACCESS_KEY_ID = data.terraform_remote_state.scaleway.outputs.gitea_app_api_access_key + MINIO_SECRET_ACCESS_KEY = data.terraform_remote_state.scaleway.outputs.gitea_app_api_secret_key + MINIO_BUCKET = data.terraform_remote_state.scaleway.outputs.gitea_bucket_name + MINIO_LOCATION = "fr-par" + MINIO_USE_SSL = true + } # sftpgo sftpgo_version = "2.6.x" @@ -210,22 +219,6 @@ locals { # telegram_chat_id = "-950480346" # alexpires.me group telegram_message = file("${path.module}/resources/telegram.tpl") - # vaultwarden - vaultwarden_folder = "${local.persistent_folder}/vaultwarden" - vaultwarden_fqdn = "vaultwarden.${local.primary_domain}" - vaultwarden_issuer = "internal-ca" - vaultwarden_version = "1.36.0" - vaultwarden_smtp_host = "" - vaultwarden_smtp_port = 587 - vaultwarden_smtp_security = "starttls" - vaultwarden_smtp_from = "" - vaultwarden_smtp_from_name = "Vaultwarden" - vaultwarden_smtp_username = "" - vaultwarden_smtp_timeout = 15 - vaultwarden_smtp_auth_mechanism = "" - vaultwarden_smtp_helo_name = "" - vaultwarden_smtp_embed_images = true - # get secrets from remote state backup_bucket_name = data.terraform_remote_state.scaleway.outputs.backup_bucket_name backup_app_api_secret_key = data.terraform_remote_state.scaleway.outputs.backup_app_api_secret_key diff --git a/terraform/apps/prod-01/secrets.tf b/terraform/apps/prod-01/secrets.tf index ae0e576..4b4cc0f 100644 --- a/terraform/apps/prod-01/secrets.tf +++ b/terraform/apps/prod-01/secrets.tf @@ -134,16 +134,3 @@ variable "telegram_bot_token" { type = string sensitive = true } - -variable "vaultwarden_admin_token" { - description = "The admin token for VaultWarden" - type = string - sensitive = true -} - -variable "vaultwarden_smtp_password" { - description = "SMTP password for VaultWarden email" - type = string - sensitive = true - default = "" -} diff --git a/terraform/apps/prod-01/sectool.env b/terraform/apps/prod-01/sectool.env index 0e3a31d..4cf4889 100644 --- a/terraform/apps/prod-01/sectool.env +++ b/terraform/apps/prod-01/sectool.env @@ -33,5 +33,3 @@ TF_VAR_wireguard_1_public_key=$WIREGUARD_1_PUBLIC_KEY TF_VAR_wireguard_1_pre_shared_key=$WIREGUARD_1_PRE_SHARED_KEY TF_VAR_nginx_token_bearer=$NGINX_TOKEN_BEARER TF_VAR_telegram_bot_token=$TELEGRAM_BOT_TOKEN -TF_VAR_vaultwarden_admin_token=$VAULTWARDEN_ADMIN_TOKEN -TF_VAR_vaultwarden_smtp_password=$VAULTWARDEN_SMTP_PASSWORD diff --git a/terraform/apps/prod-01/sectool.json b/terraform/apps/prod-01/sectool.json new file mode 120000 index 0000000..681e1f8 --- /dev/null +++ b/terraform/apps/prod-01/sectool.json @@ -0,0 +1 @@ +../../../sectool.json \ No newline at end of file diff --git a/terraform/iac/scaleway/buckets.tf b/terraform/iac/scaleway/buckets.tf index 220c439..12458b8 100644 --- a/terraform/iac/scaleway/buckets.tf +++ b/terraform/iac/scaleway/buckets.tf @@ -165,3 +165,50 @@ resource "scaleway_object_bucket_policy" "sftpgo" { }) } +resource "scaleway_object_bucket" "gitea" { + name = "a13labs-gitea-packages-${random_string.bucket_suffix.result}" + project_id = var.scaleway_project_id + region = "fr-par" +} + +resource "scaleway_object_bucket_policy" "gitea" { + bucket = scaleway_object_bucket.gitea.name + policy = jsonencode({ + Version = "2023-04-17", + Id = "AllowAccess", + Statement = [ + { + Effect = "Allow" + Action = [ + "s3:*", + ] + Principal = { + SCW = "user_id:${var.scaleway_user_id}" + } + Resource = [ + scaleway_object_bucket.gitea.name, + "${scaleway_object_bucket.gitea.name}/*", + ] + }, + { + Effect = "Allow" + Action = [ + "s3:*", + ] + Principal = { + SCW = "application_id:${scaleway_iam_application.gitea_app.id}" + } + Resource = [ + scaleway_object_bucket.gitea.name, + "${scaleway_object_bucket.gitea.name}/*", + ], + Condition = { + IpAddress = { + "aws:SourceIp" = local.instance_ips + } + }, + }, + ] + }) +} + diff --git a/terraform/iac/scaleway/iam.tf b/terraform/iac/scaleway/iam.tf index 504efb8..1be7fb8 100644 --- a/terraform/iac/scaleway/iam.tf +++ b/terraform/iac/scaleway/iam.tf @@ -56,6 +56,27 @@ resource "scaleway_iam_policy" "object_read_write_sftpgo" { } } +resource "scaleway_iam_application" "gitea_app" { + name = "gitea_app" +} + +resource "scaleway_iam_policy" "object_read_write_gitea" { + name = "Gitea app policy" + description = "Gives gitea job access to object storage in project" + application_id = scaleway_iam_application.gitea_app.id + + rule { + project_ids = [data.scaleway_account_project.default.id] + permission_set_names = [ + "ObjectStorageObjectsWrite", + "ObjectStorageObjectsRead", + "ObjectStorageBucketsRead", + "ObjectStorageBucketsWrite", + "ObjectStorageObjectsDelete" + ] + } +} + resource "scaleway_iam_api_key" "backup_app_api" { application_id = scaleway_iam_application.backup_app.id description = "k8s backup app API key" @@ -70,3 +91,8 @@ resource "scaleway_iam_api_key" "sftpgo_app_api" { application_id = scaleway_iam_application.sftpgo_app.id description = "sftpgo access API key" } + +resource "scaleway_iam_api_key" "gitea_app_api" { + application_id = scaleway_iam_application.gitea_app.id + description = "gitea access API key" +} diff --git a/terraform/iac/scaleway/outputs.tf b/terraform/iac/scaleway/outputs.tf index 8486678..45f04e6 100644 --- a/terraform/iac/scaleway/outputs.tf +++ b/terraform/iac/scaleway/outputs.tf @@ -32,3 +32,20 @@ output "sftpgo_app_api_secret_key" { value = scaleway_iam_api_key.sftpgo_app_api.secret_key sensitive = true } + +output "gitea_app_api_access_key" { + description = "The access key for the Gitea app API." + value = scaleway_iam_api_key.gitea_app_api.access_key + sensitive = true +} + +output "gitea_app_api_secret_key" { + description = "The secret key for the Gitea app API." + value = scaleway_iam_api_key.gitea_app_api.secret_key + sensitive = true +} + +output "gitea_bucket_name" { + description = "The name of the Gitea bucket." + value = scaleway_object_bucket.gitea.name +} diff --git a/terraform/iac/scaleway/sectool.json b/terraform/iac/scaleway/sectool.json new file mode 120000 index 0000000..681e1f8 --- /dev/null +++ b/terraform/iac/scaleway/sectool.json @@ -0,0 +1 @@ +../../../sectool.json \ No newline at end of file diff --git a/terraform/modules/apps/gitea/config.tf b/terraform/modules/apps/gitea/config.tf index 3440cb4..c69d0ff 100644 --- a/terraform/modules/apps/gitea/config.tf +++ b/terraform/modules/apps/gitea/config.tf @@ -35,6 +35,7 @@ locals { SMTP_HOST = var.app_config.smtp_host SMTP_PORT = var.app_config.smtp_port SSH_SERVER_KEY_EXCHANGES = "mlkem768x25519-sha256" + S3_STORAGE = var.app_config.s3_storage }) config_checksum = sha256(local.config) } diff --git a/terraform/modules/apps/gitea/resources/app.ini.tpl b/terraform/modules/apps/gitea/resources/app.ini.tpl index ad5c0ca..30feceb 100644 --- a/terraform/modules/apps/gitea/resources/app.ini.tpl +++ b/terraform/modules/apps/gitea/resources/app.ini.tpl @@ -37,8 +37,11 @@ OFFLINE_MODE = false SHELL = /bin/sh SSH_SERVER_KEY_EXCHANGES=${SSH_SERVER_KEY_EXCHANGES} +%{ if S3_STORAGE != "" ~} +%{ else ~} [lfs] PATH = /data/git/lfs +%{ endif } [database] PATH = /data/gitea/gitea.db @@ -97,3 +100,8 @@ SMTP_PORT = ${SMTP_PORT} [openid] ENABLE_OPENID_SIGNIN = true ENABLE_OPENID_SIGNUP = false + +%{ if S3_STORAGE != "" ~} +[storage] +${S3_STORAGE} +%{ endif } diff --git a/terraform/modules/apps/gitea/variables.tf b/terraform/modules/apps/gitea/variables.tf index d43e461..ba89000 100644 --- a/terraform/modules/apps/gitea/variables.tf +++ b/terraform/modules/apps/gitea/variables.tf @@ -84,5 +84,6 @@ variable "app_config" { db_user = optional(string, "gitea") smtp_protocol = optional(string, "SMTPS") smtp_port = optional(string, "587") + s3_storage = optional(string, "") }) } diff --git a/terraform/modules/apps/nextcloud/config.tf b/terraform/modules/apps/nextcloud/config.tf index 23fef37..459a256 100644 --- a/terraform/modules/apps/nextcloud/config.tf +++ b/terraform/modules/apps/nextcloud/config.tf @@ -35,7 +35,7 @@ locals { OVERWRITECLIURL = "https://${var.fqdn}" # PHP - PHP_MEMORY_LIMIT = "512M" + PHP_MEMORY_LIMIT = "2048M" }, var.db_credentials_are_secrets ? {} : local.database_credentials) nextcloud_secrets = merge({ diff --git a/terraform/modules/apps/terraform-mcp/config.tf b/terraform/modules/apps/terraform-mcp/config.tf new file mode 100644 index 0000000..59a8315 --- /dev/null +++ b/terraform/modules/apps/terraform-mcp/config.tf @@ -0,0 +1,4 @@ +locals { + app_version = var.tag + app_fqdn = var.fqdn +} diff --git a/terraform/modules/apps/terraform-mcp/ingress.tf b/terraform/modules/apps/terraform-mcp/ingress.tf new file mode 100644 index 0000000..c91d9ed --- /dev/null +++ b/terraform/modules/apps/terraform-mcp/ingress.tf @@ -0,0 +1,24 @@ +resource "kubernetes_ingress_v1" "terraform_mcp" { + metadata { + name = "ingress" + namespace = kubernetes_namespace.terraform_mcp.metadata[0].name + } + + spec { + rule { + host = var.fqdn + http { + path { + backend { + service { + name = kubernetes_service.terraform_mcp.metadata[0].name + port { + number = 80 + } + } + } + } + } + } + } +} diff --git a/terraform/modules/apps/terraform-mcp/main.tf b/terraform/modules/apps/terraform-mcp/main.tf new file mode 100644 index 0000000..3db1511 --- /dev/null +++ b/terraform/modules/apps/terraform-mcp/main.tf @@ -0,0 +1,131 @@ +resource "kubernetes_namespace" "terraform_mcp" { + metadata { + name = "terraform-mcp" + } +} + +resource "kubernetes_service_account" "terraform_mcp" { + metadata { + name = "terraform-mcp-sa" + namespace = kubernetes_namespace.terraform_mcp.metadata[0].name + } + + automount_service_account_token = false +} + +resource "kubernetes_deployment" "terraform_mcp" { + metadata { + name = "terraform-mcp" + namespace = kubernetes_namespace.terraform_mcp.metadata[0].name + labels = { + app = "terraform-mcp" + } + } + + spec { + replicas = 1 + + selector { + match_labels = { + app = "terraform-mcp" + } + } + + strategy { + type = "Recreate" + } + + template { + metadata { + labels = { + app = "terraform-mcp" + } + } + + spec { + service_account_name = kubernetes_service_account.terraform_mcp.metadata[0].name + automount_service_account_token = false + + container { + name = "terraform-mcp" + image = "hashicorp/terraform-mcp-server:${local.app_version}" + + env { + name = "TRANSPORT_MODE" + value = "streamable-http" + } + + env { + name = "TRANSPORT_PORT" + value = "8084" + } + + env { + name = "TRANSPORT_HOST" + value = "0.0.0.0" + } + + security_context { + allow_privilege_escalation = false + privileged = false + + capabilities { + drop = ["ALL"] + } + } + + port { + name = "http" + container_port = 8084 + protocol = "TCP" + } + + liveness_probe { + http_get { + path = "/health" + port = "http" + } + initial_delay_seconds = 10 + period_seconds = 15 + } + + readiness_probe { + http_get { + path = "/health" + port = "http" + } + initial_delay_seconds = 5 + period_seconds = 10 + } + } + } + } + } +} + +resource "kubernetes_service" "terraform_mcp" { + metadata { + name = "terraform-mcp-service" + namespace = kubernetes_namespace.terraform_mcp.metadata[0].name + } + + spec { + selector = { + app = "terraform-mcp" + } + + port { + name = "http" + port = 80 + target_port = 8084 + } + + type = "ClusterIP" + } + + lifecycle { + ignore_changes = [ + metadata[0].annotations + ] + } +} diff --git a/terraform/modules/apps/terraform-mcp/provider.tf b/terraform/modules/apps/terraform-mcp/provider.tf new file mode 100644 index 0000000..2eaa508 --- /dev/null +++ b/terraform/modules/apps/terraform-mcp/provider.tf @@ -0,0 +1,9 @@ +terraform { + required_version = "~>1.8" + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "2.36.0" + } + } +} diff --git a/terraform/modules/apps/terraform-mcp/variables.tf b/terraform/modules/apps/terraform-mcp/variables.tf new file mode 100644 index 0000000..4d0ed49 --- /dev/null +++ b/terraform/modules/apps/terraform-mcp/variables.tf @@ -0,0 +1,15 @@ +variable "fqdn" { + description = "FQDN for the service" + type = string +} + +variable "tag" { + description = "Image tag to deploy" + type = string + default = "1.0.0" +} + +variable "persistent_folder" { + description = "Path for persistent data on the host" + type = string +}