diff --git a/TOOLS/resource-generator/internal/loader/loader.go b/TOOLS/resource-generator/internal/loader/loader.go index 38082e8..296b410 100644 --- a/TOOLS/resource-generator/internal/loader/loader.go +++ b/TOOLS/resource-generator/internal/loader/loader.go @@ -116,6 +116,11 @@ func LoadSpecs(dir string) ([]types.GenResource, []types.GenSubresource, []types suspendOnDestroy = *spec.Lifecycle.SuspendOnDestroyDefault } + keepOnDestroy := false + if spec.Lifecycle.KeepOnDestroyDefault != nil { + keepOnDestroy = *spec.Lifecycle.KeepOnDestroyDefault + } + gr := types.GenResource{ Name: spec.Name, ServiceID: spec.ServiceID, @@ -128,6 +133,7 @@ func LoadSpecs(dir string) ([]types.GenResource, []types.GenSubresource, []types HasRefSvcParams: HasRefSvcParams(schemaParams), SupportsSuspendDestroy: supportsSuspendDestroy, SuspendOnDestroy: suspendOnDestroy, + KeepOnDestroy: keepOnDestroy, AdoptExistingOnCreate: adoptExistingOnCreate, HasDomainParam: hasDomainParam, } diff --git a/TOOLS/resource-generator/internal/templates/instance.go b/TOOLS/resource-generator/internal/templates/instance.go index 62b929c..bb5eaaa 100644 --- a/TOOLS/resource-generator/internal/templates/instance.go +++ b/TOOLS/resource-generator/internal/templates/instance.go @@ -79,6 +79,7 @@ type {{ToCamel .Name}}Model struct { {{- if .SupportsSuspendDestroy }} SuspendOnDestroy types.Bool ` + "`" + `tfsdk:"suspend_on_destroy"` + "`" + ` {{- end }} + KeepOnDestroy types.Bool ` + "`" + `tfsdk:"keep_on_destroy"` + "`" + ` AdoptExistingOnCreate types.Bool ` + "`" + `tfsdk:"adopt_existing_on_create"` + "`" + ` {{- range .OutputParams }} {{ToCamel .Code}} {{OutputType .}} ` + "`" + `tfsdk:"{{ToSnake .Code}}"` + "`" + ` @@ -128,6 +129,7 @@ func (r *{{ToCamel .Name}}Resource) Schema(ctx context.Context, req resource.Sch {{- if .SupportsSuspendDestroy }} "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool({{.SuspendOnDestroy}})}, {{- end }} + "keep_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool({{.KeepOnDestroy}}), MarkdownDescription: "Режим state_only при destroy: ресурс не удаляется и не меняется в облаке, только убирается из состояния. Имеет приоритет над suspend_on_destroy. false = обычное удаление."}, "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool({{.AdoptExistingOnCreate}})}, {{- range .OutputParams }} {{- if or (OutputIsMap .) (OutputIsList .) }} @@ -543,14 +545,15 @@ func (r *{{ToCamel .Name}}Resource) Delete(ctx context.Context, req resource.Del return } + deleteMode := "delete" {{- if .SupportsSuspendDestroy }} - deleteMode := "state_only" if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() { deleteMode = "suspend" } - {{- else }} - deleteMode := "delete" {{- end }} + if !state.KeepOnDestroy.IsNull() && !state.KeepOnDestroy.IsUnknown() && state.KeepOnDestroy.ValueBool() { + deleteMode = "state_only" + } operationTimeout := "" if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() { @@ -563,6 +566,19 @@ func (r *{{ToCamel .Name}}Resource) Delete(ctx context.Context, req resource.Del resp.Diagnostics.AddError("Ошибка клиента", err.Error()) return } + + switch deleteMode { + case "suspend": + resp.Diagnostics.AddWarning( + "Ресурс заморожен, а не удалён", + "destroy: {{.Name}} (service_id={{.ServiceID}}) переведён в suspend, удаление не выполнялось. Для полного удаления выставьте suspend_on_destroy = false.", + ) + case "state_only": + resp.Diagnostics.AddWarning( + "Ресурс оставлен как есть, а не удалён", + "destroy: {{.Name}} (service_id={{.ServiceID}}) не изменялся в облаке и только убран из состояния (keep_on_destroy = true). Для полного удаления выставьте keep_on_destroy = false.", + ) + } } func (r *{{ToCamel .Name}}Resource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { diff --git a/TOOLS/resource-generator/internal/types/types.go b/TOOLS/resource-generator/internal/types/types.go index f4ed71f..e47a000 100644 --- a/TOOLS/resource-generator/internal/types/types.go +++ b/TOOLS/resource-generator/internal/types/types.go @@ -32,6 +32,9 @@ type ServiceSpec struct { Lifecycle struct { SuspendOnDestroyDefault *bool `yaml:"suspend_on_destroy_default"` AdoptExistingOnCreateDefault *bool `yaml:"adopt_existing_on_create_default"` + // KeepOnDestroyDefault: дефолт ресурса для режима state_only (ничего не менять в облаке). + // Нужен там, где сервис не умеет suspend (например, Эдж) — иначе destroy удаляет объект. + KeepOnDestroyDefault *bool `yaml:"keep_on_destroy_default"` } `yaml:"lifecycle"` Operations []OperationSpec `yaml:"operations"` } @@ -75,18 +78,21 @@ type GenResource struct { HasRefSvcParams bool SupportsSuspendDestroy bool SuspendOnDestroy bool - AdoptExistingOnCreate bool - UsesBool bool - UsesInt64 bool - UsesString bool - HasDefaults bool - NeedsBoolDefault bool - NeedsInt64Default bool - NeedsStringDefault bool - NeedsBoolUseStateForUnknown bool - NeedsInt64UseStateForUnknown bool - HasDomainParam bool - DomainServiceIDs []int + // KeepOnDestroy: destroy только убирает ресурс из состояния (state_only), + // ничего не меняя в облаке. Приоритетнее suspend_on_destroy. + KeepOnDestroy bool + AdoptExistingOnCreate bool + UsesBool bool + UsesInt64 bool + UsesString bool + HasDefaults bool + NeedsBoolDefault bool + NeedsInt64Default bool + NeedsStringDefault bool + NeedsBoolUseStateForUnknown bool + NeedsInt64UseStateForUnknown bool + HasDomainParam bool + DomainServiceIDs []int // HasRedeploy: сервис поддерживает redeploy (пересборка из git). // Если true — в основной ресурс добавляется поле git_revision. // При изменении git_revision вызывается redeploy вместо modify. @@ -154,12 +160,12 @@ type GenAction struct { // GenModifier — отдельный ресурс для отложенной parent-level modify операции. // Delete намеренно не содержит rollback: API-контракт обратного payload не подтверждён. type GenModifier struct { - ServiceName string - ServiceID int - ModifierName string - OperationName string - Params []Param - SchemaParams []Param + ServiceName string + ServiceID int + ModifierName string + OperationName string + Params []Param + SchemaParams []Param // DeleteStrategy — noop_warn | inverse | error (нормализовано из YAML, пусто → noop_warn). DeleteStrategy string // Idempotency — none | check_before_run (нормализовано из YAML, пусто → none).