Files
hrbox-helm-chart/.helm/templates/00-validate.yaml
T
gnome627andClaude Opus 5 efc506e5de DEVOPS-117: чарт on-premise 3.0 — Nanabush Player, секреты в Secret, валидация values
Актуализация чарта по продовому .helm из HRBOX.

Nanabush Player перенесён из прода и упрощён под one-release-топологию
on-premise: без карт env/ci_dc, но с сохранёнными инвариантами (audience =
https://<host>, basePath отдельно от aud, allowlist обратного канала только
на внутрикластерный web, метрики на непубликуемом порту). Выделенного
поддомена в on-premise нет, поэтому плеер монтируется на основной домен под
/nanabush-player. Три переключателя для аварийного отката сохранены.

Из прода также перенесены: пул конвертации видео, PodDisruptionBudget для
web, OpenTelemetry-сайдкар, assetlinks, набор location в nginx (/healthz,
/health-check, потоковый /api/v1/integration/commit, /ai/, sw.js, шрифты).
Версии образов подтянуты к продовым.

Приведение чарта в порядок: все образы в блоке image, imagePullSecrets в
настройках, девять одинаковых define ресурсов заменены одним хелпером,
удалено ~100 строк мёртвого кода в _helpers.tpl, пароли и ключи уехали в
Secret и читаются через secretKeyRef, добавлены 00-validate.yaml и NOTES.txt.

Исправлено в 2.x:
- SERVICES_INTERNAL_SECRET имел захардкоженное значение по умолчанию, то есть
  все установки, где его не заполнили, работали на одном секрете межсервисной
  аутентификации;
- cluster.domain игнорировался: маршруты кластера NATS были захардкожены на
  cluster.local;
- CLUSTER_ADVERTISE без сегмента svc — ноды NATS объявляли соседям
  недостижимый адрес;
- nats.replicas и nats.cluster.replicas задавались независимо, при
  расхождении часть нод не входила в кластер;
- пробы web проверяли только TCP-порт 9000, поэтому под с неработающим PHP
  считался готовым;
- внутренние URL были захардкожены строками hrbox-* и молча ломались при
  nameOverride.

Имена объектов и селекторы Deployment не менялись — обновление 2.x -> 3.0 не
пересоздаёт объекты. Переехавшие ключи values.yaml чарт распознаёт и
останавливает установку с подсказкой; порядок перехода — в CHANGELOG.md.

Проверено: helm lint чистый; отрендерены 4 конфигурации (дефолт, всё
включено, плеер и инфра выключены, nameOverride); структурная проверка
рендера без замечаний; 20 негативных сценариев срабатывают с ожидаемыми
сообщениями; реалистичный values.yaml из 2.x последовательно ловится всеми
шестью guard'ами.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 16:37:42 +06:00

152 lines
9.0 KiB
YAML
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.
{{/*
============================================================================
Проверка values.yaml
============================================================================
Этот файл не создаёт ни одного объекта. Он выполняется первым и падает с
понятным сообщением, если конфигурация неполная или противоречивая, — до
того, как в кластере появятся поды, которые всё равно не заработают.
Проверяется три вещи:
1) ключи, переехавшие в версии 3.0 (подсказка вместо тихого игнора);
2) обязательные значения, без которых приложение не поднимется;
3) инварианты Nanabush Player.
*/}}
{{/* --- 1. Ключи из чарта 2.x ---------------------------------------------- */}}
{{- if .Values.app.image }}
{{- fail "app.image переехал в image.hrbox (см. CHANGELOG, миграция 2.x -> 3.0)" }}
{{- end }}
{{- if .Values.app.chatbox.image }}
{{- fail "app.chatbox.image переехал в image.chatbox" }}
{{- end }}
{{- if .Values.app.goworker.image }}
{{- fail "app.goworker.image переехал в image.goworker" }}
{{- end }}
{{- if .Values.app.kedoca.image }}
{{- fail "app.kedoca.image переехал в image.kedoca" }}
{{- end }}
{{- if .Values.app.file_processor }}
{{- fail "app.file_processor переименован в app.fileProcessor, а образ переехал в image.fileProcessor" }}
{{- end }}
{{- if .Values.app.custom_policy }}
{{- fail "app.custom_policy переименован в app.customPolicy" }}
{{- end }}
{{- if .Values.app.replicas.websocket }}
{{- fail "app.replicas.websocket переименован в app.replicas.chatbox ещё в версии 2.0" }}
{{- end }}
{{- if .Values.resources.websocket }}
{{- fail "resources.websocket переименован в resources.chatbox ещё в версии 2.0" }}
{{- end }}
{{- if .Values.nats.image }}
{{- fail "nats.image переехал в image.nats" }}
{{- end }}
{{/* --- 2. Обязательные значения ------------------------------------------- */}}
{{- if not .Values.ingress.host }}
{{- fail "Заполните ingress.host — домен, по которому открывается HRBox" }}
{{- end }}
{{- if not .Values.app.defaultTenantHostname }}
{{- fail "Заполните app.defaultTenantHostname (обычно совпадает с ingress.host)" }}
{{- end }}
{{- if not .Values.app.postgres.password }}
{{- fail "Заполните app.postgres.password" }}
{{- end }}
{{- if not .Values.app.s3.key }}
{{- fail "Заполните app.s3.key — без хранилища файлов HRBox не работает" }}
{{- end }}
{{- if not .Values.app.s3.secret }}
{{- fail "Заполните app.s3.secret" }}
{{- end }}
{{- if not .Values.app.hub.token }}
{{- fail "Заполните app.hub.token — токен выдают сотрудники HRBox" }}
{{- end }}
{{- if not .Values.secrets.existingSecret }}
{{- if not .Values.secrets.cookieValidationKey }}
{{- fail "Заполните secrets.cookieValidationKey (openssl rand -hex 16)" }}
{{- end }}
{{- if not .Values.secrets.encryptionKey }}
{{- fail "Заполните secrets.encryptionKey (openssl rand -base64 48). Потеря ключа делает зашифрованные данные нечитаемыми" }}
{{- end }}
{{- if not .Values.secrets.servicesInternalSecret }}
{{- fail "Заполните secrets.servicesInternalSecret (openssl rand -base64 48)" }}
{{- end }}
{{- if not .Values.app.chatbox.wrappingKey }}
{{- fail "Заполните app.chatbox.wrappingKey (openssl rand -hex 16)" }}
{{- end }}
{{- end }}
{{- if .Values.ingress.tls.enabled }}
{{- if not .Values.ingress.tls.secretName }}
{{- fail "При ingress.tls.enabled нужен ingress.tls.secretName с TLS-сертификатом" }}
{{- end }}
{{- end }}
{{/* --- 3. Внешние зависимости ---------------------------------------------- */}}
{{- if and (not .Values.dragonfly.enabled) (not .Values.app.redis.host) }}
{{- fail "dragonfly.enabled: false требует app.redis.host — иначе приложение обратится к сервису, которого нет в релизе" }}
{{- end }}
{{- if and (not .Values.nats.enabled) (not .Values.app.nats.url) }}
{{- fail "nats.enabled: false требует app.nats.url — иначе приложение обратится к брокеру, которого нет в релизе" }}
{{- end }}
{{- if and .Values.nats.enabled .Values.nats.cluster.enabled }}
{{- if ne (.Values.nats.replicas | int) (.Values.nats.cluster.replicas | int) }}
{{- fail (printf "nats.replicas (%d) и nats.cluster.replicas (%d) должны совпадать: иначе часть нод не войдёт в кластер, а реплики JetStream-стримов будут посчитаны неверно" (.Values.nats.replicas | int) (.Values.nats.cluster.replicas | int)) }}
{{- end }}
{{- end }}
{{/* --- 4. Nanabush Player -------------------------------------------------- */}}
{{- $player := .Values.app.nanabushPlayer }}
{{- if and $player.enabled (not $player.deployment.enabled) }}
{{- fail "app.nanabushPlayer.enabled требует deployment.enabled: HRBox нельзя переключить на плеер, которого нет в кластере" }}
{{- end }}
{{- if and $player.enabled (not $player.ingress.enabled) }}
{{- fail "app.nanabushPlayer.enabled требует ingress.enabled: иначе HRBox выдаст ссылку на недоступный адрес" }}
{{- end }}
{{- if and $player.ingress.enabled (not $player.deployment.enabled) }}
{{- fail "app.nanabushPlayer.ingress.enabled требует deployment.enabled: маршрут вёл бы в несуществующий Service" }}
{{- end }}
{{- if and $player.ingress.enabled (not .Values.ingress.enabled) }}
{{- fail "Путь плеера публикуется на основном Ingress, поэтому нужен ingress.enabled: true" }}
{{- end }}
{{- if $player.deployment.enabled }}
{{- $basePath := $player.basePath | default "/nanabush-player" }}
{{- if eq (trimSuffix "/" $basePath) "" }}
{{- fail "app.nanabushPlayer.basePath не может быть корнем: корень домена занят самим HRBox" }}
{{- end }}
{{- if not (hasPrefix "/" $basePath) }}
{{- fail "app.nanabushPlayer.basePath должен начинаться со слэша, например /nanabush-player" }}
{{- end }}
{{- if not (include "hrbox.imageTag" .Values.image.nanabushPlayer) }}
{{- fail "image.nanabushPlayer должен содержать явный тег версии, например nanabush-player:1.0.11 — из него выводится версия плеера в launch-тикете" }}
{{- end }}
{{- if not $player.deployment.binaryCapabilities.basePath }}
{{- fail "On-premise монтирует плеер под путём, поэтому нужен образ с поддержкой base path. Проверьте сборку и верните deployment.binaryCapabilities.basePath: true" }}
{{- end }}
{{- if not $player.deployment.existingSecret.name }}
{{- fail "Заполните app.nanabushPlayer.deployment.existingSecret.name" }}
{{- end }}
{{- if $player.deployment.existingSecret.create }}
{{- if not $player.keys.ticketHs256 }}
{{- fail "Заполните app.nanabushPlayer.keys.ticketHs256 (openssl rand -base64 48)" }}
{{- end }}
{{- if not $player.keys.sessionHs256 }}
{{- fail "Заполните app.nanabushPlayer.keys.sessionHs256 (openssl rand -base64 48)" }}
{{- end }}
{{- if eq $player.keys.ticketHs256 $player.keys.sessionHs256 }}
{{- fail "app.nanabushPlayer.keys.ticketHs256 и sessionHs256 должны отличаться: это ключи разных контуров" }}
{{- end }}
{{- if and $player.deployment.existingSecret.keys.ticketKeys (not $player.keys.ticketKeys) }}
{{- fail "Указано имя ключа ticketKeys в секрете, но само кольцо app.nanabushPlayer.keys.ticketKeys пустое" }}
{{- end }}
{{- end }}
{{- if and $player.deployment.redis.urlFromExistingSecret $player.deployment.existingSecret.create }}
{{- fail "redis.urlFromExistingSecret: true требует existingSecret.create: false — Secret, создаваемый чартом, не содержит URL Redis" }}
{{- end }}
{{- if $player.deployment.metrics.enabled }}
{{- if eq ($player.deployment.metrics.port | int) ($player.service.port | int) }}
{{- fail "Порт метрик плеера должен отличаться от публичного порта сервиса, иначе метрики окажутся доступны содержимому курсов" }}
{{- end }}
{{- end }}
{{- end }}