From 7f4019e1f65f7cdc98426e9152473aca9b1731ff Mon Sep 17 00:00:00 2001 From: nozaq Date: Wed, 16 Feb 2022 01:12:55 +0900 Subject: [PATCH] jsonconfig: fix keys for default providers Fixes provider config keys to reflect implicit provider inheritance. --- internal/command/jsonconfig/config.go | 62 ++-- .../provider-aliasing-default/child/main.tf | 19 ++ .../child/nested-no-requirements/main.tf | 3 + .../child/nested/main.tf | 11 + .../provider-aliasing-default/main.tf | 19 ++ .../provider-aliasing-default/output.json | 270 ++++++++++++++++++ 6 files changed, 368 insertions(+), 16 deletions(-) create mode 100644 internal/command/testdata/show-json/provider-aliasing-default/child/main.tf create mode 100644 internal/command/testdata/show-json/provider-aliasing-default/child/nested-no-requirements/main.tf create mode 100644 internal/command/testdata/show-json/provider-aliasing-default/child/nested/main.tf create mode 100644 internal/command/testdata/show-json/provider-aliasing-default/main.tf create mode 100644 internal/command/testdata/show-json/provider-aliasing-default/output.json diff --git a/internal/command/jsonconfig/config.go b/internal/command/jsonconfig/config.go index 807444d6e..9670fd5e6 100644 --- a/internal/command/jsonconfig/config.go +++ b/internal/command/jsonconfig/config.go @@ -231,9 +231,37 @@ func marshalProviderConfigs( p.VersionConstraint = getproviders.VersionConstraintsString(vc) } + if c.Parent != nil { + parentKey := opaqueProviderKey(pr.Name, c.Parent.Path.String()) + p.parentKey = findSourceProviderKey(parentKey, m) + } + m[key] = p } + // In child modules, providers defined in the parent module can be implicitly used. + // Such providers could have no requirements and configuration blocks defined. + if c.Parent != nil { + for req := range reqs { + // Implicit inheritance only applies to the default provider, + // so the provider name must be same as the provider type. + key := opaqueProviderKey(req.Type, c.Path.String()) + if _, exists := m[key]; exists { + continue + } + + parentKey := opaqueProviderKey(req.Type, c.Parent.Path.String()) + p := providerConfig{ + Name: req.Type, + FullName: req.String(), + ModuleAddress: c.Path.String(), + parentKey: findSourceProviderKey(parentKey, m), + } + + m[key] = p + } + } + // Must also visit our child modules, recursively. for name, mc := range c.Module.ModuleCalls { // Keys in c.Children are guaranteed to match those in c.Module.ModuleCalls @@ -259,22 +287,7 @@ func marshalProviderConfigs( key := opaqueProviderKey(moduleProviderName, cc.Path.String()) parentKey := opaqueProviderKey(parentProviderName, cc.Parent.Path.String()) - - // Traverse up the module call tree until we find the provider - // configuration which has no linked parent config. This is then - // the source of the configuration used in this module call, so - // we link to it directly - for { - parent, exists := m[parentKey] - if !exists { - break - } - p.parentKey = parentKey - parentKey = parent.parentKey - if parentKey == "" { - break - } - } + p.parentKey = findSourceProviderKey(parentKey, m) m[key] = p } @@ -527,3 +540,20 @@ func opaqueProviderKey(provider string, addr string) (key string) { } return key } + +// Traverse up the module call tree until we find the provider +// configuration which has no linked parent config. This is then +// the source of the configuration used in this module call, so +// we link to it directly +func findSourceProviderKey(startKey string, m map[string]providerConfig) string { + parentKey := startKey + for { + parent, exists := m[parentKey] + if !exists || parent.parentKey == "" { + break + } + parentKey = parent.parentKey + } + + return parentKey +} diff --git a/internal/command/testdata/show-json/provider-aliasing-default/child/main.tf b/internal/command/testdata/show-json/provider-aliasing-default/child/main.tf new file mode 100644 index 000000000..1ff9e8969 --- /dev/null +++ b/internal/command/testdata/show-json/provider-aliasing-default/child/main.tf @@ -0,0 +1,19 @@ +terraform { + required_providers { + test = { + source = "hashicorp/test" + } + } +} + +resource "test_instance" "test" { + ami = "bar" +} + +module "with_requirement" { + source = "./nested" +} + +module "no_requirements" { + source = "./nested-no-requirements" +} diff --git a/internal/command/testdata/show-json/provider-aliasing-default/child/nested-no-requirements/main.tf b/internal/command/testdata/show-json/provider-aliasing-default/child/nested-no-requirements/main.tf new file mode 100644 index 000000000..207818696 --- /dev/null +++ b/internal/command/testdata/show-json/provider-aliasing-default/child/nested-no-requirements/main.tf @@ -0,0 +1,3 @@ +resource "test_instance" "test" { + ami = "qux" +} diff --git a/internal/command/testdata/show-json/provider-aliasing-default/child/nested/main.tf b/internal/command/testdata/show-json/provider-aliasing-default/child/nested/main.tf new file mode 100644 index 000000000..1590c5cea --- /dev/null +++ b/internal/command/testdata/show-json/provider-aliasing-default/child/nested/main.tf @@ -0,0 +1,11 @@ +terraform { + required_providers { + test = { + source = "hashicorp/test" + } + } +} + +resource "test_instance" "test" { + ami = "baz" +} diff --git a/internal/command/testdata/show-json/provider-aliasing-default/main.tf b/internal/command/testdata/show-json/provider-aliasing-default/main.tf new file mode 100644 index 000000000..f5e63f0aa --- /dev/null +++ b/internal/command/testdata/show-json/provider-aliasing-default/main.tf @@ -0,0 +1,19 @@ +provider "test" { + region = "somewhere" +} + +provider "test" { + alias = "backup" + region = "elsewhere" +} + +resource "test_instance" "test" { + ami = "foo" +} + +module "child" { + source = "./child" + providers = { + test = test.backup + } +} diff --git a/internal/command/testdata/show-json/provider-aliasing-default/output.json b/internal/command/testdata/show-json/provider-aliasing-default/output.json new file mode 100644 index 000000000..d59e111b4 --- /dev/null +++ b/internal/command/testdata/show-json/provider-aliasing-default/output.json @@ -0,0 +1,270 @@ +{ + "format_version": "1.0", + "terraform_version": "1.1.0-dev", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "test_instance.test", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "foo" + }, + "sensitive_values": {} + } + ], + "child_modules": [ + { + "resources": [ + { + "address": "module.child.test_instance.test", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "bar" + }, + "sensitive_values": {} + } + ], + "address": "module.child", + "child_modules": [ + { + "resources": [ + { + "address": "module.child.module.with_requirement.test_instance.test", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "baz" + }, + "sensitive_values": {} + } + ], + "address": "module.child.module.with_requirement" + }, + { + "resources": [ + { + "address": "module.child.module.no_requirements.test_instance.test", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "qux" + }, + "sensitive_values": {} + } + ], + "address": "module.child.module.no_requirements" + } + ] + } + ] + } + }, + "resource_changes": [ + { + "address": "module.child.module.no_requirements.test_instance.test", + "module_address": "module.child.module.no_requirements", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "qux" + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "module.child.module.with_requirement.test_instance.test", + "module_address": "module.child.module.with_requirement", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "baz" + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "module.child.test_instance.test", + "module_address": "module.child", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "bar" + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "test_instance.test", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "foo" + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + } + ], + "configuration": { + "provider_config": { + "test": { + "name": "test", + "full_name": "registry.terraform.io/hashicorp/test", + "expressions": { + "region": { + "constant_value": "somewhere" + } + } + }, + "test.backup": { + "name": "test", + "full_name": "registry.terraform.io/hashicorp/test", + "alias": "backup", + "expressions": { + "region": { + "constant_value": "elsewhere" + } + } + } + }, + "root_module": { + "resources": [ + { + "address": "test_instance.test", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_config_key": "test", + "expressions": { + "ami": { + "constant_value": "foo" + } + }, + "schema_version": 0 + } + ], + "module_calls": { + "child": { + "source": "./child", + "module": { + "resources": [ + { + "address": "test_instance.test", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_config_key": "test.backup", + "expressions": { + "ami": { + "constant_value": "bar" + } + }, + "schema_version": 0 + } + ], + "module_calls": { + "no_requirements": { + "source": "./nested-no-requirements", + "module": { + "resources": [ + { + "address": "test_instance.test", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_config_key": "test.backup", + "expressions": { + "ami": { + "constant_value": "qux" + } + }, + "schema_version": 0 + } + ] + } + }, + "with_requirement": { + "source": "./nested", + "module": { + "resources": [ + { + "address": "test_instance.test", + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_config_key": "test.backup", + "expressions": { + "ami": { + "constant_value": "baz" + } + }, + "schema_version": 0 + } + ] + } + } + } + } + } + } + } + } +}