github.com/hashicorp/terraform-plugin-sdk@v1.17.2/terraform/eval_provider.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"github.com/hashicorp/hcl/v2"
     8  
     9  	"github.com/hashicorp/terraform-plugin-sdk/internal/addrs"
    10  	"github.com/hashicorp/terraform-plugin-sdk/internal/configs"
    11  	"github.com/hashicorp/terraform-plugin-sdk/internal/providers"
    12  	"github.com/hashicorp/terraform-plugin-sdk/internal/tfdiags"
    13  )
    14  
    15  func buildProviderConfig(ctx EvalContext, addr addrs.ProviderConfig, config *configs.Provider) hcl.Body {
    16  	var configBody hcl.Body
    17  	if config != nil {
    18  		configBody = config.Config
    19  	}
    20  
    21  	var inputBody hcl.Body
    22  	inputConfig := ctx.ProviderInput(addr)
    23  	if len(inputConfig) > 0 {
    24  		inputBody = configs.SynthBody("<input-prompt>", inputConfig)
    25  	}
    26  
    27  	switch {
    28  	case configBody != nil && inputBody != nil:
    29  		log.Printf("[TRACE] buildProviderConfig for %s: merging explicit config and input", addr)
    30  		// Note that the inputBody is the _base_ here, because configs.MergeBodies
    31  		// expects the base have all of the required fields, while these are
    32  		// forced to be optional for the override. The input process should
    33  		// guarantee that we have a value for each of the required arguments and
    34  		// that in practice the sets of attributes in each body will be
    35  		// disjoint.
    36  		return configs.MergeBodies(inputBody, configBody)
    37  	case configBody != nil:
    38  		log.Printf("[TRACE] buildProviderConfig for %s: using explicit config only", addr)
    39  		return configBody
    40  	case inputBody != nil:
    41  		log.Printf("[TRACE] buildProviderConfig for %s: using input only", addr)
    42  		return inputBody
    43  	default:
    44  		log.Printf("[TRACE] buildProviderConfig for %s: no configuration at all", addr)
    45  		return hcl.EmptyBody()
    46  	}
    47  }
    48  
    49  // EvalConfigProvider is an EvalNode implementation that configures
    50  // a provider that is already initialized and retrieved.
    51  type EvalConfigProvider struct {
    52  	Addr     addrs.ProviderConfig
    53  	Provider *providers.Interface
    54  	Config   *configs.Provider
    55  }
    56  
    57  func (n *EvalConfigProvider) Eval(ctx EvalContext) (interface{}, error) {
    58  	if n.Provider == nil {
    59  		return nil, fmt.Errorf("EvalConfigProvider Provider is nil")
    60  	}
    61  
    62  	var diags tfdiags.Diagnostics
    63  	provider := *n.Provider
    64  	config := n.Config
    65  
    66  	configBody := buildProviderConfig(ctx, n.Addr, config)
    67  
    68  	resp := provider.GetSchema()
    69  	diags = diags.Append(resp.Diagnostics)
    70  	if diags.HasErrors() {
    71  		return nil, diags.NonFatalErr()
    72  	}
    73  
    74  	configSchema := resp.Provider.Block
    75  	configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey)
    76  	diags = diags.Append(evalDiags)
    77  	if evalDiags.HasErrors() {
    78  		return nil, diags.NonFatalErr()
    79  	}
    80  
    81  	configDiags := ctx.ConfigureProvider(n.Addr, configVal)
    82  	configDiags = configDiags.InConfigBody(configBody)
    83  
    84  	return nil, configDiags.ErrWithWarnings()
    85  }
    86  
    87  // EvalInitProvider is an EvalNode implementation that initializes a provider
    88  // and returns nothing. The provider can be retrieved again with the
    89  // EvalGetProvider node.
    90  type EvalInitProvider struct {
    91  	TypeName string
    92  	Addr     addrs.ProviderConfig
    93  }
    94  
    95  func (n *EvalInitProvider) Eval(ctx EvalContext) (interface{}, error) {
    96  	return ctx.InitProvider(n.TypeName, n.Addr)
    97  }
    98  
    99  // EvalCloseProvider is an EvalNode implementation that closes provider
   100  // connections that aren't needed anymore.
   101  type EvalCloseProvider struct {
   102  	Addr addrs.ProviderConfig
   103  }
   104  
   105  func (n *EvalCloseProvider) Eval(ctx EvalContext) (interface{}, error) {
   106  	ctx.CloseProvider(n.Addr)
   107  	return nil, nil
   108  }
   109  
   110  // EvalGetProvider is an EvalNode implementation that retrieves an already
   111  // initialized provider instance for the given name.
   112  //
   113  // Unlike most eval nodes, this takes an _absolute_ provider configuration,
   114  // because providers can be passed into and inherited between modules.
   115  // Resource nodes must therefore know the absolute path of the provider they
   116  // will use, which is usually accomplished by implementing
   117  // interface GraphNodeProviderConsumer.
   118  type EvalGetProvider struct {
   119  	Addr   addrs.AbsProviderConfig
   120  	Output *providers.Interface
   121  
   122  	// If non-nil, Schema will be updated after eval to refer to the
   123  	// schema of the provider.
   124  	Schema **ProviderSchema
   125  }
   126  
   127  func (n *EvalGetProvider) Eval(ctx EvalContext) (interface{}, error) {
   128  	if n.Addr.ProviderConfig.Type == "" {
   129  		// Should never happen
   130  		panic("EvalGetProvider used with uninitialized provider configuration address")
   131  	}
   132  
   133  	result := ctx.Provider(n.Addr)
   134  	if result == nil {
   135  		return nil, fmt.Errorf("provider %s not initialized", n.Addr)
   136  	}
   137  
   138  	if n.Output != nil {
   139  		*n.Output = result
   140  	}
   141  
   142  	if n.Schema != nil {
   143  		*n.Schema = ctx.ProviderSchema(n.Addr)
   144  	}
   145  
   146  	return nil, nil
   147  }