diff --git a/command/e2etest/init_test.go b/command/e2etest/init_test.go index 7993c4e13..5da646913 100644 --- a/command/e2etest/init_test.go +++ b/command/e2etest/init_test.go @@ -311,3 +311,43 @@ func TestInit_fromModule(t *testing.T) { t.Fatalf("main.tf doesn't appear to be a vault configuration: \n%s", content) } } + +func TestInitProviderNotFound(t *testing.T) { + t.Parallel() + + // This test will reach out to registry.terraform.io as one of the possible + // installation locations for hashicorp/nonexist, which should not exist. + skipIfCannotAccessNetwork(t) + + fixturePath := filepath.Join("testdata", "provider-not-found") + tf := e2e.NewBinary(terraformBin, fixturePath) + defer tf.Close() + + t.Run("registry provider not found", func(t *testing.T) { + _, stderr, err := tf.Run("init") + if err == nil { + t.Fatal("expected error, got success") + } + + if !strings.Contains(stderr, "provider registry registry.terraform.io does not have a\nprovider named registry.terraform.io/hashicorp/nonexist") { + t.Errorf("expected error message is missing from output:\n%s", stderr) + } + }) + + t.Run("local provider not found", func(t *testing.T) { + // The -plugin-dir directory must exist for the provider installer to search it. + pluginDir := tf.Path("empty") + if err := os.Mkdir(pluginDir, os.ModePerm); err != nil { + t.Fatal(err) + } + + _, stderr, err := tf.Run("init", "-plugin-dir="+pluginDir) + if err == nil { + t.Fatal("expected error, got success") + } + + if !strings.Contains(stderr, "provider registry.terraform.io/hashicorp/nonexist was not\nfound in any of the search locations\n\n- "+pluginDir) { + t.Errorf("expected error message is missing from output:\n%s", stderr) + } + }) +} diff --git a/command/e2etest/testdata/provider-not-found/main.tf b/command/e2etest/testdata/provider-not-found/main.tf new file mode 100644 index 000000000..3305c612b --- /dev/null +++ b/command/e2etest/testdata/provider-not-found/main.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + nonexist = { + source = "registry.terraform.io/hashicorp/nonexist" + } + } +} diff --git a/command/init.go b/command/init.go index f5fd8cd17..21e9959ca 100644 --- a/command/init.go +++ b/command/init.go @@ -505,7 +505,7 @@ func (c *InitCommand) getProviders(earlyConfig *earlyconfig.Config, state *state diags = diags.Append(tfdiags.Sourceless( tfdiags.Error, "Failed to query available provider packages", - fmt.Sprintf("Could not retrieve the list of available versions for provider %s: %s\n\n%s ", + fmt.Sprintf("Could not retrieve the list of available versions for provider %s: %s\n\n%s", provider.ForDisplay(), err, strings.Join(displaySources, "\n"), ), )) @@ -513,7 +513,7 @@ func (c *InitCommand) getProviders(earlyConfig *earlyconfig.Config, state *state diags = diags.Append(tfdiags.Sourceless( tfdiags.Error, "Failed to query available provider packages", - fmt.Sprintf("Could not retrieve the list of available versions for provider %s: %s ", + fmt.Sprintf("Could not retrieve the list of available versions for provider %s: %s", provider.ForDisplay(), err, ), )) diff --git a/internal/getproviders/errors.go b/internal/getproviders/errors.go index ca8cb046d..c5f5191e0 100644 --- a/internal/getproviders/errors.go +++ b/internal/getproviders/errors.go @@ -196,7 +196,7 @@ func (err ErrQueryFailed) Unwrap() error { // grow in future. func ErrIsNotExist(err error) bool { switch err.(type) { - case ErrProviderNotFound, ErrPlatformNotSupported: + case ErrProviderNotFound, ErrRegistryProviderNotKnown, ErrPlatformNotSupported: return true default: return false diff --git a/internal/getproviders/filesystem_mirror_source.go b/internal/getproviders/filesystem_mirror_source.go index 18cfba6cb..801116e69 100644 --- a/internal/getproviders/filesystem_mirror_source.go +++ b/internal/getproviders/filesystem_mirror_source.go @@ -122,6 +122,5 @@ func (s *FilesystemMirrorSource) scanAllVersions() error { } func (s *FilesystemMirrorSource) ForDisplay(provider addrs.Provider) string { - // TODO: Since we have the provider, this could show the entire search path return s.baseDir } diff --git a/internal/getproviders/memoize_source_test.go b/internal/getproviders/memoize_source_test.go index a2765d877..12c8b9dc5 100644 --- a/internal/getproviders/memoize_source_test.go +++ b/internal/getproviders/memoize_source_test.go @@ -39,7 +39,7 @@ func TestMemoizeSource(t *testing.T) { } _, err = source.AvailableVersions(nonexistProvider) - if want, ok := err.(ErrProviderNotFound); !ok { + if want, ok := err.(ErrRegistryProviderNotKnown); !ok { t.Fatalf("wrong error type from nonexist call:\ngot: %T\nwant: %T", err, want) } @@ -122,11 +122,11 @@ func TestMemoizeSource(t *testing.T) { source := NewMemoizeSource(mock) _, err := source.AvailableVersions(nonexistProvider) - if want, ok := err.(ErrProviderNotFound); !ok { + if want, ok := err.(ErrRegistryProviderNotKnown); !ok { t.Fatalf("wrong error type from first call:\ngot: %T\nwant: %T", err, want) } _, err = source.AvailableVersions(nonexistProvider) - if want, ok := err.(ErrProviderNotFound); !ok { + if want, ok := err.(ErrRegistryProviderNotKnown); !ok { t.Fatalf("wrong error type from second call:\ngot: %T\nwant: %T", err, want) } diff --git a/internal/getproviders/mock_source.go b/internal/getproviders/mock_source.go index 3e90a07e8..1672cc896 100644 --- a/internal/getproviders/mock_source.go +++ b/internal/getproviders/mock_source.go @@ -51,7 +51,7 @@ func (s *MockSource) AvailableVersions(provider addrs.Provider) (VersionList, er if len(ret) == 0 { // In this case, we'll behave like a registry that doesn't know about // this provider at all, rather than just returning an empty result. - return nil, ErrProviderNotFound{provider, []string{"mock source"}} + return nil, ErrRegistryProviderNotKnown{provider} } ret.Sort() return ret, nil diff --git a/internal/getproviders/multi_source_test.go b/internal/getproviders/multi_source_test.go index 448354833..db81355fd 100644 --- a/internal/getproviders/multi_source_test.go +++ b/internal/getproviders/multi_source_test.go @@ -73,7 +73,7 @@ func TestMultiSourceAvailableVersions(t *testing.T) { } _, err = multi.AvailableVersions(addrs.NewDefaultProvider("baz")) - if want, ok := err.(ErrProviderNotFound); !ok { + if want, ok := err.(ErrRegistryProviderNotKnown); !ok { t.Fatalf("wrong error type:\ngot: %T\nwant: %T", err, want) } }) @@ -147,7 +147,7 @@ func TestMultiSourceAvailableVersions(t *testing.T) { } _, err = multi.AvailableVersions(addrs.NewDefaultProvider("baz")) - if want, ok := err.(ErrProviderNotFound); !ok { + if want, ok := err.(ErrRegistryProviderNotKnown); !ok { t.Fatalf("wrong error type:\ngot: %T\nwant: %T", err, want) } }) @@ -165,8 +165,7 @@ func TestMultiSourceAvailableVersions(t *testing.T) { t.Fatal("expected error, got success") } - wantErr := `provider registry.terraform.io/hashicorp/foo was not found in any of the search locations` - _ = []string{"mock source", "mock source"} + wantErr := `provider registry registry.terraform.io does not have a provider named registry.terraform.io/hashicorp/foo` if err.Error() != wantErr { t.Fatalf("wrong error.\ngot: %s\nwant: %s\n", err, wantErr)