feat: add generated parent modify resources
Introduce the modifier YAML kind for delayed parent-level modify operations and generate dedicated Terraform resources with typed parameters. Keep modifier parameters out of the ordinary instance CRUD resource, register modifiers separately, and leave delete as a no-op until an inverse API payload is confirmed. Mark vcOrg and vcNsxt modify operations during YAML generation so the contract survives regeneration.
This commit is contained in:
@@ -24,11 +24,12 @@ import (
|
||||
"resource-generator/internal/types"
|
||||
)
|
||||
|
||||
// LoadSpecs загружает все YAML-спеки из директории и строит GenResource/GenSubresource/GenAction.
|
||||
func LoadSpecs(dir string) ([]types.GenResource, []types.GenSubresource, []types.GenAction, error) {
|
||||
// LoadSpecs загружает все YAML-спеки из директории и строит модели всех ресурсов.
|
||||
func LoadSpecs(dir string) ([]types.GenResource, []types.GenSubresource, []types.GenAction, []types.GenModifier, error) {
|
||||
var services []types.GenResource
|
||||
var subs []types.GenSubresource
|
||||
var actions []types.GenAction
|
||||
var modifiers []types.GenModifier
|
||||
domainServiceIDsSet := map[int]struct{}{}
|
||||
walkErr := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
@@ -56,6 +57,24 @@ func LoadSpecs(dir string) ([]types.GenResource, []types.GenSubresource, []types
|
||||
modifyParams := []types.Param{}
|
||||
supportsSuspendDestroy := false
|
||||
for _, op := range spec.Operations {
|
||||
if op.Kind == "modifier" {
|
||||
name := strings.TrimSpace(op.Modifier)
|
||||
if name == "" {
|
||||
name = strings.TrimSpace(op.Action)
|
||||
}
|
||||
modifier := types.GenModifier{
|
||||
ServiceName: spec.Name,
|
||||
ServiceID: spec.ServiceID,
|
||||
ModifierName: name,
|
||||
OperationName: op.Action,
|
||||
Params: ConvertParams(op.Params),
|
||||
}
|
||||
modifier.SchemaParams = modifier.Params
|
||||
params.Analyze(&modifier.UsesBool, &modifier.UsesInt64, &modifier.UsesString, &modifier.HasDefaults, &modifier.NeedsBoolDefault, &modifier.NeedsInt64Default, &modifier.NeedsStringDefault, modifier.SchemaParams)
|
||||
modifier.NeedsJsonPlanMod = params.AnalyzeJsonPlanMod(modifier.SchemaParams)
|
||||
modifiers = append(modifiers, modifier)
|
||||
continue
|
||||
}
|
||||
if op.Kind != "instance" {
|
||||
continue
|
||||
}
|
||||
@@ -192,7 +211,7 @@ func LoadSpecs(dir string) ([]types.GenResource, []types.GenSubresource, []types
|
||||
})
|
||||
|
||||
if walkErr != nil {
|
||||
return nil, nil, nil, walkErr
|
||||
return nil, nil, nil, nil, walkErr
|
||||
}
|
||||
|
||||
domainServiceIDs := make([]int, 0, len(domainServiceIDsSet))
|
||||
@@ -221,8 +240,14 @@ func LoadSpecs(dir string) ([]types.GenResource, []types.GenSubresource, []types
|
||||
}
|
||||
return actions[i].ServiceName < actions[j].ServiceName
|
||||
})
|
||||
sort.Slice(modifiers, func(i, j int) bool {
|
||||
if modifiers[i].ServiceName == modifiers[j].ServiceName {
|
||||
return modifiers[i].ModifierName < modifiers[j].ModifierName
|
||||
}
|
||||
return modifiers[i].ServiceName < modifiers[j].ServiceName
|
||||
})
|
||||
|
||||
return services, subs, actions, nil
|
||||
return services, subs, actions, modifiers, nil
|
||||
}
|
||||
|
||||
// ConvertParams конвертирует []ParamSpec → []Param с нормализацией типов.
|
||||
@@ -313,6 +338,7 @@ var KnownKinds = map[string]bool{
|
||||
"instance": true,
|
||||
"subresource": true,
|
||||
"action": true,
|
||||
"modifier": true,
|
||||
}
|
||||
|
||||
// ValidateSpec проверяет YAML-спек на обязательные поля и неизвестные kinds.
|
||||
@@ -329,7 +355,7 @@ func ValidateSpec(path string, spec *types.ServiceSpec) error {
|
||||
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)
|
||||
return fmt.Errorf("operation[%d] %q: unknown kind %q (valid: instance, subresource, action, modifier)", 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)
|
||||
@@ -337,6 +363,9 @@ func ValidateSpec(path string, spec *types.ServiceSpec) error {
|
||||
if op.Kind == "subresource" && op.Subresource == "" {
|
||||
return fmt.Errorf("operation[%d] %q (kind=subresource): missing required field: subresource", i, op.Name)
|
||||
}
|
||||
if op.Kind == "modifier" && strings.TrimSpace(op.Action) == "" {
|
||||
return fmt.Errorf("operation[%d] %q (kind=modifier): missing required field: action", i, op.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user