From 78464f251a0883f272a7ca920cde054f5f31d806 Mon Sep 17 00:00:00 2001 From: Christian Mesh Date: Thu, 14 Dec 2023 12:21:16 -0500 Subject: [PATCH] Add a warning when multiple likely forks of a provider are detected (#1009) Signed-off-by: Christian Mesh --- CHANGELOG.md | 1 + internal/command/init.go | 20 ++++++ internal/command/init_test.go | 65 +++++++++++++++++++ .../child/main.tf | 10 +++ .../main.tf | 15 +++++ 5 files changed, 111 insertions(+) create mode 100644 internal/command/testdata/init-get-provider-detected-duplicate/child/main.tf create mode 100644 internal/command/testdata/init-get-provider-detected-duplicate/main.tf diff --git a/CHANGELOG.md b/CHANGELOG.md index 36bd77ab3c..269da51c85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ ENHANCEMENTS: * state: Provider addresses in the statefile referring to registry.terraform.io will be treated as referring to registry.opentofu.org unless the full provider address is specified in the config or `OPENTOFU_STATEFILE_PROVIDER_ADDRESS_TRANSLATION` is set to `0`. ([#773](https://github.com/opentofu/opentofu/pull/773)) * The default provider namespace has been changed from "hasicorp" to "opentofu". This only impacts providers that do not explicitly have a namespace set, ex "aws" vs "hasicorp/aws". This change should be transparent and not require action to be taken by users. * init: Ensured that the `tofu init` command has consistent spelling of the word `initialization` in its output. ([#855](https://github.com/opentofu/opentofu/pull/855/files)) +* init: A warning is now emitted when two providers who share the same name are detected. This can help prevent misconfigurations when switching a project to use a fork of a provider. ([#1009](https://github.com/opentofu/opentofu/pull/1009)) BUG FIXES: diff --git a/internal/command/init.go b/internal/command/init.go index 36b2c34552..e5225615fc 100644 --- a/internal/command/init.go +++ b/internal/command/init.go @@ -546,7 +546,13 @@ func (c *InitCommand) getProviders(ctx context.Context, config *configs.Config, reqs = reqs.Merge(stateReqs) } + potentialProviderConflicts := make(map[string][]string) + for providerAddr := range reqs { + if providerAddr.Namespace == "hashicorp" || providerAddr.Namespace == "opentofu" { + potentialProviderConflicts[providerAddr.Type] = append(potentialProviderConflicts[providerAddr.Type], providerAddr.ForDisplay()) + } + if providerAddr.IsLegacy() { diags = diags.Append(tfdiags.Sourceless( tfdiags.Error, @@ -559,6 +565,20 @@ func (c *InitCommand) getProviders(ctx context.Context, config *configs.Config, } } + for name, addrs := range potentialProviderConflicts { + if len(addrs) > 1 { + diags = diags.Append(tfdiags.Sourceless( + tfdiags.Warning, + "Potential provider misconfiguration", + fmt.Sprintf( + "OpenTofu has detected multiple providers of type %s (%s) which may be a misconfiguration.\n\nIf this is intentional you can ignore this warning", + name, + strings.Join(addrs, ", "), + ), + )) + } + } + previousLocks, moreDiags := c.lockedDependencies() diags = diags.Append(moreDiags) diff --git a/internal/command/init_test.go b/internal/command/init_test.go index dd6305dc14..c801f8e9e7 100644 --- a/internal/command/init_test.go +++ b/internal/command/init_test.go @@ -1631,6 +1631,71 @@ func TestInit_getProviderDetectedLegacy(t *testing.T) { } } +func TestInit_getProviderDetectedDuplicate(t *testing.T) { + // Create a temporary working directory that is empty + td := t.TempDir() + testCopyDir(t, testFixturePath("init-get-provider-detected-duplicate"), td) + defer testChdir(t, td)() + + // We need to construct a multisource with a mock source and a registry + // source: the mock source will return ErrRegistryProviderNotKnown for an + // unknown provider, and the registry source will allow us to look up the + // appropriate namespace if possible. + providerSource, psClose := newMockProviderSource(t, map[string][]string{ + "hashicorp/foo": {"1.2.3"}, + "opentofu/foo": {"1.2.3"}, + "hashicorp/bar": {"1.2.3"}, + }) + defer psClose() + registrySource, rsClose := testRegistrySource(t) + defer rsClose() + multiSource := getproviders.MultiSource{ + {Source: providerSource}, + {Source: registrySource}, + } + + ui := new(cli.MockUi) + view, _ := testView(t) + m := Meta{ + Ui: ui, + View: view, + ProviderSource: multiSource, + } + + c := &InitCommand{ + Meta: m, + } + + args := []string{ + "-backend=false", // should be possible to install plugins without backend init + } + if code := c.Run(args); code != 0 { + t.Fatalf("expected error, got output: \n%s\n%s", ui.OutputWriter.String(), ui.ErrorWriter.String()) + } + + // error output is the main focus of this test + errOutput := ui.ErrorWriter.String() + errors := []string{ + "Warning: Potential provider misconfiguration", + "OpenTofu has detected multiple providers of type foo", + "If this is intentional you can ignore this warning", + } + unexpected := []string{ + "OpenTofu has detected multiple providers of type bar", + } + for _, want := range errors { + if !strings.Contains(errOutput, want) { + t.Fatalf("expected error %q: %s", want, errOutput) + } + } + for _, unwanted := range unexpected { + if strings.Contains(errOutput, unwanted) { + t.Fatalf("unexpected error %q: %s", unwanted, errOutput) + } + } + +} + func TestInit_providerSource(t *testing.T) { // Create a temporary working directory that is empty td := t.TempDir() diff --git a/internal/command/testdata/init-get-provider-detected-duplicate/child/main.tf b/internal/command/testdata/init-get-provider-detected-duplicate/child/main.tf new file mode 100644 index 0000000000..f2cea5e5b9 --- /dev/null +++ b/internal/command/testdata/init-get-provider-detected-duplicate/child/main.tf @@ -0,0 +1,10 @@ +terraform { + required_providers { + dupechild = { + source = "hashicorp/bar" + } + } +} + +// This will try to install hashicorp/foo +provider foo {} diff --git a/internal/command/testdata/init-get-provider-detected-duplicate/main.tf b/internal/command/testdata/init-get-provider-detected-duplicate/main.tf new file mode 100644 index 0000000000..4b6e9f22fa --- /dev/null +++ b/internal/command/testdata/init-get-provider-detected-duplicate/main.tf @@ -0,0 +1,15 @@ +terraform { + required_providers { + foo = { + // This will conflict with the child modules hashicorp/foo + source = "opentofu/foo" + } + dupe = { + // This should not conflict with the child modules hashicorp/bar + source = "bar" + } + } +} +module "some-baz-stuff" { + source = "./child" +}