fix(core,gen): UseStateForUnknown для Optional+Computed + live-dосылка без тихого fallback (R1+R3+A/B)
This commit is contained in:
@@ -4,7 +4,7 @@ TOKEN_FILE="secrets/dev.token"
|
||||
|
||||
# Release versions
|
||||
# Version
|
||||
VERSION="2.0.14"
|
||||
VERSION="2.0.15"
|
||||
|
||||
NAMESPACE="nubes-dev"
|
||||
PROVIDER_NAME="nubes"
|
||||
|
||||
@@ -105,6 +105,24 @@ func ShouldBeOptionalComputed(p types.Param) bool {
|
||||
return !p.Required && p.RefSvcId == 0 && p.Default == ""
|
||||
}
|
||||
|
||||
// ShouldUseStateForUnknown решает, нужен ли UseStateForUnknown() plan-modifier
|
||||
// для скалярного параметра.
|
||||
//
|
||||
// Зачем: Optional+Computed параметр БЕЗ Default при незаданном значении в плане
|
||||
// = unknown. Если Update не перезаписывает его (в т.ч. ветка no-op с ранним
|
||||
// return, см. instance.go), unknown протекает в state и Terraform падает с
|
||||
// "Provider produced invalid result object after apply: ... unknown".
|
||||
// UseStateForUnknown схлопывает unknown в предыдущее known-значение из state,
|
||||
// не требуя сетевого вызова.
|
||||
//
|
||||
// НЕ применяем к JSON (у них свой JsonNormalize) и к полям с Default/Required.
|
||||
func ShouldUseStateForUnknown(p types.Param) bool {
|
||||
if p.IsJson {
|
||||
return false
|
||||
}
|
||||
return ShouldBeOptionalComputed(p)
|
||||
}
|
||||
|
||||
// ParamFormat возвращает вызов Format* для форматирования значения параметра.
|
||||
func ParamFormat(p types.Param, varName string) string {
|
||||
switch strings.ToLower(p.Type) {
|
||||
|
||||
@@ -132,6 +132,7 @@ func LoadSpecs(dir string) ([]types.GenResource, []types.GenSubresource, []types
|
||||
HasDomainParam: hasDomainParam,
|
||||
}
|
||||
params.Analyze(&gr.UsesBool, &gr.UsesInt64, &gr.UsesString, &gr.HasDefaults, &gr.NeedsBoolDefault, &gr.NeedsInt64Default, &gr.NeedsStringDefault, gr.SchemaParams)
|
||||
gr.NeedsBoolUseStateForUnknown, gr.NeedsInt64UseStateForUnknown = analyzeUseStateForUnknown(gr.SchemaParams)
|
||||
// Анализируем nested sub-params для default-импортов
|
||||
if params.AnalyzeNestedDefaults(&gr.NeedsBoolDefault, &gr.NeedsInt64Default, &gr.NeedsStringDefault, gr.SchemaParams) {
|
||||
gr.NeedsFmtImport = true
|
||||
@@ -452,3 +453,21 @@ func validateModifierOperation(i int, op *lib.OperationSpec) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// analyzeUseStateForUnknown определяет, нужны ли импорты boolplanmodifier/int64planmodifier:
|
||||
// есть ли среди SchemaParams скалярный Optional+Computed (без Default) параметр
|
||||
// соответствующего типа, для которого генерируется UseStateForUnknown().
|
||||
func analyzeUseStateForUnknown(schemaParams []types.Param) (needsBool, needsInt64 bool) {
|
||||
for _, p := range schemaParams {
|
||||
if p.IsJson || p.Required || p.RefSvcId != 0 || p.Default != "" {
|
||||
continue
|
||||
}
|
||||
switch strings.ToLower(p.Type) {
|
||||
case "bool":
|
||||
needsBool = true
|
||||
case "int", "int64", "number":
|
||||
needsInt64 = true
|
||||
}
|
||||
}
|
||||
return needsBool, needsInt64
|
||||
}
|
||||
|
||||
@@ -25,6 +25,12 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
|
||||
{{- end }}
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
{{- if .NeedsBoolUseStateForUnknown }}
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
|
||||
{{- end }}
|
||||
{{- if .NeedsInt64UseStateForUnknown }}
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
|
||||
{{- end }}
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
)
|
||||
@@ -109,7 +115,7 @@ func (r *{{ToCamel .Name}}Resource) Schema(ctx context.Context, req resource.Sch
|
||||
{{- if ne (ParamDefaultExpr .) "" }}Computed: true, Default: {{ParamDefaultExpr .}},{{- else if or .IsJson (ShouldBeOptionalComputed .) }}Computed: true,{{- end }}
|
||||
{{- if ne (ParamDescription .) "" }}MarkdownDescription: {{ParamDescription .}},{{end}}
|
||||
{{- if .Sensitive }}Sensitive: true,{{end}}
|
||||
{{- if .IsJson }}PlanModifiers: []planmodifier.String{resources_core.JsonNormalize()},{{- end }}
|
||||
{{- if .IsJson }}PlanModifiers: []planmodifier.String{resources_core.JsonNormalize()},{{- else if ShouldUseStateForUnknown . }}PlanModifiers: []planmodifier.{{if eq (ParamType .) "types.Bool"}}Bool{boolplanmodifier.UseStateForUnknown()}{{else if eq (ParamType .) "types.Int64"}}Int64{int64planmodifier.UseStateForUnknown()}{{else}}String{stringplanmodifier.UseStateForUnknown()}{{end}},{{- end }}
|
||||
},
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -83,6 +83,8 @@ type GenResource struct {
|
||||
NeedsBoolDefault bool
|
||||
NeedsInt64Default bool
|
||||
NeedsStringDefault bool
|
||||
NeedsBoolUseStateForUnknown bool
|
||||
NeedsInt64UseStateForUnknown bool
|
||||
HasDomainParam bool
|
||||
DomainServiceIDs []int
|
||||
// HasRedeploy: сервис поддерживает redeploy (пересборка из git).
|
||||
|
||||
@@ -35,6 +35,7 @@ func WriteInstanceResource(outDir string, svc types.GenResource) error {
|
||||
// читает обратно из state_params, обязан быть Optional+Computed, если он
|
||||
// не Required и без Default. См. подробное объяснение в helpers.go.
|
||||
"ShouldBeOptionalComputed": helpers.ShouldBeOptionalComputed,
|
||||
"ShouldUseStateForUnknown": helpers.ShouldUseStateForUnknown,
|
||||
"ParamFormat": helpers.ParamFormat,
|
||||
"ParamParse": helpers.ParamParse,
|
||||
"ParamDescription": helpers.ParamDescription,
|
||||
|
||||
Reference in New Issue
Block a user