mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
The graph node types related to resources and resource instances use a bunch of helper functions in different combinations, rather than calling directly into the provider API. This commit plumbs context.Context through to the functions that _do_ eventually call methods directly on the provider object, leaving us just one more step away from plumbing the context through to the actual gRPC calls. The next step (in a future commit) will be to update the providers.Interface methods to take context.Context arguments and then have the gRPC-based implementations of that interface pass the context through to the gRPC client stub calls, and then we should be pretty close to being able to turn on OTel tracing instrumentation for our gRPC client requests. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
118 lines
4.1 KiB
Go
118 lines
4.1 KiB
Go
// Copyright (c) The OpenTofu Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package tofu
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/opentofu/opentofu/internal/configs"
|
|
"github.com/opentofu/opentofu/internal/configs/configschema"
|
|
"github.com/opentofu/opentofu/internal/dag"
|
|
)
|
|
|
|
// GraphNodeAttachResourceSchema is an interface implemented by node types
|
|
// that need a resource schema attached.
|
|
type GraphNodeAttachResourceSchema interface {
|
|
GraphNodeConfigResource
|
|
GraphNodeProviderConsumer
|
|
|
|
AttachResourceSchema(schema *configschema.Block, version uint64)
|
|
}
|
|
|
|
// GraphNodeAttachProviderConfigSchema is an interface implemented by node types
|
|
// that need a provider configuration schema attached.
|
|
type GraphNodeAttachProviderConfigSchema interface {
|
|
GraphNodeProvider
|
|
|
|
AttachProviderConfigSchema(*configschema.Block)
|
|
}
|
|
|
|
// GraphNodeAttachProvisionerSchema is an interface implemented by node types
|
|
// that need one or more provisioner schemas attached.
|
|
type GraphNodeAttachProvisionerSchema interface {
|
|
ProvisionedBy() []string
|
|
|
|
// SetProvisionerSchema is called during transform for each provisioner
|
|
// type returned from ProvisionedBy, providing the configuration schema
|
|
// for each provisioner in turn. The implementer should save these for
|
|
// later use in evaluating provisioner configuration blocks.
|
|
AttachProvisionerSchema(name string, schema *configschema.Block)
|
|
}
|
|
|
|
// AttachSchemaTransformer finds nodes that implement
|
|
// GraphNodeAttachResourceSchema, GraphNodeAttachProviderConfigSchema, or
|
|
// GraphNodeAttachProvisionerSchema, looks up the needed schemas for each
|
|
// and then passes them to a method implemented by the node.
|
|
type AttachSchemaTransformer struct {
|
|
Plugins *contextPlugins
|
|
Config *configs.Config
|
|
}
|
|
|
|
func (t *AttachSchemaTransformer) Transform(ctx context.Context, g *Graph) error {
|
|
if t.Plugins == nil {
|
|
// Should never happen with a reasonable caller, but we'll return a
|
|
// proper error here anyway so that we'll fail gracefully.
|
|
return fmt.Errorf("AttachSchemaTransformer used with nil Plugins")
|
|
}
|
|
|
|
for _, v := range g.Vertices() {
|
|
|
|
if tv, ok := v.(GraphNodeAttachResourceSchema); ok {
|
|
addr := tv.ResourceAddr()
|
|
mode := addr.Resource.Mode
|
|
typeName := addr.Resource.Type
|
|
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)
|
|
}
|
|
if schema == nil {
|
|
log.Printf("[ERROR] AttachSchemaTransformer: No resource schema available for %s", addr)
|
|
continue
|
|
}
|
|
log.Printf("[TRACE] AttachSchemaTransformer: attaching resource schema to %s", dag.VertexName(v))
|
|
tv.AttachResourceSchema(schema, version)
|
|
}
|
|
|
|
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)
|
|
}
|
|
if schema == nil {
|
|
log.Printf("[ERROR] AttachSchemaTransformer: No provider config schema available for %s", providerAddr)
|
|
continue
|
|
}
|
|
log.Printf("[TRACE] AttachSchemaTransformer: attaching provider config schema to %s", dag.VertexName(v))
|
|
tv.AttachProviderConfigSchema(schema)
|
|
}
|
|
|
|
if tv, ok := v.(GraphNodeAttachProvisionerSchema); ok {
|
|
names := tv.ProvisionedBy()
|
|
for _, name := range names {
|
|
schema, err := t.Plugins.ProvisionerSchema(name)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read provisioner configuration schema for %q: %w", name, err)
|
|
}
|
|
if schema == nil {
|
|
log.Printf("[ERROR] AttachSchemaTransformer: No schema available for provisioner %q on %q", name, dag.VertexName(v))
|
|
continue
|
|
}
|
|
log.Printf("[TRACE] AttachSchemaTransformer: attaching provisioner %q config schema to %s", name, dag.VertexName(v))
|
|
tv.AttachProvisionerSchema(name, schema)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|