Files
opentf/internal/providercache/dir_modify.go
Martin Atkins 0ad4c1be2f internal/getproviders: Tidy up some confusion about package hashes
Earlier on in the stubbing of this package we realized that it wasn't
going to be possible to populate the authentication-related bits for all
packages because the relevant metadata just isn't available for packages
that are already local.

However, we just moved ahead with that awkward design at the time because
we needed to get other work done, and so we've been mostly producing
PackageMeta values with all-zeros hashes and just ignoring them entirely
as a temporary workaround.

This is a first step towards what is hopefully a more intuitive model:
authentication is an optional thing in a PackageMeta that is currently
populated only for packages coming from a registry.

So far this still just models checking a SHA256 hash, which is not a
sufficient set of checks for a real release but hopefully the "real"
implementation is a natural iteration of this starting point, and if not
then at least this interim step is a bit more honest about the fact that
Authentication will not be populated on every PackageMeta.
2020-04-06 16:31:23 -07:00

72 lines
3.0 KiB
Go

package providercache
import (
"context"
"fmt"
"log"
"github.com/hashicorp/terraform/internal/getproviders"
)
// InstallPackage takes a metadata object describing a package available for
// installation, retrieves that package, and installs it into the receiving
// cache directory.
func (d *Dir) InstallPackage(ctx context.Context, meta getproviders.PackageMeta) error {
if meta.TargetPlatform != d.targetPlatform {
return fmt.Errorf("can't install %s package into cache directory expecting %s", meta.TargetPlatform, d.targetPlatform)
}
newPath := getproviders.UnpackedDirectoryPathForPackage(
d.baseDir, meta.Provider, meta.Version, d.targetPlatform,
)
// Invalidate our metaCache so that subsequent read calls will re-scan to
// incorporate any changes we make here.
d.metaCache = nil
// TODO: If meta.Authentication is non-nil, we should call it at some point
// in the rest of this process (perhaps inside installFromLocalArchive and
// installFromLocalDir, so we already have the local copy?) and return an
// error if the authentication fails.
log.Printf("[TRACE] providercache.Dir.InstallPackage: installing %s v%s from %s", meta.Provider, meta.Version, meta.Location)
switch location := meta.Location.(type) {
case getproviders.PackageHTTPURL:
return installFromHTTPURL(ctx, string(location), newPath)
case getproviders.PackageLocalArchive:
return installFromLocalArchive(ctx, string(location), newPath)
case getproviders.PackageLocalDir:
return installFromLocalDir(ctx, string(location), newPath)
default:
// Should not get here, because the above should be exhaustive for
// all implementations of getproviders.Location.
return fmt.Errorf("don't know how to install from a %T location", location)
}
}
// LinkFromOtherCache takes a CachedProvider value produced from another Dir
// and links it into the cache represented by the receiver Dir.
//
// This is used to implement tiered caching, where new providers are first
// populated into a system-wide shared cache and then linked from there into
// a configuration-specific local cache.
//
// It's invalid to link a CachedProvider from a particular Dir into that same
// Dir, because that would otherwise potentially replace a real package
// directory with a circular link back to itself.
func (d *Dir) LinkFromOtherCache(entry *CachedProvider) error {
newPath := getproviders.UnpackedDirectoryPathForPackage(
d.baseDir, entry.Provider, entry.Version, d.targetPlatform,
)
currentPath := entry.PackageDir
log.Printf("[TRACE] providercache.Dir.LinkFromOtherCache: linking %s v%s from existing cache %s to %s", entry.Provider, entry.Version, currentPath, newPath)
// Invalidate our metaCache so that subsequent read calls will re-scan to
// incorporate any changes we make here.
d.metaCache = nil
// We re-use the process of installing from a local directory here, because
// the two operations are fundamentally the same: symlink if possible,
// deep-copy otherwise.
return installFromLocalDir(context.TODO(), currentPath, newPath)
}