From 9380ba19f0bedb39d72fc6cc598669738ef31ab8 Mon Sep 17 00:00:00 2001 From: Jonathan Oddy Date: Mon, 18 Mar 2024 12:25:20 +0000 Subject: [PATCH] Move applying SSA merge default config to provider. Use correct Computed value for list merge keys --- pkg/config/provider.go | 53 +++++++++++++++++++++++++++++++++++++++ pkg/types/builder.go | 56 +----------------------------------------- 2 files changed, 54 insertions(+), 55 deletions(-) diff --git a/pkg/config/provider.go b/pkg/config/provider.go index ee03b5f0..74544078 100644 --- a/pkg/config/provider.go +++ b/pkg/config/provider.go @@ -351,6 +351,7 @@ func NewProvider(schema []byte, prefix string, modulePath string, metadata []byt p.Resources[name] = DefaultResource(name, terraformResource, terraformPluginFrameworkResource, providerMetadata.Resources[name], p.DefaultResourceOptions...) p.Resources[name].useTerraformPluginSDKClient = isTerraformPluginSDK p.Resources[name].useTerraformPluginFrameworkClient = isPluginFrameworkResource + p.injectServerSideApplyDefaults(p.Resources[name], terraformResource, "") } for i, refInjector := range p.refInjectors { if err := refInjector.InjectReferences(p.Resources); err != nil { @@ -360,6 +361,58 @@ func NewProvider(schema []byte, prefix string, modulePath string, metadata []byt return p } +func (p *Provider) injectServerSideApplyDefaults(cfg *Resource, res *schema.Resource, basePath string) { //nolint:gocyclo // Easier to follow the logic in a single function + + for k, es := range res.Schema { + + var fieldPath string + if basePath == "" { + fieldPath = k + } else { + fieldPath = fmt.Sprintf("%s.%s", basePath, k) + } + + if r, ok := es.Elem.(*schema.Resource); ok { + if es.Type == schema.TypeList && es.MaxItems == 1 { + cfg.ServerSideApplyMergeStrategies[fieldPath] = MergeStrategy{ + ListMergeStrategy: ListMergeStrategy{ + MergeStrategy: ListTypeMap, + ListMapKeys: ListMapKeys{InjectedKey: InjectedKey{ + Key: "ssamergekey", + DefaultValue: `"0"`, + }}, + }, + } + } + p.injectServerSideApplyDefaults(cfg, r, fieldPath) + } else { + switch es.Type { //nolint:exhaustive + case schema.TypeSet: + if el, ok := es.Elem.(*schema.Schema); ok { + switch el.Type { //nolint:exhaustive + case schema.TypeString, schema.TypeBool, schema.TypeInt, schema.TypeFloat: + cfg.ServerSideApplyMergeStrategies[fieldPath] = MergeStrategy{ + ListMergeStrategy: ListMergeStrategy{ + MergeStrategy: ListTypeSet, + }, + } + } + } + case schema.TypeMap: + if el, ok := es.Elem.(*schema.Schema); ok { + switch el.Type { //nolint:exhaustive + case schema.TypeString, schema.TypeBool, schema.TypeInt, schema.TypeFloat: + // TODO(jono): I think this may be unnecessary since maps appear to default to granular? + cfg.ServerSideApplyMergeStrategies[fieldPath] = MergeStrategy{ + MapMergeStrategy: MapTypeGranular, + } + } + } + } + } + } +} + // AddResourceConfigurator adds resource specific configurators. func (p *Provider) AddResourceConfigurator(resource string, c ResourceConfiguratorFn) { //nolint:interfacer // Note(turkenh): nolint reasoning - easier to provide a function without diff --git a/pkg/types/builder.go b/pkg/types/builder.go index 074268ea..38a129ac 100644 --- a/pkg/types/builder.go +++ b/pkg/types/builder.go @@ -70,7 +70,6 @@ func NewBuilder(pkg *types.Package) *Builder { // Build returns parameters and observation types built out of Terraform schema. func (g *Builder) Build(cfg *config.Resource) (Generated, error) { - injectServerSideApplyDefaults(cfg, cfg.TerraformResource, "") if err := injectServerSideApplyListMergeKeys(cfg); err != nil { return Generated{}, errors.Wrapf(err, "cannot inject server-side apply merge keys for resource %q", cfg.Name) } @@ -86,60 +85,6 @@ func (g *Builder) Build(cfg *config.Resource) (Generated, error) { }, errors.Wrapf(err, "cannot build the Types for resource %q", cfg.Name) } -func injectServerSideApplyDefaults(cfg *config.Resource, res *schema.Resource, basePath string) { //nolint:gocyclo // Easier to follow the logic in a single function - - for k, es := range res.Schema { - fieldPath := k - if basePath != "" { - fieldPath = fmt.Sprintf("%s.%s", basePath, k) - } - - if el, ok := es.Elem.(*schema.Resource); ok { - if _, ok := cfg.ServerSideApplyMergeStrategies[fieldPath]; !ok { - if es.Type == schema.TypeList && es.MaxItems == 1 { - cfg.ServerSideApplyMergeStrategies[fieldPath] = config.MergeStrategy{ - ListMergeStrategy: config.ListMergeStrategy{ - MergeStrategy: config.ListTypeMap, - ListMapKeys: config.ListMapKeys{InjectedKey: config.InjectedKey{ - Key: "ssamergekey", - DefaultValue: `"0"`, - }}, - }, - } - } - } - injectServerSideApplyDefaults(cfg, el, fieldPath) - } else { - if _, ok := cfg.ServerSideApplyMergeStrategies[fieldPath]; ok { - continue - } - switch es.Type { //nolint:exhaustive - case schema.TypeSet: - if el, ok := es.Elem.(*schema.Schema); ok { - switch el.Type { //nolint:exhaustive - case schema.TypeString, schema.TypeBool, schema.TypeInt, schema.TypeFloat: - cfg.ServerSideApplyMergeStrategies[fieldPath] = config.MergeStrategy{ - ListMergeStrategy: config.ListMergeStrategy{ - MergeStrategy: config.ListTypeSet, - }, - } - } - } - case schema.TypeMap: - if el, ok := es.Elem.(*schema.Schema); ok { - switch el.Type { //nolint:exhaustive - case schema.TypeString, schema.TypeBool, schema.TypeInt, schema.TypeFloat: - // TODO(jono): I think this may be unnecessary since maps appear to default to granular? - cfg.ServerSideApplyMergeStrategies[fieldPath] = config.MergeStrategy{ - MapMergeStrategy: config.MapTypeGranular, - } - } - } - } - } - } -} - func injectServerSideApplyListMergeKeys(cfg *config.Resource) error { //nolint:gocyclo // Easier to follow the logic in a single function for f, s := range cfg.ServerSideApplyMergeStrategies { if s.ListMergeStrategy.MergeStrategy != config.ListTypeMap { @@ -170,6 +115,7 @@ func injectServerSideApplyListMergeKeys(cfg *config.Resource) error { //nolint:g el.Schema[s.ListMergeStrategy.ListMapKeys.InjectedKey.Key] = &schema.Schema{ Type: schema.TypeString, Required: true, + Computed: sch.Computed, Description: descriptionInjectedKey, } if s.ListMergeStrategy.ListMapKeys.InjectedKey.DefaultValue != "" {