126 lines
4.0 KiB
Go
126 lines
4.0 KiB
Go
// service_spec_gen — генератор YAML-спеков сервисов из API Nubes.
|
|
//
|
|
// Читает список сервисов, дёргает API, собирает операции/параметры/MAN,
|
|
// пишет один YAML на сервис в resources_yaml/.
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
"yaml-generator/internal/client"
|
|
"yaml-generator/internal/config"
|
|
"yaml-generator/internal/normalize"
|
|
"yaml-generator/internal/spec"
|
|
"yaml-generator/internal/types"
|
|
)
|
|
|
|
// serviceSpecificModifiers — реестр исключений (ДАННЫЕ, не логика).
|
|
// Ключ — стабильное имя сервиса (как в YAML), значение — имя modifier-ресурса,
|
|
// который генерируется для его операции modify (отложенный modify над инстансом).
|
|
//
|
|
// ЧТО: операция modify сервиса помечается kind=modifier + modifier=<имя>.
|
|
// ЧТО ДЕЛАЕТ: yaml-generator создаёт для неё отдельный ресурс nubes_<svc>_<modifier>.
|
|
// ПОЧЕМУ: эти modify — отдельный шаг цепочки (аллокация IP / SNAT), их нельзя
|
|
// выполнять в том же ресурсе инстанса (чередующаяся зависимость).
|
|
// ГДЕ: TOOLS/ARCHITECTURE.md, раздел «Реестр исключений».
|
|
//
|
|
// Добавлять только здесь. Grep-гейт TOOLS/scripts/check_hardcoded_service_ids.sh
|
|
// запрещает сравнения svc.ID == N вне этого файла.
|
|
var serviceSpecificModifiers = map[string]string{
|
|
"vc_org": "ip_space",
|
|
"vc_nsxt": "network",
|
|
}
|
|
|
|
func main() {
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
cli := client.New(cfg.APIEndpoint, cfg.APIToken)
|
|
|
|
services := cfg.Services
|
|
if cfg.SingleServiceID > 0 {
|
|
services = []config.ServiceRef{{ID: cfg.SingleServiceID, Name: cfg.SingleServiceName}}
|
|
}
|
|
|
|
outputDir := cfg.OutputDir
|
|
if outputDir == "" {
|
|
panic("NUBES_OUTPUT_DIR is required — generated files must go to generated/{stand}/resources_yaml/")
|
|
}
|
|
if err := spec.ValidateOutputDir(outputDir); err != nil {
|
|
panic(err)
|
|
}
|
|
if err := os.MkdirAll(outputDir, 0o755); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
for _, svc := range services {
|
|
if svc.ID <= 0 {
|
|
continue
|
|
}
|
|
fmt.Fprintf(os.Stderr, " service %d (%s): fetching...\n", svc.ID, svc.Name)
|
|
info, err := cli.GetService(svc.ID)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, " ⚠ service %d (%s) skipped: %v\n", svc.ID, svc.Name, err)
|
|
continue
|
|
}
|
|
name := strings.TrimSpace(svc.Name)
|
|
if name == "" {
|
|
name = strings.TrimSpace(info.ShortName)
|
|
}
|
|
if name == "" {
|
|
name = strings.TrimSpace(info.DisplayName)
|
|
}
|
|
name = normalize.ServiceName(name)
|
|
if name == "" {
|
|
name = fmt.Sprintf("service_%d", svc.ID)
|
|
}
|
|
|
|
fmt.Fprintf(os.Stderr, " %d operations to fetch...\n", len(info.Operations))
|
|
|
|
ops, hasSuspend, _, _, err := cli.CollectOperations(info.Operations)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
for idx := range ops {
|
|
if !strings.EqualFold(ops[idx].Action, "modify") {
|
|
continue
|
|
}
|
|
if modName, ok := serviceSpecificModifiers[name]; ok {
|
|
ops[idx].Kind = "modifier"
|
|
ops[idx].Modifier = modName
|
|
}
|
|
}
|
|
|
|
specYAML := types.ServiceSpec{
|
|
Name: name,
|
|
ServiceID: svc.ID,
|
|
ServiceDisplayName: strings.TrimSpace(info.DisplayName),
|
|
ServiceShortName: strings.TrimSpace(info.ShortName),
|
|
ServiceMan: strings.TrimSpace(info.Man),
|
|
Lifecycle: types.Lifecycle{
|
|
SuspendOnDestroyDefault: hasSuspend,
|
|
AdoptExistingOnCreateDefault: false,
|
|
},
|
|
Outputs: types.OutputSection{Params: spec.DefaultOutputParams()},
|
|
Operations: ops,
|
|
}
|
|
|
|
outPath := filepath.Join(outputDir, fmt.Sprintf("%d_%s.yaml", svc.ID, name))
|
|
buf, err := yaml.Marshal(specYAML)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if err := os.WriteFile(outPath, buf, 0o644); err != nil {
|
|
panic(err)
|
|
}
|
|
fmt.Printf("written %s\n", outPath)
|
|
}
|
|
}
|