providercache: Lazily detect executable file

Instead of searching the installed provider package directory for a
binary as we install it, we can lazily detect the executable as it is
required. Doing so allows us to separately report an invalid unpacked
package, giving the user more actionable error messages.
This commit is contained in:
Alisdair McDiarmid 2020-07-07 14:36:04 -04:00
parent c4ce84269a
commit 8e87ccb689
8 changed files with 217 additions and 194 deletions

View File

@ -1060,26 +1060,23 @@ func TestInit_providerSource(t *testing.T) {
wantPackages := map[addrs.Provider][]providercache.CachedProvider{
addrs.NewDefaultProvider("test"): {
{
Provider: addrs.NewDefaultProvider("test"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("test", "1.2.3", false),
ExecutableFile: expectedPackageInstallPath("test", "1.2.3", true),
Provider: addrs.NewDefaultProvider("test"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("test", "1.2.3", false),
},
},
addrs.NewDefaultProvider("test-beta"): {
{
Provider: addrs.NewDefaultProvider("test-beta"),
Version: getproviders.MustParseVersion("1.2.4"),
PackageDir: expectedPackageInstallPath("test-beta", "1.2.4", false),
ExecutableFile: expectedPackageInstallPath("test-beta", "1.2.4", true),
Provider: addrs.NewDefaultProvider("test-beta"),
Version: getproviders.MustParseVersion("1.2.4"),
PackageDir: expectedPackageInstallPath("test-beta", "1.2.4", false),
},
},
addrs.NewDefaultProvider("source"): {
{
Provider: addrs.NewDefaultProvider("source"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("source", "1.2.3", false),
ExecutableFile: expectedPackageInstallPath("source", "1.2.3", true),
Provider: addrs.NewDefaultProvider("source"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("source", "1.2.3", false),
},
},
}
@ -1094,22 +1091,19 @@ func TestInit_providerSource(t *testing.T) {
}
wantSelected := map[addrs.Provider]*providercache.CachedProvider{
addrs.NewDefaultProvider("test-beta"): {
Provider: addrs.NewDefaultProvider("test-beta"),
Version: getproviders.MustParseVersion("1.2.4"),
PackageDir: expectedPackageInstallPath("test-beta", "1.2.4", false),
ExecutableFile: expectedPackageInstallPath("test-beta", "1.2.4", true),
Provider: addrs.NewDefaultProvider("test-beta"),
Version: getproviders.MustParseVersion("1.2.4"),
PackageDir: expectedPackageInstallPath("test-beta", "1.2.4", false),
},
addrs.NewDefaultProvider("test"): {
Provider: addrs.NewDefaultProvider("test"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("test", "1.2.3", false),
ExecutableFile: expectedPackageInstallPath("test", "1.2.3", true),
Provider: addrs.NewDefaultProvider("test"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("test", "1.2.3", false),
},
addrs.NewDefaultProvider("source"): {
Provider: addrs.NewDefaultProvider("source"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("source", "1.2.3", false),
ExecutableFile: expectedPackageInstallPath("source", "1.2.3", true),
Provider: addrs.NewDefaultProvider("source"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("source", "1.2.3", false),
},
}
if diff := cmp.Diff(wantSelected, gotSelected); diff != "" {
@ -1169,27 +1163,24 @@ func TestInit_getUpgradePlugins(t *testing.T) {
// the newest available version that matched the version constraints.
addrs.NewDefaultProvider("between"): {
{
Provider: addrs.NewDefaultProvider("between"),
Version: getproviders.MustParseVersion("2.3.4"),
PackageDir: expectedPackageInstallPath("between", "2.3.4", false),
ExecutableFile: expectedPackageInstallPath("between", "2.3.4", true),
Provider: addrs.NewDefaultProvider("between"),
Version: getproviders.MustParseVersion("2.3.4"),
PackageDir: expectedPackageInstallPath("between", "2.3.4", false),
},
},
// The existing version of "exact" did not match the version constraints,
// so we installed what the configuration selected as well.
addrs.NewDefaultProvider("exact"): {
{
Provider: addrs.NewDefaultProvider("exact"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("exact", "1.2.3", false),
ExecutableFile: expectedPackageInstallPath("exact", "1.2.3", true),
Provider: addrs.NewDefaultProvider("exact"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("exact", "1.2.3", false),
},
// Previous version is still there, but not selected
{
Provider: addrs.NewDefaultProvider("exact"),
Version: getproviders.MustParseVersion("0.0.1"),
PackageDir: expectedPackageInstallPath("exact", "0.0.1", false),
ExecutableFile: expectedPackageInstallPath("exact", "0.0.1", true),
Provider: addrs.NewDefaultProvider("exact"),
Version: getproviders.MustParseVersion("0.0.1"),
PackageDir: expectedPackageInstallPath("exact", "0.0.1", false),
},
},
// The existing version of "greater-than" _did_ match the constraints,
@ -1197,17 +1188,15 @@ func TestInit_getUpgradePlugins(t *testing.T) {
// -upgrade and so we upgraded it anyway.
addrs.NewDefaultProvider("greater-than"): {
{
Provider: addrs.NewDefaultProvider("greater-than"),
Version: getproviders.MustParseVersion("2.3.4"),
PackageDir: expectedPackageInstallPath("greater-than", "2.3.4", false),
ExecutableFile: expectedPackageInstallPath("greater-than", "2.3.4", true),
Provider: addrs.NewDefaultProvider("greater-than"),
Version: getproviders.MustParseVersion("2.3.4"),
PackageDir: expectedPackageInstallPath("greater-than", "2.3.4", false),
},
// Previous version is still there, but not selected
{
Provider: addrs.NewDefaultProvider("greater-than"),
Version: getproviders.MustParseVersion("2.3.3"),
PackageDir: expectedPackageInstallPath("greater-than", "2.3.3", false),
ExecutableFile: expectedPackageInstallPath("greater-than", "2.3.3", true),
Provider: addrs.NewDefaultProvider("greater-than"),
Version: getproviders.MustParseVersion("2.3.3"),
PackageDir: expectedPackageInstallPath("greater-than", "2.3.3", false),
},
},
}
@ -1222,22 +1211,19 @@ func TestInit_getUpgradePlugins(t *testing.T) {
}
wantSelected := map[addrs.Provider]*providercache.CachedProvider{
addrs.NewDefaultProvider("between"): {
Provider: addrs.NewDefaultProvider("between"),
Version: getproviders.MustParseVersion("2.3.4"),
PackageDir: expectedPackageInstallPath("between", "2.3.4", false),
ExecutableFile: expectedPackageInstallPath("between", "2.3.4", true),
Provider: addrs.NewDefaultProvider("between"),
Version: getproviders.MustParseVersion("2.3.4"),
PackageDir: expectedPackageInstallPath("between", "2.3.4", false),
},
addrs.NewDefaultProvider("exact"): {
Provider: addrs.NewDefaultProvider("exact"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("exact", "1.2.3", false),
ExecutableFile: expectedPackageInstallPath("exact", "1.2.3", true),
Provider: addrs.NewDefaultProvider("exact"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("exact", "1.2.3", false),
},
addrs.NewDefaultProvider("greater-than"): {
Provider: addrs.NewDefaultProvider("greater-than"),
Version: getproviders.MustParseVersion("2.3.4"),
PackageDir: expectedPackageInstallPath("greater-than", "2.3.4", false),
ExecutableFile: expectedPackageInstallPath("greater-than", "2.3.4", true),
Provider: addrs.NewDefaultProvider("greater-than"),
Version: getproviders.MustParseVersion("2.3.4"),
PackageDir: expectedPackageInstallPath("greater-than", "2.3.4", false),
},
}
if diff := cmp.Diff(wantSelected, gotSelected); diff != "" {
@ -1480,22 +1466,19 @@ func TestInit_pluginDirProviders(t *testing.T) {
}
wantSelected := map[addrs.Provider]*providercache.CachedProvider{
addrs.NewDefaultProvider("between"): {
Provider: addrs.NewDefaultProvider("between"),
Version: getproviders.MustParseVersion("2.3.4"),
PackageDir: expectedPackageInstallPath("between", "2.3.4", false),
ExecutableFile: expectedPackageInstallPath("between", "2.3.4", true),
Provider: addrs.NewDefaultProvider("between"),
Version: getproviders.MustParseVersion("2.3.4"),
PackageDir: expectedPackageInstallPath("between", "2.3.4", false),
},
addrs.NewDefaultProvider("exact"): {
Provider: addrs.NewDefaultProvider("exact"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("exact", "1.2.3", false),
ExecutableFile: expectedPackageInstallPath("exact", "1.2.3", true),
Provider: addrs.NewDefaultProvider("exact"),
Version: getproviders.MustParseVersion("1.2.3"),
PackageDir: expectedPackageInstallPath("exact", "1.2.3", false),
},
addrs.NewDefaultProvider("greater-than"): {
Provider: addrs.NewDefaultProvider("greater-than"),
Version: getproviders.MustParseVersion("2.3.4"),
PackageDir: expectedPackageInstallPath("greater-than", "2.3.4", false),
ExecutableFile: expectedPackageInstallPath("greater-than", "2.3.4", true),
Provider: addrs.NewDefaultProvider("greater-than"),
Version: getproviders.MustParseVersion("2.3.4"),
PackageDir: expectedPackageInstallPath("greater-than", "2.3.4", false),
},
}
if diff := cmp.Diff(wantSelected, gotSelected); diff != "" {

View File

@ -209,12 +209,17 @@ func providerFactory(meta *providercache.CachedProvider) providers.Factory {
Output: os.Stderr,
})
execFile, err := meta.ExecutableFile()
if err != nil {
return nil, err
}
config := &plugin.ClientConfig{
HandshakeConfig: tfplugin.Handshake,
Logger: logger,
AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
Managed: true,
Cmd: exec.Command(meta.ExecutableFile),
Cmd: exec.Command(execFile),
AutoMTLS: enableProviderAutoMTLS,
VersionedPlugins: tfplugin.VersionedPlugins,
}

View File

@ -1,6 +1,11 @@
package providercache
import (
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/internal/getproviders"
)
@ -20,16 +25,6 @@ type CachedProvider struct {
// both slashes and backslashes as long as the separators are consistent
// within a particular path string.
PackageDir string
// ExecutableFile is the local filesystem path to the main plugin executable
// for the provider, which is always a file within the directory given
// in PackageDir.
//
// The path always uses slashes as path separators, even on Windows, so
// that the results are consistent between platforms. Windows accepts
// both slashes and backslashes as long as the separators are consistent
// within a particular path string.
ExecutableFile string
}
// PackageLocation returns the package directory given in the PackageDir field
@ -77,3 +72,70 @@ func (cp *CachedProvider) MatchesHash(want string) (bool, error) {
func (cp *CachedProvider) HashV1() (string, error) {
return getproviders.PackageHashV1(cp.PackageLocation())
}
// ExecutableFile inspects the cached provider's unpacked package directory for
// something that looks like it's intended to be the executable file for the
// plugin.
//
// This is a bit messy and heuristic-y because historically Terraform used the
// filename itself for local filesystem discovery, allowing some variance in
// the filenames to capture extra metadata, whereas now we're using the
// directory structure leading to the executable instead but need to remain
// compatible with the executable names bundled into existing provider packages.
//
// It will return an error if it can't find a file following the expected
// convention in the given directory.
//
// If found, the path always uses slashes as path separators, even on Windows,
// so that the results are consistent between platforms. Windows accepts both
// slashes and backslashes as long as the separators are consistent within a
// particular path string.
func (cp *CachedProvider) ExecutableFile() (string, error) {
infos, err := ioutil.ReadDir(cp.PackageDir)
if err != nil {
// If the directory itself doesn't exist or isn't readable then we
// can't access an executable in it.
return "", fmt.Errorf("could not read package directory: %s", err)
}
// For a provider named e.g. tf.example.com/awesomecorp/happycloud, we
// expect an executable file whose name starts with
// "terraform-provider-happycloud", followed by zero or more additional
// characters. If there _are_ additional characters then the first one
// must be an underscore or a period, like in thse examples:
// - terraform-provider-happycloud_v1.0.0
// - terraform-provider-happycloud.exe
//
// We don't require the version in the filename to match because the
// executable's name is no longer authoritative, but packages of "official"
// providers may continue to use versioned executable names for backward
// compatibility with Terraform 0.12.
//
// We also presume that providers packaged for Windows will include the
// necessary .exe extension on their filenames but do not explicitly check
// for that. If there's a provider package for Windows that has a file
// without that suffix then it will be detected as an executable but then
// we'll presumably fail later trying to run it.
wantPrefix := "terraform-provider-" + cp.Provider.Type
// We'll visit all of the directory entries and take the first (in
// name-lexical order) that looks like a plausible provider executable
// name. A package with multiple files meeting these criteria is degenerate
// but we will tolerate it by ignoring the subsequent entries.
for _, info := range infos {
if info.IsDir() {
continue // A directory can never be an executable
}
name := info.Name()
if !strings.HasPrefix(name, wantPrefix) {
continue
}
remainder := name[len(wantPrefix):]
if len(remainder) > 0 && (remainder[0] != '_' && remainder[0] != '.') {
continue // subsequent characters must be delimited by _ or .
}
return filepath.ToSlash(filepath.Join(cp.PackageDir, name)), nil
}
return "", fmt.Errorf("could not find executable file starting with %s", wantPrefix)
}

View File

@ -15,8 +15,7 @@ func TestCachedProviderHash(t *testing.T) {
),
Version: getproviders.MustParseVersion("2.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64",
ExecutableFile: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64/terraform-provider-null",
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/darwin_amd64",
}
want := "h1:qjsREM4DqEWECD43FcPqddZ9oxCG+IaMTxvWPciS05g="
@ -46,8 +45,7 @@ func TestCachedProviderHash(t *testing.T) {
),
Version: getproviders.MustParseVersion("2.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
ExecutableFile: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null",
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
}
gotMatches, err = cp2.MatchesHash(want)
if err != nil {
@ -58,3 +56,58 @@ func TestCachedProviderHash(t *testing.T) {
}
}
func TestExecutableFile(t *testing.T) {
testCases := map[string]struct {
cp *CachedProvider
file string
err string
}{
"linux": {
cp: &CachedProvider{
Provider: addrs.NewProvider(addrs.DefaultRegistryHost, "hashicorp", "null"),
Version: getproviders.MustParseVersion("2.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64",
},
file: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null",
},
"windows": {
cp: &CachedProvider{
Provider: addrs.NewProvider(addrs.DefaultRegistryHost, "hashicorp", "null"),
Version: getproviders.MustParseVersion("2.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
},
file: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe",
},
"missing-executable": {
cp: &CachedProvider{
Provider: addrs.NewProvider(addrs.DefaultRegistryHost, "missing", "executable"),
Version: getproviders.MustParseVersion("2.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/missing/executable/2.0.0/linux_amd64",
},
err: "could not find executable file starting with terraform-provider-executable",
},
"missing-dir": {
cp: &CachedProvider{
Provider: addrs.NewProvider(addrs.DefaultRegistryHost, "missing", "packagedir"),
Version: getproviders.MustParseVersion("2.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/missing/packagedir/2.0.0/linux_amd64",
},
err: "could not read package directory: open testdata/cachedir/registry.terraform.io/missing/packagedir/2.0.0/linux_amd64: no such file or directory",
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
file, err := tc.cp.ExecutableFile()
if file != tc.file {
t.Errorf("wrong file\n got: %q\nwant: %q", file, tc.file)
}
if err == nil && tc.err != "" {
t.Fatalf("no error returned, want: %q", tc.err)
} else if err != nil && err.Error() != tc.err {
t.Errorf("wrong error\n got: %q\nwant: %q", err, tc.err)
}
})
}
}

View File

@ -1,11 +1,9 @@
package providercache
import (
"io/ioutil"
"log"
"path/filepath"
"sort"
"strings"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/internal/getproviders"
@ -165,20 +163,12 @@ func (d *Dir) fillMetaCache() error {
}
packageDir := filepath.Clean(string(meta.Location.(getproviders.PackageLocalDir)))
execFile := findProviderExecutableInLocalPackage(meta)
if execFile == "" {
// If the package doesn't contain a suitable executable then
// it isn't considered to be part of our cache.
log.Printf("[TRACE] providercache.fillMetaCache: ignoring %s because it is does not seem to contain a suitable plugin executable", meta.Location)
continue
}
log.Printf("[TRACE] providercache.fillMetaCache: including %s as a candidate package for %s %s", meta.Location, providerAddr, meta.Version)
data[providerAddr] = append(data[providerAddr], CachedProvider{
Provider: providerAddr,
Version: meta.Version,
PackageDir: filepath.ToSlash(packageDir),
ExecutableFile: filepath.ToSlash(execFile),
Provider: providerAddr,
Version: meta.Version,
PackageDir: filepath.ToSlash(packageDir),
})
}
}
@ -200,75 +190,3 @@ func (d *Dir) fillMetaCache() error {
d.metaCache = data
return nil
}
// This is a helper function to peep into the unpacked directory associated
// with the given package meta and find something that looks like it's intended
// to be the executable file for the plugin.
//
// This is a bit messy and heuristic-y because historically Terraform used the
// filename itself for local filesystem discovery, allowing some variance in
// the filenames to capture extra metadata, whereas now we're using the
// directory structure leading to the executable instead but need to remain
// compatible with the executable names bundled into existing provider packages.
//
// It will return a zero-length string if it can't find a file following
// the expected convention in the given directory.
func findProviderExecutableInLocalPackage(meta getproviders.PackageMeta) string {
packageDir, ok := meta.Location.(getproviders.PackageLocalDir)
if !ok {
// This should never happen because the providercache package only
// uses the local unpacked directory layout. If anything else ends
// up in here then we'll indicate that no executable is available,
// because all other locations require a fetch/unpack step first.
return ""
}
infos, err := ioutil.ReadDir(string(packageDir))
if err != nil {
// If the directory itself doesn't exist or isn't readable then we
// can't access an executable in it.
return ""
}
// For a provider named e.g. tf.example.com/awesomecorp/happycloud, we
// expect an executable file whose name starts with
// "terraform-provider-happycloud", followed by zero or more additional
// characters. If there _are_ additional characters then the first one
// must be an underscore or a period, like in thse examples:
// - terraform-provider-happycloud_v1.0.0
// - terraform-provider-happycloud.exe
//
// We don't require the version in the filename to match because the
// executable's name is no longer authoritative, but packages of "official"
// providers may continue to use versioned executable names for backward
// compatibility with Terraform 0.12.
//
// We also presume that providers packaged for Windows will include the
// necessary .exe extension on their filenames but do not explicitly check
// for that. If there's a provider package for Windows that has a file
// without that suffix then it will be detected as an executable but then
// we'll presumably fail later trying to run it.
wantPrefix := "terraform-provider-" + meta.Provider.Type
// We'll visit all of the directory entries and take the first (in
// name-lexical order) that looks like a plausible provider executable
// name. A package with multiple files meeting these criteria is degenerate
// but we will tolerate it by ignoring the subsequent entries.
for _, info := range infos {
if info.IsDir() {
continue // A directory can never be an executable
}
name := info.Name()
if !strings.HasPrefix(name, wantPrefix) {
continue
}
remainder := name[len(wantPrefix):]
if len(remainder) > 0 && (remainder[0] != '_' && remainder[0] != '.') {
continue // subsequent characters must be delimited by _
}
return filepath.Join(string(packageDir), name)
}
// If we fall out here then nothing has matched.
return ""
}

View File

@ -58,8 +58,7 @@ func TestInstallPackage(t *testing.T) {
Version: versions.MustParseVersion("2.1.0"),
PackageDir: tmpDirPath + "/registry.terraform.io/hashicorp/null/2.1.0/linux_amd64",
ExecutableFile: tmpDirPath + "/registry.terraform.io/hashicorp/null/2.1.0/linux_amd64/terraform-provider-null",
PackageDir: tmpDirPath + "/registry.terraform.io/hashicorp/null/2.1.0/linux_amd64",
},
},
}
@ -101,8 +100,7 @@ func TestLinkFromOtherCache(t *testing.T) {
// still packed and thus not considered to be a cache member.
Version: versions.MustParseVersion("2.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
ExecutableFile: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe",
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
},
},
}
@ -138,8 +136,7 @@ func TestLinkFromOtherCache(t *testing.T) {
// still packed and thus not considered to be a cache member.
Version: versions.MustParseVersion("2.0.0"),
PackageDir: tmpDirPath + "/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
ExecutableFile: tmpDirPath + "/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe",
PackageDir: tmpDirPath + "/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
},
},
}

View File

@ -37,6 +37,9 @@ func TestDirReading(t *testing.T) {
addrs.DefaultRegistryHost, "bloop", "nonexist",
)
legacyProvider := addrs.NewLegacyProvider("legacy")
missingExecutableProvider := addrs.NewProvider(
addrs.DefaultRegistryHost, "missing", "executable",
)
t.Run("ProviderLatestVersion", func(t *testing.T) {
t.Run("exists", func(t *testing.T) {
@ -50,8 +53,7 @@ func TestDirReading(t *testing.T) {
// still packed and thus not considered to be a cache member.
Version: versions.MustParseVersion("2.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
ExecutableFile: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe",
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
}
if diff := cmp.Diff(want, got); diff != "" {
@ -91,8 +93,7 @@ func TestDirReading(t *testing.T) {
Provider: nullProvider,
Version: versions.MustParseVersion("2.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
ExecutableFile: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64/terraform-provider-null.exe",
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/windows_amd64",
}
if diff := cmp.Diff(want, got); diff != "" {
@ -141,34 +142,37 @@ func TestDirReading(t *testing.T) {
want := map[addrs.Provider][]CachedProvider{
legacyProvider: {
{
Provider: legacyProvider,
Version: versions.MustParseVersion("1.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/-/legacy/1.0.0/linux_amd64",
ExecutableFile: "testdata/cachedir/registry.terraform.io/-/legacy/1.0.0/linux_amd64/terraform-provider-legacy",
Provider: legacyProvider,
Version: versions.MustParseVersion("1.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/-/legacy/1.0.0/linux_amd64",
},
},
nullProvider: {
{
Provider: nullProvider,
Version: versions.MustParseVersion("2.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64",
ExecutableFile: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64/terraform-provider-null",
Provider: nullProvider,
Version: versions.MustParseVersion("2.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64",
},
},
randomProvider: {
{
Provider: randomProvider,
Version: versions.MustParseVersion("1.2.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64",
ExecutableFile: "testdata/cachedir/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64/terraform-provider-random",
Provider: randomProvider,
Version: versions.MustParseVersion("1.2.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/random/1.2.0/linux_amd64",
},
},
randomBetaProvider: {
{
Provider: randomBetaProvider,
Version: versions.MustParseVersion("1.2.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64",
ExecutableFile: "testdata/cachedir/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64/terraform-provider-random-beta",
Provider: randomBetaProvider,
Version: versions.MustParseVersion("1.2.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/hashicorp/random-beta/1.2.0/linux_amd64",
},
},
missingExecutableProvider: {
{
Provider: missingExecutableProvider,
Version: versions.MustParseVersion("2.0.0"),
PackageDir: "testdata/cachedir/registry.terraform.io/missing/executable/2.0.0/linux_amd64",
},
},
}

View File

@ -0,0 +1 @@
This file represents a misnamed provider executable.