diff --git a/command/init.go b/command/init.go index 627bb5de3..656be36ef 100644 --- a/command/init.go +++ b/command/init.go @@ -5,7 +5,6 @@ import ( "fmt" "log" "os" - "path/filepath" "strings" "github.com/hashicorp/hcl/v2" @@ -483,7 +482,6 @@ func (c *InitCommand) getProviders(config *configs.Config, state *states.State, // things relatively concise. Later it'd be nice to have a progress UI // where statuses update in-place, but we can't do that as long as we // are shimming our vt100 output to the legacy console API on Windows. - missingProviders := make(map[addrs.Provider]struct{}) evts := &providercache.InstallerEvents{ PendingProviders: func(reqs map[addrs.Provider]getproviders.VersionConstraints) { c.Ui.Output(c.Colorize().Color( @@ -521,10 +519,6 @@ func (c *InitCommand) getProviders(config *configs.Config, state *states.State, c.Ui.Info(fmt.Sprintf("- Installing %s v%s...", provider.ForDisplay(), version)) }, QueryPackagesFailure: func(provider addrs.Provider, err error) { - // We track providers that had missing metadata because we might - // generate additional hints for some of them at the end. - missingProviders[provider] = struct{}{} - switch errorTy := err.(type) { case getproviders.ErrProviderNotFound: sources := errorTy.Sources @@ -769,60 +763,6 @@ func (c *InitCommand) getProviders(config *configs.Config, state *states.State, c.Ui.Error("Provider installation was canceled by an interrupt signal.") return true, true, diags } - if len(missingProviders) > 0 { - // If we encountered requirements for one or more providers where we - // weren't able to find any metadata, that _might_ be because a - // user had previously (before 0.14) been incorrectly using the - // .terraform/plugins directory as if it were a local filesystem - // mirror, rather than as the main cache directory. - // - // We no longer allow that because it'd be ambiguous whether plugins in - // there are explictly intended to be a local mirror or if they are - // just leftover cache entries from provider installation in - // Terraform 0.13. - // - // To help those users migrate we have a specialized warning message - // for it, which we'll produce only if one of the missing providers can - // be seen in the "legacy" cache directory, which is what we're now - // considering .terraform/plugins to be. (The _current_ cache directory - // is .terraform/providers.) - // - // This is only a heuristic, so it might potentially produce false - // positives if a user happens to encounter another sort of error - // while they are upgrading from Terraform 0.13 to 0.14. Aside from - // upgrading users should not end up in here because they won't - // have a legacy cache directory at all. - legacyDir := c.providerLegacyCacheDir() - if legacyDir != nil { // if the legacy directory is present at all - for missingProvider := range missingProviders { - if missingProvider.IsDefault() { - // If we get here for a default provider then it's more - // likely that something _else_ went wrong, like a network - // problem, so we'll skip the warning in this case to - // avoid potentially misleading the user into creating an - // unnecessary local mirror for an official provider. - continue - } - entry := legacyDir.ProviderLatestVersion(missingProvider) - if entry == nil { - continue - } - // If we get here then the missing provider was cached, which - // implies that it might be an in-house provider the user - // placed manually to try to make Terraform use it as if it - // were a local mirror directory. - wantDir := filepath.FromSlash(fmt.Sprintf("terraform.d/plugins/%s/%s/%s", missingProvider, entry.Version, getproviders.CurrentPlatform)) - diags = diags.Append(tfdiags.Sourceless( - tfdiags.Warning, - "Missing provider is in legacy cache directory", - fmt.Sprintf( - "Terraform supports a number of local directories that can serve as automatic local filesystem mirrors, but .terraform/plugins is not one of them because Terraform v0.13 and earlier used this directory to cache copies of provider plugins retrieved from elsewhere.\n\nIf you intended to use this directory as a filesystem mirror for %s, place it instead in the following directory:\n %s", - missingProvider, wantDir, - ), - )) - } - } - } if err != nil { // The errors captured in "err" should be redundant with what we // received via the InstallerEvents callbacks above, so we'll diff --git a/command/init_test.go b/command/init_test.go index cda78e446..f7f5af923 100644 --- a/command/init_test.go +++ b/command/init_test.go @@ -1053,85 +1053,6 @@ func TestInit_getProviderSource(t *testing.T) { } } -func TestInit_getProviderInLegacyPluginCacheDir(t *testing.T) { - // Create a temporary working directory that is empty - td := tempDir(t) - testCopyDir(t, testFixturePath("init-legacy-provider-cache"), td) - defer os.RemoveAll(td) - defer testChdir(t, td)() - - // The test fixture has placeholder os_arch directories which we must - // now rename to match the current platform, or else the entries inside - // will be ignored. - platformStr := getproviders.CurrentPlatform.String() - if err := os.Rename( - ".terraform/plugins/example.com/test/b/1.1.0/os_arch", - ".terraform/plugins/example.com/test/b/1.1.0/"+platformStr, - ); err != nil { - t.Fatal(err) - } - if err := os.Rename( - ".terraform/plugins/registry.terraform.io/hashicorp/c/2.0.0/os_arch", - ".terraform/plugins/registry.terraform.io/hashicorp/c/2.0.0/"+platformStr, - ); err != nil { - t.Fatal(err) - } - - // An empty MultiSource serves as a way to make sure no providers are - // actually available for installation, which suits us here because - // we're testing an error case. - providerSource := getproviders.MultiSource{} - - ui := cli.NewMockUi() - m := Meta{ - Ui: ui, - ProviderSource: providerSource, - } - - c := &InitCommand{ - Meta: m, - } - - args := []string{ - "-backend=false", - } - if code := c.Run(args); code == 0 { - t.Fatalf("succeeded; want error\n%s", ui.OutputWriter.String()) - } - - // We remove all of the newlines so that we don't need to contend with - // the automatic word wrapping that our diagnostic printer does. - stderr := strings.Replace(ui.ErrorWriter.String(), "\n", " ", -1) - - if got, want := stderr, `example.com/test/a: no available releases match the given constraints`; !strings.Contains(got, want) { - t.Errorf("missing error about example.com/test/a\nwant substring: %s\n%s", want, got) - } - if got, want := stderr, `example.com/test/b: no available releases match the given constraints`; !strings.Contains(got, want) { - t.Errorf("missing error about example.com/test/b\nwant substring: %s\n%s", want, got) - } - if got, want := stderr, `hashicorp/c: no available releases match the given constraints`; !strings.Contains(got, want) { - t.Errorf("missing error about registry.terraform.io/hashicorp/c\nwant substring: %s\n%s", want, got) - } - - if got, want := stderr, `terraform.d/plugins/example.com/test/a`; strings.Contains(got, want) { - // We _don't_ expect to see a warning about the "a" provider, because - // there's no copy of that in the legacy plugin cache dir. - t.Errorf("unexpected suggested path for local example.com/test/a\ndon't want substring: %s\n%s", want, got) - } - if got, want := stderr, `terraform.d/plugins/example.com/test/b/1.1.0/`+platformStr; !strings.Contains(got, want) { - // ...but we should see a warning about the "b" provider, because - // there's an entry for that in the legacy cache dir. - t.Errorf("missing suggested path for local example.com/test/b 1.0.0 on %s\nwant substring: %s\n%s", platformStr, want, got) - } - if got, want := stderr, `terraform.d/plugins/registry.terraform.io/hashicorp/c`; strings.Contains(got, want) { - // We _don't_ expect to see a warning about the "a" provider, even - // though it's in the cache dir, because it's an official provider - // and so we assume it ended up there as a result of normal provider - // installation in Terraform 0.13. - t.Errorf("unexpected suggested path for local hashicorp/c\ndon't want substring: %s\n%s", want, got) - } -} - func TestInit_getProviderLegacyFromState(t *testing.T) { // Create a temporary working directory that is empty td := tempDir(t) diff --git a/command/meta_providers.go b/command/meta_providers.go index c20c79f2c..9daa93125 100644 --- a/command/meta_providers.go +++ b/command/meta_providers.go @@ -128,31 +128,6 @@ func (m *Meta) providerGlobalCacheDir() *providercache.Dir { return providercache.NewDir(dir) } -// providerLegacyCacheDir returns an object representing the former location -// of the local cache directory from Terraform 0.13 and earlier. -// -// This is no longer viable for use as a real cache directory because some -// incorrect documentation called for Terraform Cloud users to use it as if it -// were an implied local filesystem mirror directory. Therefore we now use it -// only to generate some hopefully-helpful migration guidance during -// "terraform init" for anyone who _was_ trying to use it as a local filesystem -// mirror directory. -// -// providerLegacyCacheDir returns nil if the legacy cache directory isn't -// present or isn't a directory, so that callers can more easily skip over -// any backward compatibility behavior that applies only when the directory -// is present. -// -// Callers must use the resulting object in a read-only mode only. Don't -// install any new providers into this directory. -func (m *Meta) providerLegacyCacheDir() *providercache.Dir { - dir := filepath.Join(m.DataDir(), "plugins") - if info, err := os.Stat(dir); err != nil || !info.IsDir() { - return nil - } - return providercache.NewDir(dir) -} - // providerInstallSource returns an object that knows how to consult one or // more external sources to determine the availability of and package // locations for versions of Terraform providers that are available for