From aa0f7f6402784c7fe9ba7b3e12c232212433c79c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Thu, 3 Sep 2026 16:14:28 +0300 Subject: [PATCH] fix(docs): remove stand-specific hardcodes --- ...ocs_hardcodes_removed_and_dev_published.md | 67 ++++++++++++ TOOLS/docs-generator/main.go | 12 ++- .../02_generate_resources_and_docs_v2.sh | 16 ++- TOOLS/scripts/04_build_and_publish_docs.sh | 102 ++++++++++++------ docs/30_registry/guides/getting-started.md | 16 +-- docs/curated/postgres/pg_user_db.md | 6 +- mkdocs.yml | 2 +- 7 files changed, 170 insertions(+), 51 deletions(-) create mode 100644 HISTORY/2026-09-03_docs_hardcodes_removed_and_dev_published.md diff --git a/HISTORY/2026-09-03_docs_hardcodes_removed_and_dev_published.md b/HISTORY/2026-09-03_docs_hardcodes_removed_and_dev_published.md new file mode 100644 index 0000000..342ce56 --- /dev/null +++ b/HISTORY/2026-09-03_docs_hardcodes_removed_and_dev_published.md @@ -0,0 +1,67 @@ +# 2026-09-03 — Устранение хардкодов документации и публикация DEV + +## Найденная причина + +Общие материалы `docs/30_registry/` и `docs/curated/` копировались в каждый `generated//docs/`, но подстановка выполнялась только для части `getting-started.md`. Поэтому в DEV попадали TEST-значения: + +- TEST provider source; +- `5.0.5`; +- TEST API endpoint; +- `deck-test.ngcloud.ru`. + +Дополнительно `02_generate_resources_and_docs_v2.sh` не очищал старые generated-файлы. Ресурс, отсутствующий в текущем `services_list.txt`, мог остаться от предыдущей генерации. + +## Изменения + +- Общие документы используют placeholders: + - `{{NAMESPACE}}`; + - `{{VERSION}}`; + - `{{PROVIDER_SOURCE}}`; + - `{{NUBES_API_ENDPOINT}}`; + - `{{DASHBOARD_URL}}`. +- `04_build_and_publish_docs.sh` подставляет значения рекурсивно во все скопированные Markdown-файлы. +- Добавлена проверка чужих namespace, API/dashboard host и старого `registry.kube5s.ru` до сборки. +- Профиль стал обязательным; обязательные значения не берутся из PROD fallback. +- `02_generate_resources_and_docs_v2.sh` очищает только собственный `generated//docs` перед генерацией. +- `docs-generator` больше не содержит DEV default для API/provider source. +- Базовый `mkdocs.yml` больше не содержит versioned URL. + +## Проверки + +- `bash -n` для обоих docs scripts — PASS. +- `go test ./...` и `go build ./...` в `TOOLS/docs-generator` — PASS. +- DEV regeneration — PASS. +- DEV MkDocs build — PASS; contamination check — PASS. +- В DEV отсутствуют `5.0.5`, TEST API, `deck-test.ngcloud.ru` и `registry.kube5s.ru`. +- Legacy generated `vc_vm_v2` удалён чистой генерацией, так как отсутствует в актуальном `services_list.txt`. + +## Публикация + +Локальный рекурсивный S3 mirror завершался `unexpected EOF`, поэтому exit code штатного скрипта нельзя считать достаточным подтверждением загрузки. Проверенный артефакт `site/` был передан на ВМ `5.172.178.213` по SSH и атомарно установлен в: + +```text +/var/www/tf-docs/nubes-dev/ +``` + +На ВМ проверены страницы getting-started и curated PostgreSQL: + +- namespace `nubes-dev`; +- provider version `2.0.0`; +- DEV API endpoint; +- DEV dashboard URL; +- отсутствие TEST-значений. + +Legacy versioned каталоги TEST ранее удалены и после публикации отсутствуют: + +```text +/var/www/tf-docs/nubes-test/5.0.5 +/var/www/tf-docs/nubes-test/5.0.57 +``` + +Публичный путь документации: + +```text +https://tf-docs.nodejsk8s.dev.nubes.ru/nubes-dev/ +``` + +Публичный `curl` завершался timeout на большом HTML; содержимое активного зеркала ВМ проверено напрямую. diff --git a/TOOLS/docs-generator/main.go b/TOOLS/docs-generator/main.go index fae146c..8cd69c9 100644 --- a/TOOLS/docs-generator/main.go +++ b/TOOLS/docs-generator/main.go @@ -24,10 +24,8 @@ func main() { servicesListFlag := flag.String("services", "", "Path to TOOLS/config/{stand}/services_list.txt") excludeFlag := flag.String("exclude", "", "Comma-separated resource names to skip") versionFlag := flag.String("version", "", "Provider version for example block") - // ⛔ LEGACY DEFAULT (index.cfm) — переопределяется через NUBES_API_ENDPOINT в profile.env. - // Никогда не использовать deck-api.ngcloud.ru напрямую. - apiEndpointFlag := flag.String("api-endpoint", "https://lk-api-gateway.ngcloud.ru/api/v1/svc", "API endpoint for example block") - providerSourceFlag := flag.String("provider-source", "tf-registry.containerk8s.services.ngcloud.ru/nubes-dev/nubes", "Provider source for example block") + apiEndpointFlag := flag.String("api-endpoint", "", "API endpoint for example block (required)") + providerSourceFlag := flag.String("provider-source", "", "Provider source for example block (required)") opsFlag := flag.Bool("ops", false, "Generate per-service operations docs (resources_ops_yaml → docs/.../operations)") flag.Parse() @@ -52,7 +50,13 @@ func main() { panic("--version is required") } apiEndpoint := *apiEndpointFlag + if apiEndpoint == "" { + panic("--api-endpoint is required") + } providerSource := *providerSourceFlag + if providerSource == "" { + panic("--provider-source is required") + } servicesOrder := loadServicesList(servicesList) specs := loadSpecs(resourcesDir, servicesOrder) diff --git a/TOOLS/scripts/02_generate_resources_and_docs_v2.sh b/TOOLS/scripts/02_generate_resources_and_docs_v2.sh index c7148e3..b1bba59 100755 --- a/TOOLS/scripts/02_generate_resources_and_docs_v2.sh +++ b/TOOLS/scripts/02_generate_resources_and_docs_v2.sh @@ -80,6 +80,13 @@ if [[ ! -f "$SERVICES_LIST_PATH" ]]; then exit 2 fi +for required_var in VERSION NAMESPACE PROVIDER_NAME NUBES_API_ENDPOINT REGISTRY_HOSTNAME; do + if [[ -z "${!required_var:-}" ]]; then + echo "Error: $required_var is required in profile.env or registry.env" >&2 + exit 2 + fi +done + cd "$PROVIDER_DIR" echo "Generating resources from unified YAML specs..." @@ -96,11 +103,10 @@ cp -R "$TMP_GEN_DIR/." "$GO_OUTPUT_DIR/" echo "Generating docs via template generator..." mkdir -p "$DOCS_DIR" +find "$DOCS_DIR" -mindepth 1 -maxdepth 1 -exec rm -rf -- {} + -# Determine API endpoint for doc examples. -# Use NUBES_API_ENDPOINT from profile.env, fall back to production default. -# ⛔ LEGACY: deck-api.ngcloud.ru ЗАКРЫВАЕТСЯ. Default = Gateway. Override via NUBES_API_ENDPOINT. -DOCS_API_ENDPOINT="${NUBES_API_ENDPOINT:-https://lk-api-gateway.ngcloud.ru/api/v1/svc}" +# Determine API endpoint for doc examples from the selected profile. +DOCS_API_ENDPOINT="$NUBES_API_ENDPOINT" # If endpoint looks like new REST gateway (no index.cfm), keep as-is. # If it's old-style without index.cfm, append it for backward compat in docs. if [[ "$DOCS_API_ENDPOINT" != *"/index.cfm"* ]] && [[ "$DOCS_API_ENDPOINT" != *"/svc"* ]]; then @@ -111,7 +117,7 @@ ${ROOT_DIR}/TOOLS/bin/docs-generator \ -resources "$RESOURCES_YAML_DIR" \ -docs "$DOCS_DIR" \ -services "$SERVICES_LIST_PATH" \ - -version "${VERSION:-2.x}" \ + -version "$VERSION" \ -api-endpoint "$DOCS_API_ENDPOINT" \ -provider-source "${REGISTRY_HOSTNAME}/${NAMESPACE}/${PROVIDER_NAME}" diff --git a/TOOLS/scripts/04_build_and_publish_docs.sh b/TOOLS/scripts/04_build_and_publish_docs.sh index 1ae6a1c..113ed5a 100755 --- a/TOOLS/scripts/04_build_and_publish_docs.sh +++ b/TOOLS/scripts/04_build_and_publish_docs.sh @@ -36,8 +36,27 @@ if [[ -n "$PROFILE_DIR" ]]; then source "$PROFILE_ENV_FILE" set +a fi + REGISTRY_ENV_FILE="${ROOT_DIR}/TOOLS/config/registry.env" + if [[ -f "$REGISTRY_ENV_FILE" ]]; then + set -a + # shellcheck disable=SC1090 + source "$REGISTRY_ENV_FILE" + set +a + fi fi +if [[ -z "$PROFILE_DIR" ]]; then + echo "Error: --profile is required" >&2 + exit 2 +fi + +for required_var in VERSION NAMESPACE PROVIDER_NAME NUBES_API_ENDPOINT REGISTRY_HOSTNAME; do + if [[ -z "${!required_var:-}" ]]; then + echo "Error: $required_var is required in profile.env or registry.env" >&2 + exit 2 + fi +done + resolve_root_path() { local path_value="$1" if [[ -z "$path_value" ]]; then @@ -51,9 +70,9 @@ resolve_root_path() { echo "${ROOT_DIR}/${path_value}" } -VERSION="${1:-}" -if [[ -z "$VERSION" ]]; then - VERSION="${VERSION:-}" +VERSION_ARG="${1:-}" +if [[ -n "$VERSION_ARG" ]]; then + VERSION="$VERSION_ARG" fi if [[ -z "$VERSION" ]]; then VERSION=$(grep -E 'version string' "$PROVIDER_MAIN" | sed -E 's/.*"([0-9.]+)".*/\1/') @@ -65,8 +84,6 @@ if [[ -z "$VERSION" ]]; then fi REGISTRY_HOST="${REGISTRY_HOST:-tf-docs.nodejsk8s.dev.nubes.ru}" -NAMESPACE="${NAMESPACE:-nubes}" -PROVIDER_NAME="${PROVIDER_NAME:-nubes}" export REGISTRY_HOST NAMESPACE PROVIDER_NAME VERSION S3CFG_REGISTRY="${S3CFG_REGISTRY:-${ROOT_DIR}/secrets/.s3cfg_registry}" @@ -85,9 +102,15 @@ if [[ -n "$PROFILE_DIR" ]]; then fi fi -# ⛔ LEGACY: deck-api.ngcloud.ru ЗАКРЫВАЕТСЯ. Default = Gateway. -DOCS_API_ENDPOINT="${NUBES_API_ENDPOINT:-https://lk-api-gateway.ngcloud.ru/api/v1/svc}" +DOCS_API_ENDPOINT="$NUBES_API_ENDPOINT" DOCS_API_ENDPOINT="$(normalize_api_endpoint "$DOCS_API_ENDPOINT")" +DASHBOARD_HOST="deck" +if [[ "$NAMESPACE" != "nubes" ]]; then + DASHBOARD_HOST="deck-${NAMESPACE#nubes-}" +fi +DASHBOARD_URL="https://${DASHBOARD_HOST}.ngcloud.ru" +PROVIDER_SOURCE="${REGISTRY_HOSTNAME}/${NAMESPACE}/${PROVIDER_NAME}" +export DOCS_API_ENDPOINT DASHBOARD_URL PROVIDER_SOURCE load_s3cfg_registry() { local cfg="$1" @@ -143,37 +166,56 @@ if [[ -n "${MKDOCS_DOCS_DIR:-}" ]]; then fi fi -# Per-стенд подстановка в getting-started (после копирования 30_registry в docs_dir) +# Per-стенд подстановка во все скопированные Markdown-файлы. if [[ -n "${MKDOCS_DOCS_DIR:-}" ]]; then - export DOCS_GUIDE_VERSION="$VERSION" - export DOCS_GUIDE_API_ENDPOINT="$DOCS_API_ENDPOINT" - export DOCS_GUIDE_NAMESPACE="$NAMESPACE" - export DOCS_GUIDE_FILE="${MKDOCS_DOCS_DIR}/30_registry/guides/getting-started.md" + export DOCS_SUBSTITUTION_ROOT="$MKDOCS_DOCS_DIR" python3 - <<'PY' import os import re from pathlib import Path -guide_path = Path(os.environ["DOCS_GUIDE_FILE"]) -if guide_path.exists(): - text = guide_path.read_text(encoding="utf-8") - # source namespace: .../{{NAMESPACE}}/nubes -> ...//nubes - text = text.replace("{{NAMESPACE}}", os.environ["DOCS_GUIDE_NAMESPACE"]) - # version (первое вхождение version = "x.y.z" — блок required_providers) - text = re.sub( - r'(version\s*=\s*")([0-9.]+)(")', - lambda m: f'{m.group(1)}{os.environ["DOCS_GUIDE_VERSION"]}{m.group(3)}', - text, - count=1, +root = Path(os.environ["DOCS_SUBSTITUTION_ROOT"]) +values = { + "{{NAMESPACE}}": os.environ["NAMESPACE"], + "{{VERSION}}": os.environ["VERSION"], + "{{NUBES_API_ENDPOINT}}": os.environ["DOCS_API_ENDPOINT"], + "{{DASHBOARD_URL}}": os.environ["DASHBOARD_URL"], + "{{PROVIDER_SOURCE}}": os.environ["PROVIDER_SOURCE"], + "{{REGISTRY_HOST}}": os.environ["REGISTRY_HOSTNAME"], +} +legacy_provider_source = re.compile( + r'(source\s*=\s*")registry\.kube5s\.ru/[^"\n]+(")' + ) +for path in root.rglob("*.md"): + text = path.read_text(encoding="utf-8") + for placeholder, value in values.items(): + text = text.replace(placeholder, value) + text = legacy_provider_source.sub( + lambda match: f'{match.group(1)}{os.environ["PROVIDER_SOURCE"]}{match.group(2)}', + text, ) - text = re.sub( - r'(api_endpoint\s*=\s*")([^"]+)(")', - lambda m: f'{m.group(1)}{os.environ["DOCS_GUIDE_API_ENDPOINT"]}{m.group(3)}', - text, - count=1, - ) - guide_path.write_text(text, encoding="utf-8") + path.write_text(text, encoding="utf-8") + +for path in root.rglob("*.md"): + text = path.read_text(encoding="utf-8") + if "{{" in text or "}}" in text: + raise SystemExit(f"unresolved documentation placeholder: {path}") PY + + foreign_namespace="" + foreign_api="" + foreign_dashboard="" + case "$NAMESPACE" in + nubes) foreign_namespace="nubes-dev|nubes-test"; foreign_api="lk-api-gateway-(dev|test)"; foreign_dashboard="deck-(dev|test)" ;; + nubes-dev) foreign_namespace="nubes-test"; foreign_api="lk-api-gateway\.ngcloud\.ru|lk-api-gateway-test\.ngcloud\.ru"; foreign_dashboard="deck\.ngcloud\.ru|deck-test\.ngcloud\.ru" ;; + nubes-test) foreign_namespace="nubes-dev"; foreign_api="lk-api-gateway\.ngcloud\.ru|lk-api-gateway-dev\.ngcloud\.ru"; foreign_dashboard="deck\.ngcloud\.ru|deck-dev\.ngcloud\.ru" ;; + *) echo "Error: unsupported namespace for documentation validation: $NAMESPACE" >&2; exit 2 ;; + esac + if grep -RInE "$foreign_namespace|$foreign_api|$foreign_dashboard|registry\.kube5s\.ru" "$MKDOCS_DOCS_DIR" --include='*.md' >/tmp/docs-stand-contamination.txt 2>/dev/null; then + echo "Error: stand-specific contamination detected in generated docs:" >&2 + cat /tmp/docs-stand-contamination.txt >&2 + exit 2 + fi fi python3 - <<'PY' diff --git a/docs/30_registry/guides/getting-started.md b/docs/30_registry/guides/getting-started.md index 1f0ef15..2cf34dc 100644 --- a/docs/30_registry/guides/getting-started.md +++ b/docs/30_registry/guides/getting-started.md @@ -24,14 +24,14 @@ terraform { required_providers { nubes = { - source = "tf-registry.containerk8s.services.ngcloud.ru/{{NAMESPACE}}/nubes" - version = "0.0.0" # автозамена на версию стенда при сборке (prod=1.x, dev=2.x, test=3.x) + source = "{{PROVIDER_SOURCE}}" + version = "{{VERSION}}" } } } provider "nubes" { - api_endpoint = "https://lk-api-gateway.ngcloud.ru/api/v1/svc" + api_endpoint = "{{NUBES_API_ENDPOINT}}" api_token = var.api_token } @@ -41,11 +41,11 @@ variable "api_token" { } ``` -!!! info "TEST стенд (обязательные адреса)" - Эта документация относится к TEST стенду. +!!! info "Стенд {{NAMESPACE}} (обязательные адреса)" + Эта документация относится к стенду `{{NAMESPACE}}`. - - Личный кабинет: https://deck-test.ngcloud.ru/dashboard/ - - API endpoint: https://lk-api-gateway-test.ngcloud.ru/api/v1/svc + - Личный кабинет: {{DASHBOARD_URL}}/dashboard/ + - API endpoint: {{NUBES_API_ENDPOINT}} !!! tip "Безопасность" Никогда не храните токен прямо в файле `main.tf`, если планируете загружать код в систему контроля версий (git). Используйте `variables.tf` или файл `terraform.tfvars`. @@ -55,7 +55,7 @@ variable "api_token" { Токен (Access Token) необходим провайдеру для авторизации ваших действий в облаке. Если нет ТОКЕНА доступа или хотите создать новый - -В Личном Кабинете - на странице Профиля пользователя https://deck.ngcloud.ru/authorization/profile +В Личном Кабинете - на странице Профиля пользователя {{DASHBOARD_URL}}/authorization/profile во вкладке Токены - нажать "Выпустить тех-токен" Значение токена показывается только при его создании, надо его сохранить diff --git a/docs/curated/postgres/pg_user_db.md b/docs/curated/postgres/pg_user_db.md index 1220059..68255c9 100644 --- a/docs/curated/postgres/pg_user_db.md +++ b/docs/curated/postgres/pg_user_db.md @@ -27,8 +27,8 @@ s3_name = "my-s3" # ИМЯ экземпляра S3 (не UUID terraform { required_providers { nubes = { - source = "tf-registry.containerk8s.services.ngcloud.ru/nubes-test/nubes" - version = "5.0.5" + source = "{{PROVIDER_SOURCE}}" + version = "{{VERSION}}" } } } @@ -39,7 +39,7 @@ variable "s3_name" { type = string } provider "nubes" { api_token = var.api_token - api_endpoint = "https://lk-api-gateway-test.ngcloud.ru/api/v1/svc" + api_endpoint = "{{NUBES_API_ENDPOINT}}" } ``` diff --git a/mkdocs.yml b/mkdocs.yml index de58b26..b202729 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,5 +1,5 @@ site_name: Провайдер Terraform Nubes -site_url: https://tf-registry.containerk8s.services.ngcloud.ru/docs/nubes/nubes/2.0.1/ +site_url: / exclude_docs: | README.md