From 22c6c83a0fc4b3e1e64047ee9937459e81189617 Mon Sep 17 00:00:00 2001 From: Nail Date: Thu, 24 Sep 2026 19:06:40 +0300 Subject: [PATCH] =?UTF-8?q?generator:=20=D1=82=D1=80=D0=B5=D1=82=D0=B8?= =?UTF-8?q?=D0=B9=20=D1=80=D0=B5=D0=B6=D0=B8=D0=BC=20destroy=20keep=5Fon?= =?UTF-8?q?=5Fdestroy=20(state=5Fonly)=20=D0=B4=D0=BB=D1=8F=20=D0=B2=D1=81?= =?UTF-8?q?=D0=B5=D1=85=20instance-=D1=80=D0=B5=D1=81=D1=83=D1=80=D1=81?= =?UTF-8?q?=D0=BE=D0=B2=20+=20=D0=BF=D1=80=D0=B5=D0=B4=D1=83=D0=BF=D1=80?= =?UTF-8?q?=D0=B5=D0=B6=D0=B4=D0=B5=D0=BD=D0=B8=D1=8F=20=C2=AB=D0=B7=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D1=80=D0=BE=D0=B6=D0=B5=D0=BD/=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=BA=D0=B0=D0=BA=20=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D1=8C=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../internal/loader/loader.go | 6 +++ .../internal/templates/instance.go | 22 ++++++++-- .../internal/types/types.go | 42 +++++++++++-------- 3 files changed, 49 insertions(+), 21 deletions(-) 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).