mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
[OpenTelemetry] Add module init tracing (#2711)
Signed-off-by: James Humphries <james@james-humphries.co.uk>
This commit is contained in:
@@ -25,6 +25,9 @@ import (
|
||||
"github.com/opentofu/opentofu/internal/tofumigrate"
|
||||
)
|
||||
|
||||
// Ensure that local.Local implements the backend.Local interface.
|
||||
var _ backend.Local = (*Local)(nil)
|
||||
|
||||
// backend.Local implementation.
|
||||
func (b *Local) LocalRun(ctx context.Context, op *backend.Operation) (*backend.LocalRun, statemgr.Full, tfdiags.Diagnostics) {
|
||||
// Make sure the type is invalid. We use this as a way to know not
|
||||
@@ -98,7 +101,7 @@ func (b *Local) localRun(ctx context.Context, op *backend.Operation) (*backend.L
|
||||
stateMeta = &m
|
||||
}
|
||||
log.Printf("[TRACE] backend/local: populating backend.LocalRun from plan file")
|
||||
ret, configSnap, ctxDiags = b.localRunForPlanFile(op, lp, ret, &coreOpts, stateMeta)
|
||||
ret, configSnap, ctxDiags = b.localRunForPlanFile(ctx, op, lp, ret, &coreOpts, stateMeta)
|
||||
if ctxDiags.HasErrors() {
|
||||
diags = diags.Append(ctxDiags)
|
||||
return nil, nil, nil, diags
|
||||
@@ -109,7 +112,7 @@ func (b *Local) localRun(ctx context.Context, op *backend.Operation) (*backend.L
|
||||
op.ConfigLoader.ImportSourcesFromSnapshot(configSnap)
|
||||
} else {
|
||||
log.Printf("[TRACE] backend/local: populating backend.LocalRun for current working directory")
|
||||
ret, configSnap, ctxDiags = b.localRunDirect(op, ret, &coreOpts, s)
|
||||
ret, configSnap, ctxDiags = b.localRunDirect(ctx, op, ret, &coreOpts, s)
|
||||
}
|
||||
diags = diags.Append(ctxDiags)
|
||||
if diags.HasErrors() {
|
||||
@@ -142,11 +145,11 @@ func (b *Local) localRun(ctx context.Context, op *backend.Operation) (*backend.L
|
||||
return ret, configSnap, s, diags
|
||||
}
|
||||
|
||||
func (b *Local) localRunDirect(op *backend.Operation, run *backend.LocalRun, coreOpts *tofu.ContextOpts, s statemgr.Full) (*backend.LocalRun, *configload.Snapshot, tfdiags.Diagnostics) {
|
||||
func (b *Local) localRunDirect(ctx context.Context, op *backend.Operation, run *backend.LocalRun, coreOpts *tofu.ContextOpts, s statemgr.Full) (*backend.LocalRun, *configload.Snapshot, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
// Load the configuration using the caller-provided configuration loader.
|
||||
config, configSnap, configDiags := op.ConfigLoader.LoadConfigWithSnapshot(op.ConfigDir, op.RootCall)
|
||||
config, configSnap, configDiags := op.ConfigLoader.LoadConfigWithSnapshot(ctx, op.ConfigDir, op.RootCall)
|
||||
diags = diags.Append(configDiags)
|
||||
if configDiags.HasErrors() {
|
||||
return nil, nil, diags
|
||||
@@ -233,7 +236,7 @@ func (b *Local) localRunDirect(op *backend.Operation, run *backend.LocalRun, cor
|
||||
return run, configSnap, diags
|
||||
}
|
||||
|
||||
func (b *Local) localRunForPlanFile(op *backend.Operation, pf *planfile.Reader, run *backend.LocalRun, coreOpts *tofu.ContextOpts, currentStateMeta *statemgr.SnapshotMeta) (*backend.LocalRun, *configload.Snapshot, tfdiags.Diagnostics) {
|
||||
func (b *Local) localRunForPlanFile(ctx context.Context, op *backend.Operation, pf *planfile.Reader, run *backend.LocalRun, coreOpts *tofu.ContextOpts, currentStateMeta *statemgr.SnapshotMeta) (*backend.LocalRun, *configload.Snapshot, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
const errSummary = "Invalid plan file"
|
||||
@@ -292,7 +295,7 @@ func (b *Local) localRunForPlanFile(op *backend.Operation, pf *planfile.Reader,
|
||||
})
|
||||
|
||||
loader := configload.NewLoaderFromSnapshot(snap)
|
||||
config, configDiags := loader.LoadConfig(snap.Modules[""].Dir, subCall)
|
||||
config, configDiags := loader.LoadConfig(ctx, snap.Modules[""].Dir, subCall)
|
||||
diags = diags.Append(configDiags)
|
||||
if configDiags.HasErrors() {
|
||||
return nil, snap, diags
|
||||
|
||||
@@ -23,6 +23,8 @@ import (
|
||||
"github.com/hashicorp/terraform-svchost/disco"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/mitchellh/colorstring"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/backend"
|
||||
"github.com/opentofu/opentofu/internal/configs/configschema"
|
||||
"github.com/opentofu/opentofu/internal/encryption"
|
||||
@@ -33,7 +35,6 @@ import (
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
"github.com/opentofu/opentofu/internal/tofu"
|
||||
tfversion "github.com/opentofu/opentofu/version"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
backendLocal "github.com/opentofu/opentofu/internal/backend/local"
|
||||
)
|
||||
@@ -789,7 +790,7 @@ func (b *Remote) Operation(ctx context.Context, op *backend.Operation) (*backend
|
||||
op.Workspace = w.Name
|
||||
|
||||
// Determine the function to call for our operation
|
||||
var f func(context.Context, context.Context, *backend.Operation, *tfe.Workspace) (*tfe.Run, error)
|
||||
var f func(context.Context, context.Context, context.Context, *backend.Operation, *tfe.Workspace) (*tfe.Run, error)
|
||||
switch op.Type {
|
||||
case backend.OperationTypePlan:
|
||||
f = b.opPlan
|
||||
@@ -835,7 +836,7 @@ func (b *Remote) Operation(ctx context.Context, op *backend.Operation) (*backend
|
||||
|
||||
defer b.opLock.Unlock()
|
||||
|
||||
r, opErr := f(stopCtx, cancelCtx, op, w)
|
||||
r, opErr := f(ctx, stopCtx, cancelCtx, op, w)
|
||||
if opErr != nil && opErr != context.Canceled {
|
||||
var diags tfdiags.Diagnostics
|
||||
diags = diags.Append(opErr)
|
||||
|
||||
@@ -14,13 +14,14 @@ import (
|
||||
|
||||
tfe "github.com/hashicorp/go-tfe"
|
||||
version "github.com/hashicorp/go-version"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/backend"
|
||||
"github.com/opentofu/opentofu/internal/plans"
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
"github.com/opentofu/opentofu/internal/tofu"
|
||||
)
|
||||
|
||||
func (b *Remote) opApply(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
|
||||
func (b *Remote) opApply(ctx context.Context, stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
|
||||
log.Printf("[INFO] backend/remote: starting Apply operation")
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
@@ -65,7 +66,7 @@ func (b *Remote) opApply(stopCtx, cancelCtx context.Context, op *backend.Operati
|
||||
))
|
||||
}
|
||||
|
||||
if b.hasExplicitVariableValues(op) {
|
||||
if b.hasExplicitVariableValues(ctx, op) {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Run variables are currently not supported",
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"time"
|
||||
|
||||
tfe "github.com/hashicorp/go-tfe"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/backend"
|
||||
"github.com/opentofu/opentofu/internal/logging"
|
||||
"github.com/opentofu/opentofu/internal/plans"
|
||||
@@ -221,9 +222,9 @@ func (b *Remote) waitForRun(stopCtx, cancelCtx context.Context, op *backend.Oper
|
||||
// individual variable values are invalid. That's okay because we only use this
|
||||
// result to hint the user to set variables a different way. It's always the
|
||||
// remote system's responsibility to do final validation of the input.
|
||||
func (b *Remote) hasExplicitVariableValues(op *backend.Operation) bool {
|
||||
func (b *Remote) hasExplicitVariableValues(ctx context.Context, op *backend.Operation) bool {
|
||||
// Load the configuration using the caller-provided configuration loader.
|
||||
config, _, configDiags := op.ConfigLoader.LoadConfigWithSnapshot(op.ConfigDir, op.RootCall)
|
||||
config, _, configDiags := op.ConfigLoader.LoadConfigWithSnapshot(ctx, op.ConfigDir, op.RootCall)
|
||||
if configDiags.HasErrors() {
|
||||
// If we can't load the configuration then we'll assume no explicit
|
||||
// variable values just to let the remote operation start and let
|
||||
|
||||
@@ -14,16 +14,20 @@ import (
|
||||
tfe "github.com/hashicorp/go-tfe"
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/backend"
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
"github.com/opentofu/opentofu/internal/states/statemgr"
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
"github.com/opentofu/opentofu/internal/tofu"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// Context implements backend.Local.
|
||||
func (b *Remote) LocalRun(_ context.Context, op *backend.Operation) (*backend.LocalRun, statemgr.Full, tfdiags.Diagnostics) {
|
||||
// Ensure that remote.Remote implements the backend.Local interface.
|
||||
var _ backend.Local = (*Remote)(nil)
|
||||
|
||||
// LocalRun implements backend.Local.
|
||||
func (b *Remote) LocalRun(ctx context.Context, op *backend.Operation) (*backend.LocalRun, statemgr.Full, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
ret := &backend.LocalRun{
|
||||
PlanOpts: &tofu.PlanOpts{
|
||||
@@ -82,7 +86,7 @@ func (b *Remote) LocalRun(_ context.Context, op *backend.Operation) (*backend.Lo
|
||||
ret.InputState = stateMgr.State()
|
||||
|
||||
log.Printf("[TRACE] backend/remote: loading configuration for the current working directory")
|
||||
config, configDiags := op.ConfigLoader.LoadConfig(op.ConfigDir, op.RootCall)
|
||||
config, configDiags := op.ConfigLoader.LoadConfig(ctx, op.ConfigDir, op.RootCall)
|
||||
diags = diags.Append(configDiags)
|
||||
if configDiags.HasErrors() {
|
||||
return nil, nil, diags
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
tfe "github.com/hashicorp/go-tfe"
|
||||
version "github.com/hashicorp/go-version"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/backend"
|
||||
"github.com/opentofu/opentofu/internal/logging"
|
||||
"github.com/opentofu/opentofu/internal/plans"
|
||||
@@ -28,7 +29,7 @@ import (
|
||||
|
||||
var planConfigurationVersionsPollInterval = 500 * time.Millisecond
|
||||
|
||||
func (b *Remote) opPlan(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
|
||||
func (b *Remote) opPlan(ctx, stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
|
||||
log.Printf("[INFO] backend/remote: starting Plan operation")
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
@@ -79,7 +80,7 @@ func (b *Remote) opPlan(stopCtx, cancelCtx context.Context, op *backend.Operatio
|
||||
))
|
||||
}
|
||||
|
||||
if b.hasExplicitVariableValues(op) {
|
||||
if b.hasExplicitVariableValues(ctx, op) {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Run variables are currently not supported",
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestChecksHappyPath(t *testing.T) {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
cfg, hclDiags := loader.LoadConfig(fixtureDir, configs.RootModuleCallForTesting())
|
||||
cfg, hclDiags := loader.LoadConfig(t.Context(), fixtureDir, configs.RootModuleCallForTesting())
|
||||
if hclDiags.HasErrors() {
|
||||
t.Fatalf("invalid configuration: %s", hclDiags.Error())
|
||||
}
|
||||
|
||||
@@ -806,7 +806,7 @@ func (b *Cloud) Operation(ctx context.Context, op *backend.Operation) (*backend.
|
||||
op.Workspace = w.Name
|
||||
|
||||
// Determine the function to call for our operation
|
||||
var f func(context.Context, context.Context, *backend.Operation, *tfe.Workspace) (*tfe.Run, error)
|
||||
var f func(context.Context, context.Context, context.Context, *backend.Operation, *tfe.Workspace) (*tfe.Run, error)
|
||||
switch op.Type {
|
||||
case backend.OperationTypePlan:
|
||||
f = b.opPlan
|
||||
@@ -856,7 +856,7 @@ func (b *Cloud) Operation(ctx context.Context, op *backend.Operation) (*backend.
|
||||
|
||||
defer b.opLock.Unlock()
|
||||
|
||||
r, opErr := f(stopCtx, cancelCtx, op, w)
|
||||
r, opErr := f(ctx, stopCtx, cancelCtx, op, w)
|
||||
if opErr != nil && opErr != context.Canceled {
|
||||
var diags tfdiags.Diagnostics
|
||||
diags = diags.Append(opErr)
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"strings"
|
||||
|
||||
tfe "github.com/hashicorp/go-tfe"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/backend"
|
||||
"github.com/opentofu/opentofu/internal/command/jsonformat"
|
||||
"github.com/opentofu/opentofu/internal/plans"
|
||||
@@ -22,7 +23,7 @@ import (
|
||||
"github.com/opentofu/opentofu/internal/tofu"
|
||||
)
|
||||
|
||||
func (b *Cloud) opApply(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
|
||||
func (b *Cloud) opApply(ctx, stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
|
||||
log.Printf("[INFO] cloud: starting Apply operation")
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
@@ -137,7 +138,7 @@ func (b *Cloud) opApply(stopCtx, cancelCtx context.Context, op *backend.Operatio
|
||||
} else {
|
||||
log.Printf("[TRACE] Running new cloud plan for apply")
|
||||
// Run the plan phase.
|
||||
r, err = b.plan(stopCtx, cancelCtx, op, w)
|
||||
r, err = b.plan(ctx, stopCtx, cancelCtx, op, w)
|
||||
|
||||
if err != nil {
|
||||
return r, err
|
||||
|
||||
@@ -453,7 +453,7 @@ func TestCloud_applyWithCloudPlan(t *testing.T) {
|
||||
t.Fatalf("Couldn't read workspace: %s", err)
|
||||
}
|
||||
|
||||
planRun, err := b.plan(context.Background(), context.Background(), op, ws)
|
||||
planRun, err := b.plan(context.Background(), context.Background(), context.Background(), op, ws)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't perform plan: %s", err)
|
||||
}
|
||||
|
||||
@@ -14,16 +14,20 @@ import (
|
||||
|
||||
tfe "github.com/hashicorp/go-tfe"
|
||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/backend"
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
"github.com/opentofu/opentofu/internal/states/statemgr"
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
"github.com/opentofu/opentofu/internal/tofu"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// Ensure that Cloud implements the backend.Local interface.
|
||||
var _ backend.Local = (*Cloud)(nil)
|
||||
|
||||
// LocalRun implements backend.Local
|
||||
func (b *Cloud) LocalRun(_ context.Context, op *backend.Operation) (*backend.LocalRun, statemgr.Full, tfdiags.Diagnostics) {
|
||||
func (b *Cloud) LocalRun(ctx context.Context, op *backend.Operation) (*backend.LocalRun, statemgr.Full, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
ret := &backend.LocalRun{
|
||||
PlanOpts: &tofu.PlanOpts{
|
||||
@@ -82,7 +86,7 @@ func (b *Cloud) LocalRun(_ context.Context, op *backend.Operation) (*backend.Loc
|
||||
ret.InputState = stateMgr.State()
|
||||
|
||||
log.Printf("[TRACE] cloud: loading configuration for the current working directory")
|
||||
config, configDiags := op.ConfigLoader.LoadConfig(op.ConfigDir, op.RootCall)
|
||||
config, configDiags := op.ConfigLoader.LoadConfig(ctx, op.ConfigDir, op.RootCall)
|
||||
diags = diags.Append(configDiags)
|
||||
if configDiags.HasErrors() {
|
||||
return nil, nil, diags
|
||||
|
||||
@@ -34,7 +34,7 @@ import (
|
||||
|
||||
var planConfigurationVersionsPollInterval = 500 * time.Millisecond
|
||||
|
||||
func (b *Cloud) opPlan(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
|
||||
func (b *Cloud) opPlan(ctx, stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
|
||||
log.Printf("[INFO] cloud: starting Plan operation")
|
||||
|
||||
var diags tfdiags.Diagnostics
|
||||
@@ -97,7 +97,7 @@ func (b *Cloud) opPlan(stopCtx, cancelCtx context.Context, op *backend.Operation
|
||||
}
|
||||
|
||||
// If the run errored, exit before checking whether to save a plan file
|
||||
run, err := b.plan(stopCtx, cancelCtx, op, w)
|
||||
run, err := b.plan(ctx, stopCtx, cancelCtx, op, w)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -117,7 +117,7 @@ func (b *Cloud) opPlan(stopCtx, cancelCtx context.Context, op *backend.Operation
|
||||
return run, nil
|
||||
}
|
||||
|
||||
func (b *Cloud) plan(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
|
||||
func (b *Cloud) plan(ctx, stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
|
||||
if b.CLI != nil {
|
||||
header := planDefaultHeader
|
||||
if op.Type == backend.OperationTypeApply || op.Type == backend.OperationTypeRefresh {
|
||||
@@ -264,7 +264,7 @@ in order to capture the filesystem context the remote workspace expects:
|
||||
}
|
||||
}
|
||||
|
||||
config, _, configDiags := op.ConfigLoader.LoadConfigWithSnapshot(op.ConfigDir, op.RootCall)
|
||||
config, _, configDiags := op.ConfigLoader.LoadConfigWithSnapshot(ctx, op.ConfigDir, op.RootCall)
|
||||
if configDiags.HasErrors() {
|
||||
return nil, fmt.Errorf("error loading config with snapshot: %w", configDiags.Errs()[0])
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ func testModuleWithSnapshot(t *testing.T, name string) (*configs.Config, *config
|
||||
t.Fatal(instDiags.Err())
|
||||
}
|
||||
|
||||
config, snap, diags := loader.LoadConfigWithSnapshot(dir, configs.RootModuleCallForTesting())
|
||||
config, snap, diags := loader.LoadConfigWithSnapshot(t.Context(), dir, configs.RootModuleCallForTesting())
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Error())
|
||||
}
|
||||
|
||||
@@ -407,7 +407,7 @@ func (c *InitCommand) getModules(ctx context.Context, path, testsDir string, ear
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
ctx, span := tracing.Tracer().Start(ctx, "Get modules", trace.WithAttributes(
|
||||
ctx, span := tracing.Tracer().Start(ctx, "Get Modules", trace.WithAttributes(
|
||||
otelAttr.Bool("opentofu.modules.upgrade", upgrade),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
@@ -896,7 +896,7 @@ func (m *Meta) checkRequiredVersion(ctx context.Context) tfdiags.Diagnostics {
|
||||
return diags
|
||||
}
|
||||
|
||||
config, configDiags := loader.LoadConfig(pwd, call)
|
||||
config, configDiags := loader.LoadConfig(ctx, pwd, call)
|
||||
if configDiags.HasErrors() {
|
||||
diags = diags.Append(configDiags)
|
||||
return diags
|
||||
|
||||
@@ -56,7 +56,7 @@ func (m *Meta) loadConfig(ctx context.Context, rootDir string) (*configs.Config,
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
config, hclDiags := loader.LoadConfig(rootDir, call)
|
||||
config, hclDiags := loader.LoadConfig(ctx, rootDir, call)
|
||||
diags = diags.Append(hclDiags)
|
||||
return config, diags
|
||||
}
|
||||
@@ -79,7 +79,7 @@ func (m *Meta) loadConfigWithTests(ctx context.Context, rootDir, testDir string)
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
config, hclDiags := loader.LoadConfigWithTests(rootDir, testDir, call)
|
||||
config, hclDiags := loader.LoadConfigWithTests(ctx, rootDir, testDir, call)
|
||||
diags = diags.Append(hclDiags)
|
||||
return config, diags
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ type ShowCommand struct {
|
||||
|
||||
func (c *ShowCommand) Run(rawArgs []string) int {
|
||||
ctx := c.CommandContext()
|
||||
|
||||
// Parse and apply global view arguments
|
||||
common, rawArgs := arguments.ParseView(rawArgs)
|
||||
c.View.Configure(common)
|
||||
@@ -364,7 +365,7 @@ func (c *ShowCommand) getPlanFromPath(ctx context.Context, path string, enc encr
|
||||
}
|
||||
|
||||
if lp, ok := pf.Local(); ok {
|
||||
plan, stateFile, config, err = getDataFromPlanfileReader(lp, rootCall)
|
||||
plan, stateFile, config, err = getDataFromPlanfileReader(ctx, lp, rootCall)
|
||||
} else if cp, ok := pf.Cloud(); ok {
|
||||
redacted := c.viewType != arguments.ViewJSON
|
||||
jsonPlan, err = c.getDataFromCloudPlan(ctx, cp, redacted, enc)
|
||||
@@ -404,7 +405,7 @@ func (c *ShowCommand) maybeGetSchemas(ctx context.Context, stateFile *statefile.
|
||||
}
|
||||
|
||||
// getDataFromPlanfileReader returns a plan, statefile, and config, extracted from a local plan file.
|
||||
func getDataFromPlanfileReader(planReader *planfile.Reader, rootCall configs.StaticModuleCall) (*plans.Plan, *statefile.File, *configs.Config, error) {
|
||||
func getDataFromPlanfileReader(ctx context.Context, planReader *planfile.Reader, rootCall configs.StaticModuleCall) (*plans.Plan, *statefile.File, *configs.Config, error) {
|
||||
// Get plan
|
||||
plan, err := planReader.ReadPlan()
|
||||
if err != nil {
|
||||
@@ -444,7 +445,7 @@ func getDataFromPlanfileReader(planReader *planfile.Reader, rootCall configs.Sta
|
||||
})
|
||||
|
||||
// Get config
|
||||
config, diags := planReader.ReadConfig(subCall)
|
||||
config, diags := planReader.ReadConfig(ctx, subCall)
|
||||
if diags.HasErrors() {
|
||||
return nil, nil, nil, errUnusable(diags.Err(), "local plan")
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
@@ -24,14 +25,14 @@ import (
|
||||
// file-level invariants validated. If the returned diagnostics contains errors,
|
||||
// the returned module tree may be incomplete but can still be used carefully
|
||||
// for static analysis.
|
||||
func BuildConfig(root *Module, walker ModuleWalker) (*Config, hcl.Diagnostics) {
|
||||
func BuildConfig(ctx context.Context, root *Module, walker ModuleWalker) (*Config, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
cfg := &Config{
|
||||
Module: root,
|
||||
}
|
||||
cfg.Root = cfg // Root module is self-referential.
|
||||
cfg.Children, diags = buildChildModules(cfg, walker)
|
||||
diags = append(diags, buildTestModules(cfg, walker)...)
|
||||
cfg.Children, diags = buildChildModules(ctx, cfg, walker)
|
||||
diags = append(diags, buildTestModules(ctx, cfg, walker)...)
|
||||
|
||||
// Skip provider resolution if there are any errors, since the provider
|
||||
// configurations themselves may not be valid.
|
||||
@@ -48,7 +49,7 @@ func BuildConfig(root *Module, walker ModuleWalker) (*Config, hcl.Diagnostics) {
|
||||
return cfg, diags
|
||||
}
|
||||
|
||||
func buildTestModules(root *Config, walker ModuleWalker) hcl.Diagnostics {
|
||||
func buildTestModules(ctx context.Context, root *Config, walker ModuleWalker) hcl.Diagnostics {
|
||||
var diags hcl.Diagnostics
|
||||
|
||||
for name, file := range root.Module.Tests {
|
||||
@@ -83,7 +84,7 @@ func buildTestModules(root *Config, walker ModuleWalker) hcl.Diagnostics {
|
||||
CallRange: run.Module.DeclRange,
|
||||
}
|
||||
|
||||
cfg, modDiags := loadModule(root, &req, walker)
|
||||
cfg, modDiags := loadModule(ctx, root, &req, walker)
|
||||
diags = append(diags, modDiags...)
|
||||
|
||||
if cfg != nil {
|
||||
@@ -114,7 +115,7 @@ func buildTestModules(root *Config, walker ModuleWalker) hcl.Diagnostics {
|
||||
return diags
|
||||
}
|
||||
|
||||
func buildChildModules(parent *Config, walker ModuleWalker) (map[string]*Config, hcl.Diagnostics) {
|
||||
func buildChildModules(ctx context.Context, parent *Config, walker ModuleWalker) (map[string]*Config, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
ret := map[string]*Config{}
|
||||
|
||||
@@ -147,7 +148,7 @@ func buildChildModules(parent *Config, walker ModuleWalker) (map[string]*Config,
|
||||
// Invalid modules sometimes have a nil source field which is handled through loadModule below
|
||||
req.SourceAddrRange = call.Source.Range()
|
||||
}
|
||||
child, modDiags := loadModule(parent.Root, &req, walker)
|
||||
child, modDiags := loadModule(ctx, parent.Root, &req, walker)
|
||||
diags = append(diags, modDiags...)
|
||||
if child == nil {
|
||||
// This means an error occurred, there should be diagnostics within
|
||||
@@ -161,10 +162,10 @@ func buildChildModules(parent *Config, walker ModuleWalker) (map[string]*Config,
|
||||
return ret, diags
|
||||
}
|
||||
|
||||
func loadModule(root *Config, req *ModuleRequest, walker ModuleWalker) (*Config, hcl.Diagnostics) {
|
||||
func loadModule(ctx context.Context, root *Config, req *ModuleRequest, walker ModuleWalker) (*Config, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
|
||||
mod, ver, modDiags := walker.LoadModule(req)
|
||||
mod, ver, modDiags := walker.LoadModule(ctx, req)
|
||||
diags = append(diags, modDiags...)
|
||||
if mod == nil {
|
||||
// nil can be returned if the source address was invalid and so
|
||||
@@ -184,7 +185,7 @@ func loadModule(root *Config, req *ModuleRequest, walker ModuleWalker) (*Config,
|
||||
Version: ver,
|
||||
}
|
||||
|
||||
cfg.Children, modDiags = buildChildModules(cfg, walker)
|
||||
cfg.Children, modDiags = buildChildModules(ctx, cfg, walker)
|
||||
diags = append(diags, modDiags...)
|
||||
|
||||
if mod.Backend != nil {
|
||||
@@ -244,16 +245,16 @@ type ModuleWalker interface {
|
||||
// ensure that the basic file- and module-validations performed by the
|
||||
// LoadConfigDir function (valid syntax, no namespace collisions, etc) have
|
||||
// been performed before returning a module.
|
||||
LoadModule(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics)
|
||||
LoadModule(ctx context.Context, req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics)
|
||||
}
|
||||
|
||||
// ModuleWalkerFunc is an implementation of ModuleWalker that directly wraps
|
||||
// a callback function, for more convenient use of that interface.
|
||||
type ModuleWalkerFunc func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics)
|
||||
type ModuleWalkerFunc func(ctx context.Context, req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics)
|
||||
|
||||
// LoadModule implements ModuleWalker.
|
||||
func (f ModuleWalkerFunc) LoadModule(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
return f(req)
|
||||
func (f ModuleWalkerFunc) LoadModule(ctx context.Context, req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
return f(ctx, req)
|
||||
}
|
||||
|
||||
// ModuleRequest is used with the ModuleWalker interface to describe a child
|
||||
@@ -316,7 +317,7 @@ type ModuleRequest struct {
|
||||
var DisabledModuleWalker ModuleWalker
|
||||
|
||||
func init() {
|
||||
DisabledModuleWalker = ModuleWalkerFunc(func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
DisabledModuleWalker = ModuleWalkerFunc(func(ctx context.Context, req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
return nil, nil, hcl.Diagnostics{
|
||||
{
|
||||
Severity: hcl.DiagError,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
@@ -30,8 +31,8 @@ func TestBuildConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
versionI := 0
|
||||
cfg, diags := BuildConfig(mod, ModuleWalkerFunc(
|
||||
func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
cfg, diags := BuildConfig(t.Context(), mod, ModuleWalkerFunc(
|
||||
func(_ context.Context, req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
// For the sake of this test we're going to just treat our
|
||||
// SourceAddr as a path relative to our fixture directory.
|
||||
// A "real" implementation of ModuleWalker should accept the
|
||||
@@ -86,8 +87,8 @@ func TestBuildConfigDiags(t *testing.T) {
|
||||
}
|
||||
|
||||
versionI := 0
|
||||
cfg, diags := BuildConfig(mod, ModuleWalkerFunc(
|
||||
func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
cfg, diags := BuildConfig(t.Context(), mod, ModuleWalkerFunc(
|
||||
func(_ context.Context, req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
// For the sake of this test we're going to just treat our
|
||||
// SourceAddr as a path relative to our fixture directory.
|
||||
// A "real" implementation of ModuleWalker should accept the
|
||||
@@ -130,8 +131,8 @@ func TestBuildConfigChildModuleBackend(t *testing.T) {
|
||||
t.Fatal("got nil root module; want non-nil")
|
||||
}
|
||||
|
||||
cfg, diags := BuildConfig(mod, ModuleWalkerFunc(
|
||||
func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
cfg, diags := BuildConfig(t.Context(), mod, ModuleWalkerFunc(
|
||||
func(_ context.Context, req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
// For the sake of this test we're going to just treat our
|
||||
// SourceAddr as a path relative to our fixture directory.
|
||||
// A "real" implementation of ModuleWalker should accept the
|
||||
@@ -216,8 +217,8 @@ func TestBuildConfigInvalidModules(t *testing.T) {
|
||||
expectedErrs := readDiags(os.ReadFile(filepath.Join(testDir, name, "errors")))
|
||||
expectedWarnings := readDiags(os.ReadFile(filepath.Join(testDir, name, "warnings")))
|
||||
|
||||
_, buildDiags := BuildConfig(mod, ModuleWalkerFunc(
|
||||
func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
_, buildDiags := BuildConfig(t.Context(), mod, ModuleWalkerFunc(
|
||||
func(_ context.Context, req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
// for simplicity, these tests will treat all source
|
||||
// addresses as relative to the root module
|
||||
sourcePath := filepath.Join(path, req.SourceAddr.String())
|
||||
@@ -302,8 +303,8 @@ func TestBuildConfig_WithNestedTestModules(t *testing.T) {
|
||||
t.Fatal("got nil root module; want non-nil")
|
||||
}
|
||||
|
||||
cfg, diags := BuildConfig(mod, ModuleWalkerFunc(
|
||||
func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
cfg, diags := BuildConfig(t.Context(), mod, ModuleWalkerFunc(
|
||||
func(_ context.Context, req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
|
||||
// Bit of a hack to get the test working, but we know all the source
|
||||
// addresses in this test are locals, so we can just treat them as
|
||||
@@ -382,8 +383,8 @@ func TestBuildConfig_WithTestModule(t *testing.T) {
|
||||
t.Fatal("got nil root module; want non-nil")
|
||||
}
|
||||
|
||||
cfg, diags := BuildConfig(mod, ModuleWalkerFunc(
|
||||
func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
cfg, diags := BuildConfig(t.Context(), mod, ModuleWalkerFunc(
|
||||
func(_ context.Context, req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
// For the sake of this test we're going to just treat our
|
||||
// SourceAddr as a path relative to our fixture directory.
|
||||
// A "real" implementation of ModuleWalker should accept the
|
||||
|
||||
@@ -18,9 +18,10 @@ import (
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/hclparse"
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
||||
svchost "github.com/hashicorp/terraform-svchost"
|
||||
@@ -37,7 +38,7 @@ func TestConfigProviderTypes(t *testing.T) {
|
||||
t.Fatal("expected empty result from empty config")
|
||||
}
|
||||
|
||||
cfg, diags := testModuleConfigFromFile("testdata/valid-files/providers-explicit-implied.tf")
|
||||
cfg, diags := testModuleConfigFromFile(t.Context(), "testdata/valid-files/providers-explicit-implied.tf")
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Error())
|
||||
}
|
||||
@@ -82,7 +83,7 @@ func TestConfigProviderTypes_nested(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfigResolveAbsProviderAddr(t *testing.T) {
|
||||
cfg, diags := testModuleConfigFromDir("testdata/providers-explicit-fqn")
|
||||
cfg, diags := testModuleConfigFromDir(t.Context(), "testdata/providers-explicit-fqn")
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Error())
|
||||
}
|
||||
@@ -640,7 +641,7 @@ func TestVerifyDependencySelections(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfigProviderForConfigAddr(t *testing.T) {
|
||||
cfg, diags := testModuleConfigFromDir("testdata/valid-modules/providers-fqns")
|
||||
cfg, diags := testModuleConfigFromDir(t.Context(), "testdata/valid-modules/providers-fqns")
|
||||
assertNoDiagnostics(t, diags)
|
||||
|
||||
got := cfg.ProviderForConfigAddr(addrs.NewDefaultLocalProviderConfig("foo-test"))
|
||||
@@ -658,7 +659,7 @@ func TestConfigProviderForConfigAddr(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfigAddProviderRequirements(t *testing.T) {
|
||||
cfg, diags := testModuleConfigFromFile("testdata/valid-files/providers-explicit-implied.tf")
|
||||
cfg, diags := testModuleConfigFromFile(t.Context(), "testdata/valid-files/providers-explicit-implied.tf")
|
||||
assertNoDiagnostics(t, diags)
|
||||
|
||||
reqs := getproviders.Requirements{
|
||||
@@ -688,7 +689,7 @@ Use the providers argument within the module block to configure providers for al
|
||||
}
|
||||
|
||||
func TestConfigImportProviderClashesWithResources(t *testing.T) {
|
||||
cfg, diags := testModuleConfigFromFile("testdata/invalid-import-files/import-and-resource-clash.tf")
|
||||
cfg, diags := testModuleConfigFromFile(t.Context(), "testdata/invalid-import-files/import-and-resource-clash.tf")
|
||||
assertNoDiagnostics(t, diags)
|
||||
qualifs := new(getproviders.ProvidersQualification)
|
||||
|
||||
@@ -699,7 +700,7 @@ func TestConfigImportProviderClashesWithResources(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfigImportProviderWithNoResourceProvider(t *testing.T) {
|
||||
cfg, diags := testModuleConfigFromFile("testdata/invalid-import-files/import-and-no-resource.tf")
|
||||
cfg, diags := testModuleConfigFromFile(t.Context(), "testdata/invalid-import-files/import-and-no-resource.tf")
|
||||
assertNoDiagnostics(t, diags)
|
||||
|
||||
qualifs := new(getproviders.ProvidersQualification)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package configload
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
@@ -24,17 +25,19 @@ import (
|
||||
//
|
||||
// LoadConfig performs the basic syntax and uniqueness validations that are
|
||||
// required to process the individual modules
|
||||
func (l *Loader) LoadConfig(rootDir string, call configs.StaticModuleCall) (*configs.Config, hcl.Diagnostics) {
|
||||
return l.loadConfig(l.parser.LoadConfigDir(rootDir, call))
|
||||
func (l *Loader) LoadConfig(ctx context.Context, rootDir string, call configs.StaticModuleCall) (*configs.Config, hcl.Diagnostics) {
|
||||
config, diags := l.parser.LoadConfigDir(rootDir, call)
|
||||
return l.loadConfig(ctx, config, diags)
|
||||
}
|
||||
|
||||
// LoadConfigWithTests matches LoadConfig, except the configs.Config contains
|
||||
// any relevant .tftest.hcl files.
|
||||
func (l *Loader) LoadConfigWithTests(rootDir string, testDir string, call configs.StaticModuleCall) (*configs.Config, hcl.Diagnostics) {
|
||||
return l.loadConfig(l.parser.LoadConfigDirWithTests(rootDir, testDir, call))
|
||||
func (l *Loader) LoadConfigWithTests(ctx context.Context, rootDir string, testDir string, call configs.StaticModuleCall) (*configs.Config, hcl.Diagnostics) {
|
||||
config, diags := l.parser.LoadConfigDirWithTests(rootDir, testDir, call)
|
||||
return l.loadConfig(ctx, config, diags)
|
||||
}
|
||||
|
||||
func (l *Loader) loadConfig(rootMod *configs.Module, diags hcl.Diagnostics) (*configs.Config, hcl.Diagnostics) {
|
||||
func (l *Loader) loadConfig(ctx context.Context, rootMod *configs.Module, diags hcl.Diagnostics) (*configs.Config, hcl.Diagnostics) {
|
||||
if rootMod == nil || diags.HasErrors() {
|
||||
// Ensure we return any parsed modules here so that required_version
|
||||
// constraints can be verified even when encountering errors.
|
||||
@@ -45,7 +48,7 @@ func (l *Loader) loadConfig(rootMod *configs.Module, diags hcl.Diagnostics) (*co
|
||||
return cfg, diags
|
||||
}
|
||||
|
||||
cfg, cDiags := configs.BuildConfig(rootMod, configs.ModuleWalkerFunc(l.moduleWalkerLoad))
|
||||
cfg, cDiags := configs.BuildConfig(ctx, rootMod, configs.ModuleWalkerFunc(l.moduleWalkerLoad))
|
||||
diags = append(diags, cDiags...)
|
||||
|
||||
return cfg, diags
|
||||
@@ -53,7 +56,7 @@ func (l *Loader) loadConfig(rootMod *configs.Module, diags hcl.Diagnostics) (*co
|
||||
|
||||
// moduleWalkerLoad is a configs.ModuleWalkerFunc for loading modules that
|
||||
// are presumed to have already been installed.
|
||||
func (l *Loader) moduleWalkerLoad(req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
|
||||
func (l *Loader) moduleWalkerLoad(ctx context.Context, req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
|
||||
// Since we're just loading here, we expect that all referenced modules
|
||||
// will be already installed and described in our manifest. However, we
|
||||
// do verify that the manifest and the configuration are in agreement
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestLoaderLoadConfig_okay(t *testing.T) {
|
||||
t.Fatalf("unexpected error from NewLoader: %s", err)
|
||||
}
|
||||
|
||||
cfg, diags := loader.LoadConfig(fixtureDir, configs.RootModuleCallForTesting())
|
||||
cfg, diags := loader.LoadConfig(t.Context(), fixtureDir, configs.RootModuleCallForTesting())
|
||||
assertNoDiagnostics(t, diags)
|
||||
if cfg == nil {
|
||||
t.Fatalf("config is nil; want non-nil")
|
||||
@@ -75,7 +75,7 @@ func TestLoaderLoadConfig_addVersion(t *testing.T) {
|
||||
t.Fatalf("unexpected error from NewLoader: %s", err)
|
||||
}
|
||||
|
||||
_, diags := loader.LoadConfig(fixtureDir, configs.RootModuleCallForTesting())
|
||||
_, diags := loader.LoadConfig(t.Context(), fixtureDir, configs.RootModuleCallForTesting())
|
||||
if !diags.HasErrors() {
|
||||
t.Fatalf("success; want error")
|
||||
}
|
||||
@@ -96,7 +96,7 @@ func TestLoaderLoadConfig_loadDiags(t *testing.T) {
|
||||
t.Fatalf("unexpected error from NewLoader: %s", err)
|
||||
}
|
||||
|
||||
cfg, diags := loader.LoadConfig(fixtureDir, configs.RootModuleCallForTesting())
|
||||
cfg, diags := loader.LoadConfig(t.Context(), fixtureDir, configs.RootModuleCallForTesting())
|
||||
if !diags.HasErrors() {
|
||||
t.Fatal("success; want error")
|
||||
}
|
||||
@@ -120,7 +120,7 @@ func TestLoaderLoadConfig_loadDiagsFromSubmodules(t *testing.T) {
|
||||
t.Fatalf("unexpected error from NewLoader: %s", err)
|
||||
}
|
||||
|
||||
cfg, diags := loader.LoadConfig(fixtureDir, configs.RootModuleCallForTesting())
|
||||
cfg, diags := loader.LoadConfig(t.Context(), fixtureDir, configs.RootModuleCallForTesting())
|
||||
if !diags.HasErrors() {
|
||||
t.Fatalf("loading succeeded; want an error")
|
||||
}
|
||||
@@ -170,7 +170,7 @@ func TestLoaderLoadConfig_childProviderGrandchildCount(t *testing.T) {
|
||||
t.Fatalf("unexpected error from NewLoader: %s", err)
|
||||
}
|
||||
|
||||
cfg, diags := loader.LoadConfig(fixtureDir, configs.RootModuleCallForTesting())
|
||||
cfg, diags := loader.LoadConfig(t.Context(), fixtureDir, configs.RootModuleCallForTesting())
|
||||
assertNoDiagnostics(t, diags)
|
||||
if cfg == nil {
|
||||
t.Fatalf("config is nil; want non-nil")
|
||||
@@ -200,7 +200,7 @@ func TestLoaderLoadConfig_childProviderGrandchildCount(t *testing.T) {
|
||||
t.Fatalf("unexpected error from NewLoader: %s", err)
|
||||
}
|
||||
|
||||
_, diags := loader.LoadConfig(fixtureDir, configs.RootModuleCallForTesting())
|
||||
_, diags := loader.LoadConfig(t.Context(), fixtureDir, configs.RootModuleCallForTesting())
|
||||
if !diags.HasErrors() {
|
||||
t.Fatalf("loading succeeded; want an error")
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package configload
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -15,15 +16,16 @@ import (
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/spf13/afero"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
"github.com/opentofu/opentofu/internal/modsdir"
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
// LoadConfigWithSnapshot is a variant of LoadConfig that also simultaneously
|
||||
// creates an in-memory snapshot of the configuration files used, which can
|
||||
// be later used to create a loader that may read only from this snapshot.
|
||||
func (l *Loader) LoadConfigWithSnapshot(rootDir string, call configs.StaticModuleCall) (*configs.Config, *Snapshot, hcl.Diagnostics) {
|
||||
func (l *Loader) LoadConfigWithSnapshot(ctx context.Context, rootDir string, call configs.StaticModuleCall) (*configs.Config, *Snapshot, hcl.Diagnostics) {
|
||||
rootMod, diags := l.parser.LoadConfigDir(rootDir, call)
|
||||
if rootMod == nil {
|
||||
return nil, nil, diags
|
||||
@@ -33,7 +35,7 @@ func (l *Loader) LoadConfigWithSnapshot(rootDir string, call configs.StaticModul
|
||||
Modules: map[string]*SnapshotModule{},
|
||||
}
|
||||
walker := l.makeModuleWalkerSnapshot(snap)
|
||||
cfg, cDiags := configs.BuildConfig(rootMod, walker)
|
||||
cfg, cDiags := configs.BuildConfig(ctx, rootMod, walker)
|
||||
diags = append(diags, cDiags...)
|
||||
|
||||
addDiags := l.addModuleToSnapshot(snap, "", rootDir, "", nil)
|
||||
@@ -135,8 +137,8 @@ func (s *Snapshot) moduleManifest() modsdir.Manifest {
|
||||
// source files from the referenced modules into the given snapshot.
|
||||
func (l *Loader) makeModuleWalkerSnapshot(snap *Snapshot) configs.ModuleWalker {
|
||||
return configs.ModuleWalkerFunc(
|
||||
func(req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
|
||||
mod, v, diags := l.moduleWalkerLoad(req)
|
||||
func(ctx context.Context, req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
|
||||
mod, v, diags := l.moduleWalkerLoad(ctx, req)
|
||||
if diags.HasErrors() {
|
||||
return mod, v, diags
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/go-test/deep"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
)
|
||||
|
||||
@@ -25,7 +26,7 @@ func TestLoadConfigWithSnapshot(t *testing.T) {
|
||||
t.Fatalf("unexpected error from NewLoader: %s", err)
|
||||
}
|
||||
|
||||
_, got, diags := loader.LoadConfigWithSnapshot(fixtureDir, configs.RootModuleCallForTesting())
|
||||
_, got, diags := loader.LoadConfigWithSnapshot(t.Context(), fixtureDir, configs.RootModuleCallForTesting())
|
||||
assertNoDiagnostics(t, diags)
|
||||
if got == nil {
|
||||
t.Fatalf("snapshot is nil; want non-nil")
|
||||
@@ -96,7 +97,7 @@ func TestLoadConfigWithSnapshot_invalidSource(t *testing.T) {
|
||||
t.Fatalf("unexpected error from NewLoader: %s", err)
|
||||
}
|
||||
|
||||
_, _, diags := loader.LoadConfigWithSnapshot(".", configs.RootModuleCallForTesting())
|
||||
_, _, diags := loader.LoadConfigWithSnapshot(t.Context(), ".", configs.RootModuleCallForTesting())
|
||||
if !diags.HasErrors() {
|
||||
t.Error("LoadConfigWithSnapshot succeeded; want errors", configs.RootModuleCallForTesting())
|
||||
}
|
||||
@@ -111,7 +112,7 @@ func TestSnapshotRoundtrip(t *testing.T) {
|
||||
t.Fatalf("unexpected error from NewLoader: %s", err)
|
||||
}
|
||||
|
||||
_, snap, diags := loader.LoadConfigWithSnapshot(fixtureDir, configs.RootModuleCallForTesting())
|
||||
_, snap, diags := loader.LoadConfigWithSnapshot(t.Context(), fixtureDir, configs.RootModuleCallForTesting())
|
||||
assertNoDiagnostics(t, diags)
|
||||
if snap == nil {
|
||||
t.Fatalf("snapshot is nil; want non-nil")
|
||||
@@ -122,7 +123,7 @@ func TestSnapshotRoundtrip(t *testing.T) {
|
||||
t.Fatalf("loader is nil; want non-nil")
|
||||
}
|
||||
|
||||
config, diags := snapLoader.LoadConfig(fixtureDir, configs.RootModuleCallForTesting())
|
||||
config, diags := snapLoader.LoadConfig(t.Context(), fixtureDir, configs.RootModuleCallForTesting())
|
||||
assertNoDiagnostics(t, diags)
|
||||
if config == nil {
|
||||
t.Fatalf("config is nil; want non-nil")
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
@@ -45,12 +46,12 @@ func testParser(files map[string]string) *Parser {
|
||||
|
||||
// testModuleConfigFrom File reads a single file from the given path as a
|
||||
// module and returns its configuration. This is a helper for use in unit tests.
|
||||
func testModuleConfigFromFile(filename string) (*Config, hcl.Diagnostics) {
|
||||
func testModuleConfigFromFile(ctx context.Context, filename string) (*Config, hcl.Diagnostics) {
|
||||
parser := NewParser(nil)
|
||||
f, diags := parser.LoadConfigFile(filename)
|
||||
mod, modDiags := NewModule([]*File{f}, nil, RootModuleCallForTesting(), filename, SelectiveLoadAll)
|
||||
diags = append(diags, modDiags...)
|
||||
cfg, moreDiags := BuildConfig(mod, nil)
|
||||
cfg, moreDiags := BuildConfig(ctx, mod, nil)
|
||||
return cfg, append(diags, moreDiags...)
|
||||
}
|
||||
|
||||
@@ -63,10 +64,10 @@ func testModuleFromDir(path string) (*Module, hcl.Diagnostics) {
|
||||
|
||||
// testModuleFromDir reads configuration from the given directory path as a
|
||||
// module and returns its configuration. This is a helper for use in unit tests.
|
||||
func testModuleConfigFromDir(path string) (*Config, hcl.Diagnostics) {
|
||||
func testModuleConfigFromDir(ctx context.Context, path string) (*Config, hcl.Diagnostics) {
|
||||
parser := NewParser(nil)
|
||||
mod, diags := parser.LoadConfigDir(path, RootModuleCallForTesting())
|
||||
cfg, moreDiags := BuildConfig(mod, nil)
|
||||
cfg, moreDiags := BuildConfig(ctx, mod, nil)
|
||||
return cfg, append(diags, moreDiags...)
|
||||
}
|
||||
|
||||
@@ -81,7 +82,7 @@ func testNestedModuleConfigFromDirWithTests(t *testing.T, path string) (*Config,
|
||||
t.Fatal("got nil root module; want non-nil")
|
||||
}
|
||||
|
||||
cfg, nestedDiags := buildNestedModuleConfig(mod, path, parser)
|
||||
cfg, nestedDiags := buildNestedModuleConfig(t.Context(), mod, path, parser)
|
||||
|
||||
diags = append(diags, nestedDiags...)
|
||||
return cfg, diags
|
||||
@@ -99,16 +100,16 @@ func testNestedModuleConfigFromDir(t *testing.T, path string) (*Config, hcl.Diag
|
||||
t.Fatal("got nil root module; want non-nil")
|
||||
}
|
||||
|
||||
cfg, nestedDiags := buildNestedModuleConfig(mod, path, parser)
|
||||
cfg, nestedDiags := buildNestedModuleConfig(t.Context(), mod, path, parser)
|
||||
|
||||
diags = append(diags, nestedDiags...)
|
||||
return cfg, diags
|
||||
}
|
||||
|
||||
func buildNestedModuleConfig(mod *Module, path string, parser *Parser) (*Config, hcl.Diagnostics) {
|
||||
func buildNestedModuleConfig(ctx context.Context, mod *Module, path string, parser *Parser) (*Config, hcl.Diagnostics) {
|
||||
versionI := 0
|
||||
return BuildConfig(mod, ModuleWalkerFunc(
|
||||
func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
return BuildConfig(ctx, mod, ModuleWalkerFunc(
|
||||
func(_ context.Context, req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||
// For the sake of this test we're going to just treat our
|
||||
// SourceAddr as a path relative to the calling module.
|
||||
// A "real" implementation of ModuleWalker should accept the
|
||||
|
||||
@@ -9,12 +9,15 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
cleanhttp "github.com/hashicorp/go-cleanhttp"
|
||||
getter "github.com/hashicorp/go-getter"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/copy"
|
||||
)
|
||||
|
||||
@@ -109,7 +112,9 @@ var goGetterGetters = map[string]getter.Getter{
|
||||
"s3": new(getter.S3Getter),
|
||||
}
|
||||
|
||||
var getterHTTPClient = cleanhttp.DefaultClient()
|
||||
var getterHTTPClient = &http.Client{
|
||||
Transport: otelhttp.NewTransport(cleanhttp.DefaultTransport()),
|
||||
}
|
||||
|
||||
var getterHTTPGetter = &getter.HttpGetter{
|
||||
Client: getterHTTPClient,
|
||||
|
||||
@@ -9,6 +9,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"maps"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.30.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/tracing"
|
||||
)
|
||||
|
||||
// PackageFetcher is a low-level utility for fetching remote module packages
|
||||
@@ -65,7 +70,16 @@ func NewPackageFetcher(env PackageFetcherEnvironment) *PackageFetcher {
|
||||
// caller must resolve that itself, possibly with the help of the
|
||||
// getmodules.SplitPackageSubdir and getmodules.ExpandSubdirGlobs functions.
|
||||
func (f *PackageFetcher) FetchPackage(ctx context.Context, instDir string, packageAddr string) error {
|
||||
return f.getter.getWithGoGetter(ctx, instDir, packageAddr)
|
||||
ctx, span := tracing.Tracer().Start(ctx, "Fetch Package",
|
||||
trace.WithAttributes(semconv.URLFull(packageAddr)),
|
||||
)
|
||||
defer span.End()
|
||||
err := f.getter.getWithGoGetter(ctx, instDir, packageAddr)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PackageFetcherEnvironment is an interface used with [NewPackageFetcher]
|
||||
|
||||
@@ -15,14 +15,16 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/addrs"
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
"github.com/opentofu/opentofu/internal/configs/configload"
|
||||
"github.com/opentofu/opentofu/internal/copy"
|
||||
"github.com/opentofu/opentofu/internal/getmodules"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/modsdir"
|
||||
"github.com/opentofu/opentofu/internal/registry"
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
@@ -170,7 +172,7 @@ func DirFromModule(ctx context.Context, loader *configload.Loader, rootDir, modu
|
||||
}
|
||||
|
||||
walker := inst.moduleInstallWalker(ctx, instManifest, true, wrapHooks, remoteFetcher)
|
||||
_, cDiags := inst.installDescendentModules(fakeRootModule, instManifest, walker, true)
|
||||
_, cDiags := inst.installDescendentModules(ctx, fakeRootModule, instManifest, walker, true)
|
||||
if cDiags.HasErrors() {
|
||||
return diags.Append(cDiags)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
version "github.com/hashicorp/go-version"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
"github.com/opentofu/opentofu/internal/configs/configload"
|
||||
"github.com/opentofu/opentofu/internal/copy"
|
||||
@@ -109,7 +110,7 @@ func TestDirFromModule_registry(t *testing.T) {
|
||||
|
||||
// Make sure the configuration is loadable now.
|
||||
// (This ensures that correct information is recorded in the manifest.)
|
||||
config, loadDiags := loader.LoadConfig(".", configs.RootModuleCallForTesting())
|
||||
config, loadDiags := loader.LoadConfig(t.Context(), ".", configs.RootModuleCallForTesting())
|
||||
if assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) {
|
||||
return
|
||||
}
|
||||
@@ -202,7 +203,7 @@ func TestDirFromModule_submodules(t *testing.T) {
|
||||
|
||||
// Make sure the configuration is loadable now.
|
||||
// (This ensures that correct information is recorded in the manifest.)
|
||||
config, loadDiags := loader.LoadConfig(".", configs.RootModuleCallForTesting())
|
||||
config, loadDiags := loader.LoadConfig(t.Context(), ".", configs.RootModuleCallForTesting())
|
||||
if assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) {
|
||||
return
|
||||
}
|
||||
@@ -354,7 +355,7 @@ func TestDirFromModule_rel_submodules(t *testing.T) {
|
||||
|
||||
// Make sure the configuration is loadable now.
|
||||
// (This ensures that correct information is recorded in the manifest.)
|
||||
config, loadDiags := loader.LoadConfig(".", configs.RootModuleCallForTesting())
|
||||
config, loadDiags := loader.LoadConfig(t.Context(), ".", configs.RootModuleCallForTesting())
|
||||
if assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import (
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
||||
otelAttr "go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/addrs"
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
@@ -30,6 +32,8 @@ import (
|
||||
"github.com/opentofu/opentofu/internal/registry/regsrc"
|
||||
"github.com/opentofu/opentofu/internal/registry/response"
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
"github.com/opentofu/opentofu/internal/tracing"
|
||||
"github.com/opentofu/opentofu/internal/tracing/traceattrs"
|
||||
)
|
||||
|
||||
type ModuleInstaller struct {
|
||||
@@ -159,15 +163,15 @@ func (i *ModuleInstaller) InstallModules(ctx context.Context, rootDir, testsDir
|
||||
}
|
||||
walker := i.moduleInstallWalker(ctx, manifest, upgrade, hooks, fetcher)
|
||||
|
||||
cfg, instDiags := i.installDescendentModules(rootMod, manifest, walker, installErrsOnly)
|
||||
cfg, instDiags := i.installDescendentModules(ctx, rootMod, manifest, walker, installErrsOnly)
|
||||
diags = append(diags, instDiags...)
|
||||
|
||||
return cfg, diags
|
||||
}
|
||||
|
||||
func (i *ModuleInstaller) moduleInstallWalker(ctx context.Context, manifest modsdir.Manifest, upgrade bool, hooks ModuleInstallHooks, fetcher *getmodules.PackageFetcher) configs.ModuleWalker {
|
||||
func (i *ModuleInstaller) moduleInstallWalker(_ context.Context, manifest modsdir.Manifest, upgrade bool, hooks ModuleInstallHooks, fetcher *getmodules.PackageFetcher) configs.ModuleWalker {
|
||||
return configs.ModuleWalkerFunc(
|
||||
func(req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
|
||||
func(ctx context.Context, req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
|
||||
if req.SourceAddr == nil {
|
||||
@@ -196,6 +200,14 @@ func (i *ModuleInstaller) moduleInstallWalker(ctx context.Context, manifest mods
|
||||
key := manifest.ModuleKey(req.Path)
|
||||
instPath := i.packageInstallPath(req.Path)
|
||||
|
||||
ctx, span := tracing.Tracer().Start(ctx,
|
||||
fmt.Sprintf("Install Module %q", req.Name),
|
||||
trace.WithAttributes(
|
||||
otelAttr.String(traceattrs.ModuleCallName, req.Name),
|
||||
otelAttr.String(traceattrs.ModuleSource, req.SourceAddr.String()),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
log.Printf("[DEBUG] Module installer: begin %s", key)
|
||||
|
||||
// First we'll check if we need to upgrade/replace an existing
|
||||
@@ -206,12 +218,15 @@ func (i *ModuleInstaller) moduleInstallWalker(ctx context.Context, manifest mods
|
||||
switch {
|
||||
case !recorded:
|
||||
log.Printf("[TRACE] ModuleInstaller: %s is not yet installed", key)
|
||||
span.AddEvent("Module not yet installed")
|
||||
replace = true
|
||||
case record.SourceAddr != req.SourceAddr.String():
|
||||
log.Printf("[TRACE] ModuleInstaller: %s source address has changed from %q to %q", key, record.SourceAddr, req.SourceAddr)
|
||||
span.AddEvent("Module source address changed")
|
||||
replace = true
|
||||
case record.Version != nil && !req.VersionConstraint.Required.Check(record.Version):
|
||||
log.Printf("[TRACE] ModuleInstaller: %s version %s no longer compatible with constraints %s", key, record.Version, req.VersionConstraint.Required)
|
||||
span.AddEvent("Module version constraint changed")
|
||||
replace = true
|
||||
}
|
||||
}
|
||||
@@ -288,13 +303,15 @@ func (i *ModuleInstaller) moduleInstallWalker(ctx context.Context, manifest mods
|
||||
|
||||
case addrs.ModuleSourceLocal:
|
||||
log.Printf("[TRACE] ModuleInstaller: %s has local path %q", key, addr.String())
|
||||
mod, mDiags := i.installLocalModule(req, key, manifest, hooks)
|
||||
span.SetAttributes(otelAttr.String("opentofu.module.source_type", "local"))
|
||||
mod, mDiags := i.installLocalModule(ctx, req, key, manifest, hooks)
|
||||
mDiags = maybeImproveLocalInstallError(req, mDiags)
|
||||
diags = append(diags, mDiags...)
|
||||
return mod, nil, diags
|
||||
|
||||
case addrs.ModuleSourceRegistry:
|
||||
log.Printf("[TRACE] ModuleInstaller: %s is a registry module at %s", key, addr.String())
|
||||
span.SetAttributes(otelAttr.String("opentofu.module.source_type", "registry"))
|
||||
mod, v, mDiags := i.installRegistryModule(ctx, req, key, instPath, addr, manifest, hooks, fetcher)
|
||||
diags = append(diags, mDiags...)
|
||||
return mod, v, diags
|
||||
@@ -314,7 +331,7 @@ func (i *ModuleInstaller) moduleInstallWalker(ctx context.Context, manifest mods
|
||||
)
|
||||
}
|
||||
|
||||
func (i *ModuleInstaller) installDescendentModules(rootMod *configs.Module, manifest modsdir.Manifest, installWalker configs.ModuleWalker, installErrsOnly bool) (*configs.Config, tfdiags.Diagnostics) {
|
||||
func (i *ModuleInstaller) installDescendentModules(ctx context.Context, rootMod *configs.Module, manifest modsdir.Manifest, installWalker configs.ModuleWalker, installErrsOnly bool) (*configs.Config, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
// When attempting to initialize the current directory with a module
|
||||
@@ -327,14 +344,14 @@ func (i *ModuleInstaller) installDescendentModules(rootMod *configs.Module, mani
|
||||
var instDiags hcl.Diagnostics
|
||||
walker := installWalker
|
||||
if installErrsOnly {
|
||||
walker = configs.ModuleWalkerFunc(func(req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
|
||||
mod, version, diags := installWalker.LoadModule(req)
|
||||
walker = configs.ModuleWalkerFunc(func(ctx context.Context, req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
|
||||
mod, version, diags := installWalker.LoadModule(ctx, req)
|
||||
instDiags = instDiags.Extend(diags)
|
||||
return mod, version, diags
|
||||
})
|
||||
}
|
||||
|
||||
cfg, cDiags := configs.BuildConfig(rootMod, walker)
|
||||
cfg, cDiags := configs.BuildConfig(ctx, rootMod, walker)
|
||||
diags = diags.Append(cDiags)
|
||||
if installErrsOnly {
|
||||
// We can't continue if there was an error during installation, but
|
||||
@@ -366,9 +383,15 @@ func (i *ModuleInstaller) installDescendentModules(rootMod *configs.Module, mani
|
||||
return cfg, diags
|
||||
}
|
||||
|
||||
func (i *ModuleInstaller) installLocalModule(req *configs.ModuleRequest, key string, manifest modsdir.Manifest, hooks ModuleInstallHooks) (*configs.Module, hcl.Diagnostics) {
|
||||
func (i *ModuleInstaller) installLocalModule(ctx context.Context, req *configs.ModuleRequest, key string, manifest modsdir.Manifest, hooks ModuleInstallHooks) (*configs.Module, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
|
||||
_, span := tracing.Tracer().Start(ctx, "Install Local Module",
|
||||
trace.WithAttributes(otelAttr.String(traceattrs.ModuleCallName, req.Name)),
|
||||
trace.WithAttributes(otelAttr.String(traceattrs.ModuleSource, req.SourceAddr.String())),
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
parentKey := manifest.ModuleKey(req.Parent.Path)
|
||||
parentRecord, recorded := manifest[parentKey]
|
||||
if !recorded {
|
||||
@@ -421,6 +444,10 @@ func (i *ModuleInstaller) installLocalModule(req *configs.ModuleRequest, key str
|
||||
diags = diags.Extend(mDiags)
|
||||
}
|
||||
|
||||
if diags.HasErrors() {
|
||||
tracing.SetSpanError(span, diags)
|
||||
}
|
||||
|
||||
// Note the local location in our manifest.
|
||||
manifest[key] = modsdir.Record{
|
||||
Key: key,
|
||||
@@ -441,6 +468,13 @@ var versionRegexp = regexp.MustCompile(version.VersionRegexpRaw)
|
||||
func (i *ModuleInstaller) installRegistryModule(ctx context.Context, req *configs.ModuleRequest, key string, instPath string, addr addrs.ModuleSourceRegistry, manifest modsdir.Manifest, hooks ModuleInstallHooks, fetcher *getmodules.PackageFetcher) (*configs.Module, *version.Version, hcl.Diagnostics) {
|
||||
var diags hcl.Diagnostics
|
||||
|
||||
ctx, span := tracing.Tracer().Start(ctx, "Install Registry Module",
|
||||
trace.WithAttributes(otelAttr.String(traceattrs.ModuleCallName, req.Name)),
|
||||
trace.WithAttributes(otelAttr.String(traceattrs.ModuleSource, req.SourceAddr.String())),
|
||||
trace.WithAttributes(otelAttr.String(traceattrs.ModuleVersion, req.VersionConstraint.Required.String())),
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
if i.reg == nil || fetcher == nil {
|
||||
// Only local package sources are available when we have no registry
|
||||
// client or no fetcher, since both would be needed for successful install.
|
||||
@@ -451,6 +485,7 @@ func (i *ModuleInstaller) installRegistryModule(ctx context.Context, req *config
|
||||
Detail: "Only local module sources are supported in this context.",
|
||||
Subject: req.CallRange.Ptr(),
|
||||
})
|
||||
tracing.SetSpanError(span, diags)
|
||||
return nil, nil, diags
|
||||
}
|
||||
|
||||
@@ -502,6 +537,7 @@ func (i *ModuleInstaller) installRegistryModule(ctx context.Context, req *config
|
||||
Subject: req.CallRange.Ptr(),
|
||||
})
|
||||
}
|
||||
tracing.SetSpanError(span, diags)
|
||||
return nil, nil, diags
|
||||
}
|
||||
i.registryPackageVersions[packageAddr] = resp
|
||||
@@ -651,6 +687,7 @@ func (i *ModuleInstaller) installRegistryModule(ctx context.Context, req *config
|
||||
Detail: fmt.Sprintf("Module %q (%s:%d) has no versions available on %s.", addr, req.CallRange.Filename, req.CallRange.Start.Line, hostname),
|
||||
Subject: req.CallRange.Ptr(),
|
||||
})
|
||||
tracing.SetSpanError(span, diags)
|
||||
return nil, nil, diags
|
||||
}
|
||||
|
||||
@@ -661,6 +698,7 @@ func (i *ModuleInstaller) installRegistryModule(ctx context.Context, req *config
|
||||
Detail: fmt.Sprintf("There is no available version of module %q (%s:%d) which matches the given version constraint. The newest available version is %s.", addr, req.CallRange.Filename, req.CallRange.Start.Line, latestVersion),
|
||||
Subject: req.CallRange.Ptr(),
|
||||
})
|
||||
tracing.SetSpanError(span, diags)
|
||||
return nil, nil, diags
|
||||
}
|
||||
|
||||
@@ -682,6 +720,7 @@ func (i *ModuleInstaller) installRegistryModule(ctx context.Context, req *config
|
||||
Summary: "Error accessing remote module registry",
|
||||
Detail: fmt.Sprintf("Failed to retrieve a download URL for %s %s from %s: %s", addr, latestMatch, hostname, err),
|
||||
})
|
||||
tracing.SetSpanError(span, diags)
|
||||
return nil, nil, diags
|
||||
}
|
||||
realAddr, err := addrs.ParseModuleSource(realAddrRaw)
|
||||
@@ -691,8 +730,12 @@ func (i *ModuleInstaller) installRegistryModule(ctx context.Context, req *config
|
||||
Summary: "Invalid package location from module registry",
|
||||
Detail: fmt.Sprintf("Module registry %s returned invalid source location %q for %s %s: %s.", hostname, realAddrRaw, addr, latestMatch, err),
|
||||
})
|
||||
tracing.SetSpanError(span, diags)
|
||||
return nil, nil, diags
|
||||
}
|
||||
|
||||
span.SetAttributes(otelAttr.String(traceattrs.ModuleSource, realAddr.String()))
|
||||
|
||||
switch realAddr := realAddr.(type) {
|
||||
// Only a remote source address is allowed here: a registry isn't
|
||||
// allowed to return a local path (because it doesn't know what
|
||||
@@ -706,6 +749,7 @@ func (i *ModuleInstaller) installRegistryModule(ctx context.Context, req *config
|
||||
Summary: "Invalid package location from module registry",
|
||||
Detail: fmt.Sprintf("Module registry %s returned invalid source location %q for %s %s: must be a direct remote package address.", hostname, realAddrRaw, addr, latestMatch),
|
||||
})
|
||||
tracing.SetSpanError(span, diags)
|
||||
return nil, nil, diags
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func TestModuleInstaller(t *testing.T) {
|
||||
|
||||
// Make sure the configuration is loadable now.
|
||||
// (This ensures that correct information is recorded in the manifest.)
|
||||
config, loadDiags := loader.LoadConfig(".", configs.RootModuleCallForTesting())
|
||||
config, loadDiags := loader.LoadConfig(t.Context(), ".", configs.RootModuleCallForTesting())
|
||||
assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags))
|
||||
|
||||
wantTraces := map[string]string{
|
||||
@@ -441,7 +441,7 @@ func TestModuleInstaller_symlink(t *testing.T) {
|
||||
|
||||
// Make sure the configuration is loadable now.
|
||||
// (This ensures that correct information is recorded in the manifest.)
|
||||
config, loadDiags := loader.LoadConfig(".", configs.RootModuleCallForTesting())
|
||||
config, loadDiags := loader.LoadConfig(t.Context(), ".", configs.RootModuleCallForTesting())
|
||||
assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags))
|
||||
|
||||
wantTraces := map[string]string{
|
||||
@@ -597,7 +597,7 @@ func TestLoaderInstallModules_registry(t *testing.T) {
|
||||
|
||||
// Make sure the configuration is loadable now.
|
||||
// (This ensures that correct information is recorded in the manifest.)
|
||||
config, loadDiags := loader.LoadConfig(".", configs.RootModuleCallForTesting())
|
||||
config, loadDiags := loader.LoadConfig(t.Context(), ".", configs.RootModuleCallForTesting())
|
||||
assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags))
|
||||
|
||||
wantTraces := map[string]string{
|
||||
@@ -725,7 +725,7 @@ func TestLoaderInstallModules_goGetter(t *testing.T) {
|
||||
|
||||
// Make sure the configuration is loadable now.
|
||||
// (This ensures that correct information is recorded in the manifest.)
|
||||
config, loadDiags := loader.LoadConfig(".", configs.RootModuleCallForTesting())
|
||||
config, loadDiags := loader.LoadConfig(t.Context(), ".", configs.RootModuleCallForTesting())
|
||||
assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags))
|
||||
|
||||
wantTraces := map[string]string{
|
||||
@@ -785,7 +785,7 @@ func TestModuleInstaller_fromTests(t *testing.T) {
|
||||
|
||||
// Make sure the configuration is loadable now.
|
||||
// (This ensures that correct information is recorded in the manifest.)
|
||||
config, loadDiags := loader.LoadConfigWithTests(".", "tests", configs.RootModuleCallForTesting())
|
||||
config, loadDiags := loader.LoadConfigWithTests(t.Context(), ".", "tests", configs.RootModuleCallForTesting())
|
||||
assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags))
|
||||
|
||||
if config.Module.Tests[filepath.Join("tests", "main.tftest.hcl")].Runs[0].ConfigUnderTest == nil {
|
||||
@@ -891,7 +891,7 @@ func TestLoadInstallModules_registryFromTest(t *testing.T) {
|
||||
|
||||
// Make sure the configuration is loadable now.
|
||||
// (This ensures that correct information is recorded in the manifest.)
|
||||
config, loadDiags := loader.LoadConfigWithTests(".", "tests", configs.RootModuleCallForTesting())
|
||||
config, loadDiags := loader.LoadConfigWithTests(t.Context(), ".", "tests", configs.RootModuleCallForTesting())
|
||||
assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags))
|
||||
|
||||
if config.Module.Tests["main.tftest.hcl"].Runs[0].ConfigUnderTest == nil {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
package initwd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
@@ -38,7 +37,7 @@ func LoadConfigForTests(t testing.TB, rootDir string, testsDir string) (*configs
|
||||
inst := NewModuleInstaller(loader.ModulesDir(), loader, registry.NewClient(nil, nil), nil)
|
||||
|
||||
call := configs.RootModuleCallForTesting()
|
||||
_, moreDiags := inst.InstallModules(context.Background(), rootDir, testsDir, true, false, ModuleInstallHooksImpl{}, call)
|
||||
_, moreDiags := inst.InstallModules(t.Context(), rootDir, testsDir, true, false, ModuleInstallHooksImpl{}, call)
|
||||
diags = diags.Append(moreDiags)
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Err())
|
||||
@@ -51,7 +50,7 @@ func LoadConfigForTests(t testing.TB, rootDir string, testsDir string) (*configs
|
||||
t.Fatalf("failed to refresh modules after installation: %s", err)
|
||||
}
|
||||
|
||||
config, hclDiags := loader.LoadConfig(rootDir, call)
|
||||
config, hclDiags := loader.LoadConfig(t.Context(), rootDir, call)
|
||||
diags = diags.Append(hclDiags)
|
||||
return config, loader, diags
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ func testAnalyzer(t *testing.T, fixtureName string) *Analyzer {
|
||||
t.Fatalf("failed to refresh modules after install: %s", err)
|
||||
}
|
||||
|
||||
cfg, loadDiags := loader.LoadConfig(configDir, configs.RootModuleCallForTesting())
|
||||
cfg, loadDiags := loader.LoadConfig(t.Context(), configDir, configs.RootModuleCallForTesting())
|
||||
if loadDiags.HasErrors() {
|
||||
t.Fatalf("unexpected configuration errors: %s", loadDiags.Error())
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestConfigSnapshotRoundtrip(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, snapIn, diags := loader.LoadConfigWithSnapshot(fixtureDir, configs.RootModuleCallForTesting())
|
||||
_, snapIn, diags := loader.LoadConfigWithSnapshot(t.Context(), fixtureDir, configs.RootModuleCallForTesting())
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Error())
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestRoundtrip(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, snapIn, diags := loader.LoadConfigWithSnapshot(fixtureDir, configs.RootModuleCallForTesting())
|
||||
_, snapIn, diags := loader.LoadConfigWithSnapshot(t.Context(), fixtureDir, configs.RootModuleCallForTesting())
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Error())
|
||||
}
|
||||
@@ -164,7 +164,7 @@ func TestRoundtrip(t *testing.T) {
|
||||
// Reading from snapshots is tested in the configload package, so
|
||||
// here we'll just test that we can successfully do it, to see if the
|
||||
// glue code in _this_ package is correct.
|
||||
_, diags := pr.ReadConfig(configs.RootModuleCallForTesting())
|
||||
_, diags := pr.ReadConfig(t.Context(), configs.RootModuleCallForTesting())
|
||||
if diags.HasErrors() {
|
||||
t.Errorf("when reading config: %s", diags.Err())
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ package planfile
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -213,7 +214,7 @@ func (r *Reader) ReadConfigSnapshot() (*configload.Snapshot, error) {
|
||||
// Internally this function delegates to the configs/configload package to
|
||||
// parse the embedded configuration and so it returns diagnostics (rather than
|
||||
// a native Go error as with other methods on Reader).
|
||||
func (r *Reader) ReadConfig(rootCall configs.StaticModuleCall) (*configs.Config, tfdiags.Diagnostics) {
|
||||
func (r *Reader) ReadConfig(ctx context.Context, rootCall configs.StaticModuleCall) (*configs.Config, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
snap, err := r.ReadConfigSnapshot()
|
||||
@@ -228,7 +229,7 @@ func (r *Reader) ReadConfig(rootCall configs.StaticModuleCall) (*configs.Config,
|
||||
|
||||
loader := configload.NewLoaderFromSnapshot(snap)
|
||||
rootDir := snap.Modules[""].Dir // Root module base directory
|
||||
config, configDiags := loader.LoadConfig(rootDir, rootCall)
|
||||
config, configDiags := loader.LoadConfig(ctx, rootDir, rootCall)
|
||||
diags = diags.Append(configDiags)
|
||||
|
||||
return config, diags
|
||||
|
||||
@@ -449,7 +449,7 @@ func (i *Installer) ensureProviderVersionsInstall(
|
||||
|
||||
for provider, version := range need {
|
||||
traceCtx, span := tracing.Tracer().Start(ctx,
|
||||
"Install Provider",
|
||||
fmt.Sprintf("Install Provider %q", provider.String()),
|
||||
trace.WithAttributes(
|
||||
otelAttr.String(traceattrs.ProviderAddress, provider.String()),
|
||||
otelAttr.String(traceattrs.ProviderVersion, version.String()),
|
||||
|
||||
@@ -551,7 +551,7 @@ func loadRefactoringFixture(t *testing.T, dir string) (*configs.Config, instance
|
||||
t.Fatalf("failed to refresh modules after installation: %s", err)
|
||||
}
|
||||
|
||||
rootCfg, diags := loader.LoadConfig(dir, configs.RootModuleCallForTesting())
|
||||
rootCfg, diags := loader.LoadConfig(t.Context(), dir, configs.RootModuleCallForTesting())
|
||||
if diags.HasErrors() {
|
||||
t.Fatalf("failed to load root module: %s", diags.Error())
|
||||
}
|
||||
|
||||
@@ -22,11 +22,16 @@ import (
|
||||
"github.com/hashicorp/go-retryablehttp"
|
||||
svchost "github.com/hashicorp/terraform-svchost"
|
||||
"github.com/hashicorp/terraform-svchost/disco"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
otelAttr "go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/httpclient"
|
||||
"github.com/opentofu/opentofu/internal/logging"
|
||||
"github.com/opentofu/opentofu/internal/registry/regsrc"
|
||||
"github.com/opentofu/opentofu/internal/registry/response"
|
||||
"github.com/opentofu/opentofu/internal/tracing"
|
||||
"github.com/opentofu/opentofu/internal/tracing/traceattrs"
|
||||
"github.com/opentofu/opentofu/version"
|
||||
)
|
||||
|
||||
@@ -90,6 +95,8 @@ func NewClient(services *disco.Disco, client *http.Client) *Client {
|
||||
retryableClient.RequestLogHook = requestLogHook
|
||||
retryableClient.ErrorHandler = maxRetryErrorHandler
|
||||
|
||||
retryableClient.HTTPClient.Transport = otelhttp.NewTransport(retryableClient.HTTPClient.Transport)
|
||||
|
||||
logOutput := logging.LogOutput()
|
||||
retryableClient.Logger = log.New(logOutput, "", log.Flags())
|
||||
|
||||
@@ -117,6 +124,13 @@ func (c *Client) Discover(host svchost.Hostname, serviceID string) (*url.URL, er
|
||||
|
||||
// ModuleVersions queries the registry for a module, and returns the available versions.
|
||||
func (c *Client) ModuleVersions(ctx context.Context, module *regsrc.Module) (*response.ModuleVersions, error) {
|
||||
ctx, span := tracing.Tracer().Start(ctx, "List Versions",
|
||||
trace.WithAttributes(
|
||||
otelAttr.String("opentofu.module.name", module.RawName),
|
||||
),
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
host, err := module.SvcHost()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -136,7 +150,7 @@ func (c *Client) ModuleVersions(ctx context.Context, module *regsrc.Module) (*re
|
||||
|
||||
log.Printf("[DEBUG] fetching module versions from %q", service)
|
||||
|
||||
req, err := retryablehttp.NewRequest("GET", service.String(), nil)
|
||||
req, err := retryablehttp.NewRequestWithContext(ctx, "GET", service.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -191,6 +205,15 @@ func (c *Client) addRequestCreds(host svchost.Hostname, req *http.Request) {
|
||||
// ModuleLocation find the download location for a specific version module.
|
||||
// This returns a string, because the final location may contain special go-getter syntax.
|
||||
func (c *Client) ModuleLocation(ctx context.Context, module *regsrc.Module, version string) (string, error) {
|
||||
ctx, span := tracing.Tracer().Start(ctx, "Find Module Location",
|
||||
trace.WithAttributes(
|
||||
otelAttr.String(traceattrs.ModuleCallName, module.RawName),
|
||||
otelAttr.String(traceattrs.ModuleSource, module.Module()),
|
||||
otelAttr.String(traceattrs.ModuleVersion, version),
|
||||
),
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
host, err := module.SvcHost()
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -214,7 +237,7 @@ func (c *Client) ModuleLocation(ctx context.Context, module *regsrc.Module, vers
|
||||
|
||||
log.Printf("[DEBUG] looking up module location from %q", download)
|
||||
|
||||
req, err := retryablehttp.NewRequest("GET", download.String(), nil)
|
||||
req, err := retryablehttp.NewRequestWithContext(ctx, "GET", download.String(), nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
"github.com/opentofu/opentofu/internal/configs/configload"
|
||||
"github.com/opentofu/opentofu/internal/configs/configschema"
|
||||
@@ -32,7 +34,6 @@ import (
|
||||
"github.com/opentofu/opentofu/internal/states/statefile"
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
tfversion "github.com/opentofu/opentofu/version"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -742,7 +743,7 @@ func contextOptsForPlanViaFile(t *testing.T, configSnap *configload.Snapshot, pl
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
config, diags := pr.ReadConfig(configs.RootModuleCallForTesting())
|
||||
config, diags := pr.ReadConfig(t.Context(), configs.RootModuleCallForTesting())
|
||||
if diags.HasErrors() {
|
||||
return nil, nil, nil, diags.Err()
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ func testModuleWithSnapshot(t testing.TB, name string) (*configs.Config, *config
|
||||
t.Fatalf("failed to refresh modules after installation: %s", err)
|
||||
}
|
||||
|
||||
config, snap, diags := loader.LoadConfigWithSnapshot(dir, configs.RootModuleCallForTesting())
|
||||
config, snap, diags := loader.LoadConfigWithSnapshot(t.Context(), dir, configs.RootModuleCallForTesting())
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Error())
|
||||
}
|
||||
@@ -133,7 +133,7 @@ func testModuleInline(t testing.TB, sources map[string]string) *configs.Config {
|
||||
t.Fatalf("failed to refresh modules after installation: %s", err)
|
||||
}
|
||||
|
||||
config, diags := loader.LoadConfigWithTests(cfgPath, "tests", configs.RootModuleCallForTesting())
|
||||
config, diags := loader.LoadConfigWithTests(t.Context(), cfgPath, "tests", configs.RootModuleCallForTesting())
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Error())
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ func TestMigrateStateProviderAddresses(t *testing.T) {
|
||||
var cfg *configs.Config
|
||||
if tt.args.configDir != "" {
|
||||
var hclDiags hcl.Diagnostics
|
||||
cfg, hclDiags = loader.LoadConfig(tt.args.configDir, configs.RootModuleCallForTesting())
|
||||
cfg, hclDiags = loader.LoadConfig(t.Context(), tt.args.configDir, configs.RootModuleCallForTesting())
|
||||
if hclDiags.HasErrors() {
|
||||
t.Fatalf("invalid configuration: %s", hclDiags.Error())
|
||||
}
|
||||
|
||||
@@ -12,4 +12,8 @@ const (
|
||||
ProviderVersion = "opentofu.provider.version"
|
||||
|
||||
TargetPlatform = "opentofu.target_platform"
|
||||
|
||||
ModuleCallName = "opentofu.module.name"
|
||||
ModuleSource = "opentofu.module.source"
|
||||
ModuleVersion = "opentofu.module.version"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user