generator: третий режим destroy keep_on_destroy (state_only) для всех instance-ресурсов + предупреждения «заморожен/оставлен как есть»

This commit is contained in:
Nail
2026-09-24 19:06:40 +03:00
parent 0de72e09f0
commit 22c6c83a0f
3 changed files with 49 additions and 21 deletions
@@ -116,6 +116,11 @@ func LoadSpecs(dir string) ([]types.GenResource, []types.GenSubresource, []types
suspendOnDestroy = *spec.Lifecycle.SuspendOnDestroyDefault suspendOnDestroy = *spec.Lifecycle.SuspendOnDestroyDefault
} }
keepOnDestroy := false
if spec.Lifecycle.KeepOnDestroyDefault != nil {
keepOnDestroy = *spec.Lifecycle.KeepOnDestroyDefault
}
gr := types.GenResource{ gr := types.GenResource{
Name: spec.Name, Name: spec.Name,
ServiceID: spec.ServiceID, ServiceID: spec.ServiceID,
@@ -128,6 +133,7 @@ func LoadSpecs(dir string) ([]types.GenResource, []types.GenSubresource, []types
HasRefSvcParams: HasRefSvcParams(schemaParams), HasRefSvcParams: HasRefSvcParams(schemaParams),
SupportsSuspendDestroy: supportsSuspendDestroy, SupportsSuspendDestroy: supportsSuspendDestroy,
SuspendOnDestroy: suspendOnDestroy, SuspendOnDestroy: suspendOnDestroy,
KeepOnDestroy: keepOnDestroy,
AdoptExistingOnCreate: adoptExistingOnCreate, AdoptExistingOnCreate: adoptExistingOnCreate,
HasDomainParam: hasDomainParam, HasDomainParam: hasDomainParam,
} }
@@ -79,6 +79,7 @@ type {{ToCamel .Name}}Model struct {
{{- if .SupportsSuspendDestroy }} {{- if .SupportsSuspendDestroy }}
SuspendOnDestroy types.Bool ` + "`" + `tfsdk:"suspend_on_destroy"` + "`" + ` SuspendOnDestroy types.Bool ` + "`" + `tfsdk:"suspend_on_destroy"` + "`" + `
{{- end }} {{- end }}
KeepOnDestroy types.Bool ` + "`" + `tfsdk:"keep_on_destroy"` + "`" + `
AdoptExistingOnCreate types.Bool ` + "`" + `tfsdk:"adopt_existing_on_create"` + "`" + ` AdoptExistingOnCreate types.Bool ` + "`" + `tfsdk:"adopt_existing_on_create"` + "`" + `
{{- range .OutputParams }} {{- range .OutputParams }}
{{ToCamel .Code}} {{OutputType .}} ` + "`" + `tfsdk:"{{ToSnake .Code}}"` + "`" + ` {{ToCamel .Code}} {{OutputType .}} ` + "`" + `tfsdk:"{{ToSnake .Code}}"` + "`" + `
@@ -128,6 +129,7 @@ func (r *{{ToCamel .Name}}Resource) Schema(ctx context.Context, req resource.Sch
{{- if .SupportsSuspendDestroy }} {{- if .SupportsSuspendDestroy }}
"suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool({{.SuspendOnDestroy}})}, "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool({{.SuspendOnDestroy}})},
{{- end }} {{- 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}})}, "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool({{.AdoptExistingOnCreate}})},
{{- range .OutputParams }} {{- range .OutputParams }}
{{- if or (OutputIsMap .) (OutputIsList .) }} {{- if or (OutputIsMap .) (OutputIsList .) }}
@@ -543,14 +545,15 @@ func (r *{{ToCamel .Name}}Resource) Delete(ctx context.Context, req resource.Del
return return
} }
deleteMode := "delete"
{{- if .SupportsSuspendDestroy }} {{- if .SupportsSuspendDestroy }}
deleteMode := "state_only"
if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() { if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
deleteMode = "suspend" deleteMode = "suspend"
} }
{{- else }}
deleteMode := "delete"
{{- end }} {{- end }}
if !state.KeepOnDestroy.IsNull() && !state.KeepOnDestroy.IsUnknown() && state.KeepOnDestroy.ValueBool() {
deleteMode = "state_only"
}
operationTimeout := "" operationTimeout := ""
if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() { 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()) resp.Diagnostics.AddError("Ошибка клиента", err.Error())
return 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) { func (r *{{ToCamel .Name}}Resource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
@@ -32,6 +32,9 @@ type ServiceSpec struct {
Lifecycle struct { Lifecycle struct {
SuspendOnDestroyDefault *bool `yaml:"suspend_on_destroy_default"` SuspendOnDestroyDefault *bool `yaml:"suspend_on_destroy_default"`
AdoptExistingOnCreateDefault *bool `yaml:"adopt_existing_on_create_default"` AdoptExistingOnCreateDefault *bool `yaml:"adopt_existing_on_create_default"`
// KeepOnDestroyDefault: дефолт ресурса для режима state_only (ничего не менять в облаке).
// Нужен там, где сервис не умеет suspend (например, Эдж) — иначе destroy удаляет объект.
KeepOnDestroyDefault *bool `yaml:"keep_on_destroy_default"`
} `yaml:"lifecycle"` } `yaml:"lifecycle"`
Operations []OperationSpec `yaml:"operations"` Operations []OperationSpec `yaml:"operations"`
} }
@@ -75,18 +78,21 @@ type GenResource struct {
HasRefSvcParams bool HasRefSvcParams bool
SupportsSuspendDestroy bool SupportsSuspendDestroy bool
SuspendOnDestroy bool SuspendOnDestroy bool
AdoptExistingOnCreate bool // KeepOnDestroy: destroy только убирает ресурс из состояния (state_only),
UsesBool bool // ничего не меняя в облаке. Приоритетнее suspend_on_destroy.
UsesInt64 bool KeepOnDestroy bool
UsesString bool AdoptExistingOnCreate bool
HasDefaults bool UsesBool bool
NeedsBoolDefault bool UsesInt64 bool
NeedsInt64Default bool UsesString bool
NeedsStringDefault bool HasDefaults bool
NeedsBoolUseStateForUnknown bool NeedsBoolDefault bool
NeedsInt64UseStateForUnknown bool NeedsInt64Default bool
HasDomainParam bool NeedsStringDefault bool
DomainServiceIDs []int NeedsBoolUseStateForUnknown bool
NeedsInt64UseStateForUnknown bool
HasDomainParam bool
DomainServiceIDs []int
// HasRedeploy: сервис поддерживает redeploy (пересборка из git). // HasRedeploy: сервис поддерживает redeploy (пересборка из git).
// Если true — в основной ресурс добавляется поле git_revision. // Если true — в основной ресурс добавляется поле git_revision.
// При изменении git_revision вызывается redeploy вместо modify. // При изменении git_revision вызывается redeploy вместо modify.
@@ -154,12 +160,12 @@ type GenAction struct {
// GenModifier — отдельный ресурс для отложенной parent-level modify операции. // GenModifier — отдельный ресурс для отложенной parent-level modify операции.
// Delete намеренно не содержит rollback: API-контракт обратного payload не подтверждён. // Delete намеренно не содержит rollback: API-контракт обратного payload не подтверждён.
type GenModifier struct { type GenModifier struct {
ServiceName string ServiceName string
ServiceID int ServiceID int
ModifierName string ModifierName string
OperationName string OperationName string
Params []Param Params []Param
SchemaParams []Param SchemaParams []Param
// DeleteStrategy — noop_warn | inverse | error (нормализовано из YAML, пусто → noop_warn). // DeleteStrategy — noop_warn | inverse | error (нормализовано из YAML, пусто → noop_warn).
DeleteStrategy string DeleteStrategy string
// Idempotency — none | check_before_run (нормализовано из YAML, пусто → none). // Idempotency — none | check_before_run (нормализовано из YAML, пусто → none).