diff --git a/pkg/recipes/terraform/config/config.go b/pkg/recipes/terraform/config/config.go index e50adddbdbb..ace2b59a33f 100644 --- a/pkg/recipes/terraform/config/config.go +++ b/pkg/recipes/terraform/config/config.go @@ -136,6 +136,41 @@ func (cfg *TerraformConfig) AddProviders(ctx context.Context, requiredProviders return nil } +// UpdateModuleProvidersWithAliases updates the module provider configuration in the Terraform config +// by adding aliases to the provider configurations. +func (cfg *TerraformConfig) UpdateModuleProvidersWithAliases(ctx context.Context) error { + if cfg == nil { + return fmt.Errorf("terraform configuration is not initialized") + } + + providerConfigs := cfg.Provider + moduleAliasConfig := map[string]string{} + + // For each provider in the providerConfigs, if provider has a property "alias", + // add entry to the module provider configuration + for providerName, providerConfigList := range providerConfigs { + providerConfigDetails, ok := providerConfigList.([]map[string]any) + if !ok { + return fmt.Errorf("providerConfigList is not of type []map[string]any") + } + for _, providerConfig := range providerConfigDetails { + if alias, ok := providerConfig["alias"]; ok { + moduleAliasConfig[providerName+"."+fmt.Sprintf("%v", alias)] = providerName + "." + fmt.Sprintf("%v", alias) + } + } + } + + // Update the module provider configuration in the Terraform config. + if len(moduleAliasConfig) > 0 { + moduleConfig := cfg.Module + for _, module := range moduleConfig { + module["providers"] = moduleAliasConfig + } + } + + return nil +} + // AddRecipeContext adds RecipeContext to TerraformConfig module parameters if recipeCtx is not nil. // Save() must be called after adding recipe context to the module config. func (cfg *TerraformConfig) AddRecipeContext(ctx context.Context, moduleName string, recipeCtx *recipecontext.Context) error { diff --git a/pkg/recipes/terraform/config/config_test.go b/pkg/recipes/terraform/config/config_test.go index 0782809b47f..33d507eabe3 100644 --- a/pkg/recipes/terraform/config/config_test.go +++ b/pkg/recipes/terraform/config/config_test.go @@ -681,6 +681,114 @@ func Test_AddOutputs(t *testing.T) { } } +func TestUpdateModuleProvidersWithAliases(t *testing.T) { + tests := []struct { + name string + cfg *TerraformConfig + expectedConfig *TerraformConfig + expectedConfigFile string + wantErr bool + }{ + { + name: "Test with valid provider config", + cfg: &TerraformConfig{ + Provider: map[string]any{ + "aws": []map[string]any{ + { + "alias": "alias1", + "region": "us-west-2", + }, + { + "alias": "alias2", + "region": "us-east-1", + }, + }, + }, + Module: map[string]TFModuleConfig{ + "redis-azure": map[string]any{ + "redis_cache_name": "redis-test", + "resource_group_name": "test-rg", + "sku": "P", + "source": "Azure/redis/azurerm", + "version": "1.1.0", + }, + "test-module": map[string]any{ + "resource_group_name": "test-rg", + "sku": "C", + }, + }, + }, + expectedConfig: &TerraformConfig{ + Provider: map[string]any{ + "aws": []map[string]any{ + { + "alias": "alias1", + "region": "us-west-2", + }, + { + "alias": "alias2", + "region": "us-east-1", + }, + }, + }, + Module: map[string]TFModuleConfig{ + "redis-azure": map[string]any{ + "redis_cache_name": "redis-test", + "resource_group_name": "test-rg", + "sku": "P", + "source": "Azure/redis/azurerm", + "version": "1.1.0", + "providers": map[string]string{ + "aws.alias1": "aws.alias1", + "aws.alias2": "aws.alias2", + }, + }, + "test-module": map[string]any{ + "resource_group_name": "test-rg", + "sku": "C", + "providers": map[string]string{ + "aws.alias1": "aws.alias1", + "aws.alias2": "aws.alias2", + }, + }, + }, + }, + expectedConfigFile: "testdata/providers-modules-aliases.tf.json", + wantErr: false, + }, + { + name: "TerraformConfig is nil", + cfg: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := testcontext.New(t) + err := tt.cfg.UpdateModuleProvidersWithAliases(ctx) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + + workingDir := t.TempDir() + err = tt.cfg.Save(ctx, workingDir) + require.NoError(t, err) + + // Assert generated config file matches expected config in JSON format. + actualConfig, err := os.ReadFile(getMainConfigFilePath(workingDir)) + require.NoError(t, err) + if tt.wantErr != true { + expectedConfig, err := os.ReadFile(tt.expectedConfigFile) + require.NoError(t, err) + require.Equal(t, string(expectedConfig), string(actualConfig)) + } + }) + } +} + func Test_Save_overwrite(t *testing.T) { ctx := testcontext.New(t) testDir := t.TempDir() diff --git a/pkg/recipes/terraform/config/testdata/providers-modules-aliases.tf.json b/pkg/recipes/terraform/config/testdata/providers-modules-aliases.tf.json new file mode 100644 index 00000000000..ff420951c35 --- /dev/null +++ b/pkg/recipes/terraform/config/testdata/providers-modules-aliases.tf.json @@ -0,0 +1,36 @@ +{ + "terraform": null, + "provider": { + "aws": [ + { + "alias": "alias1", + "region": "us-west-2" + }, + { + "alias": "alias2", + "region": "us-east-1" + } + ] + }, + "module": { + "redis-azure": { + "providers": { + "aws.alias1": "aws.alias1", + "aws.alias2": "aws.alias2" + }, + "redis_cache_name": "redis-test", + "resource_group_name": "test-rg", + "sku": "P", + "source": "Azure/redis/azurerm", + "version": "1.1.0" + }, + "test-module": { + "providers": { + "aws.alias1": "aws.alias1", + "aws.alias2": "aws.alias2" + }, + "resource_group_name": "test-rg", + "sku": "C" + } + } +} \ No newline at end of file diff --git a/pkg/recipes/terraform/execute.go b/pkg/recipes/terraform/execute.go index 6ef7eb75605..5bec7fb9ecd 100644 --- a/pkg/recipes/terraform/execute.go +++ b/pkg/recipes/terraform/execute.go @@ -259,6 +259,12 @@ func (e *executor) generateConfig(ctx context.Context, tf *tfexec.Terraform, opt return "", err } + // Update module configuration with aliased provider names. + logger.Info("Updating module providers with aliases") + if err := tfConfig.UpdateModuleProvidersWithAliases(ctx); err != nil { + return "", err + } + backendConfig, err := tfConfig.AddTerraformInfrastructure(options.ResourceRecipe, backends.NewKubernetesBackend(e.k8sClientSet), loadedModule.RequiredProviders) if err != nil { return "", err diff --git a/test/functional/shared/resources/testdata/corerp-resources-terraform-postgres.bicep b/test/functional/shared/resources/testdata/corerp-resources-terraform-postgres.bicep index 69258a000f4..e5572813d11 100644 --- a/test/functional/shared/resources/testdata/corerp-resources-terraform-postgres.bicep +++ b/test/functional/shared/resources/testdata/corerp-resources-terraform-postgres.bicep @@ -23,8 +23,8 @@ resource env 'Applications.Core/environments@2023-10-01-preview' = { terraform:{ providers:{ postgresql:[{ + alias: 'pgdb-test' username: userName - port: 5432 password: password sslmode: 'disable' }] @@ -32,11 +32,12 @@ resource env 'Applications.Core/environments@2023-10-01-preview' = { } env: { PGHOST: 'postgres.corerp-resources-terraform-pg-app.svc.cluster.local' + PGPORT: '5432' } } recipes: { 'Applications.Core/extenders': { - default: { + defaultpostgres: { templateKind: 'terraform' templatePath: '${moduleServer}/postgres.zip' } @@ -65,7 +66,7 @@ resource pgsapp 'Applications.Core/extenders@2023-10-01-preview' = { application: app.id environment: env.id recipe: { - name: 'default' + name: 'defaultpostgres' parameters: { password: password } diff --git a/test/functional/shared/resources/testdata/recipes/test-terraform-recipes/postgres/main.tf b/test/functional/shared/resources/testdata/recipes/test-terraform-recipes/postgres/main.tf index 29c412f5a91..ca2ac6ca391 100644 --- a/test/functional/shared/resources/testdata/recipes/test-terraform-recipes/postgres/main.tf +++ b/test/functional/shared/resources/testdata/recipes/test-terraform-recipes/postgres/main.tf @@ -7,6 +7,7 @@ terraform { postgresql = { source = "cyrilgdn/postgresql" version = "1.16.0" + configuration_aliases = [postgresql.pgdb-test] } } } @@ -74,6 +75,7 @@ resource "time_sleep" "wait_20_seconds" { } resource postgresql_database "pg_db_test" { + provider = postgresql.pgdb-test depends_on = [time_sleep.wait_20_seconds] name = "pg_db_test" }