mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-25 01:00:16 -05:00
getmodules: Add new "oci" module source address scheme
This connects up various work done in earlier commits so that it's now possible to install modules from source addresses that start with "oci:", which will each get interpreted as a reference to an artifacts in an OCI Distribution repository. For the first time we now have a getter that needs to be configured dynamically based on the CLI configuration, so this slightly reworks the "reusingGetter" type so that each instance has its own map of getters that's based on the statically-configured one. Currently "oci" is the only getter that needs this dynamic configuration, but perhaps in future we'll adopt a similar dependency inversion style for some of the other getters so that we can centralize concerns such as allowing operators to configure additional TLS certificates for OpenTofu to trust. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
@@ -91,14 +91,22 @@ var goGetterDecompressorMediaTypes = map[string]string{
|
||||
"archive/zip": "zip",
|
||||
}
|
||||
|
||||
// goGetterGetters is an initial table of getters that we use as a starting
|
||||
// point when building a _real_ table of getters to pass into a
|
||||
// [reusingGetter] instance.
|
||||
//
|
||||
// The elements mapped to nil here are those which are populated dynamically
|
||||
// based on arguments to [NewPackageFetcher], included here only so it's
|
||||
// easier to refer to the entire list of supported getter keys in one place.
|
||||
var goGetterGetters = map[string]getter.Getter{
|
||||
"file": new(getter.FileGetter),
|
||||
"gcs": new(getter.GCSGetter),
|
||||
"git": new(getter.GitGetter),
|
||||
"hg": new(getter.HgGetter),
|
||||
"s3": new(getter.S3Getter),
|
||||
"http": getterHTTPGetter,
|
||||
"https": getterHTTPGetter,
|
||||
"oci": nil, // configured dynamically using [PackageFetcherEnvironment.OCIRepositoryStore]
|
||||
"s3": new(getter.S3Getter),
|
||||
}
|
||||
|
||||
var getterHTTPClient = cleanhttp.DefaultClient()
|
||||
@@ -121,10 +129,21 @@ var getterHTTPGetter = &getter.HttpGetter{
|
||||
// imports getmodules in order to indirectly access our go-getter
|
||||
// configuration.)
|
||||
type reusingGetter struct {
|
||||
// getters are the go-getter getters that this particular instance of
|
||||
// reusingGetter should use.
|
||||
getters map[string]getter.Getter
|
||||
|
||||
previousInstalls map[string]string // initialized on first install request
|
||||
previousInstallsMu sync.Mutex // must hold while interacting with previousInstalls
|
||||
}
|
||||
|
||||
func newReusingGetter(getters map[string]getter.Getter) *reusingGetter {
|
||||
return &reusingGetter{
|
||||
getters: getters,
|
||||
// previousInstalls initialized only on request
|
||||
}
|
||||
}
|
||||
|
||||
// getWithGoGetter fetches the package at the given address into the given
|
||||
// target directory. The given address must already be in normalized form
|
||||
// (using NormalizePackageAddress) or else the behavior is undefined.
|
||||
@@ -188,7 +207,7 @@ func (g *reusingGetter) getWithGoGetter(ctx context.Context, instPath, packageAd
|
||||
|
||||
Detectors: goGetterNoDetectors, // our caller should've already done detection
|
||||
Decompressors: goGetterDecompressors,
|
||||
Getters: goGetterGetters,
|
||||
Getters: g.getters,
|
||||
Ctx: ctx,
|
||||
}
|
||||
err = client.Get()
|
||||
|
||||
@@ -8,6 +8,7 @@ package getmodules
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"maps"
|
||||
)
|
||||
|
||||
// PackageFetcher is a low-level utility for fetching remote module packages
|
||||
@@ -36,9 +37,18 @@ type PackageFetcher struct {
|
||||
// intended only for use in unit tests.
|
||||
func NewPackageFetcher(env PackageFetcherEnvironment) *PackageFetcher {
|
||||
env = preparePackageFetcherEnvironment(env)
|
||||
_ = env // TODO: Actually use this, once we have an OCI Distribution getter
|
||||
|
||||
// We use goGetterGetters as our starting point for the available
|
||||
// getters, but some need to be instantiated dynamically based on
|
||||
// the given "env". We shallow-copy the source map so that multiple
|
||||
// instances of PackageFetcher don't clobber each other's getters.
|
||||
getters := maps.Clone(goGetterGetters)
|
||||
getters["oci"] = &ociDistributionGetter{
|
||||
getOCIRepositoryStore: env.OCIRepositoryStore,
|
||||
}
|
||||
|
||||
return &PackageFetcher{
|
||||
getter: &reusingGetter{},
|
||||
getter: newReusingGetter(getters),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user