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 }