internal/getproviders: Source interface for generalization

We intend to support installation both directly from origin registries and
from mirrors in the local filesystem or over the network. This Source
interface will serve as our abstraction over those three options, allowing
calling code to treat them all the same.
This commit is contained in:
Martin Atkins 2020-01-08 16:24:41 -08:00
parent c76260e957
commit c8f7223adb
5 changed files with 47 additions and 12 deletions

View File

@ -207,8 +207,8 @@ func (c *registryClient) PackageMeta(provider addrs.Provider, version Version, t
OS: body.OS, OS: body.OS,
Arch: body.Arch, Arch: body.Arch,
}, },
Filename: body.Filename, Filename: body.Filename,
DownloadURL: body.DownloadURL, Location: PackageHTTPURL(body.DownloadURL),
// SHA256Sum is populated below // SHA256Sum is populated below
} }

View File

@ -15,6 +15,8 @@ type RegistrySource struct {
services *disco.Disco services *disco.Disco
} }
var _ Source = (*RegistrySource)(nil)
// NewRegistrySource creates and returns a new source that will install // NewRegistrySource creates and returns a new source that will install
// providers from their originating provider registries. // providers from their originating provider registries.
func NewRegistrySource(services *disco.Disco) *RegistrySource { func NewRegistrySource(services *disco.Disco) *RegistrySource {
@ -60,11 +62,11 @@ func (s *RegistrySource) AvailableVersions(provider addrs.Provider) (VersionList
return ret, nil return ret, nil
} }
// DownloadLocation returns metadata about the location and capabilities of // PackageMeta returns metadata about the location and capabilities of
// a distribution package for a particular provider at a particular version // a distribution package for a particular provider at a particular version
// targeting a particular platform. // targeting a particular platform.
// //
// Callers of DownloadLocation should first call AvailableVersions and pass // Callers of PackageMeta should first call AvailableVersions and pass
// one of the resulting versions to this function. This function cannot // one of the resulting versions to this function. This function cannot
// distinguish between a version that is not available and an unsupported // distinguish between a version that is not available and an unsupported
// target platform, so if it encounters either case it will return an error // target platform, so if it encounters either case it will return an error
@ -73,13 +75,13 @@ func (s *RegistrySource) AvailableVersions(provider addrs.Provider) (VersionList
// //
// To find a package suitable for the platform where the provider installation // To find a package suitable for the platform where the provider installation
// process is running, set the "target" argument to // process is running, set the "target" argument to
// findproviders.CurrentPlatform. // getproviders.CurrentPlatform.
// //
// If the request fails, the returned error might be an value of // If the request fails, the returned error might be an value of
// ErrHostNoProviders, ErrHostUnreachable, ErrUnauthenticated, // ErrHostNoProviders, ErrHostUnreachable, ErrUnauthenticated,
// ErrPlatformNotSupported, or ErrQueryFailed. Callers must be defensive and // ErrPlatformNotSupported, or ErrQueryFailed. Callers must be defensive and
// expect errors of other types too, to allow for future expansion. // expect errors of other types too, to allow for future expansion.
func (s *RegistrySource) DownloadLocation(provider addrs.Provider, version Version, target Platform) (PackageMeta, error) { func (s *RegistrySource) PackageMeta(provider addrs.Provider, version Version, target Platform) (PackageMeta, error) {
client, err := s.registryClient(provider.Hostname) client, err := s.registryClient(provider.Hostname)
if err != nil { if err != nil {
return PackageMeta{}, err return PackageMeta{}, err

View File

@ -105,7 +105,7 @@ func TestSourceAvailableVersions(t *testing.T) {
} }
func TestSourceDownloadLocation(t *testing.T) { func TestSourcePackageMeta(t *testing.T) {
source, close := testRegistrySource(t) source, close := testRegistrySource(t)
defer close() defer close()
@ -126,7 +126,7 @@ func TestSourceDownloadLocation(t *testing.T) {
ProtocolVersions: VersionList{versions.MustParseVersion("5.0.0")}, ProtocolVersions: VersionList{versions.MustParseVersion("5.0.0")},
TargetPlatform: Platform{"linux", "amd64"}, TargetPlatform: Platform{"linux", "amd64"},
Filename: "happycloud_1.2.0.zip", Filename: "happycloud_1.2.0.zip",
DownloadURL: "/pkg/happycloud_1.2.0.zip", Location: PackageHTTPURL("/pkg/happycloud_1.2.0.zip"),
SHA256Sum: [32]uint8{30: 0xf0, 31: 0x0d}, // fake registry uses a memorable sum SHA256Sum: [32]uint8{30: 0xf0, 31: 0x0d}, // fake registry uses a memorable sum
}, },
``, ``,
@ -181,7 +181,7 @@ func TestSourceDownloadLocation(t *testing.T) {
version := versions.MustParseVersion(test.version) version := versions.MustParseVersion(test.version)
got, err := source.DownloadLocation(providerAddr, version, Platform{test.os, test.arch}) got, err := source.PackageMeta(providerAddr, version, Platform{test.os, test.arch})
if err != nil { if err != nil {
if test.wantErr == "" { if test.wantErr == "" {

View File

@ -0,0 +1,12 @@
package getproviders
import (
"github.com/hashicorp/terraform/addrs"
)
// A Source can query a particular source for information about providers
// that are available to install.
type Source interface {
AvailableVersions(provider addrs.Provider) (VersionList, error)
PackageMeta(provider addrs.Provider, version Version, target Platform) (PackageMeta, error)
}

View File

@ -51,9 +51,30 @@ type PackageMeta struct {
ProtocolVersions VersionList ProtocolVersions VersionList
TargetPlatform Platform TargetPlatform Platform
Filename string Filename string
DownloadURL string Location PackageLocation
SHA256Sum [sha256.Size]byte SHA256Sum [sha256.Size]byte
// TODO: Extra metadata for signature verification // TODO: Extra metadata for signature verification
} }
// PackageLocation represents a location where a provider distribution package
// can be obtained. A value of this type contains either a PackageLocalPath or a
// PackageHTTPURL value.
type PackageLocation interface {
packageLocation()
}
// PackageLocalPath is a provider package location in the local filesystem.
// Its value is a local filesystem path using the syntax understood by Go's
// standard path/filepath package on the operating system where Terraform is
// running.
type PackageLocalPath string
func (p PackageLocalPath) packageLocation() {}
// PackageHTTPURL is a provider package location accessible via HTTP.
// Its value is a URL string using either the http: scheme or the https: scheme.
type PackageHTTPURL string
func (p PackageHTTPURL) packageLocation() {}