// generate_resources_v2 — главный генератор Terraform-провайдера Nubes. // // ⛔ ПОДЧИНЯЕТСЯ devops/ARCHITECTURE.md — все правила генерации прописаны там. // // Пайплайн: YAML-спеки сервисов → Go-ресурсы + registry.go. // // На вход: resources_yaml/*.yaml (сгенерированы service_spec_gen из API). // На выход: internal/resources_gen/*.go (CRUD-ресурсы, subresource'ы, registry). // // Три вида ресурсов: // - instance → nubes_{service} (основной CRUD инстанса) // - subresource → nubes_{service}_{sub} (пользователи, базы, ...) // - action → ТОЛЬКО redeploy встроен как git_revision. // restart/recovery/reconcile исключены (ARCHITECTURE.md). package main import ( "fmt" "os" "path/filepath" "strings" ) func main() { root, err := os.Getwd() if err != nil { panic(err) } resourcesDir := strings.TrimSpace(os.Getenv("NUBES_RESOURCES_DIR")) if resourcesDir == "" { resourcesDir = filepath.Join(root, "resources_yaml") } outDir := strings.TrimSpace(os.Getenv("NUBES_RESOURCES_GEN_DIR")) if outDir == "" { outDir = filepath.Join(root, "internal", "resources_gen") } instanceResources, subresources, actions, err := loadSpecs(resourcesDir) if err != nil { panic(err) } for _, svc := range instanceResources { if err := writeInstanceResource(outDir, svc); err != nil { panic(err) } } for _, sr := range subresources { if err := writeSubresource(outDir, sr); err != nil { panic(err) } } for _, act := range actions { if err := writeActionResource(outDir, act); err != nil { panic(err) } } if err := writeRegistry(outDir, instanceResources, subresources, actions); err != nil { panic(err) } } // knownKinds — допустимые значения Kind операций. var knownKinds = map[string]bool{ "instance": true, "subresource": true, "action": true, } // validateSpec проверяет YAML-спек на обязательные поля и неизвестные kinds. // P1.4: fail-fast — паника при неизвестном kind вместо тихого игнорирования. func validateSpec(path string, spec *ServiceSpec) error { if spec.Name == "" { return fmt.Errorf("missing required field: name") } if spec.ServiceID <= 0 { return fmt.Errorf("missing required field: service_id") } for i, op := range spec.Operations { if op.Kind == "" { return fmt.Errorf("operation[%d] %q: missing required field: kind", i, op.Name) } if !knownKinds[op.Kind] { return fmt.Errorf("operation[%d] %q: unknown kind %q (valid: instance, subresource, action)", i, op.Name, op.Kind) } if op.Action == "" { return fmt.Errorf("operation[%d] %q (kind=%s): missing required field: action", i, op.Name, op.Kind) } if op.Kind == "subresource" && op.Subresource == "" { return fmt.Errorf("operation[%d] %q (kind=subresource): missing required field: subresource", i, op.Name) } } return nil }