terraform-contour-mirror/live/_shared/config.hcl
Kochetkov S 0b7545670f
All checks were successful
Terraform Terragrunt (contour) / validate (push) Successful in 59s
Terraform Terragrunt (contour) / plan (push) Successful in 1m5s
Terraform Terragrunt (contour) / apply (push) Successful in 1m56s
++ service contract compiler, issues on brusnika-stage
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 16:17:33 +03:00

136 lines
6.5 KiB
HCL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Единственное место загрузки контракта сервисов (environments/<env>/*.yaml).
#
# Файл называется config.hcl, а НЕ terragrunt.hcl, намеренно: и
# scripts/run_all_stacks.sh, и scripts/generate-pipeline.sh ищут юниты строго по
# имени terragrunt.hcl, поэтому этот файл юнитом не считается и сам по себе не
# прогоняется.
#
# Стеки подключают его через read_terragrunt_config() и берут local.<...>.
# Именно read_terragrunt_config, а не dependency: dependency не виден из блока
# locals, и попытка протащить компилятор через него уже роняла пайплайн.
#
# Окружение считается переехавшим на новый формат, только если у него есть
# environments/<env>/environment.yaml. Для остальных контуров всё ниже
# вырождается в пустые списки, и concat на стороне стеков становится
# тождественной операцией.
locals {
repo_root = try(get_repo_root(), "${get_terragrunt_dir()}/../..")
infra_config = yamldecode(file("${local.repo_root}/infrastructure.yaml"))
env_override = trimspace(get_env("INFRA_ENV", ""))
env_from_file = try(trimspace(local.infra_config.current_environment), "")
env_name = local.env_override != "" ? local.env_override : (
local.env_from_file != "" ? local.env_from_file : try(sort(keys(try(local.infra_config.environments, {})))[0], "")
)
env_dir = "${local.repo_root}/environments/${local.env_name}"
# try(), а не тернарник по fileexists: в HCL обе ветки тернарника обязаны
# иметь совместимые типы, а пустой объект против объекта с backends их не
# имеет - "Inconsistent conditional result types".
environment = try(yamldecode(file("${local.env_dir}/environment.yaml")), {})
namespaces = try(yamldecode(file("${local.env_dir}/namespaces.yaml")).namespaces, {})
service_files = try(fileset(local.env_dir, "services/*.yaml"), [])
services = {
for f in local.service_files :
trimsuffix(basename(f), ".yaml") => yamldecode(file("${local.env_dir}/${f}"))
}
registry = try(local.environment.registry, null)
credentials_ref = try(local.registry.credentials_ref, "")
# ── вывод сущностей из имени сервиса ───────────────────────────────────────
# vhosts пуст -> [<service>]; первый vhost основной, его секрет зовётся просто
# rabbitmq, остальные получают суффикс - хвост после "<service>-".
service_vhosts = {
for name, svc in local.services :
name => length(try(svc.needs.rabbitmq.vhosts, [])) > 0 ? svc.needs.rabbitmq.vhosts : [name]
if try(svc.needs.rabbitmq, null) != null
}
# сервис размещён во всех namespace, где он перечислен в services[]
service_namespaces = {
for name, _ in local.services :
name => sort([for ns_key, ns in local.namespaces : ns_key if contains(try(ns.services, []), name)])
}
# ── inputs для modules/k8s-namespace ───────────────────────────────────────
namespaces_input = [
for ns_key, ns in local.namespaces : {
name = ns_key
labels = try(ns.labels, {})
annotations = try(ns.annotations, {})
manage = try(ns.manage, true)
image_pull_secret = try(ns.image_pull_secret, true)
}
]
# ── inputs для modules/rabbitmq ────────────────────────────────────────────
rabbitmq_vhosts = [
for v in sort(distinct(flatten([for _, vhosts in local.service_vhosts : vhosts]))) : { name = v }
]
rabbitmq_users = [
for name, _ in local.service_vhosts : { name = name, password_length = 32, password_special = false }
]
# владелец получает полные права в каждом своём vhost
rabbitmq_permissions = flatten([
for name, vhosts in local.service_vhosts : [
for v in vhosts : { user = name, vhost = v, configure = ".*", write = ".*", read = ".*" }
]
])
# ── секреты в форме v2-контракта ───────────────────────────────────────────
# Отдаём именно записи с targets, а не плоский список: live/secrets вливает их
# ДО собственного разбора v2, поэтому вся его машинерия (валидация ключей,
# вывод type из source.kind, разворачивание targets) работает без изменений.
secret_prefix = {
for name, _ in local.services : name => join("", [
for ns_key in local.service_namespaces[name] :
try(local.namespaces[ns_key].secret_prefix, "") == "service" ? "${name}-" : ""
])
}
rabbitmq_secrets = flatten([
for name, vhosts in local.service_vhosts : [
for ns_key in local.service_namespaces[name] : [
for idx, v in vhosts : {
id = "${name}-rabbitmq-${ns_key}-${v}"
schema = "rabbitmq.v1"
namespace = ns_key
ownership = "managed"
source = {
kind = "rabbitmq_user"
ref = { vhost = v, user = name }
}
targets = [{
kind = "kubernetes"
namespace = ns_key
name = "${try(local.namespaces[ns_key].secret_prefix, "") == "service" ? "${name}-" : ""}rabbitmq${idx == 0 ? "" : "-${trimprefix(v, "${name}-")}"}"
}]
}
]
]
])
regcred_secrets = local.credentials_ref == "" ? [] : [
for ns_key, ns in local.namespaces : {
id = "${ns_key}-regcred"
schema = "dockerconfigjson.v1"
namespace = ns_key
ownership = "referenced"
source = {
kind = "secret_ref"
ref = local.credentials_ref
}
targets = [{ kind = "kubernetes", namespace = ns_key, name = "regcred" }]
}
if try(ns.image_pull_secret, true)
]
secrets_v2 = concat(local.regcred_secrets, local.rabbitmq_secrets)
}