diff --git a/plugin/discovery/get.go b/plugin/discovery/get.go index 8ac5fd92d..40f416da5 100644 --- a/plugin/discovery/get.go +++ b/plugin/discovery/get.go @@ -270,6 +270,14 @@ func (i *ProviderInstaller) install(provider string, version Version, url string // normal resolution machinery can find it. filename := filepath.Base(cached) targetPath := filepath.Join(i.Dir, filename) + // check if the target dir exists, and create it if not + var err error + if _, StatErr := os.Stat(i.Dir); os.IsNotExist(StatErr) { + err = os.Mkdir(i.Dir, 0700) + } + if err != nil { + return err + } log.Printf("[DEBUG] installing %s %s to %s from local cache %s", provider, version, targetPath, cached) diff --git a/plugin/discovery/get_test.go b/plugin/discovery/get_test.go index 84dd68650..c2974af18 100644 --- a/plugin/discovery/get_test.go +++ b/plugin/discovery/get_test.go @@ -474,6 +474,63 @@ func TestProviderInstallerGet(t *testing.T) { } +// test that the provider installer can install plugins from a plugin cache dir +// into a target directory that does not exist. +// https://github.com/hashicorp/terraform/issues/20532 +func TestProviderInstallerGet_cache(t *testing.T) { + server := testReleaseServer() + server.Start() + defer server.Close() + + tmpDir, err := ioutil.TempDir("", "tf-plugin") + if err != nil { + t.Fatal(err) + } + + cache := NewLocalPluginCache(filepath.Join(tmpDir, "cache")) + targetDir := filepath.Join(tmpDir, "non-existant-dir") + + defer os.RemoveAll(tmpDir) + + i := &ProviderInstaller{ + Dir: targetDir, + Cache: cache, + PluginProtocolVersion: 4, + SkipVerify: true, + Ui: cli.NewMockUi(), + registry: registry.NewClient(Disco(server), nil), + OS: "mockos", + Arch: "mockarch", + } + + gotMeta, err := i.Get("test", AllVersions) + if err != nil { + t.Fatal(err) + } + + // we should have version 1.2.4 + dest := filepath.Join(targetDir, "terraform-provider-test_v1.2.4") + + wantMeta := PluginMeta{ + Name: "test", + Version: VersionStr("1.2.4"), + Path: dest, + } + if !reflect.DeepEqual(gotMeta, wantMeta) { + t.Errorf("wrong result meta\ngot: %#v\nwant: %#v", gotMeta, wantMeta) + } + + f, err := ioutil.ReadFile(dest) + if err != nil { + t.Fatal(err) + } + + // provider should have been unzipped + if string(f) != testProviderFile { + t.Fatalf("test provider contains: %q", f) + } +} + func TestProviderInstallerPurgeUnused(t *testing.T) { server := testReleaseServer() defer server.Close()