fix(docs): remove stand-specific hardcodes
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# 2026-09-03 — Устранение хардкодов документации и публикация DEV
|
||||
|
||||
## Найденная причина
|
||||
|
||||
Общие материалы `docs/30_registry/` и `docs/curated/` копировались в каждый `generated/<stand>/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/<stand>/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; содержимое активного зеркала ВМ проверено напрямую.
|
||||
@@ -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)
|
||||
|
||||
@@ -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}"
|
||||
|
||||
|
||||
@@ -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 <path> 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 -> .../<ns>/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]+(")'
|
||||
)
|
||||
text = re.sub(
|
||||
r'(api_endpoint\s*=\s*")([^"]+)(")',
|
||||
lambda m: f'{m.group(1)}{os.environ["DOCS_GUIDE_API_ENDPOINT"]}{m.group(3)}',
|
||||
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,
|
||||
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'
|
||||
|
||||
@@ -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
|
||||
во вкладке Токены - нажать "Выпустить тех-токен"
|
||||
Значение токена показывается только при его создании, надо его сохранить
|
||||
|
||||
|
||||
@@ -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}}"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user