Introduce plugin library and managers (#3652)
Some checks are pending
build / Build for freebsd_386 (push) Waiting to run
build / Build for linux_386 (push) Waiting to run
build / Build for openbsd_386 (push) Waiting to run
build / Build for windows_386 (push) Waiting to run
build / Build for freebsd_amd64 (push) Waiting to run
build / Build for linux_amd64 (push) Waiting to run
build / Build for openbsd_amd64 (push) Waiting to run
build / Build for solaris_amd64 (push) Waiting to run
build / Build for windows_amd64 (push) Waiting to run
build / Build for freebsd_arm (push) Waiting to run
build / Build for linux_arm (push) Waiting to run
build / Build for linux_arm64 (push) Waiting to run
build / Build for darwin_amd64 (push) Waiting to run
build / Build for darwin_arm64 (push) Waiting to run
build / End-to-end Tests for linux_386 (push) Waiting to run
build / End-to-end Tests for windows_386 (push) Waiting to run
build / End-to-end Tests for darwin_amd64 (push) Waiting to run
build / End-to-end Tests for linux_amd64 (push) Waiting to run
build / End-to-end Tests for windows_amd64 (push) Waiting to run
Quick Checks / List files changed for pull request (push) Waiting to run
Quick Checks / Unit tests for linux_386 (push) Blocked by required conditions
Quick Checks / Unit tests for linux_amd64 (push) Blocked by required conditions
Quick Checks / Unit tests for windows_amd64 (push) Blocked by required conditions
Quick Checks / Unit tests for linux_arm (push) Blocked by required conditions
Quick Checks / Unit tests for darwin_arm64 (push) Blocked by required conditions
Quick Checks / Unit tests for linux_arm64 (push) Blocked by required conditions
Quick Checks / Race Tests (push) Blocked by required conditions
Quick Checks / End-to-end Tests (push) Blocked by required conditions
Quick Checks / Code Consistency Checks (push) Blocked by required conditions
Quick Checks / License Checks (push) Waiting to run
Website checks / List files changed for pull request (push) Waiting to run
Website checks / Build (push) Blocked by required conditions
Website checks / Test Installation Instructions (push) Blocked by required conditions

Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
This commit is contained in:
Christian Mesh 2026-02-24 08:51:48 -05:00 committed by GitHub
parent d358f5743a
commit ef97fd2b51
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
57 changed files with 2421 additions and 2342 deletions

View file

@ -17,6 +17,7 @@ import (
"github.com/opentofu/opentofu/internal/backend"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/encryption"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/states/statemgr"
@ -105,9 +106,9 @@ func TestLocalProvider(t *testing.T, b *Local, name string, schema providers.Pro
}
// Set up our provider
b.ContextOpts.Providers = map[addrs.Provider]providers.Factory{
b.ContextOpts.Plugins = plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider(name): providers.FactoryFixed(p),
}
}, nil)
return p

View file

@ -1132,8 +1132,12 @@ func TestApply_shutdown(t *testing.T) {
},
}
// Provider is started multiple times, plus it's left running after the schema call
var stopOnce sync.Once
p.StopFn = func() error {
close(cancelled)
stopOnce.Do(func() {
close(cancelled)
})
return nil
}

View file

@ -39,6 +39,7 @@ import (
"github.com/opentofu/opentofu/internal/getmodules"
"github.com/opentofu/opentofu/internal/getproviders"
legacy "github.com/opentofu/opentofu/internal/legacy/tofu"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/states"
@ -568,13 +569,17 @@ func (m *Meta) contextOpts(ctx context.Context) (*tofu.ContextOpts, error) {
// and just work with what we've been given, thus allowing the tests
// to provide mock providers and provisioners.
if m.testingOverrides != nil {
opts.Providers = m.testingOverrides.Providers
opts.Provisioners = m.testingOverrides.Provisioners
opts.Plugins = plugins.NewLibrary(
m.testingOverrides.Providers,
m.testingOverrides.Provisioners,
)
} else {
var providerFactories map[addrs.Provider]providers.Factory
providerFactories, err = m.providerFactories()
opts.Providers = providerFactories
opts.Provisioners = m.provisionerFactories()
opts.Plugins = plugins.NewLibrary(
providerFactories,
m.provisionerFactories(),
)
}
opts.Meta = &tofu.ContextMeta{

View file

@ -1520,8 +1520,12 @@ func TestPlan_shutdown(t *testing.T) {
},
}
// Provider is started multiple times, plus it's left running after the schema call
var stopOnce sync.Once
p.StopFn = func() error {
close(cancelled)
stopOnce.Do(func() {
close(cancelled)
})
return nil
}

View file

@ -14,8 +14,8 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/lang/eval"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/tfdiags"
"github.com/zclconf/go-cty/cty"
)
@ -80,8 +80,8 @@ type Provisioners interface {
}
type newRuntimePlugins struct {
providers map[addrs.Provider]providers.Factory
provisioners map[string]provisioners.Factory
providers plugins.ProviderManager
provisioners plugins.ProvisionerManager
// unconfiguredInsts is all of the provider instances we've created for
// unconfigured uses such as schema fetching and validation, which we
@ -96,70 +96,41 @@ type newRuntimePlugins struct {
var _ Providers = (*newRuntimePlugins)(nil)
var _ Provisioners = (*newRuntimePlugins)(nil)
func NewRuntimePlugins(providers map[addrs.Provider]providers.Factory, provisioners map[string]provisioners.Factory) Plugins {
func NewRuntimePluginsTemp(providerManager plugins.ProviderManager, provisionerManager plugins.ProvisionerManager) Plugins {
return &newRuntimePlugins{
providers: providers,
provisioners: provisioners,
providers: providerManager,
provisioners: provisionerManager,
unconfiguredInsts: map[addrs.Provider]providers.Unconfigured{},
}
}
func NewRuntimePlugins(plugins plugins.Library) Plugins {
return &newRuntimePlugins{
providers: plugins.NewProviderManager(),
provisioners: plugins.NewProvisionerManager(),
unconfiguredInsts: map[addrs.Provider]providers.Unconfigured{},
}
}
// NewConfiguredProvider implements evalglue.Providers.
func (n *newRuntimePlugins) NewConfiguredProvider(ctx context.Context, provider addrs.Provider, configVal cty.Value) (providers.Configured, tfdiags.Diagnostics) {
inst, diags := n.newProviderInst(ctx, provider)
if diags.HasErrors() {
return nil, diags
}
unmarkedConfigVal, _ := configVal.UnmarkDeep()
resp := inst.ConfigureProvider(ctx, providers.ConfigureProviderRequest{
Config: unmarkedConfigVal,
// We aren't actually Terraform, so we'll just pretend to be a
// Terraform version that has roughly the same functionality that
// OpenTofu currently has, since providers are permitted to use this to
// adapt their behavior for older versions of Terraform.
TerraformVersion: "1.13.0",
})
diags = diags.Append(resp.Diagnostics)
if resp.Diagnostics.HasErrors() {
return nil, diags
}
return inst, diags
return n.providers.NewConfiguredProvider(ctx, provider, configVal)
}
// ProviderConfigSchema implements evalglue.Providers.
func (n *newRuntimePlugins) ProviderConfigSchema(ctx context.Context, provider addrs.Provider) (*providers.Schema, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
inst, moreDiags := n.unconfiguredProviderInst(ctx, provider)
diags = diags.Append(moreDiags)
if moreDiags.HasErrors() {
schema, diags := n.providers.GetProviderSchema(ctx, provider)
if diags.HasErrors() {
return nil, diags
}
resp := inst.GetProviderSchema(ctx)
diags = diags.Append(resp.Diagnostics)
if resp.Diagnostics.HasErrors() {
return nil, diags
}
return &resp.Provider, diags
return &schema.Provider, diags
}
// ResourceTypeSchema implements evalglue.Providers.
func (n *newRuntimePlugins) ResourceTypeSchema(ctx context.Context, provider addrs.Provider, mode addrs.ResourceMode, typeName string) (*providers.Schema, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
inst, moreDiags := n.unconfiguredProviderInst(ctx, provider)
diags = diags.Append(moreDiags)
if moreDiags.HasErrors() {
return nil, diags
}
resp := inst.GetProviderSchema(ctx)
diags = diags.Append(resp.Diagnostics)
if resp.Diagnostics.HasErrors() {
schema, diags := n.providers.GetProviderSchema(ctx, provider)
if diags.HasErrors() {
return nil, diags
}
@ -171,11 +142,11 @@ func (n *newRuntimePlugins) ResourceTypeSchema(ctx context.Context, provider add
var types map[string]providers.Schema
switch mode {
case addrs.ManagedResourceMode:
types = resp.ResourceTypes
types = schema.ResourceTypes
case addrs.DataResourceMode:
types = resp.DataSources
types = schema.DataSources
case addrs.EphemeralResourceMode:
types = resp.EphemeralResources
types = schema.EphemeralResources
default:
// We don't support any other modes, so we'll just treat these as
// a request for a resource type that doesn't exist at all.
@ -255,7 +226,7 @@ func (m *newRuntimePlugins) unconfiguredProviderInst(ctx context.Context, provid
return running, nil
}
inst, diags := m.newProviderInst(ctx, provider)
inst, diags := m.providers.NewProvider(ctx, provider)
if diags.HasErrors() {
return nil, diags
}
@ -267,47 +238,6 @@ func (m *newRuntimePlugins) unconfiguredProviderInst(ctx context.Context, provid
return inst, diags
}
// newProviderInst creates a new instance of the given provider.
//
// The result is not retained anywhere inside the receiver. Each call to this
// function returns a new object. A successful result is always an unconfigured
// provider, but we return [providers.Interface] in case the caller would like
// to subsequently configure the result before returning it as
// [providers.Configured].
//
// If you intend to use the resulting instance only for "unconfigured"
// operations like fetching schema, use
// [newRuntimePlugins.unconfiguredProviderInst] instead to potentially reuse
// an already-active instance of the same provider.
func (m *newRuntimePlugins) newProviderInst(_ context.Context, provider addrs.Provider) (providers.Interface, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
factory, ok := m.providers[provider]
if !ok {
// FIXME: If this error remains reachable in the final version of this
// code (i.e. if some caller isn't already guaranteeing that all
// providers from the configuration and state are included here) then
// we should make this error message more actionable.
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Provider unavailable",
fmt.Sprintf("This configuration requires provider %q, but it isn't installed.", provider),
))
return nil, diags
}
inst, err := factory()
if err != nil {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Provider failed to start",
fmt.Sprintf("Failed to launch provider %q: %s.", provider, tfdiags.FormatError(err)),
))
return nil, diags
}
return inst, diags
}
// ProvisionerConfigSchema implements evalglue.Provisioners.
func (n *newRuntimePlugins) ProvisionerConfigSchema(ctx context.Context, typeName string) (*configschema.Block, tfdiags.Diagnostics) {
// TODO: Implement this in terms of [newRuntimePlugins.provisioners].
@ -328,13 +258,6 @@ func (n *newRuntimePlugins) Close(ctx context.Context) error {
n.mu.Lock()
defer n.mu.Unlock()
var errs error
for addr, p := range n.unconfiguredInsts {
err := p.Close(ctx)
if err != nil {
errs = errors.Join(errs, fmt.Errorf("closing provider %q: %w", addr, err))
}
}
n.unconfiguredInsts = nil // discard all of the memoized instances
return errs
return errors.Join(n.providers.CloseAll(ctx), n.provisioners.CloseAll())
}

21
internal/plugins/doc.go Normal file
View file

@ -0,0 +1,21 @@
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
// The plugins package abstracts away many of the details in managing provider and provisioner plugins.
//
// It's primary goal is to provide a library of plugins, who's instances can be managed in different concurrent
// scopes. It also handles many of the complexities around correctly caching plugin schemas.
//
// This package was introduced to solve the following problems:
// * De-duplicate common logic between the original tofu engine and the new engine implementation
// * Re-use this common logic for backends as plugins / PSS
// * Potentially allow plugins to be used by middleware/integrations/etc... (still in the design phase)
// * Properly fix the global schema cache replacement
// * Ensure that provider schema validation is actually called (heavily bugged before)
//
// It's current design intentions are that of a building block, and is not highly opinionated on abstracting
// away the implementation details of plugins.
package plugins

View file

@ -0,0 +1,71 @@
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package plugins
import (
"sync"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/tfdiags"
)
// Library represents a suite of provider and provisioner plugins. It does not expose
// much functionality itself, instead serving as a starting point for the more complex
// managers.
type Library interface {
NewProviderManager() ProviderManager
NewProvisionerManager() ProvisionerManager
HasProvider(addr addrs.Provider) bool
HasProvisioner(typ string) bool
}
func NewLibrary(providerFactories ProviderFactories, provisionerFactories ProvisionerFactories) Library {
return &library{
providerFactories: providerFactories,
providerSchemas: map[addrs.Provider]*providerSchemaEntry{},
provisionerFactories: provisionerFactories,
provisionerSchemas: map[string]*provisionerSchemaEntry{},
}
}
// library is the default Library implementation, with included fields to facilitate
// schema caching among managers.
type library struct {
providerSchemasLock sync.Mutex
providerSchemas map[addrs.Provider]*providerSchemaEntry
providerFactories ProviderFactories
provisionerSchemasLock sync.Mutex
provisionerSchemas map[string]*provisionerSchemaEntry
provisionerFactories ProvisionerFactories
}
type providerSchemaEntry struct {
sync.Mutex
populated bool
schema providers.ProviderSchema
diags tfdiags.Diagnostics
}
type provisionerSchemaEntry struct {
sync.Mutex
populated bool
schema *configschema.Block
err error
}
func (l *library) HasProvider(addr addrs.Provider) bool {
return l.providerFactories.HasProvider(addr)
}
func (l *library) HasProvisioner(typ string) bool {
return l.provisionerFactories.HasProvisioner(typ)
}

View file

@ -0,0 +1,238 @@
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package plugins
import (
"context"
"errors"
"fmt"
"log"
"sync"
"sync/atomic"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/tfdiags"
"github.com/opentofu/opentofu/version"
"github.com/zclconf/go-cty/cty"
)
type ProviderFactories map[addrs.Provider]providers.Factory
func (p ProviderFactories) HasProvider(addr addrs.Provider) bool {
_, ok := p[addr]
return ok
}
func (p ProviderFactories) NewInstance(addr addrs.Provider) (providers.Interface, error) {
f, ok := p[addr]
if !ok {
return nil, fmt.Errorf("unavailable provider %q", addr)
}
return f()
}
// ProviderManager allows for spawning, tracking and management of provider instances.
type ProviderManager interface {
// HasProvider checks to see if the underlying library contains a given provider.
HasProvider(addr addrs.Provider) bool
// GetProviderSchema returns a fully validated and cached provider schema. This should
// always be preferred to accessing the schema directly from a provider.
GetProviderSchema(ctx context.Context, addr addrs.Provider) (providers.ProviderSchema, tfdiags.Diagnostics)
// NewProvider starts and tracks a new provider instance of the given type.
NewProvider(ctx context.Context, addr addrs.Provider) (providers.Interface, tfdiags.Diagnostics)
// NewConfiguredProvider starts, configures, and tracks a new provider instance of the give type.
NewConfiguredProvider(ctx context.Context, addr addrs.Provider, cfgVal cty.Value) (providers.Configured, tfdiags.Diagnostics)
// StopAll gracefully requests all tracked providers to stop.
// See [providers.Unconfigured.Stop] for more information.
StopAll(context.Context) error
// CloseAll forcefully closes all tracked providers.
// See [providers.Unconfigured.Close] for more information.
// See cmd/tofu/main.go:plugin.CleanupClients for the fallback.
CloseAll(context.Context) error
// Shutdown locks the provider manager in a Shutdown state and calls CloseAll,
// preventing any further usage of this object.
Shutdown(context.Context) error
}
type providerManager struct {
*library
instancesLock sync.Mutex
instances []providers.Configured
isShutdown atomic.Bool
}
func (l *library) NewProviderManager() ProviderManager {
return &providerManager{
library: l,
}
}
func (p *providerManager) HasProvider(addr addrs.Provider) bool {
return p.providerFactories.HasProvider(addr)
}
func (p *providerManager) GetProviderSchema(ctx context.Context, addr addrs.Provider) (providers.ProviderSchema, tfdiags.Diagnostics) {
if p.isShutdown.Load() {
// It's technically possible, but highly unlikely that a manager could be shutdown while fetching the schema
// In that scenario, we will start and then stop the corresponding provider internally to this function and not
// interfere with the set of known instances.
return providers.ProviderSchema{}, tfdiags.Diagnostics{}.Append(fmt.Errorf("bug: unable to start provider %s, manager is shutdown", addr))
}
// Coarse lock only for ensuring that a valid entry exists
p.providerSchemasLock.Lock()
entry, ok := p.providerSchemas[addr]
if !ok {
entry = &providerSchemaEntry{}
p.providerSchemas[addr] = entry
}
// This lock is only for access to the map. We don't need to hold the lock when updating the entry
// because we lock the individual entry for all access.
// We don't defer unlock as the majority of the work of this function happens in updating the entry
// and we want to release as soon as possible for multiple concurrent callers of different providers
p.providerSchemasLock.Unlock()
entry.Lock()
defer entry.Unlock()
if !entry.populated {
log.Printf("[TRACE] plugins.providerManager Initializing provider %q to read its schema", addr)
provider, err := p.providerFactories.NewInstance(addr)
if err != nil {
// Might be a transient error. Don't memoize this result
return providers.ProviderSchema{}, tfdiags.Diagnostics{}.Append(fmt.Errorf("failed to instantiate provider %q to obtain schema: %w", addr, err))
}
// TODO consider using the p.NewProvider(ctx, addr) call once we have a clear
// .Close() call for all usages of the provider manager
defer provider.Close(context.WithoutCancel(ctx))
entry.schema = provider.GetProviderSchema(ctx)
entry.diags = entry.diags.Append(entry.schema.Diagnostics)
entry.populated = true
if !entry.diags.HasErrors() {
// Validate only if GetProviderSchema succeeded
err := entry.schema.Validate(addr)
entry.diags = entry.diags.Append(err)
}
}
return entry.schema, entry.diags
}
func (p *providerManager) NewProvider(ctx context.Context, addr addrs.Provider) (providers.Interface, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
p.instancesLock.Lock()
defer p.instancesLock.Unlock()
if p.isShutdown.Load() {
return nil, diags.Append(fmt.Errorf("bug: unable to start provider %s, manager is shutdown", addr))
}
provider, err := p.providerFactories.NewInstance(addr)
if err != nil {
return nil, diags.Append(err)
}
p.instances = append(p.instances, provider)
return provider, diags
}
func (p *providerManager) NewConfiguredProvider(ctx context.Context, addr addrs.Provider, configVal cty.Value) (providers.Configured, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
p.instancesLock.Lock()
defer p.instancesLock.Unlock()
if p.isShutdown.Load() {
return nil, diags.Append(fmt.Errorf("bug: unable to start provider %s, manager is shutdown", addr))
}
provider, err := p.providerFactories.NewInstance(addr)
if err != nil {
return nil, diags.Append(err)
}
p.instances = append(p.instances, provider)
// If our config value contains any marked values, ensure those are
// stripped out before sending this to the provider
unmarkedConfigVal, _ := configVal.UnmarkDeep()
// Allow the provider to validate and insert any defaults into the full
// configuration.
req := providers.ValidateProviderConfigRequest{
Config: unmarkedConfigVal,
}
// ValidateProviderConfig is only used for validation. We are intentionally
// ignoring the PreparedConfig field to maintain existing behavior.
validateResp := provider.ValidateProviderConfig(ctx, req)
diags = diags.Append(validateResp.Diagnostics)
if diags.HasErrors() {
return nil, diags
}
// If the provider returns something different, log a warning to help
// indicate to provider developers that the value is not used.
preparedCfg := validateResp.PreparedConfig
if preparedCfg != cty.NilVal && !preparedCfg.IsNull() && !preparedCfg.RawEquals(unmarkedConfigVal) {
log.Printf("[WARN] ValidateProviderConfig from %q changed the config value, but that value is unused", addr)
}
configResp := provider.ConfigureProvider(ctx, providers.ConfigureProviderRequest{
// We aren't actually Terraform, so we'll just pretend to be a
// Terraform version that has roughly the same functionality that
// OpenTofu currently has, since providers are permitted to use this to
// adapt their behavior for older versions of Terraform.
TerraformVersion: version.VersionToImpersonateForProviders,
Config: unmarkedConfigVal,
})
diags = diags.Append(configResp.Diagnostics)
return provider, diags
}
func (p *providerManager) StopAll(ctx context.Context) error {
p.instancesLock.Lock()
defer p.instancesLock.Unlock()
var errs []error
for _, instance := range p.instances {
errs = append(errs, instance.Stop(ctx))
}
return errors.Join(errs...)
}
func (p *providerManager) CloseAll(ctx context.Context) error {
p.instancesLock.Lock()
defer p.instancesLock.Unlock()
var errs []error
for _, instance := range p.instances {
errs = append(errs, instance.Close(ctx))
}
return errors.Join(errs...)
}
func (p *providerManager) Shutdown(ctx context.Context) error {
// Disable any further usage of this manager
p.isShutdown.Store(true)
return p.CloseAll(ctx)
}

View file

@ -0,0 +1,207 @@
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package plugins
import (
"context"
"fmt"
"log"
"sync"
"sync/atomic"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/tfdiags"
"github.com/zclconf/go-cty/cty"
)
type ProvisionerFactories map[string]provisioners.Factory
func (p ProvisionerFactories) HasProvisioner(typ string) bool {
_, ok := p[typ]
return ok
}
func (p ProvisionerFactories) NewInstance(typ string) (provisioners.Interface, error) {
f, ok := p[typ]
if !ok {
return nil, fmt.Errorf("unavailable provisioner %q", typ)
}
return f()
}
// ProvisionerManager exposes provisioner functionality through functions, instead
// of providing access to the provisioner instances themselves.
type ProvisionerManager interface {
// HasProvisioner checks to see if the underlying library contains a given provisioner.
HasProvisioner(typ string) bool
// ProvisionerSchema is a caching wrapper for [provisioners.Interface.GetSchema]
ProvisionerSchema(typ string) (*configschema.Block, error)
// [provisioners.Interface.ValidateProvisionerConfig]
ValidateProvisionerConfig(ctx context.Context, typ string, config cty.Value) tfdiags.Diagnostics
// [provisioners.Interface.ProvisionResource]
ProvisionResource(ctx context.Context, typ string, config cty.Value, connection cty.Value, output provisioners.UIOutput) tfdiags.Diagnostics
// StopAll gracefully requests all tracked provisioners to stop.
// See [provisioners.Interface.Stop] for more information.
StopAll() error
// CloseAll forcefully closes all tracked provisioners.
// See [provisioners.Interface.Close] for more information.
// See cmd/tofu/main.go:plugin.CleanupClients for the fallback.
CloseAll() error
// Shutdown locks the provisioner manager in a Shutdown state and calls CloseAll,
// preventing any further usage of this object.
Shutdown() error
}
type provisionerManager struct {
*library
instancesLock sync.Mutex
instances map[string]provisioners.Interface
isShutdown atomic.Bool
}
func (l *library) NewProvisionerManager() ProvisionerManager {
return &provisionerManager{
library: l,
instances: map[string]provisioners.Interface{},
}
}
func (p *provisionerManager) HasProvisioner(typ string) bool {
return p.provisionerFactories.HasProvisioner(typ)
}
func (p *provisionerManager) provisioner(typ string) (provisioners.Interface, error) {
p.instancesLock.Lock()
defer p.instancesLock.Unlock()
if p.isShutdown.Load() {
return nil, fmt.Errorf("bug: unable to start provisioner %s, manager is shutdown", typ)
}
instance, ok := p.instances[typ]
if !ok {
var err error
instance, err = p.provisionerFactories.NewInstance(typ)
if err != nil {
return nil, err
}
p.instances[typ] = instance
}
return instance, nil
}
// ProvisionerSchema uses a temporary instance of the provisioner with the
// given type name to obtain the schema for that provisioner's configuration.
//
// ProvisionerSchema memoizes results by provisioner type name, so it's fine
// to repeatedly call this method with the same name if various different
// parts of OpenTofu all need the same schema information.
func (p *provisionerManager) ProvisionerSchema(typ string) (*configschema.Block, error) {
// Coarse lock only for ensuring that a valid entry exists
p.provisionerSchemasLock.Lock()
entry, ok := p.provisionerSchemas[typ]
if !ok {
entry = &provisionerSchemaEntry{}
p.provisionerSchemas[typ] = entry
}
// This lock is only for access to the map. We don't need to hold the lock when updating the entry
// because we lock the individual entry for all access.
// We don't defer unlock as the majority of the work of this function happens in updating the entry
// and we want to release as soon as possible for multiple concurrent callers of different provisioners
p.provisionerSchemasLock.Unlock()
entry.Lock()
defer entry.Unlock()
if !entry.populated {
log.Printf("[TRACE] Initializing provisioner %q to read its schema", typ)
provisioner, err := p.provisionerFactories.NewInstance(typ)
if err != nil {
// Might be a transient error. Don't memoize this result
return nil, fmt.Errorf("failed to instantiate provisioner %q to obtain schema: %w", typ, err)
}
// TODO consider using the p.provisioner(typ) call once we have a clear
// .Close() call for all usages of the provisioner manager
defer provisioner.Close()
resp := provisioner.GetSchema()
entry.populated = true
entry.schema = resp.Provisioner
if resp.Diagnostics.HasErrors() {
entry.err = fmt.Errorf("failed to retrieve schema from provisioner %q: %w", typ, resp.Diagnostics.Err())
}
}
return entry.schema, entry.err
}
func (p *provisionerManager) ValidateProvisionerConfig(ctx context.Context, typ string, config cty.Value) tfdiags.Diagnostics {
provisioner, err := p.provisioner(typ)
if err != nil {
return tfdiags.Diagnostics{}.Append(fmt.Errorf("failed to instantiate provisioner %q to validate config: %w", typ, err))
}
return provisioner.ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{
Config: config,
}).Diagnostics
}
func (p *provisionerManager) ProvisionResource(ctx context.Context, typ string, config cty.Value, connection cty.Value, output provisioners.UIOutput) tfdiags.Diagnostics {
provisioner, err := p.provisioner(typ)
if err != nil {
return tfdiags.Diagnostics{}.Append(fmt.Errorf("failed to instantiate provisioner %q to provision resource: %w", typ, err))
}
return provisioner.ProvisionResource(provisioners.ProvisionResourceRequest{
Config: config,
Connection: connection,
UIOutput: output,
}).Diagnostics
}
func (p *provisionerManager) StopAll() error {
p.instancesLock.Lock()
defer p.instancesLock.Unlock()
var diags tfdiags.Diagnostics
for name, prov := range p.instances {
err := prov.Stop()
if err != nil {
diags = diags.Append(fmt.Errorf("provisioner.Stop %s: %w", name, err))
}
}
return diags.Err()
}
func (p *provisionerManager) CloseAll() error {
p.instancesLock.Lock()
defer p.instancesLock.Unlock()
var diags tfdiags.Diagnostics
for name, prov := range p.instances {
err := prov.Close()
if err != nil {
diags = diags.Append(fmt.Errorf("provisioner.Close %s: %w", name, err))
}
}
clear(p.instances)
return diags.Err()
}
func (p *provisionerManager) Shutdown() error {
// Disable any further usage of this manager
p.isShutdown.Store(true)
return p.CloseAll()
}

View file

@ -18,6 +18,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/initwd"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tofu"
@ -286,9 +287,9 @@ func testSession(t *testing.T, test testSessionTest) {
// Build the TF context
ctx, diags := tofu.NewContext(&tofu.ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): providers.FactoryFixed(p),
},
}, nil),
})
if diags.HasErrors() {
t.Fatalf("failed to create context: %s", diags.Err())

View file

@ -15,6 +15,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
)
@ -107,9 +108,9 @@ func BenchmarkManyResourceInstances(b *testing.B) {
},
}
tofuCtx := testContext2(b, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewBuiltInProvider("test"): testProviderFuncFixed(p),
},
}, nil),
// With this many resource instances we need a high concurrency limit
// for the runtime to be in any way reasonable. In this case we're
// going to set it so high that there is effectively no limit at all,
@ -229,7 +230,7 @@ func BenchmarkManyModuleInstances(b *testing.B) {
`,
})
tofuCtx := testContext2(b, &ContextOpts{
Providers: nil, // no providers for this test
Plugins: nil, // no providers for this test
// With this many resource instances we need a high concurrency limit
// for the runtime to be in any way reasonable. In this case we're
// going to set it so high that there is effectively no limit at all,

View file

@ -14,12 +14,10 @@ import (
"github.com/zclconf/go-cty/cty"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/encryption"
"github.com/opentofu/opentofu/internal/logging"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
)
@ -40,12 +38,11 @@ const (
// ContextOpts are the user-configurable options to create a context with
// NewContext.
type ContextOpts struct {
Meta *ContextMeta
Hooks []Hook
Parallelism int
Providers map[addrs.Provider]providers.Factory
Provisioners map[string]provisioners.Factory
Encryption encryption.Encryption
Meta *ContextMeta
Hooks []Hook
Parallelism int
Plugins plugins.Library
Encryption encryption.Encryption
UIInput UIInput
}
@ -135,7 +132,7 @@ func NewContext(opts *ContextOpts) (*Context, tfdiags.Diagnostics) {
par = 10
}
plugins := newContextPlugins(opts.Providers, opts.Provisioners)
plugins := newContextPlugins(opts.Plugins)
log.Printf("[TRACE] tofu.NewContext: complete")
@ -291,44 +288,16 @@ func (c *Context) watchStop(walker *ContextGraphWalker) (chan struct{}, <-chan s
// If we're here, we're stopped, trigger the call.
log.Printf("[TRACE] Context: requesting providers and provisioners to gracefully stop")
{
// Copy the providers so that a misbehaved blocking Stop doesn't
// completely hang OpenTofu.
walker.providerLock.Lock()
toStop := make([]providers.Interface, 0, len(walker.providerCache))
for _, providerMap := range walker.providerCache {
for _, provider := range providerMap {
toStop = append(toStop, provider)
}
}
defer walker.providerLock.Unlock()
for _, p := range toStop {
// We ignore the error for now since there isn't any reasonable
// action to take if there is an error here, since the stop is still
// advisory: OpenTofu will exit once the graph node completes.
// The providers.Interface API contract requires that the
// context passed to Stop is never canceled and has no deadline.
_ = p.Stop(context.WithoutCancel(context.TODO()))
}
}
{
// Call stop on all the provisioners
walker.provisionerLock.Lock()
ps := make([]provisioners.Interface, 0, len(walker.provisionerCache))
for _, p := range walker.provisionerCache {
ps = append(ps, p)
}
defer walker.provisionerLock.Unlock()
for _, p := range ps {
// We ignore the error for now since there isn't any reasonable
// action to take if there is an error here, since the stop is still
// advisory: OpenTofu will exit once the graph node completes.
_ = p.Stop()
}
}
// We ignore the error for now since there isn't any reasonable
// action to take if there is an error here, since the stop is still
// advisory: OpenTofu will exit once the graph node completes.
// The providers.Interface API contract requires that the
// context passed to Stop is never canceled and has no deadline.
_ = walker.Context.plugins.providers.StopAll(context.WithoutCancel(context.TODO()))
// We ignore the error for now since there isn't any reasonable
// action to take if there is an error here, since the stop is still
// advisory: OpenTofu will exit once the graph node completes.
_ = walker.Context.plugins.provisioners.StopAll()
}()
return stop, wait

View file

@ -31,6 +31,7 @@ import (
"github.com/opentofu/opentofu/internal/encryption"
"github.com/opentofu/opentofu/internal/lang/marks"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/states/statefile"
@ -72,9 +73,9 @@ func TestContext2Apply_createBeforeDestroy_deposedKeyPreApply(t *testing.T) {
hook := new(MockHook)
ctx := testContext2(t, &ContextOpts{
Hooks: []Hook{hook},
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, DefaultPlanOpts)
@ -159,9 +160,9 @@ func TestContext2Apply_createBeforeDestroy_dependsNonCBDUpdate(t *testing.T) {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, DefaultPlanOpts)
@ -250,7 +251,7 @@ output "data" {
}
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), DefaultPlanOpts)
@ -265,7 +266,7 @@ output "data" {
// now destroy the whole thing
ctx = testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags = ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -335,9 +336,9 @@ resource "test_instance" "a" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, DefaultPlanOpts)
@ -427,9 +428,9 @@ resource "aws_instance" "bin" {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, DefaultPlanOpts)
@ -531,9 +532,9 @@ resource "test_resource" "b" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
@ -572,9 +573,9 @@ output "out" {
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), DefaultPlanOpts)
@ -676,9 +677,9 @@ func TestContext2Apply_sensitiveInsideUnknown(t *testing.T) {
}
tofuCtx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.MustParseProviderSourceString("example.com/foo/test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := tofuCtx.Plan(t.Context(), m, states.NewState(), SimplePlanOpts(plans.NormalMode, nil))
@ -747,9 +748,9 @@ resource "test_object" "y" {
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
@ -801,9 +802,9 @@ resource "test_object" "x" {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -857,9 +858,9 @@ resource "test_object" "x" {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -938,9 +939,9 @@ resource "test_object" "s" {
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), DefaultPlanOpts)
@ -988,9 +989,9 @@ resource "test_object" "s" {
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), DefaultPlanOpts)
@ -1044,9 +1045,9 @@ resource "test_object" "b" {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -1120,9 +1121,9 @@ resource "test_resource" "c" {
return resp
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
t.Run("condition pass", func(t *testing.T) {
@ -1430,9 +1431,9 @@ func TestContext2Apply_resourceConditionApplyTimeFail(t *testing.T) {
return resp
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
instA := mustResourceInstanceAddr("test_resource.a")
instB := mustResourceInstanceAddr("test_resource.b")
@ -1626,10 +1627,10 @@ output "out" {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(testProvider),
addrs.NewDefaultProvider("other"): testProviderFuncFixed(otherProvider),
},
}, nil),
})
opts := SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables))
@ -1748,9 +1749,9 @@ resource "test_object" "x" {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -1799,9 +1800,9 @@ resource "test_object" "y" {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
opts := SimplePlanOpts(plans.NormalMode, nil)
@ -1880,9 +1881,9 @@ output "data" {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
// apply the state
@ -1956,9 +1957,9 @@ output "from_resource" {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
opts := SimplePlanOpts(plans.DestroyMode, nil)
@ -2013,9 +2014,9 @@ output "from_resource" {
mod.SetOutputValue("from_resource", cty.StringVal("wrong val"), false, "")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
opts := SimplePlanOpts(plans.RefreshOnlyMode, nil)
@ -2083,9 +2084,9 @@ resource "test_object" "y" {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
opts := SimplePlanOpts(plans.NormalMode, nil)
@ -2118,9 +2119,9 @@ resource "test_object" "y" {
func TestContext2Apply_preconditionErrorMessageRef(t *testing.T) {
p := testProvider("test")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
m := testModuleInline(t, map[string]string{
@ -2165,9 +2166,9 @@ output "a" {
func TestContext2Apply_destroyNullModuleOutput(t *testing.T) {
p := testProvider("test")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
m := testModuleInline(t, map[string]string{
@ -2272,9 +2273,9 @@ output "resources" {
},
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
Mode: plans.NormalMode,
@ -2359,9 +2360,9 @@ resource "test_resource" "b" {
}
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
Mode: plans.NormalMode,
@ -2377,10 +2378,10 @@ func TestContext2Apply_destroyUnusedModuleProvider(t *testing.T) {
unusedProvider := testProvider("unused")
testProvider := testProvider("test")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(testProvider),
addrs.NewDefaultProvider("unused"): testProviderFuncFixed(unusedProvider),
},
}, nil),
})
unusedProvider.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
@ -2462,9 +2463,9 @@ import {
hook := new(MockHook)
ctx := testContext2(t, &ContextOpts{
Hooks: []Hook{hook},
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
Mode: plans.NormalMode,
@ -2504,9 +2505,9 @@ locals {
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), nil)
@ -2542,9 +2543,9 @@ locals {
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -2606,9 +2607,9 @@ func TestContext2Apply_forgetOrphanAndDeposed(t *testing.T) {
addrs.NoKey,
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.PlanResourceChangeFn = testDiffFn
@ -2675,9 +2676,9 @@ func TestContext2Apply_forgetOrphanAndDeposedWithDynamicProvider(t *testing.T) {
addrs.StringKey("a"),
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.PlanResourceChangeFn = testDiffFn
@ -2864,9 +2865,9 @@ func TestContext2Apply_providerExpandWithTargetOrExclude(t *testing.T) {
`,
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewBuiltInProvider("mock"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, normalPlanOpts)
assertNoErrors(t, diags)
@ -2932,9 +2933,9 @@ func TestContext2Apply_providerExpandWithTargetOrExclude(t *testing.T) {
`,
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewBuiltInProvider("mock"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, makeStep2PlanOpts(plans.NormalMode))
assertNoErrors(t, diags)
@ -3005,9 +3006,9 @@ func TestContext2Apply_providerExpandWithTargetOrExclude(t *testing.T) {
`,
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewBuiltInProvider("mock"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, normalPlanOpts)
assertNoErrors(t, diags)
@ -3069,9 +3070,9 @@ func TestContext2Apply_moduleProviderAliasExcludes(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -3109,9 +3110,9 @@ func TestContext2Apply_moduleProviderAliasExcludesNonExistent(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -3149,9 +3150,9 @@ func TestContext2Apply_moduleExclude(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -3185,9 +3186,9 @@ func TestContext2Apply_moduleExcludeDependent(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -3216,9 +3217,9 @@ func TestContext2Apply_moduleExcludeNonExistent(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -3267,9 +3268,9 @@ func TestContext2Apply_destroyExcludedNonExistentWithModuleVariableAndCount(t *t
var state *states.State
{
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
// First plan and apply a create operation
@ -3284,9 +3285,9 @@ func TestContext2Apply_destroyExcludedNonExistentWithModuleVariableAndCount(t *t
{
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -3356,9 +3357,9 @@ func TestContext2Apply_destroyExcludedWithModuleVariableAndCount(t *testing.T) {
var state *states.State
{
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
// First plan and apply a create operation
@ -3373,9 +3374,9 @@ func TestContext2Apply_destroyExcludedWithModuleVariableAndCount(t *testing.T) {
{
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -3428,9 +3429,9 @@ func TestContext2Apply_excluded(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -3468,9 +3469,9 @@ func TestContext2Apply_excludedCount(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -3510,9 +3511,9 @@ func TestContext2Apply_excludedCountIndex(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -3562,9 +3563,9 @@ func TestContext2Apply_excludedDestroy(t *testing.T) {
var state *states.State
{
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
// First plan and apply a create operation
@ -3583,9 +3584,9 @@ func TestContext2Apply_excludedDestroy(t *testing.T) {
{
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -3626,9 +3627,9 @@ func TestContext2Apply_excludedDestroyDependent(t *testing.T) {
var state *states.State
{
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
// First plan and apply a create operation
@ -3647,9 +3648,9 @@ func TestContext2Apply_excludedDestroyDependent(t *testing.T) {
{
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -3735,9 +3736,9 @@ func TestContext2Apply_excludedDestroyCountDeps(t *testing.T) {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -3813,9 +3814,9 @@ func TestContext2Apply_excludedDependentDestroyCountDeps(t *testing.T) {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -3897,9 +3898,9 @@ func TestContext2Apply_excludedDestroyModule(t *testing.T) {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -3979,9 +3980,9 @@ func TestContext2Apply_excludedDestroyCountIndex(t *testing.T) {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -4018,9 +4019,9 @@ func TestContext2Apply_excludedModule(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -4061,9 +4062,9 @@ func TestContext2Apply_excludedModuleResourceDep(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -4096,9 +4097,9 @@ func TestContext2Apply_excludedResourceDependentOnModule(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -4134,9 +4135,9 @@ func TestContext2Apply_excludedModuleDep(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -4170,9 +4171,9 @@ func TestContext2Apply_excludedModuleUnrelatedOutputs(t *testing.T) {
state := states.NewState()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -4217,9 +4218,9 @@ func TestContext2Apply_excludedModuleResource(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -4277,9 +4278,9 @@ func TestContext2Apply_excludedResourceOrphanModule(t *testing.T) {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -4330,9 +4331,9 @@ func TestContext2Apply_excludedOrphanModule(t *testing.T) {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -4381,9 +4382,9 @@ func TestContext2Apply_excludedWithTaintedInState(t *testing.T) {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{
@ -4404,9 +4405,9 @@ func TestContext2Apply_excludedWithTaintedInState(t *testing.T) {
t.Fatalf("failed to round-trip through planfile: %s", err)
}
ctxOpts.Providers = map[addrs.Provider]providers.Factory{
ctxOpts.Plugins = plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
}
}, nil)
ctx, diags = NewContext(ctxOpts)
if diags.HasErrors() {
@ -4439,9 +4440,9 @@ func TestContext2Apply_excludedModuleRecursive(t *testing.T) {
p.PlanResourceChangeFn = testDiffFn
p.ApplyResourceChangeFn = testApplyFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{
@ -4561,7 +4562,7 @@ data "test_data_source" "b_direct" {
apply := func(t *testing.T, m *configs.Config, prevState *states.State) (*states.State, tfdiags.Diagnostics) {
t.Helper()
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, prevState, DefaultPlanOpts)
@ -4574,7 +4575,7 @@ data "test_data_source" "b_direct" {
destroy := func(t *testing.T, m *configs.Config, prevState *states.State) (*states.State, tfdiags.Diagnostics) {
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, prevState, &PlanOpts{
@ -4790,7 +4791,7 @@ data "test_data_source" "b" {
apply := func(t *testing.T, m *configs.Config, prevState *states.State) (*states.State, tfdiags.Diagnostics) {
t.Helper()
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, prevState, DefaultPlanOpts)
@ -4803,7 +4804,7 @@ data "test_data_source" "b" {
destroy := func(t *testing.T, m *configs.Config, prevState *states.State) (*states.State, tfdiags.Diagnostics) {
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, prevState, &PlanOpts{
@ -5020,7 +5021,7 @@ variable "other_var" {
}
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), valid, nil, &PlanOpts{
@ -5107,7 +5108,7 @@ variable "res_data" {
apply := func(t *testing.T, m *configs.Config, prevState *states.State) (*states.State, tfdiags.Diagnostics) {
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, prevState, &PlanOpts{
@ -5123,7 +5124,7 @@ variable "res_data" {
destroy := func(t *testing.T, m *configs.Config, prevState *states.State) tfdiags.Diagnostics {
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, prevState, &PlanOpts{
@ -5408,9 +5409,9 @@ module "modfe" {
test := test
t.Run(name, func(t *testing.T) {
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
mod := testModuleInline(t, test.module)
@ -5528,7 +5529,7 @@ check "http_check" {
apply := func(t *testing.T, m *configs.Config, prevState *states.State) (*states.State, tfdiags.Diagnostics) {
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, prevState, &PlanOpts{
@ -5543,7 +5544,7 @@ check "http_check" {
destroy := func(t *testing.T, m *configs.Config, prevState *states.State) tfdiags.Diagnostics {
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, prevState, &PlanOpts{
@ -5615,7 +5616,7 @@ check "http_check" {
apply := func(t *testing.T, m *configs.Config, prevState *states.State) (*states.State, tfdiags.Diagnostics) {
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, prevState, &PlanOpts{
@ -5630,7 +5631,7 @@ check "http_check" {
destroy := func(t *testing.T, m *configs.Config, prevState *states.State) tfdiags.Diagnostics {
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, prevState, &PlanOpts{
@ -5696,7 +5697,7 @@ check "http_check" {
apply := func(t *testing.T, m *configs.Config, prevState *states.State) (*states.State, tfdiags.Diagnostics) {
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, prevState, &PlanOpts{
@ -5711,7 +5712,7 @@ check "http_check" {
destroy := func(t *testing.T, m *configs.Config, prevState *states.State) tfdiags.Diagnostics {
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
plan, diags := ctx.Plan(context.Background(), m, prevState, &PlanOpts{
@ -5770,8 +5771,8 @@ ephemeral "test_ephemeral_resource" "a" {
h := &testHook{}
apply := func(t *testing.T, m *configs.Config, prevState *states.State) (*states.State, tfdiags.Diagnostics) {
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Hooks: []Hook{h},
Plugins: plugins.NewLibrary(ps, nil),
Hooks: []Hook{h},
})
plan, diags := ctx.Plan(context.Background(), m, prevState, &PlanOpts{
@ -6343,9 +6344,9 @@ func TestContext2Apply_enabledForResource(t *testing.T) {
}
}
tfCtx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
resourceInstAddr := addrs.Resource{
Mode: addrs.ManagedResourceMode,
@ -6481,7 +6482,7 @@ func TestContext2Apply_enabledForModule(t *testing.T) {
addrs.NewDefaultProvider("test"): testProviderFuncFixed(provider),
}
tfCtx := testContext2(t, &ContextOpts{
Providers: ps,
Plugins: plugins.NewLibrary(ps, nil),
})
resourceInstAddr := mustResourceInstanceAddr(`module.mod1.test_instance.a`)
@ -6659,9 +6660,9 @@ resource "test_resource" "res" {
}
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.MustParseProviderSourceString("example.com/foo/test"): testProviderFuncFixed(&p),
},
}, nil),
})
assertState := func(t *testing.T, s *states.State) {
@ -6921,8 +6922,8 @@ func TestContext2Apply_ephemeralInModuleWithExpansion(t *testing.T) {
h := &testHook{}
apply := func(t *testing.T, m *configs.Config, prevState *states.State) (*states.State, tfdiags.Diagnostics) {
ctx := testContext2(t, &ContextOpts{
Providers: ps,
Hooks: []Hook{h},
Plugins: plugins.NewLibrary(ps, nil),
Hooks: []Hook{h},
})
plan, diags := ctx.Plan(context.Background(), m, prevState, &PlanOpts{

View file

@ -15,6 +15,7 @@ import (
"github.com/opentofu/opentofu/internal/checks"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
@ -714,9 +715,9 @@ check "error" {
t.Run(name, func(t *testing.T) {
configs := testModuleInline(t, test.configs)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider(test.provider.Meta.(string)): testProviderFuncFixed(test.provider),
},
}, nil),
})
initialState := states.NewState()

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,7 @@ import (
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/zclconf/go-cty/cty"
@ -55,9 +56,9 @@ func TestContextEval(t *testing.T) {
m := testModule(t, "eval-context-basic")
p := testProvider("test")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
scope, diags := ctx.Eval(context.Background(), m, states.NewState(), addrs.RootModuleInstance, &EvalOpts{
@ -124,9 +125,9 @@ output "out" {
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
_, diags := ctx.Eval(context.Background(), m, states.NewState(), addrs.RootModuleInstance, &EvalOpts{

View file

@ -11,6 +11,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/zclconf/go-cty/cty"
@ -30,8 +31,10 @@ type contextTestFixture struct {
// _shallow_ modifications to the options as needed.
func (f *contextTestFixture) ContextOpts() *ContextOpts {
return &ContextOpts{
Providers: f.Providers,
Provisioners: f.Provisioners,
Plugins: plugins.NewLibrary(
f.Providers,
f.Provisioners,
),
}
}

View file

@ -15,6 +15,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/lang/marks"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/tfdiags"
"github.com/zclconf/go-cty/cty"
@ -357,9 +358,9 @@ variable "obfmod" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -438,9 +439,9 @@ variable "obfmod" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -523,9 +524,9 @@ variable "obfmod" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -615,9 +616,9 @@ variable "obfmod" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
_, diags := ctx.Plan(context.Background(), m, nil, nil)
@ -699,9 +700,9 @@ variable "obfmod" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -791,9 +792,9 @@ variable "value" { }
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)

View file

@ -19,6 +19,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
@ -28,9 +29,9 @@ func TestContextImport_basic(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
@ -81,9 +82,9 @@ resource "aws_instance" "foo" {
`})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
@ -243,9 +244,9 @@ func TestContextImport_multiInstanceProviderConfig(t *testing.T) {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewBuiltInProvider("test"): providerFactory,
},
}, nil),
})
existingInstanceKey := addrs.StringKey("foo")
@ -320,9 +321,9 @@ resource "aws_instance" "foo" {
`})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
@ -382,9 +383,9 @@ func TestContextImport_collision(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
state := states.BuildState(func(s *states.SyncState) {
@ -460,9 +461,9 @@ func TestContextImport_missingType(t *testing.T) {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
state, diags := ctx.Import(context.Background(), m, states.NewState(), &ImportOpts{
@ -513,9 +514,9 @@ func TestContextImport_moduleProvider(t *testing.T) {
m := testModule(t, "import-provider")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
state, diags := ctx.Import(context.Background(), m, states.NewState(), &ImportOpts{
@ -550,9 +551,9 @@ func TestContextImport_providerModule(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-module")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
@ -617,9 +618,9 @@ func TestContextImport_providerConfig(t *testing.T) {
p := testProvider("aws")
m := testModule(t, test.module)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
@ -678,10 +679,10 @@ func TestContextImport_providerConfigResources(t *testing.T) {
pTest := testProvider("test")
m := testModule(t, "import-provider-resources")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
},
}, nil),
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
@ -736,9 +737,9 @@ data "aws_data_source" "bar" {
`})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
@ -799,9 +800,9 @@ func TestContextImport_refreshNil(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
@ -848,9 +849,9 @@ func TestContextImport_module(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-module")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
@ -891,9 +892,9 @@ func TestContextImport_moduleDepth2(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-module")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
@ -934,9 +935,9 @@ func TestContextImport_moduleDiff(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-module")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
@ -1015,9 +1016,9 @@ func TestContextImport_multiState(t *testing.T) {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
state, diags := ctx.Import(context.Background(), m, states.NewState(), &ImportOpts{
@ -1091,9 +1092,9 @@ func TestContextImport_multiStateSame(t *testing.T) {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
state, diags := ctx.Import(context.Background(), m, states.NewState(), &ImportOpts{
@ -1187,9 +1188,9 @@ resource "test_resource" "unused" {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
state, diags := ctx.Import(context.Background(), m, states.NewState(), &ImportOpts{
@ -1259,9 +1260,9 @@ resource "test_resource" "test" {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
state, diags := ctx.Import(context.Background(), m, states.NewState(), &ImportOpts{
@ -1295,9 +1296,9 @@ func TestContextImport_33572(t *testing.T) {
m := testModule(t, "issue-33572")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{

View file

@ -17,6 +17,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
)
@ -79,11 +80,11 @@ func TestContext2Input_provider(t *testing.T) {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(awsp),
addrs.NewDefaultProvider("cloudflare"): testProviderFuncFixed(cfp),
addrs.NewDefaultProvider("azurerm"): testProviderFuncFixed(azp),
},
}, nil),
UIInput: inp,
})
@ -182,11 +183,11 @@ func TestContext2Input_providerMulti(t *testing.T) {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) {
return providerFactory()
},
},
}, nil),
UIInput: inp,
})
@ -226,9 +227,9 @@ func TestContext2Input_providerOnce(t *testing.T) {
m := testModule(t, "input-provider-once")
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
if diags := ctx.Input(context.Background(), m, InputModeStd); diags.HasErrors() {
@ -262,9 +263,9 @@ func TestContext2Input_providerOnly(t *testing.T) {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
UIInput: input,
})
@ -322,9 +323,9 @@ func TestContext2Input_providerVars(t *testing.T) {
m := testModule(t, "input-provider-with-vars")
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
UIInput: input,
})
@ -366,9 +367,9 @@ func TestContext2Input_providerVarsModuleInherit(t *testing.T) {
m := testModule(t, "input-provider-with-vars-and-module")
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
UIInput: input,
})
@ -383,9 +384,9 @@ func TestContext2Input_submoduleTriggersInvalidCount(t *testing.T) {
m := testModule(t, "input-submodule-count")
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
UIInput: input,
})
@ -441,9 +442,9 @@ func TestContext2Input_dataSourceRequiresRefresh(t *testing.T) {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
},
}, nil),
UIInput: input,
})

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -7,116 +7,48 @@ package tofu
import (
"context"
"fmt"
"log"
"sync"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/tfdiags"
)
// contextPlugins represents a library of available plugins (providers and
// provisioners) which we assume will all be used with the same
// tofu.Context, and thus it'll be safe to cache certain information
// about the providers for performance reasons.
type contextPlugins struct {
providerFactories map[addrs.Provider]providers.Factory
provisionerFactories map[string]provisioners.Factory
providerSchemasLock sync.Mutex
providerSchemas map[addrs.Provider]providerSchemaEntry
provisionerSchemasLock sync.Mutex
provisionerSchemas map[string]provisionerSchemaEntry
providers plugins.ProviderManager
provisioners plugins.ProvisionerManager
}
type providerSchemaEntry func() (providers.ProviderSchema, error)
type provisionerSchemaEntry func() (*configschema.Block, error)
func newContextPlugins(providerFactories map[addrs.Provider]providers.Factory, provisionerFactories map[string]provisioners.Factory) *contextPlugins {
func newContextPlugins(library plugins.Library) *contextPlugins {
if library == nil {
// We are in a *_test.go that should be fixed
library = plugins.NewLibrary(nil, nil)
}
return &contextPlugins{
providerFactories: providerFactories,
provisionerFactories: provisionerFactories,
providerSchemas: map[addrs.Provider]providerSchemaEntry{},
provisionerSchemas: map[string]provisionerSchemaEntry{},
providers: library.NewProviderManager(),
provisioners: library.NewProvisionerManager(),
}
}
func (cp *contextPlugins) HasProvider(addr addrs.Provider) bool {
_, ok := cp.providerFactories[addr]
return ok
}
func (cp *contextPlugins) NewProviderInstance(addr addrs.Provider) (providers.Interface, error) {
f, ok := cp.providerFactories[addr]
if !ok {
return nil, fmt.Errorf("unavailable provider %q", addr.String())
}
return f()
return cp.providers.HasProvider(addr)
}
func (cp *contextPlugins) HasProvisioner(typ string) bool {
_, ok := cp.provisionerFactories[typ]
return ok
}
func (cp *contextPlugins) NewProvisionerInstance(typ string) (provisioners.Interface, error) {
f, ok := cp.provisionerFactories[typ]
if !ok {
return nil, fmt.Errorf("unavailable provisioner %q", typ)
}
return f()
}
// ProviderSchema uses a temporary instance of the provider with the given
// address to obtain the full schema for all aspects of that provider.
//
// ProviderSchema memoizes results by unique provider address, so it's fine
// to repeatedly call this method with the same address if various different
// parts of OpenTofu all need the same schema information.
func (cp *contextPlugins) ProviderSchema(ctx context.Context, addr addrs.Provider) (providers.ProviderSchema, error) {
// Coarse lock only for ensuring that a valid entry exists
cp.providerSchemasLock.Lock()
entry, ok := cp.providerSchemas[addr]
if !ok {
entry = sync.OnceValues(func() (providers.ProviderSchema, error) {
log.Printf("[TRACE] tofu.contextPlugins: Initializing provider %q to read its schema", addr)
provider, err := cp.NewProviderInstance(addr)
if err != nil {
return providers.ProviderSchema{}, fmt.Errorf("failed to instantiate provider %q to obtain schema: %w", addr, err)
}
defer provider.Close(ctx)
schema := provider.GetProviderSchema(ctx)
return schema, schema.Validate(addr)
})
cp.providerSchemas[addr] = entry
}
// This lock is only for access to the map. We don't need to hold the lock when calling
// "entry" because [sync.OnceValues] handles synchronization itself.
// We don't defer unlock as the majority of the work of this function happens in calling "entry"
// and we want to release as soon as possible for multiple concurrent callers of different providers
cp.providerSchemasLock.Unlock()
return entry()
return cp.provisioners.HasProvisioner(typ)
}
// ProviderConfigSchema is a helper wrapper around ProviderSchema which first
// reads the full schema of the given provider and then extracts just the
// provider's configuration schema, which defines what's expected in a
// "provider" block in the configuration when configuring this provider.
func (cp *contextPlugins) ProviderConfigSchema(ctx context.Context, providerAddr addrs.Provider) (*configschema.Block, error) {
providerSchema, err := cp.ProviderSchema(ctx, providerAddr)
if err != nil {
return nil, err
func (cp *contextPlugins) ProviderConfigSchema(ctx context.Context, providerAddr addrs.Provider) (*configschema.Block, tfdiags.Diagnostics) {
providerSchema, diags := cp.providers.GetProviderSchema(ctx, providerAddr)
if diags.HasErrors() {
return nil, diags
}
return providerSchema.Provider.Block, nil
return providerSchema.Provider.Block, diags
}
// ResourceTypeSchema is a helper wrapper around ProviderSchema which first
@ -130,14 +62,14 @@ func (cp *contextPlugins) ProviderConfigSchema(ctx context.Context, providerAddr
// Managed resource types have versioned schemas, so the second return value
// is the current schema version number for the requested resource. The version
// is irrelevant for other resource modes.
func (cp *contextPlugins) ResourceTypeSchema(ctx context.Context, providerAddr addrs.Provider, resourceMode addrs.ResourceMode, resourceType string) (*configschema.Block, uint64, error) {
providerSchema, err := cp.ProviderSchema(ctx, providerAddr)
if err != nil {
return nil, 0, err
func (cp *contextPlugins) ResourceTypeSchema(ctx context.Context, providerAddr addrs.Provider, resourceMode addrs.ResourceMode, resourceType string) (*configschema.Block, uint64, tfdiags.Diagnostics) {
providerSchema, diags := cp.providers.GetProviderSchema(ctx, providerAddr)
if diags.HasErrors() {
return nil, 0, diags
}
schema, version := providerSchema.SchemaForResourceType(resourceMode, resourceType)
return schema, version, nil
return schema, version, diags
}
// ProvisionerSchema uses a temporary instance of the provisioner with the
@ -147,31 +79,5 @@ func (cp *contextPlugins) ResourceTypeSchema(ctx context.Context, providerAddr a
// to repeatedly call this method with the same name if various different
// parts of OpenTofu all need the same schema information.
func (cp *contextPlugins) ProvisionerSchema(addr string) (*configschema.Block, error) {
// Coarse lock only for ensuring that a valid entry exists
cp.provisionerSchemasLock.Lock()
entry, ok := cp.provisionerSchemas[addr]
if !ok {
entry = sync.OnceValues(func() (*configschema.Block, error) {
log.Printf("[TRACE] tofu.contextPlugins: Initializing provisioner %q to read its schema", addr)
provisioner, err := cp.NewProvisionerInstance(addr)
if err != nil {
return nil, fmt.Errorf("failed to instantiate provisioner %q to obtain schema: %w", addr, err)
}
defer provisioner.Close()
resp := provisioner.GetSchema()
if resp.Diagnostics.HasErrors() {
return nil, fmt.Errorf("failed to retrieve schema from provisioner %q: %w", addr, resp.Diagnostics.Err())
}
return resp.Provisioner, nil
})
cp.provisionerSchemas[addr] = entry
}
// This lock is only for access to the map. We don't need to hold the lock when calling
// "entry" because [sync.OnceValues] handles synchronization itself.
// We don't defer unlock as the majority of the work of this function happens in calling "entry"
// and we want to release as soon as possible for multiple concurrent callers of different provisioners
cp.provisionerSchemasLock.Unlock()
return entry()
return cp.provisioners.ProvisionerSchema(addr)
}

View file

@ -10,6 +10,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
)
@ -31,7 +32,7 @@ func simpleMockPluginLibrary() *contextPlugins {
// factory into real code under test.
provider := simpleMockProvider()
provisioner := simpleMockProvisioner()
ret := newContextPlugins(map[addrs.Provider]providers.Factory{
ret := newContextPlugins(plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): func() (providers.Interface, error) {
return provider, nil
},
@ -39,7 +40,7 @@ func simpleMockPluginLibrary() *contextPlugins {
"test": func() (provisioners.Interface, error) {
return provisioner, nil
},
})
}))
return ret
}

View file

@ -20,6 +20,7 @@ import (
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/legacy/hcl2shim"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
)
@ -41,9 +42,9 @@ func TestContext2Refresh(t *testing.T) {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
@ -129,9 +130,9 @@ func TestContext2Refresh_dynamicAttr(t *testing.T) {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
schema := p.GetProviderSchemaResponse.ResourceTypes["test_instance"].Block
@ -204,9 +205,9 @@ func TestContext2Refresh_dataComputedModuleVar(t *testing.T) {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, states.NewState(), &PlanOpts{Mode: plans.RefreshOnlyMode})
@ -268,9 +269,9 @@ func TestContext2Refresh_targeted(t *testing.T) {
m := testModule(t, "refresh-targeted")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
refreshedResources := make([]string, 0, 2)
@ -355,9 +356,9 @@ func TestContext2Refresh_excluded(t *testing.T) {
m := testModule(t, "refresh-targeted")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
refreshedResources := make([]string, 0, 2)
@ -439,9 +440,9 @@ func TestContext2Refresh_targetedCount(t *testing.T) {
m := testModule(t, "refresh-targeted-count")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
refreshedResources := make([]string, 0, 2)
@ -532,9 +533,9 @@ func TestContext2Refresh_excludedCount(t *testing.T) {
m := testModule(t, "refresh-targeted-count")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
refreshedResources := make([]string, 0, 2)
@ -620,9 +621,9 @@ func TestContext2Refresh_targetedCountIndex(t *testing.T) {
m := testModule(t, "refresh-targeted-count")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
refreshedResources := make([]string, 0, 2)
@ -707,9 +708,9 @@ func TestContext2Refresh_excludedCountIndex(t *testing.T) {
m := testModule(t, "refresh-targeted-count")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
refreshedResources := make([]string, 0, 2)
@ -762,9 +763,9 @@ func TestContext2Refresh_moduleComputedVar(t *testing.T) {
m := testModule(t, "refresh-module-computed-var")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
// This was failing (see GH-2188) at some point, so this test just
@ -783,9 +784,9 @@ func TestContext2Refresh_delete(t *testing.T) {
testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.opentofu.org/hashicorp/aws"]`)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ReadResourceResponse = &providers.ReadResourceResponse{
@ -807,9 +808,9 @@ func TestContext2Refresh_ignoreUncreated(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "refresh-basic")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ReadResourceResponse = &providers.ReadResourceResponse{
@ -838,9 +839,9 @@ func TestContext2Refresh_hook(t *testing.T) {
ctx := testContext2(t, &ContextOpts{
Hooks: []Hook{h},
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
if _, diags := ctx.Refresh(context.Background(), m, state, &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
@ -865,9 +866,9 @@ func TestContext2Refresh_modules(t *testing.T) {
testSetResourceInstanceCurrent(child, "aws_instance.web", `{"id":"baz"}`, `provider["registry.opentofu.org/hashicorp/aws"]`)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
@ -923,9 +924,9 @@ func TestContext2Refresh_moduleInputComputedOutput(t *testing.T) {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
if _, diags := ctx.Refresh(context.Background(), m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
@ -937,9 +938,9 @@ func TestContext2Refresh_moduleVarModule(t *testing.T) {
m := testModule(t, "refresh-module-var-module")
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
if _, diags := ctx.Refresh(context.Background(), m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
@ -952,9 +953,9 @@ func TestContext2Refresh_noState(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "refresh-no-state")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ReadResourceResponse = &providers.ReadResourceResponse{
@ -998,9 +999,9 @@ func TestContext2Refresh_output(t *testing.T) {
root.SetOutputValue("foo", cty.StringVal("foo"), false, "")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
s, diags := ctx.Refresh(context.Background(), m, state, &PlanOpts{Mode: plans.NormalMode})
@ -1046,9 +1047,9 @@ func TestContext2Refresh_outputPartial(t *testing.T) {
testSetResourceInstanceCurrent(root, "aws_instance.foo", `{}`, `provider["registry.opentofu.org/hashicorp/aws"]`)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
s, diags := ctx.Refresh(context.Background(), m, state, &PlanOpts{Mode: plans.NormalMode})
@ -1072,9 +1073,9 @@ func TestContext2Refresh_stateBasic(t *testing.T) {
testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"bar"}`, `provider["registry.opentofu.org/hashicorp/aws"]`)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
@ -1142,9 +1143,9 @@ func TestContext2Refresh_dataCount(t *testing.T) {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
s, diags := ctx.Refresh(context.Background(), m, states.NewState(), &PlanOpts{Mode: plans.NormalMode})
@ -1177,9 +1178,9 @@ func TestContext2Refresh_dataState(t *testing.T) {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
},
}, nil),
})
var readStateVal cty.Value
@ -1241,9 +1242,9 @@ func TestContext2Refresh_dataStateRefData(t *testing.T) {
m := testModule(t, "refresh-data-ref-data")
state := states.NewState()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
},
}, nil),
})
p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
@ -1277,9 +1278,9 @@ func TestContext2Refresh_tainted(t *testing.T) {
testSetResourceInstanceTainted(root, "aws_instance.web", `{"id":"bar"}`, `provider["registry.opentofu.org/hashicorp/aws"]`)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
// add the required id
@ -1318,7 +1319,7 @@ func TestContext2Refresh_unknownProvider(t *testing.T) {
testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.opentofu.org/hashicorp/aws"]`)
c, diags := NewContext(&ContextOpts{
Providers: map[addrs.Provider]providers.Factory{},
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{}, nil),
})
assertNoDiagnostics(t, diags)
@ -1359,9 +1360,9 @@ func TestContext2Refresh_vars(t *testing.T) {
testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.opentofu.org/hashicorp/aws"]`)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
readStateVal, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
@ -1455,9 +1456,9 @@ func TestContext2Refresh_orphanModule(t *testing.T) {
testSetResourceInstanceCurrent(grandchild, "aws_instance.baz", `{"id":"i-cde345"}`, `provider["registry.opentofu.org/hashicorp/aws"]`)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
testCheckDeadlock(t, func() {
@ -1496,9 +1497,9 @@ func TestContext2Validate(t *testing.T) {
m := testModule(t, "validate-good")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -1516,9 +1517,9 @@ func TestContext2Refresh_updateProviderInState(t *testing.T) {
testSetResourceInstanceCurrent(root, "aws_instance.bar", `{"id":"foo"}`, `provider["registry.opentofu.org/hashicorp/aws"].baz`)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
expected := strings.TrimSpace(`
@ -1584,9 +1585,9 @@ func TestContext2Refresh_schemaUpgradeFlatmap(t *testing.T) {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
state, diags := ctx.Refresh(context.Background(), m, s, &PlanOpts{Mode: plans.NormalMode})
@ -1667,9 +1668,9 @@ func TestContext2Refresh_schemaUpgradeJSON(t *testing.T) {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
state, diags := ctx.Refresh(context.Background(), m, s, &PlanOpts{Mode: plans.NormalMode})
@ -1723,9 +1724,9 @@ data "aws_data_source" "foo" {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
_, diags := ctx.Refresh(context.Background(), m, states.NewState(), &PlanOpts{Mode: plans.NormalMode})
@ -1771,9 +1772,9 @@ func TestContext2Refresh_dataResourceDependsOn(t *testing.T) {
testSetResourceInstanceCurrent(root, "test_resource.a", `{"id":"a"}`, `provider["registry.opentofu.org/hashicorp/test"]`)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
_, diags := ctx.Refresh(context.Background(), m, state, &PlanOpts{Mode: plans.NormalMode})
@ -1816,9 +1817,9 @@ resource "aws_instance" "bar" {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
state, diags := ctx.Refresh(context.Background(), m, state, &PlanOpts{Mode: plans.NormalMode})
@ -1863,9 +1864,9 @@ func TestContext2Refresh_dataSourceOrphan(t *testing.T) {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
_, diags := ctx.Refresh(context.Background(), m, state, &PlanOpts{Mode: plans.NormalMode})
@ -1949,9 +1950,9 @@ resource "test_resource" "foo" {
)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
plan, diags := ctx.Plan(context.Background(), m, state, &PlanOpts{Mode: plans.RefreshOnlyMode})

View file

@ -86,7 +86,7 @@ func (c *Context) newEngineShim(ctx context.Context, config *configs.Config, inp
tempLoader, _ := configload.NewLoader(&configload.Config{})
plugins := plugins.NewRuntimePlugins(c.plugins.providerFactories, c.plugins.provisionerFactories)
plugins := plugins.NewRuntimePluginsTemp(c.plugins.providers, c.plugins.provisioners)
evalCtx := &eval.EvalContext{
RootModuleDir: config.Module.SourceDir,
OriginalWorkingDir: c.meta.OriginalWorkingDir,

View file

@ -29,6 +29,7 @@ import (
"github.com/opentofu/opentofu/internal/legacy/hcl2shim"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/plans/planfile"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/states"
@ -267,7 +268,7 @@ func TestContext_contextValuesPropagation(t *testing.T) {
ctx, probe := tracing.NewContextProbe(t, t.Context())
tofuCtx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewBuiltInProvider("test"): providers.FactoryFixed(&MockProvider{
GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
Provider: providers.Schema{
@ -288,7 +289,7 @@ func TestContext_contextValuesPropagation(t *testing.T) {
State: cty.EmptyObjectVal,
},
}),
},
}, nil),
})
m := testModuleInline(t, map[string]string{
"main.tf": `

View file

@ -16,6 +16,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/states"
@ -34,9 +35,9 @@ func TestContext2Validate_badCount(t *testing.T) {
m := testModule(t, "validate-bad-count")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -57,9 +58,9 @@ func TestContext2Validate_badResource_reference(t *testing.T) {
m := testModule(t, "validate-bad-resource-count")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -83,9 +84,9 @@ func TestContext2Validate_badVar(t *testing.T) {
m := testModule(t, "validate-bad-var")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -150,10 +151,10 @@ func TestContext2Validate_computedVar(t *testing.T) {
m := testModule(t, "validate-computed-var")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
addrs.NewDefaultProvider("test"): testProviderFuncFixed(pt),
},
}, nil),
})
p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
@ -200,9 +201,9 @@ func TestContext2Validate_computedInFunction(t *testing.T) {
m := testModule(t, "validate-computed-in-function")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -238,9 +239,9 @@ func TestContext2Validate_countComputed(t *testing.T) {
m := testModule(t, "validate-count-computed")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -262,9 +263,9 @@ func TestContext2Validate_countNegative(t *testing.T) {
}
m := testModule(t, "validate-count-negative")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -288,9 +289,9 @@ func TestContext2Validate_countVariable(t *testing.T) {
}
m := testModule(t, "apply-count-variable")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -314,9 +315,9 @@ func TestContext2Validate_countVariableNoDefault(t *testing.T) {
},
}
c, diags := NewContext(&ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
assertNoDiagnostics(t, diags)
@ -342,9 +343,9 @@ func TestContext2Validate_moduleBadOutput(t *testing.T) {
}
m := testModule(t, "validate-bad-module-output")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -368,9 +369,9 @@ func TestContext2Validate_moduleGood(t *testing.T) {
}
m := testModule(t, "validate-good-module")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -393,9 +394,9 @@ func TestContext2Validate_moduleBadResource(t *testing.T) {
}
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ValidateResourceConfigResponse = &providers.ValidateResourceConfigResponse{
@ -424,9 +425,9 @@ func TestContext2Validate_moduleDepsShouldNotCycle(t *testing.T) {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -458,9 +459,9 @@ func TestContext2Validate_moduleProviderVar(t *testing.T) {
}
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
@ -499,9 +500,9 @@ func TestContext2Validate_moduleProviderInheritUnused(t *testing.T) {
}
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
@ -535,9 +536,9 @@ func TestContext2Validate_orphans(t *testing.T) {
m := testModule(t, "validate-good")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
@ -577,9 +578,9 @@ func TestContext2Validate_providerConfig_bad(t *testing.T) {
}
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ValidateProviderConfigResponse = &providers.ValidateProviderConfigResponse{
@ -616,9 +617,9 @@ func TestContext2Validate_providerConfig_skippedEmpty(t *testing.T) {
}
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ValidateProviderConfigResponse = &providers.ValidateProviderConfigResponse{
@ -652,9 +653,9 @@ func TestContext2Validate_providerConfig_good(t *testing.T) {
}
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -687,9 +688,9 @@ func TestContext2Validate_requiredProviderConfig(t *testing.T) {
}
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -716,12 +717,11 @@ func TestContext2Validate_provisionerConfig_bad(t *testing.T) {
pr := simpleMockProvisioner()
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
Provisioners: map[string]provisioners.Factory{
}, map[string]provisioners.Factory{
"shell": testProvisionerFuncFixed(pr),
},
}),
})
p.ValidateProviderConfigResponse = &providers.ValidateProviderConfigResponse{
@ -752,12 +752,11 @@ func TestContext2Validate_badResourceConnection(t *testing.T) {
pr := simpleMockProvisioner()
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
Provisioners: map[string]provisioners.Factory{
}, map[string]provisioners.Factory{
"shell": testProvisionerFuncFixed(pr),
},
}),
})
diags := c.Validate(context.Background(), m)
@ -785,12 +784,11 @@ func TestContext2Validate_badProvisionerConnection(t *testing.T) {
pr := simpleMockProvisioner()
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
Provisioners: map[string]provisioners.Factory{
}, map[string]provisioners.Factory{
"shell": testProvisionerFuncFixed(pr),
},
}),
})
diags := c.Validate(context.Background(), m)
@ -834,12 +832,11 @@ func TestContext2Validate_provisionerConfig_good(t *testing.T) {
}
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
Provisioners: map[string]provisioners.Factory{
}, map[string]provisioners.Factory{
"shell": testProvisionerFuncFixed(pr),
},
}),
})
diags := c.Validate(context.Background(), m)
@ -863,9 +860,9 @@ func TestContext2Validate_requiredVar(t *testing.T) {
},
}
c, diags := NewContext(&ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
assertNoDiagnostics(t, diags)
@ -899,9 +896,9 @@ func TestContext2Validate_resourceConfig_bad(t *testing.T) {
},
}
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ValidateResourceConfigResponse = &providers.ValidateResourceConfigResponse{
@ -929,9 +926,9 @@ func TestContext2Validate_resourceConfig_good(t *testing.T) {
},
}
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := c.Validate(context.Background(), m)
@ -957,9 +954,9 @@ func TestContext2Validate_tainted(t *testing.T) {
m := testModule(t, "validate-good")
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
@ -1001,12 +998,11 @@ func TestContext2Validate_targetedDestroy(t *testing.T) {
testSetResourceInstanceCurrent(root, "aws_instance.bar", `{"id":"i-abc123"}`, `provider["registry.opentofu.org/hashicorp/aws"]`)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
Provisioners: map[string]provisioners.Factory{
}, map[string]provisioners.Factory{
"shell": testProvisionerFuncFixed(pr),
},
}),
})
diags := ctx.Validate(context.Background(), m)
@ -1030,9 +1026,9 @@ func TestContext2Validate_varRefUnknown(t *testing.T) {
},
}
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
var value cty.Value
@ -1071,9 +1067,9 @@ func TestContext2Validate_interpolateVar(t *testing.T) {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
},
}, nil),
UIInput: input,
})
@ -1103,9 +1099,9 @@ func TestContext2Validate_interpolateComputedModuleVarDef(t *testing.T) {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
UIInput: input,
})
@ -1123,9 +1119,9 @@ func TestContext2Validate_interpolateMap(t *testing.T) {
p := testProvider("template")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
},
}, nil),
UIInput: input,
})
@ -1174,9 +1170,9 @@ resource "aws_instance" "foo" {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1205,9 +1201,9 @@ output "out" {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1241,9 +1237,9 @@ resource "aws_instance" "foo" {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1299,9 +1295,9 @@ output "out" {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1329,9 +1325,9 @@ output "out" {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1359,9 +1355,9 @@ output "out" {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1388,9 +1384,9 @@ resource "test_instance" "bar" {
p := testProvider("test")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1420,9 +1416,9 @@ resource "test_instance" "bar" {
p := testProvider("test")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1444,9 +1440,9 @@ func TestContext2Validate_variableCustomValidationsFail(t *testing.T) {
p := testProvider("test")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1478,9 +1474,9 @@ variable "test" {
p := testProvider("test")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1539,9 +1535,9 @@ resource "aws_instance" "foo" {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1566,9 +1562,9 @@ resource "aws_instance" "foo" {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1596,9 +1592,9 @@ resource "aws_instance" "foo" {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1677,9 +1673,9 @@ output "out" {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -1791,9 +1787,9 @@ resource "test_instance" "a" {
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
if diags.HasErrors() {
@ -1830,12 +1826,11 @@ func TestContext2Validate_sensitiveProvisionerConfig(t *testing.T) {
pr := simpleMockProvisioner()
c := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
Provisioners: map[string]provisioners.Factory{
}, map[string]provisioners.Factory{
"test": testProvisionerFuncFixed(pr),
},
}),
})
pr.ValidateProvisionerConfigFn = func(r provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse {
@ -1934,9 +1929,9 @@ resource "test_instance" "c" {
`})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2001,9 +1996,9 @@ resource "test_object" "t" {
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2058,9 +2053,9 @@ output "out" {
`})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2134,9 +2129,9 @@ resource "aws_instance" "test" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2177,9 +2172,9 @@ resource "aws_instance" "test" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2223,9 +2218,9 @@ resource "aws_instance" "test" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2264,9 +2259,9 @@ resource "aws_instance" "test" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2313,9 +2308,9 @@ resource "aws_instance" "test" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2354,9 +2349,9 @@ resource "aws_instance" "test" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2400,9 +2395,9 @@ resource "aws_instance" "test" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2443,9 +2438,9 @@ resource "aws_instance" "test" {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2477,9 +2472,9 @@ locals {
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2496,9 +2491,9 @@ func TestContext2Validate_rangeOverZeroPlanTimestamp(t *testing.T) {
m := testModule(t, "plan_range_over_plan_timestamp")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2530,9 +2525,9 @@ resource "test_object" "t" {
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2561,9 +2556,9 @@ resource "test_object" "t" {
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
diags := ctx.Validate(context.Background(), m)
@ -2605,9 +2600,9 @@ func TestContext2Validate_importWithForEachOnUnknown(t *testing.T) {
hook := new(MockHook)
ctx := testContext2(t, &ContextOpts{
Hooks: []Hook{hook},
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
p.ReadResourceFn = func(request providers.ReadResourceRequest) providers.ReadResourceResponse {
return providers.ReadResourceResponse{
@ -2709,9 +2704,9 @@ func TestContext2Validate_importIntoModuleResource(t *testing.T) {
hook := new(MockHook)
ctx := testContext2(t, &ContextOpts{
Hooks: []Hook{hook},
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
p.ReadResourceFn = func(request providers.ReadResourceRequest) providers.ReadResourceResponse {
return providers.ReadResourceResponse{
@ -2763,9 +2758,9 @@ func TestContext2Validate_importIntoUnexistingResourceBlock(t *testing.T) {
hook := new(MockHook)
ctx := testContext2(t, &ContextOpts{
Hooks: []Hook{hook},
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
})
p.ReadResourceFn = func(request providers.ReadResourceRequest) providers.ReadResourceResponse {
return providers.ReadResourceResponse{

View file

@ -18,8 +18,7 @@ import (
"github.com/opentofu/opentofu/internal/instances"
"github.com/opentofu/opentofu/internal/lang"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/refactoring"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
@ -41,20 +40,12 @@ type EvalContext interface {
// Input is the UIInput object for interacting with the UI.
Input() UIInput
// InitProvider initializes the provider with the given address, and returns
// the implementation of the resource provider or an error.
//
// It is an error to initialize the same provider more than once. This
// method will panic if the module instance address of the given provider
// configuration does not match the Path() of the EvalContext.
InitProvider(ctx context.Context, addr addrs.AbsProviderConfig, key addrs.InstanceKey) (providers.Interface, error)
// ProviderSchema retrieves the schema for a particular provider, which
// must have already been initialized with InitProvider.
//
// This method expects an _absolute_ provider configuration address, since
// resources in one module are able to use providers from other modules.
ProviderSchema(context.Context, addrs.AbsProviderConfig) (providers.ProviderSchema, error)
// Providers is the [plugins.ProviderManager] for interacting
// with providers in the current operation.
Providers() plugins.ProviderManager
// Provisioners is the [plugins.ProvisionerManager] for interacting
// with provisioners in the current operation.
Provisioners() plugins.ProvisionerManager
// ProviderInput and SetProviderInput are used to configure providers
// from user input.
@ -64,17 +55,6 @@ type EvalContext interface {
ProviderInput(context.Context, addrs.AbsProviderConfig) map[string]cty.Value
SetProviderInput(context.Context, addrs.AbsProviderConfig, map[string]cty.Value)
// Provisioner gets the provisioner instance with the given name.
Provisioner(string) (provisioners.Interface, error)
// ProvisionerSchema retrieves the main configuration schema for a
// particular provisioner, which must have already been initialized with
// InitProvisioner.
ProvisionerSchema(string) (*configschema.Block, error)
// CloseProvisioner closes all provisioner plugins.
CloseProvisioners() error
// EvaluateBlock takes the given raw configuration block and associated
// schema and evaluates it to produce a value of an object type that
// conforms to the implied type of the schema.

View file

@ -22,8 +22,7 @@ import (
"github.com/opentofu/opentofu/internal/instances"
"github.com/opentofu/opentofu/internal/lang"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/refactoring"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
@ -65,12 +64,8 @@ type BuiltinEvalContext struct {
Hooks []Hook
InputValue UIInput
ProviderLock *sync.Mutex
ProviderCache map[string]map[addrs.InstanceKey]providers.Interface
ProviderInputConfig map[string]map[string]cty.Value
ProvisionerLock *sync.Mutex
ProvisionerCache map[string]provisioners.Interface
ProviderInputConfigLock *sync.Mutex
ProviderInputConfig map[string]map[string]cty.Value
ChangesValue *plans.ChangesSync
StateValue *states.SyncState
@ -127,39 +122,9 @@ func (c *BuiltinEvalContext) Input() UIInput {
return c.InputValue
}
func (c *BuiltinEvalContext) InitProvider(ctx context.Context, addr addrs.AbsProviderConfig, providerInstanceKey addrs.InstanceKey) (providers.Interface, error) {
c.ProviderLock.Lock()
defer c.ProviderLock.Unlock()
providerAddrKey := addr.String()
if c.ProviderCache[providerAddrKey] == nil {
c.ProviderCache[providerAddrKey] = make(map[addrs.InstanceKey]providers.Interface)
}
// If we have already initialized, it is an error
if _, ok := c.ProviderCache[providerAddrKey][providerInstanceKey]; ok {
return nil, fmt.Errorf("%s is already initialized", addr)
}
p, err := c.Plugins.NewProviderInstance(addr.Provider)
if err != nil {
return nil, err
}
log.Printf("[TRACE] BuiltinEvalContext: Initialized %q%s provider for %s", addr.String(), providerInstanceKey, addr)
c.ProviderCache[providerAddrKey][providerInstanceKey] = p
return p, nil
}
func (c *BuiltinEvalContext) ProviderSchema(ctx context.Context, addr addrs.AbsProviderConfig) (providers.ProviderSchema, error) {
return c.Plugins.ProviderSchema(ctx, addr.Provider)
}
func (c *BuiltinEvalContext) ProviderInput(_ context.Context, pc addrs.AbsProviderConfig) map[string]cty.Value {
c.ProviderLock.Lock()
defer c.ProviderLock.Unlock()
c.ProviderInputConfigLock.Lock()
defer c.ProviderInputConfigLock.Unlock()
if !c.Path().IsForModule(pc.Module) {
// This indicates incorrect use of InitProvider: it should be used
@ -184,46 +149,17 @@ func (c *BuiltinEvalContext) SetProviderInput(_ context.Context, pc addrs.AbsPro
}
// Save the configuration
c.ProviderLock.Lock()
c.ProviderInputConfigLock.Lock()
c.ProviderInputConfig[absProvider.String()] = vals
c.ProviderLock.Unlock()
c.ProviderInputConfigLock.Unlock()
}
func (c *BuiltinEvalContext) Provisioner(n string) (provisioners.Interface, error) {
c.ProvisionerLock.Lock()
defer c.ProvisionerLock.Unlock()
p, ok := c.ProvisionerCache[n]
if !ok {
var err error
p, err = c.Plugins.NewProvisionerInstance(n)
if err != nil {
return nil, err
}
c.ProvisionerCache[n] = p
}
return p, nil
func (c *BuiltinEvalContext) Providers() plugins.ProviderManager {
return c.Plugins.providers
}
func (c *BuiltinEvalContext) ProvisionerSchema(n string) (*configschema.Block, error) {
return c.Plugins.ProvisionerSchema(n)
}
func (c *BuiltinEvalContext) CloseProvisioners() error {
var diags tfdiags.Diagnostics
c.ProvisionerLock.Lock()
defer c.ProvisionerLock.Unlock()
for name, prov := range c.ProvisionerCache {
err := prov.Close()
if err != nil {
diags = diags.Append(fmt.Errorf("provisioner.Close %s: %w", name, err))
}
}
return diags.Err()
func (c *BuiltinEvalContext) Provisioners() plugins.ProvisionerManager {
return c.Plugins.provisioners
}
func (c *BuiltinEvalContext) EvaluateBlock(ctx context.Context, body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) {
@ -319,9 +255,9 @@ func (c *BuiltinEvalContext) EvaluateReplaceTriggeredBy(ctx context.Context, exp
// Since we have a traversal after the resource reference, we will need to
// decode the changes, which means we need a schema.
providerAddr := change.ProviderAddr
schema, err := c.ProviderSchema(ctx, providerAddr)
if err != nil {
diags = diags.Append(err)
schema, schemaDiags := c.Providers().GetProviderSchema(ctx, providerAddr.Provider)
if schemaDiags.HasErrors() {
diags = diags.Append(schemaDiags)
return nil, false, diags
}

View file

@ -11,7 +11,6 @@ import (
"testing"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/providers"
"github.com/zclconf/go-cty/cty"
)
@ -22,12 +21,12 @@ func TestBuiltinEvalContextProviderInput(t *testing.T) {
ctx1 := testBuiltinEvalContext(t)
ctx1 = ctx1.WithPath(addrs.RootModuleInstance).(*BuiltinEvalContext)
ctx1.ProviderInputConfig = cache
ctx1.ProviderLock = &lock
ctx1.ProviderInputConfigLock = &lock
ctx2 := testBuiltinEvalContext(t)
ctx2 = ctx2.WithPath(addrs.RootModuleInstance.Child("child", addrs.NoKey)).(*BuiltinEvalContext)
ctx2.ProviderInputConfig = cache
ctx2.ProviderLock = &lock
ctx2.ProviderInputConfigLock = &lock
providerAddr1 := addrs.AbsProviderConfig{
Module: addrs.RootModule,
@ -55,39 +54,6 @@ func TestBuiltinEvalContextProviderInput(t *testing.T) {
}
}
func TestBuildingEvalContextInitProvider(t *testing.T) {
var lock sync.Mutex
testP := &MockProvider{}
ctx := testBuiltinEvalContext(t)
ctx = ctx.WithPath(addrs.RootModuleInstance).(*BuiltinEvalContext)
ctx.ProviderLock = &lock
ctx.ProviderCache = make(map[string]map[addrs.InstanceKey]providers.Interface)
ctx.Plugins = newContextPlugins(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): providers.FactoryFixed(testP),
}, nil)
providerAddrDefault := addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
}
providerAddrAlias := addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.NewDefaultProvider("test"),
Alias: "foo",
}
_, err := ctx.InitProvider(t.Context(), providerAddrDefault, addrs.NoKey)
if err != nil {
t.Fatalf("error initializing provider test: %s", err)
}
_, err = ctx.InitProvider(t.Context(), providerAddrAlias, addrs.NoKey)
if err != nil {
t.Fatalf("error initializing provider test.foo: %s", err)
}
}
func testBuiltinEvalContext(t *testing.T) *BuiltinEvalContext {
return &BuiltinEvalContext{}
}

View file

@ -20,8 +20,8 @@ import (
"github.com/opentofu/opentofu/internal/instances"
"github.com/opentofu/opentofu/internal/lang"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/refactoring"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
@ -40,16 +40,8 @@ type MockEvalContext struct {
InputCalled bool
InputInput UIInput
InitProviderCalled bool
InitProviderType string
InitProviderAddr addrs.AbsProviderConfig
InitProviderProvider providers.Interface
InitProviderError error
ProviderSchemaCalled bool
ProviderSchemaAddr addrs.AbsProviderConfig
ProviderSchemaSchema providers.ProviderSchema
ProviderSchemaError error
ProvidersCalled bool
ProvidersProviders plugins.ProviderManager
ProviderInputCalled bool
ProviderInputAddr addrs.AbsProviderConfig
@ -59,16 +51,8 @@ type MockEvalContext struct {
SetProviderInputAddr addrs.AbsProviderConfig
SetProviderInputValues map[string]cty.Value
ProvisionerCalled bool
ProvisionerName string
ProvisionerProvisioner provisioners.Interface
ProvisionerSchemaCalled bool
ProvisionerSchemaName string
ProvisionerSchemaSchema *configschema.Block
ProvisionerSchemaError error
CloseProvisionersCalled bool
ProvisionersCalled bool
ProvisionersProvisioners plugins.ProvisionerManager
EvaluateBlockCalled bool
EvaluateBlockBody hcl.Body
@ -170,17 +154,15 @@ func (c *MockEvalContext) Input() UIInput {
return c.InputInput
}
func (c *MockEvalContext) InitProvider(_ context.Context, addr addrs.AbsProviderConfig, _ addrs.InstanceKey) (providers.Interface, error) {
c.InitProviderCalled = true
c.InitProviderType = addr.String()
c.InitProviderAddr = addr
return c.InitProviderProvider, c.InitProviderError
func (c *MockEvalContext) installProvider(addr addrs.Provider, p providers.Interface) {
c.ProvidersProviders = plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addr: func() (providers.Interface, error) { return p, nil },
}, nil).NewProviderManager()
}
func (c *MockEvalContext) ProviderSchema(_ context.Context, addr addrs.AbsProviderConfig) (providers.ProviderSchema, error) {
c.ProviderSchemaCalled = true
c.ProviderSchemaAddr = addr
return c.ProviderSchemaSchema, c.ProviderSchemaError
func (c *MockEvalContext) Providers() plugins.ProviderManager {
c.ProvidersCalled = true
return c.ProvidersProviders
}
func (c *MockEvalContext) ProviderInput(_ context.Context, addr addrs.AbsProviderConfig) map[string]cty.Value {
@ -195,21 +177,9 @@ func (c *MockEvalContext) SetProviderInput(_ context.Context, addr addrs.AbsProv
c.SetProviderInputValues = vals
}
func (c *MockEvalContext) Provisioner(n string) (provisioners.Interface, error) {
c.ProvisionerCalled = true
c.ProvisionerName = n
return c.ProvisionerProvisioner, nil
}
func (c *MockEvalContext) ProvisionerSchema(n string) (*configschema.Block, error) {
c.ProvisionerSchemaCalled = true
c.ProvisionerSchemaName = n
return c.ProvisionerSchemaSchema, c.ProvisionerSchemaError
}
func (c *MockEvalContext) CloseProvisioners() error {
c.CloseProvisionersCalled = true
return nil
func (c *MockEvalContext) Provisioners() plugins.ProvisionerManager {
c.ProvisionersCalled = true
return c.ProvisionersProvisioners
}
func (c *MockEvalContext) EvaluateBlock(_ context.Context, body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) {

View file

@ -1015,8 +1015,8 @@ func (d *evaluationStateData) GetResource(ctx context.Context, addr addrs.Resour
func (d *evaluationStateData) getResourceSchema(ctx context.Context, addr addrs.Resource, providerAddr addrs.Provider) *configschema.Block {
// TODO: Plumb a useful context.Context through to here.
schema, _, err := d.Evaluator.Plugins.ResourceTypeSchema(ctx, providerAddr, addr.Mode, addr.Type)
if err != nil {
schema, _, diags := d.Evaluator.Plugins.ResourceTypeSchema(ctx, providerAddr, addr.Mode, addr.Type)
if diags.HasErrors() {
// We have plenty of other codepaths that will detect and report
// schema lookup errors before we'd reach this point, so we'll just
// treat a failure here the same as having no schema.

View file

@ -234,15 +234,16 @@ func (d *evaluationStateData) staticValidateResourceReference(ctx context.Contex
// TODO: Plugin a suitable context.Context through to here.
providerFqn := modCfg.Module.ProviderForLocalConfig(cfg.ProviderConfigAddr())
schema, _, err := d.Evaluator.Plugins.ResourceTypeSchema(ctx, providerFqn, addr.Mode, addr.Type)
if err != nil {
schema, _, moreDiags := d.Evaluator.Plugins.ResourceTypeSchema(ctx, providerFqn, addr.Mode, addr.Type)
diags = diags.Append(moreDiags)
if moreDiags.HasErrors() {
// Prior validation should've taken care of a schema lookup error,
// so we should never get here but we'll handle it here anyway for
// robustness.
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: `Failed provider schema lookup`,
Detail: fmt.Sprintf(`Couldn't load schema for %s resource type %q in %s: %s.`, modeAdjective, addr.Type, providerFqn.String(), err),
Detail: fmt.Sprintf(`Couldn't load schema for %s resource type %q in %s: %s.`, modeAdjective, addr.Type, providerFqn.String(), diags.Err()),
Subject: rng.ToHCL().Ptr(),
})
}
@ -278,7 +279,7 @@ func (d *evaluationStateData) staticValidateResourceReference(ctx context.Contex
// If we got this far then we'll try to validate the remaining traversal
// steps against our schema.
moreDiags := schema.StaticValidateTraversal(remain)
moreDiags = schema.StaticValidateTraversal(remain)
diags = diags.Append(moreDiags)
return diags

View file

@ -15,6 +15,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
)
@ -780,9 +781,9 @@ func TestApplyGraphBuilder_withChecks(t *testing.T) {
},
}
plugins := newContextPlugins(map[addrs.Provider]providers.Factory{
plugins := newContextPlugins(plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): providers.FactoryFixed(awsProvider),
}, nil)
}, nil))
b := &ApplyGraphBuilder{
Config: testModule(t, "apply-with-checks"),

View file

@ -11,6 +11,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/states"
"github.com/zclconf/go-cty/cty"
@ -35,10 +36,10 @@ func TestPlanGraphBuilder(t *testing.T) {
},
}
openstackProvider := mockProviderWithResourceTypeSchema("openstack_floating_ip", simpleTestSchema())
plugins := newContextPlugins(map[addrs.Provider]providers.Factory{
plugins := newContextPlugins(plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): providers.FactoryFixed(awsProvider),
addrs.NewDefaultProvider("openstack"): providers.FactoryFixed(openstackProvider),
}, nil)
}, nil))
b := &PlanGraphBuilder{
Config: testModule(t, "graph-builder-plan-basic"),
@ -79,9 +80,9 @@ func TestPlanGraphBuilder_dynamicBlock(t *testing.T) {
},
},
})
plugins := newContextPlugins(map[addrs.Provider]providers.Factory{
plugins := newContextPlugins(plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): providers.FactoryFixed(provider),
}, nil)
}, nil))
b := &PlanGraphBuilder{
Config: testModule(t, "graph-builder-plan-dynblock"),
@ -135,9 +136,9 @@ func TestPlanGraphBuilder_attrAsBlocks(t *testing.T) {
},
},
})
plugins := newContextPlugins(map[addrs.Provider]providers.Factory{
plugins := newContextPlugins(plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): providers.FactoryFixed(provider),
}, nil)
}, nil))
b := &PlanGraphBuilder{
Config: testModule(t, "graph-builder-plan-attr-as-blocks"),
@ -221,9 +222,9 @@ func TestPlanGraphBuilder_excludeModule(t *testing.T) {
func TestPlanGraphBuilder_forEach(t *testing.T) {
awsProvider := mockProviderWithResourceTypeSchema("aws_instance", simpleTestSchema())
plugins := newContextPlugins(map[addrs.Provider]providers.Factory{
plugins := newContextPlugins(plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): providers.FactoryFixed(awsProvider),
}, nil)
}, nil))
b := &PlanGraphBuilder{
Config: testModule(t, "plan-for-each"),
@ -256,9 +257,9 @@ func TestPlanGraphBuilder_ephemeralResourceDestroy(t *testing.T) {
b := &PlanGraphBuilder{
Config: &configs.Config{Module: &configs.Module{}},
Operation: walkPlanDestroy,
Plugins: newContextPlugins(map[addrs.Provider]providers.Factory{
Plugins: newContextPlugins(plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): providers.FactoryFixed(awsProvider),
}, nil),
}, nil)),
State: &states.State{
Modules: map[string]*states.Module{
"": {

View file

@ -18,8 +18,6 @@ import (
"github.com/opentofu/opentofu/internal/encryption"
"github.com/opentofu/opentofu/internal/instances"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/refactoring"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
@ -59,11 +57,7 @@ type ContextGraphWalker struct {
variableValuesLock sync.Mutex
variableValues map[string]map[string]cty.Value
providerLock sync.Mutex
providerCache map[string]map[addrs.InstanceKey]providers.Interface
provisionerLock sync.Mutex
provisionerCache map[string]provisioners.Interface
providerInputConfigLock sync.Mutex
}
var _ GraphWalker = (*ContextGraphWalker)(nil)
@ -110,11 +104,8 @@ func (w *ContextGraphWalker) EvalContext() EvalContext {
Plugins: w.Context.plugins,
MoveResultsValue: w.MoveResults,
ImportResolverValue: w.ImportResolver,
ProviderCache: w.providerCache,
ProviderInputConfigLock: &w.providerInputConfigLock,
ProviderInputConfig: w.Context.providerInputConfig,
ProviderLock: &w.providerLock,
ProvisionerCache: w.provisionerCache,
ProvisionerLock: &w.provisionerLock,
ChangesValue: w.Changes,
ChecksValue: w.Checks,
StateValue: w.State,
@ -132,8 +123,6 @@ func (w *ContextGraphWalker) EvalContext() EvalContext {
func (w *ContextGraphWalker) init() {
w.contexts = make(map[string]*BuiltinEvalContext)
w.providerCache = make(map[string]map[addrs.InstanceKey]providers.Interface)
w.provisionerCache = make(map[string]provisioners.Interface)
w.variableValues = make(map[string]map[string]cty.Value)
// Populate root module variable values. Other modules will be populated

View file

@ -224,7 +224,11 @@ func (n *nodeCloseModule) Execute(_ context.Context, evalCtx EvalContext, op wal
// If this is the root module, we are cleaning up the walk, so close
// any running provisioners
diags = diags.Append(evalCtx.CloseProvisioners())
provisioners := evalCtx.Provisioners()
// Sometimes nil in tests
if provisioners != nil {
diags = diags.Append(provisioners.CloseAll())
}
switch op {
case walkApply, walkDestroy:

View file

@ -22,6 +22,7 @@ import (
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
@ -215,9 +216,9 @@ func TestNodeModuleVariableConstraints(t *testing.T) {
}
ctxOpts := &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
}, nil),
}
t.Run("pass", func(t *testing.T) {

View file

@ -12,15 +12,14 @@ import (
"log"
"github.com/hashicorp/hcl/v2"
"github.com/zclconf/go-cty/cty"
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/instances"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/tfdiags"
"github.com/opentofu/opentofu/internal/tracing"
"github.com/opentofu/opentofu/internal/tracing/traceattrs"
"github.com/opentofu/opentofu/version"
)
// traceAttrProviderAddress is a standardized trace span attribute name that we
@ -89,81 +88,43 @@ func (n *NodeApplyableProvider) Close(ctx context.Context) error {
// GraphNodeExecutable
func (n *NodeApplyableProvider) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) tfdiags.Diagnostics {
instances, diags := n.initInstances(ctx, evalCtx, op)
if diags.HasErrors() {
return diags
var diags tfdiags.Diagnostics
n.instances = map[addrs.InstanceKey]providers.Configured{}
var instanceData map[addrs.InstanceKey]instances.RepetitionData
if n.Config == nil || n.Config.Instances == nil {
// Stub out uninstanced
instanceData = map[addrs.InstanceKey]instances.RepetitionData{addrs.NoKey: EvalDataForNoInstanceKey}
} else {
instanceData = n.Config.Instances
}
for key, provider := range instances {
diags = diags.Append(n.executeInstance(ctx, evalCtx, op, key, provider))
if op == walkValidate {
log.Printf("[TRACE] NodeApplyableProvider: validating configuration for %s", n.Addr)
instance, newDiags := evalCtx.Providers().NewProvider(ctx, n.Addr.Provider)
n.instances[addrs.NoKey] = instance
for key, data := range instanceData {
diags = diags.Append(n.ValidateProvider(ctx, evalCtx, instance, key, data))
}
return diags.Append(newDiags)
}
verifyConfigIsKnown := op == walkImport
if verifyConfigIsKnown {
log.Printf("[TRACE] NodeApplyableProvider: configuring %s (requiring that configuration is wholly known)", n.Addr)
} else {
log.Printf("[TRACE] NodeApplyableProvider: configuring %s", n.Addr)
}
for key, data := range instanceData {
diags = diags.Append(n.ConfigureProvider(ctx, evalCtx, key, data, verifyConfigIsKnown))
}
return diags
}
func (n *NodeApplyableProvider) initInstances(ctx context.Context, evalCtx EvalContext, op walkOperation) (map[addrs.InstanceKey]providers.Interface, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
var initKeys []addrs.InstanceKey
// config -> init (different due to validate skipping most for_each logic)
instanceKeys := make(map[addrs.InstanceKey]addrs.InstanceKey)
if n.Config == nil || n.Config.Instances == nil {
initKeys = append(initKeys, addrs.NoKey)
instanceKeys[addrs.NoKey] = addrs.NoKey
} else if op == walkValidate {
// Instances are set AND we are validating
initKeys = append(initKeys, addrs.NoKey)
for key := range n.Config.Instances {
instanceKeys[key] = addrs.NoKey
}
} else {
// Instances are set AND we are not validating
for key := range n.Config.Instances {
initKeys = append(initKeys, key)
instanceKeys[key] = key
}
}
if n.instances == nil {
n.instances = map[addrs.InstanceKey]providers.Configured{}
}
for _, key := range initKeys {
instance, err := evalCtx.InitProvider(ctx, n.Addr, key)
diags = diags.Append(err)
if err == nil {
n.instances[key] = instance
}
}
if diags.HasErrors() {
return nil, diags
}
instances := make(map[addrs.InstanceKey]providers.Interface)
for configKey, initKey := range instanceKeys {
instances[configKey] = n.instances[initKey]
}
if diags.HasErrors() {
return nil, diags
}
return instances, diags
}
func (n *NodeApplyableProvider) executeInstance(ctx context.Context, evalCtx EvalContext, op walkOperation, providerKey addrs.InstanceKey, provider providers.Interface) tfdiags.Diagnostics {
switch op {
case walkValidate:
log.Printf("[TRACE] NodeApplyableProvider: validating configuration for %s", n.Addr)
return n.ValidateProvider(ctx, evalCtx, providerKey, provider)
case walkPlan, walkPlanDestroy, walkApply, walkDestroy:
log.Printf("[TRACE] NodeApplyableProvider: configuring %s", n.Addr)
return n.ConfigureProvider(ctx, evalCtx, providerKey, provider, false)
case walkImport:
log.Printf("[TRACE] NodeApplyableProvider: configuring %s (requiring that configuration is wholly known)", n.Addr)
return n.ConfigureProvider(ctx, evalCtx, providerKey, provider, true)
}
return nil
}
func (n *NodeApplyableProvider) ValidateProvider(ctx context.Context, evalCtx EvalContext, providerKey addrs.InstanceKey, provider providers.Interface) tfdiags.Diagnostics {
func (n *NodeApplyableProvider) ValidateProvider(ctx context.Context, evalCtx EvalContext, instance providers.Unconfigured, providerKey addrs.InstanceKey, data InstanceKeyEvalData) tfdiags.Diagnostics {
_, span := tracing.Tracer().Start(
ctx, "Validate provider configuration",
tracing.SpanAttributes(
@ -189,14 +150,14 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx context.Context, evalCtx Ev
return nil
}
schemaResp := provider.GetProviderSchema(ctx)
diags := schemaResp.Diagnostics.InConfigBody(configBody, n.Addr.InstanceString(providerKey))
schema, schemaDiags := evalCtx.Providers().GetProviderSchema(ctx, n.Addr.Provider)
diags := schemaDiags.InConfigBody(configBody, n.Addr.InstanceString(providerKey))
if diags.HasErrors() {
tracing.SetSpanError(span, diags)
return diags
}
configSchema := schemaResp.Provider.Block
configSchema := schema.Provider.Block
if configSchema == nil {
// Should never happen in real code, but often comes up in tests where
// mock schemas are being used that tend to be incomplete.
@ -204,11 +165,6 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx context.Context, evalCtx Ev
configSchema = &configschema.Block{}
}
data := EvalDataForNoInstanceKey
if n.Config != nil && n.Config.Instances != nil {
data = n.Config.Instances[providerKey]
}
configVal, _, evalDiags := evalCtx.EvaluateBlock(ctx, configBody, configSchema, nil, data)
if evalDiags.HasErrors() {
tracing.SetSpanError(span, diags)
@ -224,7 +180,7 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx context.Context, evalCtx Ev
Config: unmarkedConfigVal,
}
validateResp := provider.ValidateProviderConfig(ctx, req)
validateResp := instance.ValidateProviderConfig(ctx, req)
diags = diags.Append(validateResp.Diagnostics.InConfigBody(configBody, n.Addr.InstanceString(providerKey)))
tracing.SetSpanError(span, diags)
@ -234,7 +190,7 @@ func (n *NodeApplyableProvider) ValidateProvider(ctx context.Context, evalCtx Ev
// ConfigureProvider configures a provider that is already initialized and retrieved.
// If verifyConfigIsKnown is true, ConfigureProvider will return an error if the
// provider configVal is not wholly known and is meant only for use during import.
func (n *NodeApplyableProvider) ConfigureProvider(ctx context.Context, evalCtx EvalContext, providerKey addrs.InstanceKey, provider providers.Interface, verifyConfigIsKnown bool) tfdiags.Diagnostics {
func (n *NodeApplyableProvider) ConfigureProvider(ctx context.Context, evalCtx EvalContext, providerKey addrs.InstanceKey, data InstanceKeyEvalData, verifyConfigIsKnown bool) tfdiags.Diagnostics {
_, span := tracing.Tracer().Start(
ctx, "Configure provider",
tracing.SpanAttributes(
@ -247,25 +203,23 @@ func (n *NodeApplyableProvider) ConfigureProvider(ctx context.Context, evalCtx E
if n.Config != nil && n.Config.IsMocked {
// Mocked for testing
return nil
instance, diags := evalCtx.Providers().NewProvider(ctx, n.Addr.Provider)
n.instances[providerKey] = instance
return diags
}
config := n.ProviderConfig()
configBody := buildProviderConfig(ctx, evalCtx, n.Addr, config)
resp := provider.GetProviderSchema(ctx)
diags := resp.Diagnostics.InConfigBody(configBody, n.Addr.InstanceString(providerKey))
schema, schemaDiags := evalCtx.Providers().GetProviderSchema(ctx, n.Addr.Provider)
diags := schemaDiags.InConfigBody(configBody, n.Addr.InstanceString(providerKey))
if diags.HasErrors() {
tracing.SetSpanError(span, diags)
return diags
}
configSchema := resp.Provider.Block
data := EvalDataForNoInstanceKey
if n.Config != nil && n.Config.Instances != nil {
data = n.Config.Instances[providerKey]
}
configSchema := schema.Provider.Block
configVal, configBody, evalDiags := evalCtx.EvaluateBlock(ctx, configBody, configSchema, nil, data)
diags = diags.Append(evalDiags)
@ -285,20 +239,11 @@ func (n *NodeApplyableProvider) ConfigureProvider(ctx context.Context, evalCtx E
return diags
}
// If our config value contains any marked values, ensure those are
// stripped out before sending this to the provider
unmarkedConfigVal, _ := configVal.UnmarkDeep()
provider, newDiags := evalCtx.Providers().NewConfiguredProvider(ctx, n.Addr.Provider, configVal)
diags = diags.Append(newDiags.InConfigBody(configBody, n.Addr.InstanceString(providerKey)))
// Allow the provider to validate and insert any defaults into the full
// configuration.
req := providers.ValidateProviderConfigRequest{
Config: unmarkedConfigVal,
}
n.instances[providerKey] = provider
// ValidateProviderConfig is only used for validation. We are intentionally
// ignoring the PreparedConfig field to maintain existing behavior.
validateResp := provider.ValidateProviderConfig(ctx, req)
diags = diags.Append(validateResp.Diagnostics.InConfigBody(configBody, n.Addr.InstanceString(providerKey)))
if diags.HasErrors() && config == nil {
// If there isn't an explicit "provider" block in the configuration,
// this error message won't be very clear. Add some detail to the error
@ -315,29 +260,6 @@ func (n *NodeApplyableProvider) ConfigureProvider(ctx context.Context, evalCtx E
return diags
}
// If the provider returns something different, log a warning to help
// indicate to provider developers that the value is not used.
preparedCfg := validateResp.PreparedConfig
if preparedCfg != cty.NilVal && !preparedCfg.IsNull() && !preparedCfg.RawEquals(unmarkedConfigVal) {
log.Printf("[WARN] ValidateProviderConfig from %q changed the config value, but that value is unused", n.Addr)
}
configResp := provider.ConfigureProvider(ctx, providers.ConfigureProviderRequest{
TerraformVersion: version.String(),
Config: unmarkedConfigVal,
})
diags = diags.Append(configResp.Diagnostics.InConfigBody(configBody, n.Addr.InstanceString(providerKey)))
if diags.HasErrors() && config == nil {
// If there isn't an explicit "provider" block in the configuration,
// this error message won't be very clear. Add some detail to the error
// message in this case.
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Invalid provider configuration",
fmt.Sprintf(providerConfigErr, n.Addr.Provider),
))
}
tracing.SetSpanError(span, diags)
return diags
}

View file

@ -48,7 +48,6 @@ func (n *NodeEvalableProvider) Close(ctx context.Context) error {
// GraphNodeExecutable
func (n *NodeEvalableProvider) Execute(ctx context.Context, evalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
var err error
n.instance, err = evalCtx.InitProvider(ctx, n.Addr, addrs.NoKey)
return diags.Append(err)
n.instance, diags = evalCtx.Providers().NewProvider(ctx, n.Addr.Provider)
return diags
}

View file

@ -51,7 +51,8 @@ func TestNodeApplyableProviderExecute(t *testing.T) {
Config: config,
}}
evalCtx := &MockEvalContext{InitProviderProvider: provider}
evalCtx := &MockEvalContext{}
evalCtx.installProvider(providerAddr.Provider, provider)
evalCtx.installSimpleEval()
evalCtx.ProviderInputValues = map[string]cty.Value{
"pw": cty.StringVal("so secret"),
@ -98,7 +99,8 @@ func TestNodeApplyableProviderExecute_unknownImport(t *testing.T) {
Config: config,
}}
evalCtx := &MockEvalContext{InitProviderProvider: provider}
evalCtx := &MockEvalContext{}
evalCtx.installProvider(providerAddr.Provider, provider)
evalCtx.installSimpleEval()
diags := n.Execute(t.Context(), evalCtx, walkImport)
@ -132,7 +134,8 @@ func TestNodeApplyableProviderExecute_unknownApply(t *testing.T) {
Addr: providerAddr,
Config: config,
}}
evalCtx := &MockEvalContext{InitProviderProvider: provider}
evalCtx := &MockEvalContext{}
evalCtx.installProvider(providerAddr.Provider, provider)
evalCtx.installSimpleEval()
if err := n.Execute(t.Context(), evalCtx, walkApply); err != nil {
@ -170,7 +173,8 @@ func TestNodeApplyableProviderExecute_sensitive(t *testing.T) {
Config: config,
}}
evalCtx := &MockEvalContext{InitProviderProvider: provider}
evalCtx := &MockEvalContext{}
evalCtx.installProvider(providerAddr.Provider, provider)
evalCtx.installSimpleEval()
if err := n.Execute(t.Context(), evalCtx, walkApply); err != nil {
t.Fatalf("err: %s", err)
@ -207,7 +211,8 @@ func TestNodeApplyableProviderExecute_sensitiveValidate(t *testing.T) {
Config: config,
}}
evalCtx := &MockEvalContext{InitProviderProvider: provider}
evalCtx := &MockEvalContext{}
evalCtx.installProvider(providerAddr.Provider, provider)
evalCtx.installSimpleEval()
if err := n.Execute(t.Context(), evalCtx, walkValidate); err != nil {
t.Fatalf("err: %s", err)
@ -249,7 +254,8 @@ func TestNodeApplyableProviderExecute_emptyValidate(t *testing.T) {
Config: config,
}}
evalCtx := &MockEvalContext{InitProviderProvider: provider}
evalCtx := &MockEvalContext{}
evalCtx.installProvider(providerAddr.Provider, provider)
evalCtx.installSimpleEval()
if err := n.Execute(t.Context(), evalCtx, walkValidate); err != nil {
t.Fatalf("err: %s", err)
@ -261,6 +267,7 @@ func TestNodeApplyableProviderExecute_emptyValidate(t *testing.T) {
}
func TestNodeApplyableProvider_Validate(t *testing.T) {
providerAddr := mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)
provider := mockProviderWithConfigSchema(&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"region": {
@ -269,7 +276,8 @@ func TestNodeApplyableProvider_Validate(t *testing.T) {
},
},
})
evalCtx := &MockEvalContext{InitProviderProvider: provider}
evalCtx := &MockEvalContext{}
evalCtx.installProvider(providerAddr.Provider, provider)
evalCtx.installSimpleEval()
t.Run("valid", func(t *testing.T) {
@ -282,12 +290,12 @@ func TestNodeApplyableProvider_Validate(t *testing.T) {
node := NodeApplyableProvider{
NodeAbstractProvider: &NodeAbstractProvider{
Addr: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
Addr: providerAddr,
Config: config,
},
}
diags := node.ValidateProvider(t.Context(), evalCtx, addrs.NoKey, provider)
diags := node.ValidateProvider(t.Context(), evalCtx, provider, addrs.NoKey, EvalDataForNoInstanceKey)
if diags.HasErrors() {
t.Errorf("unexpected error with valid config: %s", diags.Err())
}
@ -303,12 +311,12 @@ func TestNodeApplyableProvider_Validate(t *testing.T) {
node := NodeApplyableProvider{
NodeAbstractProvider: &NodeAbstractProvider{
Addr: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
Addr: providerAddr,
Config: config,
},
}
diags := node.ValidateProvider(t.Context(), evalCtx, addrs.NoKey, provider)
diags := node.ValidateProvider(t.Context(), evalCtx, provider, addrs.NoKey, EvalDataForNoInstanceKey)
if !diags.HasErrors() {
t.Error("missing expected error with invalid config")
}
@ -317,11 +325,11 @@ func TestNodeApplyableProvider_Validate(t *testing.T) {
t.Run("empty config", func(t *testing.T) {
node := NodeApplyableProvider{
NodeAbstractProvider: &NodeAbstractProvider{
Addr: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
Addr: providerAddr,
},
}
diags := node.ValidateProvider(t.Context(), evalCtx, addrs.NoKey, provider)
diags := node.ValidateProvider(t.Context(), evalCtx, provider, addrs.NoKey, EvalDataForNoInstanceKey)
if diags.HasErrors() {
t.Errorf("unexpected error with empty config: %s", diags.Err())
}
@ -333,6 +341,7 @@ func TestNodeApplyableProvider_Validate(t *testing.T) {
// TestNodeApplyableProvider_ConfigProvider_config_fn_err for
// providers.ConfigureProviderRequest responses.
func TestNodeApplyableProvider_ConfigProvider(t *testing.T) {
providerAddr := mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)
provider := mockProviderWithConfigSchema(&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"region": {
@ -351,7 +360,8 @@ func TestNodeApplyableProvider_ConfigProvider(t *testing.T) {
}
return
}
evalCtx := &MockEvalContext{InitProviderProvider: provider}
evalCtx := &MockEvalContext{}
evalCtx.installProvider(providerAddr.Provider, provider)
evalCtx.installSimpleEval()
t.Run("valid", func(t *testing.T) {
@ -364,12 +374,13 @@ func TestNodeApplyableProvider_ConfigProvider(t *testing.T) {
node := NodeApplyableProvider{
NodeAbstractProvider: &NodeAbstractProvider{
Addr: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
Addr: providerAddr,
Config: config,
},
instances: map[addrs.InstanceKey]providers.Configured{},
}
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, provider, false)
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, EvalDataForNoInstanceKey, false)
if diags.HasErrors() {
t.Errorf("unexpected error with valid config: %s", diags.Err())
}
@ -378,11 +389,12 @@ func TestNodeApplyableProvider_ConfigProvider(t *testing.T) {
t.Run("missing required config (no config at all)", func(t *testing.T) {
node := NodeApplyableProvider{
NodeAbstractProvider: &NodeAbstractProvider{
Addr: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
Addr: providerAddr,
},
instances: map[addrs.InstanceKey]providers.Configured{},
}
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, provider, false)
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, EvalDataForNoInstanceKey, false)
if !diags.HasErrors() {
t.Fatal("missing expected error with nil config")
}
@ -398,12 +410,13 @@ func TestNodeApplyableProvider_ConfigProvider(t *testing.T) {
}
node := NodeApplyableProvider{
NodeAbstractProvider: &NodeAbstractProvider{
Addr: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
Addr: providerAddr,
Config: config,
},
instances: map[addrs.InstanceKey]providers.Configured{},
}
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, provider, false)
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, EvalDataForNoInstanceKey, false)
if !diags.HasErrors() {
t.Fatal("missing expected error with invalid config")
}
@ -416,6 +429,7 @@ func TestNodeApplyableProvider_ConfigProvider(t *testing.T) {
// This test is similar to TestNodeApplyableProvider_ConfigProvider, but tests responses from the providers.ConfigureProviderRequest
func TestNodeApplyableProvider_ConfigProvider_config_fn_err(t *testing.T) {
providerAddr := mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`)
provider := mockProviderWithConfigSchema(&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"region": {
@ -424,7 +438,8 @@ func TestNodeApplyableProvider_ConfigProvider_config_fn_err(t *testing.T) {
},
},
})
evalCtx := &MockEvalContext{InitProviderProvider: provider}
evalCtx := &MockEvalContext{}
evalCtx.installProvider(providerAddr.Provider, provider)
evalCtx.installSimpleEval()
// For this test, provider.PrepareConfigFn will succeed every time but the
// ctx.ConfigureProviderFn will return an error if a value is not found.
@ -459,12 +474,13 @@ func TestNodeApplyableProvider_ConfigProvider_config_fn_err(t *testing.T) {
node := NodeApplyableProvider{
NodeAbstractProvider: &NodeAbstractProvider{
Addr: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
Addr: providerAddr,
Config: config,
},
instances: map[addrs.InstanceKey]providers.Configured{},
}
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, provider, false)
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, EvalDataForNoInstanceKey, false)
if diags.HasErrors() {
t.Errorf("unexpected error with valid config: %s", diags.Err())
}
@ -473,11 +489,12 @@ func TestNodeApplyableProvider_ConfigProvider_config_fn_err(t *testing.T) {
t.Run("missing required config (no config at all)", func(t *testing.T) {
node := NodeApplyableProvider{
NodeAbstractProvider: &NodeAbstractProvider{
Addr: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
Addr: providerAddr,
},
instances: map[addrs.InstanceKey]providers.Configured{},
}
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, provider, false)
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, EvalDataForNoInstanceKey, false)
if !diags.HasErrors() {
t.Fatal("missing expected error with nil config")
}
@ -493,12 +510,13 @@ func TestNodeApplyableProvider_ConfigProvider_config_fn_err(t *testing.T) {
}
node := NodeApplyableProvider{
NodeAbstractProvider: &NodeAbstractProvider{
Addr: mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
Addr: providerAddr,
Config: config,
},
instances: map[addrs.InstanceKey]providers.Configured{},
}
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, provider, false)
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, EvalDataForNoInstanceKey, false)
if !diags.HasErrors() {
t.Fatal("missing expected error with invalid config")
}
@ -516,15 +534,17 @@ func TestGetSchemaError(t *testing.T) {
}
providerAddr := mustProviderConfig(`provider["terraform.io/some/provider"]`)
evalCtx := &MockEvalContext{InitProviderProvider: provider}
evalCtx := &MockEvalContext{}
evalCtx.installProvider(providerAddr.Provider, provider)
evalCtx.installSimpleEval()
node := NodeApplyableProvider{
NodeAbstractProvider: &NodeAbstractProvider{
Addr: providerAddr,
},
instances: map[addrs.InstanceKey]providers.Configured{},
}
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, provider, false)
diags := node.ConfigureProvider(t.Context(), evalCtx, addrs.NoKey, EvalDataForNoInstanceKey, false)
for _, d := range diags {
desc := d.Description()
if desc.Address != providerAddr.String() {

View file

@ -29,7 +29,6 @@ import (
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/plans/objchange"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/shared"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
@ -2644,13 +2643,7 @@ func (n *NodeAbstractResourceInstance) applyProvisioners(ctx context.Context, ev
for _, prov := range provs {
log.Printf("[TRACE] applyProvisioners: provisioning %s with %q", n.Addr, prov.Type)
// Get the provisioner
provisioner, err := evalCtx.Provisioner(prov.Type)
if err != nil {
return diags.Append(err)
}
schema, err := evalCtx.ProvisionerSchema(prov.Type)
schema, err := evalCtx.Provisioners().ProvisionerSchema(prov.Type)
if err != nil {
// This error probably won't be a great diagnostic, but in practice
// we typically catch this problem long before we get here, so
@ -2750,12 +2743,15 @@ func (n *NodeAbstractResourceInstance) applyProvisioners(ctx context.Context, ev
}
output := CallbackUIOutput{OutputFn: outputFn}
resp := provisioner.ProvisionResource(provisioners.ProvisionResourceRequest{
Config: unmarkedConfig,
Connection: unmarkedConnInfo,
UIOutput: &output,
})
applyDiags := resp.Diagnostics.InConfigBody(prov.Config, n.Addr.String())
resp := evalCtx.Provisioners().ProvisionResource(
ctx,
prov.Type,
unmarkedConfig,
unmarkedConnInfo,
&output,
)
applyDiags := resp.InConfigBody(prov.Config, n.Addr.String())
// Call post hook
hookErr := evalCtx.Hook(func(h Hook) (HookAction, error) {
@ -3181,9 +3177,9 @@ func (n *NodeAbstractResourceInstance) getProvider(ctx context.Context, evalCtx
// Not all callers require a schema, so we will leave checking for a nil
// schema to the callers.
schema, err := evalCtx.ProviderSchema(ctx, n.ResolvedProvider.ProviderConfig)
if err != nil {
return nil, providers.ProviderSchema{}, fmt.Errorf("failed to read schema for provider %s: %w", n.ResolvedProvider.ProviderConfig, err)
schema, schemaDiags := evalCtx.Providers().GetProviderSchema(ctx, n.ResolvedProvider.ProviderConfig.Provider)
if schemaDiags.HasErrors() {
return nil, providers.ProviderSchema{}, fmt.Errorf("failed to read schema for provider %s: %w", n.ResolvedProvider.ProviderConfig, schemaDiags.Err())
}
var isOverridden bool
@ -3220,7 +3216,7 @@ func (n *NodeAbstractResourceInstance) getProvider(ctx context.Context, evalCtx
return provider, schema, err
}
return underlyingProvider, schema, err
return underlyingProvider, schema, nil
}
func (n *NodeAbstractResourceInstance) applyEphemeralResource(ctx context.Context, evalCtx EvalContext) (*states.ResourceInstanceObject, instances.RepetitionData, tfdiags.Diagnostics) {

View file

@ -176,7 +176,7 @@ func TestNodeAbstractResourceInstance_WriteResourceInstanceState(t *testing.T) {
ResolvedProvider: mustResolvedProviderInRoot("aws", mockProvider),
},
}
evalCtx.ProviderSchemaSchema = mockProvider.GetProviderSchema(t.Context())
evalCtx.installProvider(addrs.NewDefaultProvider("aws"), mockProvider)
err := node.writeResourceInstanceState(t.Context(), evalCtx, obj, workingState)
if err != nil {

View file

@ -197,12 +197,14 @@ func getMockProviderForReadResourceInstanceState() *MockProvider {
ResourceTypes: map[string]providers.Schema{
"aws_instance": constructProviderSchemaForTesting(map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Type: cty.String,
Computed: true,
},
}),
"aws_instance0": constructProviderSchemaForTesting(map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Type: cty.String,
Computed: true,
},
}),
},
@ -322,8 +324,8 @@ func TestNodeAbstractResource_ReadResourceInstanceState(t *testing.T) {
evalCtx := new(MockEvalContext)
evalCtx.StateState = test.State.SyncWrapper()
evalCtx.PathPath = addrs.RootModuleInstance
evalCtx.ProviderSchemaSchema = test.Provider.GetProviderSchema(t.Context())
evalCtx.MoveResultsResults = test.MoveResults
evalCtx.installProvider(addrs.NewDefaultProvider("aws"), test.Provider)
test.Node.ResolvedProvider = mustResolvedProviderInRoot("aws", test.Provider)
got, readDiags := test.Node.readResourceInstanceState(t.Context(), evalCtx, test.Node.Addr)
@ -337,7 +339,7 @@ func TestNodeAbstractResource_ReadResourceInstanceState(t *testing.T) {
return
}
if readDiags.HasErrors() {
t.Fatalf("[%s] Got err: %#v", test.Name, readDiags.Err())
t.Fatalf("[%s] Got err: %s", test.Name, readDiags.Err())
}
expected := test.ExpectedInstanceId
@ -369,8 +371,8 @@ func TestNodeAbstractResource_ReadResourceInstanceState(t *testing.T) {
evalCtx := new(MockEvalContext)
evalCtx.StateState = test.State.SyncWrapper()
evalCtx.PathPath = addrs.RootModuleInstance
evalCtx.ProviderSchemaSchema = test.Provider.GetProviderSchema(t.Context())
evalCtx.MoveResultsResults = test.MoveResults
evalCtx.installProvider(addrs.NewDefaultProvider("aws"), test.Provider)
test.Node.ResolvedProvider = mustResolvedProviderInRoot("aws", test.Provider)
key := states.DeposedKey("00000001") // shim from legacy state assigns 0th deposed index this key

View file

@ -267,7 +267,7 @@ func TestNodeDestroyDeposedResourceInstanceObject_WriteResourceInstanceState(t *
},
},
})
evalCtx.ProviderSchemaSchema = mockProvider.GetProviderSchema(t.Context())
evalCtx.installProvider(addrs.NewDefaultProvider("aws"), mockProvider)
obj := &states.ResourceInstanceObject{
Value: cty.ObjectVal(map[string]cty.Value{
@ -300,10 +300,10 @@ aws_instance.foo: (1 deposed)
func TestNodeDestroyDeposedResourceInstanceObject_ExecuteMissingState(t *testing.T) {
p := simpleMockProvider()
evalCtx := &MockEvalContext{
StateState: states.NewState().SyncWrapper(),
ProviderSchemaSchema: p.GetProviderSchema(t.Context()),
ChangesChanges: plans.NewChanges().SyncWrapper(),
StateState: states.NewState().SyncWrapper(),
ChangesChanges: plans.NewChanges().SyncWrapper(),
}
evalCtx.installProvider(addrs.NewDefaultProvider("test"), p)
node := NodeDestroyDeposedResourceInstanceObject{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
@ -391,13 +391,15 @@ func initMockEvalContext(ctx context.Context, resourceAddrs string, deposedKey s
"id": cty.StringVal("bar"),
}),
}
return &MockEvalContext{
PrevRunStateState: state.DeepCopy().SyncWrapper(),
RefreshStateState: state.DeepCopy().SyncWrapper(),
StateState: state.SyncWrapper(),
ProviderSchemaSchema: schema,
ChangesChanges: plans.NewChanges().SyncWrapper(),
}, p
evalCtx := &MockEvalContext{
PrevRunStateState: state.DeepCopy().SyncWrapper(),
RefreshStateState: state.DeepCopy().SyncWrapper(),
StateState: state.SyncWrapper(),
ChangesChanges: plans.NewChanges().SyncWrapper(),
}
evalCtx.installProvider(addrs.NewDefaultProvider("test"), p)
return evalCtx, p
}
func assertDiags(t *testing.T, got, want tfdiags.Diagnostics) {

View file

@ -223,9 +223,9 @@ func TestNodeResourcePlanOrphan_Execute(t *testing.T) {
RefreshStateState: state.DeepCopy().SyncWrapper(),
PrevRunStateState: state.DeepCopy().SyncWrapper(),
InstanceExpanderExpander: instances.NewExpander(),
ProviderSchemaSchema: schema,
ChangesChanges: plans.NewChanges().SyncWrapper(),
}
evalCtx.installProvider(addrs.NewDefaultProvider("test"), p)
node := NodePlannableResourceInstanceOrphan{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
@ -279,6 +279,13 @@ func TestNodeResourcePlanOrphanExecute_alreadyDeleted(t *testing.T) {
changes := plans.NewChanges()
p := simpleMockProvider()
p.GetProviderSchemaResponse = &providers.ProviderSchema{
ResourceTypes: map[string]providers.Schema{
"test_object": {
Block: simpleTestSchema(),
},
},
}
p.ConfigureProvider(t.Context(), providers.ConfigureProviderRequest{})
p.ReadResourceResponse = &providers.ReadResourceResponse{
NewState: cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["test_string"].Block.ImpliedType()),
@ -288,15 +295,9 @@ func TestNodeResourcePlanOrphanExecute_alreadyDeleted(t *testing.T) {
RefreshStateState: refreshState.SyncWrapper(),
PrevRunStateState: prevRunState.SyncWrapper(),
InstanceExpanderExpander: instances.NewExpander(),
ProviderSchemaSchema: providers.ProviderSchema{
ResourceTypes: map[string]providers.Schema{
"test_object": {
Block: simpleTestSchema(),
},
},
},
ChangesChanges: changes.SyncWrapper(),
ChangesChanges: changes.SyncWrapper(),
}
evalCtx.installProvider(addrs.NewDefaultProvider("test"), p)
node := NodePlannableResourceInstanceOrphan{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{
@ -358,6 +359,13 @@ func TestNodeResourcePlanOrphanExecute_deposed(t *testing.T) {
changes := plans.NewChanges()
p := simpleMockProvider()
p.GetProviderSchemaResponse = &providers.ProviderSchema{
ResourceTypes: map[string]providers.Schema{
"test_object": {
Block: simpleTestSchema(),
},
},
}
p.ConfigureProvider(t.Context(), providers.ConfigureProviderRequest{})
p.ReadResourceResponse = &providers.ReadResourceResponse{
NewState: cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["test_string"].Block.ImpliedType()),
@ -367,15 +375,9 @@ func TestNodeResourcePlanOrphanExecute_deposed(t *testing.T) {
RefreshStateState: refreshState.SyncWrapper(),
PrevRunStateState: prevRunState.SyncWrapper(),
InstanceExpanderExpander: instances.NewExpander(),
ProviderSchemaSchema: providers.ProviderSchema{
ResourceTypes: map[string]providers.Schema{
"test_object": {
Block: simpleTestSchema(),
},
},
},
ChangesChanges: changes.SyncWrapper(),
ChangesChanges: changes.SyncWrapper(),
}
evalCtx.installProvider(addrs.NewDefaultProvider("test"), p)
node := NodePlannableResourceInstanceOrphan{
NodeAbstractResourceInstance: &NodeAbstractResourceInstance{

View file

@ -22,7 +22,6 @@ import (
"github.com/opentofu/opentofu/internal/instances"
"github.com/opentofu/opentofu/internal/lang"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/tfdiags"
"github.com/opentofu/opentofu/internal/tracing"
"github.com/opentofu/opentofu/internal/tracing/traceattrs"
@ -130,16 +129,7 @@ func (n *NodeValidatableResource) Execute(ctx context.Context, evalCtx EvalConte
func (n *NodeValidatableResource) validateProvisioner(ctx context.Context, evalCtx EvalContext, p *configs.Provisioner) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
provisioner, err := evalCtx.Provisioner(p.Type)
if err != nil {
diags = diags.Append(err)
return diags
}
if provisioner == nil {
return diags.Append(fmt.Errorf("provisioner %s not initialized", p.Type))
}
provisionerSchema, err := evalCtx.ProvisionerSchema(p.Type)
provisionerSchema, err := evalCtx.Provisioners().ProvisionerSchema(p.Type)
if err != nil {
return diags.Append(fmt.Errorf("failed to read schema for provisioner %s: %w", p.Type, err))
}
@ -158,12 +148,8 @@ func (n *NodeValidatableResource) validateProvisioner(ctx context.Context, evalC
// Use unmarked value for validate request
unmarkedConfigVal, _ := configVal.UnmarkDeep()
req := provisioners.ValidateProvisionerConfigRequest{
Config: unmarkedConfigVal,
}
resp := provisioner.ValidateProvisionerConfig(req)
diags = diags.Append(resp.Diagnostics)
resp := evalCtx.Provisioners().ValidateProvisionerConfig(ctx, p.Type, unmarkedConfigVal)
diags = diags.Append(resp)
if p.Connection != nil {
// We can't comprehensively validate the connection config since its
@ -192,8 +178,8 @@ func (n *NodeValidatableResource) validateResource(ctx context.Context, evalCtx
if diags.HasErrors() {
return diags
}
providerSchema, err := evalCtx.ProviderSchema(ctx, n.ResolvedProvider.ProviderConfig)
diags = diags.Append(err)
providerSchema, moreDiags := evalCtx.Providers().GetProviderSchema(ctx, n.ResolvedProvider.ProviderConfig.Provider)
diags = diags.Append(moreDiags)
if diags.HasErrors() {
return diags
}

View file

@ -17,6 +17,7 @@ import (
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/lang/marks"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/provisioners"
"github.com/opentofu/opentofu/internal/tfdiags"
@ -27,9 +28,11 @@ func TestNodeValidatableResource_ValidateProvisioner_valid(t *testing.T) {
ctx := &MockEvalContext{}
ctx.installSimpleEval()
mp := &MockProvisioner{}
ps := &configschema.Block{}
ctx.ProvisionerSchemaSchema = ps
ctx.ProvisionerProvisioner = mp
mp.GetSchemaResponse = provisioners.GetSchemaResponse{Provisioner: &configschema.Block{}}
ctx.ProvisionersProvisioners = plugins.NewLibrary(nil, map[string]provisioners.Factory{
"baz": func() (provisioners.Interface, error) { return mp, nil },
}).NewProvisionerManager()
pc := &configs.Provisioner{
Type: "baz",
@ -70,9 +73,10 @@ func TestNodeValidatableResource_ValidateProvisioner__warning(t *testing.T) {
ctx := &MockEvalContext{}
ctx.installSimpleEval()
mp := &MockProvisioner{}
ps := &configschema.Block{}
ctx.ProvisionerSchemaSchema = ps
ctx.ProvisionerProvisioner = mp
mp.GetSchemaResponse = provisioners.GetSchemaResponse{Provisioner: &configschema.Block{}}
ctx.ProvisionersProvisioners = plugins.NewLibrary(nil, map[string]provisioners.Factory{
"baz": func() (provisioners.Interface, error) { return mp, nil },
}).NewProvisionerManager()
pc := &configs.Provisioner{
Type: "baz",
@ -116,9 +120,10 @@ func TestNodeValidatableResource_ValidateProvisioner__connectionInvalid(t *testi
ctx := &MockEvalContext{}
ctx.installSimpleEval()
mp := &MockProvisioner{}
ps := &configschema.Block{}
ctx.ProvisionerSchemaSchema = ps
ctx.ProvisionerProvisioner = mp
mp.GetSchemaResponse = provisioners.GetSchemaResponse{Provisioner: &configschema.Block{}}
ctx.ProvisionersProvisioners = plugins.NewLibrary(nil, map[string]provisioners.Factory{
"baz": func() (provisioners.Interface, error) { return mp, nil },
}).NewProvisionerManager()
pc := &configs.Provisioner{
Type: "baz",
@ -196,7 +201,7 @@ func TestNodeValidatableResource_ValidateResource_managedResource(t *testing.T)
ctx := &MockEvalContext{}
ctx.installSimpleEval()
ctx.ProviderSchemaSchema = mp.GetProviderSchema(t.Context())
ctx.installProvider(addrs.NewDefaultProvider("test"), p)
err := node.validateResource(t.Context(), ctx)
if err != nil {
@ -225,7 +230,7 @@ func TestNodeValidatableResource_ValidateResource_managedResourceCount(t *testin
ctx := &MockEvalContext{}
ctx.installSimpleEval()
ctx.ProviderSchemaSchema = mp.GetProviderSchema(t.Context())
ctx.installProvider(addrs.NewDefaultProvider("test"), p)
tests := []struct {
name string
@ -296,7 +301,7 @@ func TestNodeValidatableResource_ValidateResource_ephemeralResource(t *testing.T
ctx := &MockEvalContext{}
ctx.installSimpleEval()
ctx.ProviderSchemaSchema = mp.GetProviderSchema(t.Context())
ctx.installProvider(addrs.NewDefaultProvider("test"), p)
t.Run("no errors", func(t *testing.T) {
mp.ValidateEphemeralConfigCalled = false
@ -385,7 +390,7 @@ func TestNodeValidatableResource_ValidateResource_dataSource(t *testing.T) {
ctx := &MockEvalContext{}
ctx.installSimpleEval()
ctx.ProviderSchemaSchema = mp.GetProviderSchema(t.Context())
ctx.installProvider(addrs.NewDefaultProvider("test"), p)
diags := node.validateResource(t.Context(), ctx)
if diags.HasErrors() {
@ -420,7 +425,7 @@ func TestNodeValidatableResource_ValidateResource_valid(t *testing.T) {
ctx := &MockEvalContext{}
ctx.installSimpleEval()
ctx.ProviderSchemaSchema = mp.GetProviderSchema(t.Context())
ctx.installProvider(addrs.NewDefaultProvider("test"), p)
diags := node.validateResource(t.Context(), ctx)
if diags.HasErrors() {
@ -456,7 +461,7 @@ func TestNodeValidatableResource_ValidateResource_warningsAndErrorsPassedThrough
ctx := &MockEvalContext{}
ctx.installSimpleEval()
ctx.ProviderSchemaSchema = mp.GetProviderSchema(t.Context())
ctx.installProvider(addrs.NewDefaultProvider("test"), p)
diags := node.validateResource(t.Context(), ctx)
if !diags.HasErrors() {
@ -517,8 +522,7 @@ func TestNodeValidatableResource_ValidateResource_invalidDependsOn(t *testing.T)
ctx := &MockEvalContext{}
ctx.installSimpleEval()
ctx.ProviderSchemaSchema = mp.GetProviderSchema(t.Context())
ctx.installProvider(addrs.NewDefaultProvider("test"), p)
diags := node.validateResource(t.Context(), ctx)
if diags.HasErrors() {
@ -600,8 +604,7 @@ func TestNodeValidatableResource_ValidateResource_invalidIgnoreChangesNonexisten
ctx := &MockEvalContext{}
ctx.installSimpleEval()
ctx.ProviderSchemaSchema = mp.GetProviderSchema(t.Context())
ctx.installProvider(addrs.NewDefaultProvider("test"), p)
diags := node.validateResource(t.Context(), ctx)
if diags.HasErrors() {
@ -682,8 +685,7 @@ func TestNodeValidatableResource_ValidateResource_invalidIgnoreChangesComputed(t
ctx := &MockEvalContext{}
ctx.installSimpleEval()
ctx.ProviderSchemaSchema = mp.GetProviderSchema(t.Context())
ctx.installProvider(addrs.NewDefaultProvider("test"), p)
diags := node.validateResource(t.Context(), ctx)
if diags.HasErrors() {
@ -809,8 +811,7 @@ func TestNodeValidatableResource_ValidateResource_suggestion(t *testing.T) {
ctx := &MockEvalContext{}
ctx.installSimpleEval()
ctx.ProviderSchemaSchema = mp.GetProviderSchema(t.Context())
ctx.installProvider(addrs.NewDefaultProvider("test"), p)
diags := node.validateResource(t.Context(), ctx)
if got, want := len(diags), 1; got != want {

View file

@ -109,14 +109,14 @@ func loadProviderSchemas(ctx context.Context, config *configs.Config, state *sta
for fqn := range schemas {
wg.Go(func() {
log.Printf("[TRACE] LoadSchemas: retrieving schema for provider type %q", fqn.String())
schema, err := plugins.ProviderSchema(ctx, fqn)
schema, schemaDiags := plugins.providers.GetProviderSchema(ctx, fqn)
// Ensure that we don't race on diags or schemas now that the hard work is done
lock.Lock()
defer lock.Unlock()
if err != nil {
diags = diags.Append(err)
if schemaDiags.HasErrors() {
diags = diags.Append(schemaDiags)
return
}

View file

@ -12,6 +12,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
)
@ -312,5 +313,5 @@ func schemaOnlyProvidersForTesting(schemas map[addrs.Provider]providers.Provider
}
}
return newContextPlugins(factories, nil)
return newContextPlugins(plugins.NewLibrary(factories, nil))
}

View file

@ -10,6 +10,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
)
@ -90,9 +91,9 @@ func setupSkipTestDefaultContext(t *testing.T) (*Context, *MockProvider) {
p.PlanResourceChangeFn = testDiffFn
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
}, nil),
})
return ctx, p

View file

@ -8,7 +8,6 @@ package tofu
import (
"context"
"fmt"
"log"
"sync"
"github.com/hashicorp/hcl/v2"
@ -22,7 +21,6 @@ import (
"github.com/opentofu/opentofu/internal/lang/marks"
"github.com/opentofu/opentofu/internal/moduletest"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
)
@ -100,70 +98,21 @@ func (tc *TestContext) evaluate(state *states.SyncState, changes *plans.ChangesS
PlanTimestamp: tc.Plan.Timestamp,
// InstanceExpander is intentionally nil for test contexts
// The GetModule function will fall back to using state/changes when it's nil
InstanceExpander: nil,
InstanceExpander: nil,
},
ModulePath: nil, // nil for the root module
InstanceKeyData: EvalDataForNoInstanceKey,
Operation: operation,
}
var providerInstanceLock sync.Mutex
providerInstances := make(map[addrs.Provider]providers.Interface)
defer func() {
for addr, inst := range providerInstances {
log.Printf("[INFO] Shutting down test provider %s", addr)
inst.Close(context.TODO())
}
}()
providerSupplier := func(addr addrs.Provider) providers.Interface {
providerInstanceLock.Lock()
defer providerInstanceLock.Unlock()
if inst, ok := providerInstances[addr]; ok {
return inst
}
factory, ok := tc.plugins.providerFactories[addr]
if !ok {
log.Printf("[WARN] Unable to find provider %s in test context", addr)
providerInstances[addr] = nil
return nil
}
log.Printf("[INFO] Starting test provider %s", addr)
inst, err := factory()
if err != nil {
log.Printf("[WARN] Unable to start provider %s in test context", addr)
providerInstances[addr] = nil
return nil
} else {
log.Printf("[INFO] Shutting down test provider %s", addr)
providerInstances[addr] = inst
return inst
}
}
scope := &lang.Scope{
Data: data,
BaseDir: ".",
PureOnly: operation != walkApply,
PlanTimestamp: tc.Plan.Timestamp,
ProviderFunctions: func(ctx context.Context, pf addrs.ProviderFunction, rng tfdiags.SourceRange) (*function.Function, tfdiags.Diagnostics) {
// This is a simpler flow than what is allowed during normal exection.
// We only support non-configured functions here.
pr, ok := tc.Config.Module.ProviderRequirements.RequiredProviders[pf.ProviderName]
if !ok {
return nil, tfdiags.Diagnostics{}.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Unknown function provider",
Detail: fmt.Sprintf("Provider %q does not exist within the required_providers of this module", pf.ProviderName),
Subject: rng.ToHCL().Ptr(),
})
}
provider := providerSupplier(pr.Type)
return evalContextProviderFunction(ctx, provider, walkPlan, pf, rng)
// TODO pass in tc.plugins
return evalContextProviderFunction(ctx, nil, walkPlan, pf, rng)
},
}

View file

@ -18,6 +18,7 @@ import (
"github.com/opentofu/opentofu/internal/lang/marks"
"github.com/opentofu/opentofu/internal/moduletest"
"github.com/opentofu/opentofu/internal/plans"
"github.com/opentofu/opentofu/internal/plugins"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/states"
"github.com/opentofu/opentofu/internal/tfdiags"
@ -373,9 +374,9 @@ run "test_case" {
t.Run(name, func(t *testing.T) {
config := testModuleInline(t, tc.configs)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(tc.provider),
},
}, nil),
})
run := moduletest.Run{
@ -569,9 +570,9 @@ run "test_case" {
t.Run(name, func(t *testing.T) {
config := testModuleInline(t, tc.configs)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
Plugins: plugins.NewLibrary(map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(tc.provider),
},
}, nil),
})
run := moduletest.Run{

View file

@ -70,9 +70,9 @@ func (t *AttachSchemaTransformer) Transform(ctx context.Context, g *Graph) error
providerFqn := tv.Provider()
// TODO: Plumb a useful context.Context through to here.
schema, version, err := t.Plugins.ResourceTypeSchema(ctx, providerFqn, mode, typeName)
if err != nil {
return fmt.Errorf("failed to read schema for %s in %s: %w", addr, providerFqn, err)
schema, version, diags := t.Plugins.ResourceTypeSchema(ctx, providerFqn, mode, typeName)
if diags.HasErrors() {
return fmt.Errorf("failed to read schema for %s in %s: %w", addr, providerFqn, diags.Err())
}
if schema == nil {
log.Printf("[ERROR] AttachSchemaTransformer: No resource schema available for %s", addr)
@ -85,9 +85,9 @@ func (t *AttachSchemaTransformer) Transform(ctx context.Context, g *Graph) error
if tv, ok := v.(GraphNodeAttachProviderConfigSchema); ok {
providerAddr := tv.ProviderAddr()
// TODO: Plumb a useful context.Context through to here.
schema, err := t.Plugins.ProviderConfigSchema(ctx, providerAddr.Provider)
if err != nil {
return fmt.Errorf("failed to read provider configuration schema for %s: %w", providerAddr.Provider, err)
schema, diags := t.Plugins.ProviderConfigSchema(ctx, providerAddr.Provider)
if diags.HasErrors() {
return fmt.Errorf("failed to read provider configuration schema for %s: %w", providerAddr.Provider, diags.Err())
}
if schema == nil {
log.Printf("[ERROR] AttachSchemaTransformer: No provider config schema available for %s", providerAddr)

View file

@ -67,23 +67,24 @@ func TestGraphNodeImportStateSubExecute(t *testing.T) {
state := states.NewState()
provider := testProvider("aws")
provider.ConfigureProvider(t.Context(), providers.ConfigureProviderRequest{})
evalCtx := &MockEvalContext{
StateState: state.SyncWrapper(),
ProviderSchemaSchema: providers.ProviderSchema{
ResourceTypes: map[string]providers.Schema{
"aws_instance": {
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Computed: true,
},
provider.GetProviderSchemaResponse = &providers.ProviderSchema{
ResourceTypes: map[string]providers.Schema{
"aws_instance": {
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Computed: true,
},
},
},
},
},
}
evalCtx := &MockEvalContext{
StateState: state.SyncWrapper(),
}
evalCtx.installProvider(addrs.NewDefaultProvider("aws"), provider)
importedResource := providers.ImportedResource{
TypeName: "aws_instance",
@ -124,18 +125,14 @@ func TestGraphNodeImportStateSubExecuteNull(t *testing.T) {
}))
return resp
}
evalCtx := &MockEvalContext{
StateState: state.SyncWrapper(),
ProviderSchemaSchema: providers.ProviderSchema{
ResourceTypes: map[string]providers.Schema{
"aws_instance": {
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Computed: true,
},
provider.GetProviderSchemaResponse = &providers.ProviderSchema{
ResourceTypes: map[string]providers.Schema{
"aws_instance": {
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"id": {
Type: cty.String,
Computed: true,
},
},
},
@ -143,6 +140,11 @@ func TestGraphNodeImportStateSubExecuteNull(t *testing.T) {
},
}
evalCtx := &MockEvalContext{
StateState: state.SyncWrapper(),
}
evalCtx.installProvider(addrs.NewDefaultProvider("aws"), provider)
importedResource := providers.ImportedResource{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{"id": cty.StringVal("bar")}),

View file

@ -62,3 +62,12 @@ func String() string {
}
return Version
}
// This ONLY represents what features OpenTofu currently intends to support from
// providers which may change their behavior given a particular TerraformVersion.
// It explicitly does NOT represent any sort of compatibility promise or guarantee.
// This value should ONLY ever be used by the provider.ConfigureProvider call, any
// other usage is WRONG and a PROGRAMMING ERROR.
// This value should be carefully updated as we add OpenTofu support for new protocol
// features.
const VersionToImpersonateForProviders = "1.13.0"