From f5b90f84a8f309d295d1dc53536d5b7f7f7a4753 Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Fri, 10 Dec 2021 12:48:32 -0500 Subject: [PATCH] jsonconfig: Improve provider configuration output When rendering configuration as JSON, we have a single map of provider configurations at the top level, since these are globally applicable. Each resource has an opaque key into this map which points at the configuration data for the provider. This commit fixes two bugs in this implementation: - Resources in non-root modules had an invalid provider config key, which meant that there was never a valid reference to the provider config block. These keys were prefixed with the local module name instead of the path to the module. This is now corrected. - Modules with passed provider configs would point to either an empty provider config block or one which is not present at all. This has been fixed so that these resources point to the provider config block from the calling module (or wherever up the module tree it was originally defined). We also add a "full_name" key-value pair to the provider config block, with the entire fully-qualified provider name including hostname and namespace. --- internal/command/jsonconfig/config.go | 110 +++- .../testdata/show-json-sensitive/output.json | 1 + .../show-json/basic-create/output.json | 1 + .../testdata/show-json/modules/output.json | 7 +- .../show-json/nested-modules/output.json | 2 +- .../show-json/provider-aliasing/child/main.tf | 26 + .../provider-aliasing/child/nested/main.tf | 18 + .../show-json/provider-aliasing/main.tf | 34 ++ .../show-json/provider-aliasing/output.json | 567 ++++++++++++++++++ .../provider-version-no-config/output.json | 1 + .../show-json/provider-version/output.json | 1 + website/docs/internals/json-format.mdx | 11 +- 12 files changed, 768 insertions(+), 11 deletions(-) create mode 100644 internal/command/testdata/show-json/provider-aliasing/child/main.tf create mode 100644 internal/command/testdata/show-json/provider-aliasing/child/nested/main.tf create mode 100644 internal/command/testdata/show-json/provider-aliasing/main.tf create mode 100755 internal/command/testdata/show-json/provider-aliasing/output.json diff --git a/internal/command/jsonconfig/config.go b/internal/command/jsonconfig/config.go index 617181ba6..807444d6e 100644 --- a/internal/command/jsonconfig/config.go +++ b/internal/command/jsonconfig/config.go @@ -27,10 +27,12 @@ type config struct { // module boundaries. type providerConfig struct { Name string `json:"name,omitempty"` + FullName string `json:"full_name,omitempty"` Alias string `json:"alias,omitempty"` VersionConstraint string `json:"version_constraint,omitempty"` ModuleAddress string `json:"module_address,omitempty"` Expressions map[string]interface{} `json:"expressions,omitempty"` + parentKey string } type module struct { @@ -120,7 +122,6 @@ func Marshal(c *configs.Config, schemas *terraform.Schemas) ([]byte, error) { pcs := make(map[string]providerConfig) marshalProviderConfigs(c, schemas, pcs) - output.ProviderConfigs = pcs rootModule, err := marshalModule(c, schemas, "") if err != nil { @@ -128,6 +129,15 @@ func Marshal(c *configs.Config, schemas *terraform.Schemas) ([]byte, error) { } output.RootModule = rootModule + normalizeModuleProviderKeys(&rootModule, pcs) + + for name, pc := range pcs { + if pc.parentKey != "" { + delete(pcs, name) + } + } + output.ProviderConfigs = pcs + ret, err := json.Marshal(output) return ret, err } @@ -154,6 +164,7 @@ func marshalProviderConfigs( p := providerConfig{ Name: pc.Name, + FullName: providerFqn.String(), Alias: pc.Alias, ModuleAddress: c.Path.String(), Expressions: marshalExpressions(pc.Config, schema), @@ -176,6 +187,30 @@ func marshalProviderConfigs( // Ensure that any required providers with no associated configuration // block are included in the set. for k, pr := range c.Module.ProviderRequirements.RequiredProviders { + // If a provider has aliases defined, process those first. + for _, alias := range pr.Aliases { + // If there exists a value for this provider, we have nothing to add + // to it, so skip. + key := opaqueProviderKey(alias.StringCompact(), c.Path.String()) + if _, exists := m[key]; exists { + continue + } + // Given no provider configuration block exists, the only fields we can + // fill here are the local name, FQN, module address, and version + // constraints. + p := providerConfig{ + Name: pr.Name, + FullName: pr.Type.String(), + ModuleAddress: c.Path.String(), + } + + if vc, ok := reqs[pr.Type]; ok { + p.VersionConstraint = getproviders.VersionConstraintsString(vc) + } + + m[key] = p + } + // If there exists a value for this provider, we have nothing to add // to it, so skip. key := opaqueProviderKey(k, c.Path.String()) @@ -188,6 +223,7 @@ func marshalProviderConfigs( // constraints. p := providerConfig{ Name: pr.Name, + FullName: pr.Type.String(), ModuleAddress: c.Path.String(), } @@ -199,7 +235,53 @@ func marshalProviderConfigs( } // Must also visit our child modules, recursively. - for _, cc := range c.Children { + for name, mc := range c.Module.ModuleCalls { + // Keys in c.Children are guaranteed to match those in c.Module.ModuleCalls + cc := c.Children[name] + + // Add provider config map entries for passed provider configs, + // pointing at the passed configuration + for _, ppc := range mc.Providers { + // These provider names include aliases, if set + moduleProviderName := ppc.InChild.String() + parentProviderName := ppc.InParent.String() + + // Look up the provider FQN from the module context, using the non-aliased local name + providerFqn := cc.ProviderForConfigAddr(addrs.LocalProviderConfig{LocalName: ppc.InChild.Name}) + + // The presence of passed provider configs means that we cannot have + // any configuration expressions or version constraints here + p := providerConfig{ + Name: moduleProviderName, + FullName: providerFqn.String(), + ModuleAddress: cc.Path.String(), + } + + 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 + } + } + + m[key] = p + } + + // Finally, marshal any other provider configs within the called module. + // It is safe to do this last because it is invalid to configure a + // provider which has passed provider configs in the module call. marshalProviderConfigs(cc, schemas, m) } } @@ -319,7 +401,9 @@ func marshalModuleCall(c *configs.Config, mc *configs.ModuleCall, schemas *terra } ret.Expressions = marshalExpressions(mc.Config, schema) - module, _ := marshalModule(c, schemas, mc.Name) + + module, _ := marshalModule(c, schemas, c.Path.String()) + ret.Module = module if len(mc.DependsOn) > 0 { @@ -342,11 +426,12 @@ func marshalModuleCall(c *configs.Config, mc *configs.ModuleCall, schemas *terra func marshalResources(resources map[string]*configs.Resource, schemas *terraform.Schemas, moduleAddr string) ([]resource, error) { var rs []resource for _, v := range resources { + providerConfigKey := opaqueProviderKey(v.ProviderConfigAddr().StringCompact(), moduleAddr) r := resource{ Address: v.Addr().String(), Type: v.Type, Name: v.Name, - ProviderConfigKey: opaqueProviderKey(v.ProviderConfigAddr().StringCompact(), moduleAddr), + ProviderConfigKey: providerConfigKey, } switch v.Mode { @@ -416,6 +501,23 @@ func marshalResources(resources map[string]*configs.Resource, schemas *terraform return rs, nil } +// Flatten all resource provider keys in a module and its descendents, such +// that any resources from providers using a configuration passed through the +// module call have a direct refernce to that provider configuration. +func normalizeModuleProviderKeys(m *module, pcs map[string]providerConfig) { + for i, r := range m.Resources { + if pc, exists := pcs[r.ProviderConfigKey]; exists { + if _, hasParent := pcs[pc.parentKey]; hasParent { + m.Resources[i].ProviderConfigKey = pc.parentKey + } + } + } + + for _, mc := range m.ModuleCalls { + normalizeModuleProviderKeys(&mc.Module, pcs) + } +} + // opaqueProviderKey generates a unique absProviderConfig-like string from the module // address and provider func opaqueProviderKey(provider string, addr string) (key string) { diff --git a/internal/command/testdata/show-json-sensitive/output.json b/internal/command/testdata/show-json-sensitive/output.json index 206fbb7f6..9d1ec24bc 100644 --- a/internal/command/testdata/show-json-sensitive/output.json +++ b/internal/command/testdata/show-json-sensitive/output.json @@ -164,6 +164,7 @@ "provider_config": { "test": { "name": "test", + "full_name": "registry.terraform.io/hashicorp/test", "expressions": { "region": { "constant_value": "somewhere" diff --git a/internal/command/testdata/show-json/basic-create/output.json b/internal/command/testdata/show-json/basic-create/output.json index d1b8aae53..83c144580 100644 --- a/internal/command/testdata/show-json/basic-create/output.json +++ b/internal/command/testdata/show-json/basic-create/output.json @@ -152,6 +152,7 @@ "provider_config": { "test": { "name": "test", + "full_name": "registry.terraform.io/hashicorp/test", "expressions": { "region": { "constant_value": "somewhere" diff --git a/internal/command/testdata/show-json/modules/output.json b/internal/command/testdata/show-json/modules/output.json index 4ed0ea45d..172828259 100644 --- a/internal/command/testdata/show-json/modules/output.json +++ b/internal/command/testdata/show-json/modules/output.json @@ -224,7 +224,7 @@ "mode": "managed", "type": "test_instance", "name": "test", - "provider_config_key": "module_test_bar:test", + "provider_config_key": "module.module_test_bar:test", "expressions": { "ami": { "references": [ @@ -265,7 +265,7 @@ "mode": "managed", "type": "test_instance", "name": "test", - "provider_config_key": "module_test_foo:test", + "provider_config_key": "module.module_test_foo:test", "expressions": { "ami": { "references": [ @@ -291,7 +291,8 @@ "provider_config": { "module.module_test_foo:test": { "module_address": "module.module_test_foo", - "name": "test" + "name": "test", + "full_name": "registry.terraform.io/hashicorp/test" } } } diff --git a/internal/command/testdata/show-json/nested-modules/output.json b/internal/command/testdata/show-json/nested-modules/output.json index 359ea9ae1..6d0af8a14 100644 --- a/internal/command/testdata/show-json/nested-modules/output.json +++ b/internal/command/testdata/show-json/nested-modules/output.json @@ -68,7 +68,7 @@ "mode": "managed", "type": "test_instance", "name": "test", - "provider_config_key": "more:test", + "provider_config_key": "module.my_module.module.more:test", "expressions": { "ami": { "references": [ diff --git a/internal/command/testdata/show-json/provider-aliasing/child/main.tf b/internal/command/testdata/show-json/provider-aliasing/child/main.tf new file mode 100644 index 000000000..42555752c --- /dev/null +++ b/internal/command/testdata/show-json/provider-aliasing/child/main.tf @@ -0,0 +1,26 @@ +terraform { + required_providers { + test = { + source = "hashicorp/test" + configuration_aliases = [test, test.second] + } + } +} + +resource "test_instance" "test_primary" { + ami = "primary" + provider = test +} + +resource "test_instance" "test_secondary" { + ami = "secondary" + provider = test.second +} + +module "grandchild" { + source = "./nested" + providers = { + test = test + test.alt = test.second + } +} diff --git a/internal/command/testdata/show-json/provider-aliasing/child/nested/main.tf b/internal/command/testdata/show-json/provider-aliasing/child/nested/main.tf new file mode 100644 index 000000000..ff1fe9a1a --- /dev/null +++ b/internal/command/testdata/show-json/provider-aliasing/child/nested/main.tf @@ -0,0 +1,18 @@ +terraform { + required_providers { + test = { + source = "hashicorp/test" + configuration_aliases = [test, test.alt] + } + } +} + +resource "test_instance" "test_main" { + ami = "main" + provider = test +} + +resource "test_instance" "test_alternate" { + ami = "secondary" + provider = test.alt +} diff --git a/internal/command/testdata/show-json/provider-aliasing/main.tf b/internal/command/testdata/show-json/provider-aliasing/main.tf new file mode 100644 index 000000000..7f6b0a3e3 --- /dev/null +++ b/internal/command/testdata/show-json/provider-aliasing/main.tf @@ -0,0 +1,34 @@ +provider "test" { + region = "somewhere" +} + +provider "test" { + alias = "backup" + region = "elsewhere" +} + +resource "test_instance" "test" { + ami = "foo" + provider = test +} + +resource "test_instance" "test_backup" { + ami = "foo-backup" + provider = test.backup +} + +module "child" { + source = "./child" + providers = { + test = test + test.second = test.backup + } +} + +module "sibling" { + source = "./child" + providers = { + test = test + test.second = test + } +} diff --git a/internal/command/testdata/show-json/provider-aliasing/output.json b/internal/command/testdata/show-json/provider-aliasing/output.json new file mode 100755 index 000000000..187141c9c --- /dev/null +++ b/internal/command/testdata/show-json/provider-aliasing/output.json @@ -0,0 +1,567 @@ +{ + "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": {} + }, + { + "address": "test_instance.test_backup", + "mode": "managed", + "type": "test_instance", + "name": "test_backup", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "foo-backup" + }, + "sensitive_values": {} + } + ], + "child_modules": [ + { + "resources": [ + { + "address": "module.child.test_instance.test_primary", + "mode": "managed", + "type": "test_instance", + "name": "test_primary", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "primary" + }, + "sensitive_values": {} + }, + { + "address": "module.child.test_instance.test_secondary", + "mode": "managed", + "type": "test_instance", + "name": "test_secondary", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "secondary" + }, + "sensitive_values": {} + } + ], + "address": "module.child", + "child_modules": [ + { + "resources": [ + { + "address": "module.child.module.grandchild.test_instance.test_alternate", + "mode": "managed", + "type": "test_instance", + "name": "test_alternate", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "secondary" + }, + "sensitive_values": {} + }, + { + "address": "module.child.module.grandchild.test_instance.test_main", + "mode": "managed", + "type": "test_instance", + "name": "test_main", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "main" + }, + "sensitive_values": {} + } + ], + "address": "module.child.module.grandchild" + } + ] + }, + { + "resources": [ + { + "address": "module.sibling.test_instance.test_primary", + "mode": "managed", + "type": "test_instance", + "name": "test_primary", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "primary" + }, + "sensitive_values": {} + }, + { + "address": "module.sibling.test_instance.test_secondary", + "mode": "managed", + "type": "test_instance", + "name": "test_secondary", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "secondary" + }, + "sensitive_values": {} + } + ], + "address": "module.sibling", + "child_modules": [ + { + "resources": [ + { + "address": "module.sibling.module.grandchild.test_instance.test_alternate", + "mode": "managed", + "type": "test_instance", + "name": "test_alternate", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "secondary" + }, + "sensitive_values": {} + }, + { + "address": "module.sibling.module.grandchild.test_instance.test_main", + "mode": "managed", + "type": "test_instance", + "name": "test_main", + "provider_name": "registry.terraform.io/hashicorp/test", + "schema_version": 0, + "values": { + "ami": "main" + }, + "sensitive_values": {} + } + ], + "address": "module.sibling.module.grandchild" + } + ] + } + ] + } + }, + "resource_changes": [ + { + "address": "module.child.module.grandchild.test_instance.test_alternate", + "module_address": "module.child.module.grandchild", + "mode": "managed", + "type": "test_instance", + "name": "test_alternate", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "secondary" + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "module.child.module.grandchild.test_instance.test_main", + "module_address": "module.child.module.grandchild", + "mode": "managed", + "type": "test_instance", + "name": "test_main", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "main" + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "module.child.test_instance.test_primary", + "module_address": "module.child", + "mode": "managed", + "type": "test_instance", + "name": "test_primary", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "primary" + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "module.child.test_instance.test_secondary", + "module_address": "module.child", + "mode": "managed", + "type": "test_instance", + "name": "test_secondary", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "secondary" + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "module.sibling.module.grandchild.test_instance.test_alternate", + "module_address": "module.sibling.module.grandchild", + "mode": "managed", + "type": "test_instance", + "name": "test_alternate", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "secondary" + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "module.sibling.module.grandchild.test_instance.test_main", + "module_address": "module.sibling.module.grandchild", + "mode": "managed", + "type": "test_instance", + "name": "test_main", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "main" + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "module.sibling.test_instance.test_primary", + "module_address": "module.sibling", + "mode": "managed", + "type": "test_instance", + "name": "test_primary", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "primary" + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "module.sibling.test_instance.test_secondary", + "module_address": "module.sibling", + "mode": "managed", + "type": "test_instance", + "name": "test_secondary", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "secondary" + }, + "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": {} + } + }, + { + "address": "test_instance.test_backup", + "mode": "managed", + "type": "test_instance", + "name": "test_backup", + "provider_name": "registry.terraform.io/hashicorp/test", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "ami": "foo-backup" + }, + "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 + }, + { + "address": "test_instance.test_backup", + "mode": "managed", + "type": "test_instance", + "name": "test_backup", + "provider_config_key": "test.backup", + "expressions": { + "ami": { + "constant_value": "foo-backup" + } + }, + "schema_version": 0 + } + ], + "module_calls": { + "child": { + "source": "./child", + "module": { + "resources": [ + { + "address": "test_instance.test_primary", + "mode": "managed", + "type": "test_instance", + "name": "test_primary", + "provider_config_key": "test", + "expressions": { + "ami": { + "constant_value": "primary" + } + }, + "schema_version": 0 + }, + { + "address": "test_instance.test_secondary", + "mode": "managed", + "type": "test_instance", + "name": "test_secondary", + "provider_config_key": "test.backup", + "expressions": { + "ami": { + "constant_value": "secondary" + } + }, + "schema_version": 0 + } + ], + "module_calls": { + "grandchild": { + "source": "./nested", + "module": { + "resources": [ + { + "address": "test_instance.test_alternate", + "mode": "managed", + "type": "test_instance", + "name": "test_alternate", + "provider_config_key": "test.backup", + "expressions": { + "ami": { + "constant_value": "secondary" + } + }, + "schema_version": 0 + }, + { + "address": "test_instance.test_main", + "mode": "managed", + "type": "test_instance", + "name": "test_main", + "provider_config_key": "test", + "expressions": { + "ami": { + "constant_value": "main" + } + }, + "schema_version": 0 + } + ] + } + } + } + } + }, + "sibling": { + "source": "./child", + "module": { + "resources": [ + { + "address": "test_instance.test_primary", + "mode": "managed", + "type": "test_instance", + "name": "test_primary", + "provider_config_key": "test", + "expressions": { + "ami": { + "constant_value": "primary" + } + }, + "schema_version": 0 + }, + { + "address": "test_instance.test_secondary", + "mode": "managed", + "type": "test_instance", + "name": "test_secondary", + "provider_config_key": "test", + "expressions": { + "ami": { + "constant_value": "secondary" + } + }, + "schema_version": 0 + } + ], + "module_calls": { + "grandchild": { + "source": "./nested", + "module": { + "resources": [ + { + "address": "test_instance.test_alternate", + "mode": "managed", + "type": "test_instance", + "name": "test_alternate", + "provider_config_key": "test", + "expressions": { + "ami": { + "constant_value": "secondary" + } + }, + "schema_version": 0 + }, + { + "address": "test_instance.test_main", + "mode": "managed", + "type": "test_instance", + "name": "test_main", + "provider_config_key": "test", + "expressions": { + "ami": { + "constant_value": "main" + } + }, + "schema_version": 0 + } + ] + } + } + } + } + } + } + } + } +} diff --git a/internal/command/testdata/show-json/provider-version-no-config/output.json b/internal/command/testdata/show-json/provider-version-no-config/output.json index 6a8b1f451..b5e78402d 100644 --- a/internal/command/testdata/show-json/provider-version-no-config/output.json +++ b/internal/command/testdata/show-json/provider-version-no-config/output.json @@ -152,6 +152,7 @@ "provider_config": { "test": { "name": "test", + "full_name": "registry.terraform.io/hashicorp/test", "version_constraint": ">= 1.2.3" } }, diff --git a/internal/command/testdata/show-json/provider-version/output.json b/internal/command/testdata/show-json/provider-version/output.json index 11fd3bd64..4d86a29b0 100644 --- a/internal/command/testdata/show-json/provider-version/output.json +++ b/internal/command/testdata/show-json/provider-version/output.json @@ -152,6 +152,7 @@ "provider_config": { "test": { "name": "test", + "full_name": "registry.terraform.io/hashicorp/test", "expressions": { "region": { "constant_value": "somewhere" diff --git a/website/docs/internals/json-format.mdx b/website/docs/internals/json-format.mdx index 556d442ee..9d76f4c74 100644 --- a/website/docs/internals/json-format.mdx +++ b/website/docs/internals/json-format.mdx @@ -323,7 +323,7 @@ Because the configuration models are produced at a stage prior to expression eva // the configuration tree, flattened into a single map for convenience since // provider configurations are the one concept in Terraform that can span // across module boundaries. - "provider_configs": { + "provider_config": { // Keys in the provider_configs map are to be considered opaque by callers, // and used just for lookups using the "provider_config_key" property in each @@ -333,6 +333,9 @@ Because the configuration models are produced at a stage prior to expression eva // "name" is the name of the provider without any alias "name": "aws", + // "full_name" is the fully-qualified provider name + "full_name": "registry.terraform.io/hashicorp/aws", + // "alias" is the alias set for a non-default configuration, or unset for // a default configuration. "alias": "foo", @@ -378,7 +381,9 @@ Because the configuration models are produced at a stage prior to expression eva // "provider_config_key" is the key into "provider_configs" (shown // above) for the provider configuration that this resource is - // associated with. + // associated with. If the provider configuration was passed into + // this module from the parent module, the key will point to the + // original provider config block. "provider_config_key": "opaque_provider_ref_aws", // "provisioners" is an optional field which describes any provisioners. @@ -440,7 +445,7 @@ Because the configuration models are produced at a stage prior to expression eva // "module" is a representation of the configuration of the child module // itself, using the same structure as the "root_module" object, // recursively describing the full module tree. - "module": , + "module": } } }