github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/terraform/node_provider.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"github.com/hashicorp/hcl/v2"
     8  	"github.com/muratcelep/terraform/not-internal/configs/configschema"
     9  	"github.com/muratcelep/terraform/not-internal/providers"
    10  	"github.com/muratcelep/terraform/not-internal/tfdiags"
    11  	"github.com/zclconf/go-cty/cty"
    12  )
    13  
    14  // NodeApplyableProvider represents a provider during an apply.
    15  type NodeApplyableProvider struct {
    16  	*NodeAbstractProvider
    17  }
    18  
    19  var (
    20  	_ GraphNodeExecutable = (*NodeApplyableProvider)(nil)
    21  )
    22  
    23  // GraphNodeExecutable
    24  func (n *NodeApplyableProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
    25  	_, err := ctx.InitProvider(n.Addr)
    26  	diags = diags.Append(err)
    27  	if diags.HasErrors() {
    28  		return diags
    29  	}
    30  	provider, _, err := getProvider(ctx, n.Addr)
    31  	diags = diags.Append(err)
    32  	if diags.HasErrors() {
    33  		return diags
    34  	}
    35  
    36  	switch op {
    37  	case walkValidate:
    38  		log.Printf("[TRACE] NodeApplyableProvider: validating configuration for %s", n.Addr)
    39  		return diags.Append(n.ValidateProvider(ctx, provider))
    40  	case walkPlan, walkApply, walkDestroy:
    41  		// walkPlanDestroy is purposely skipped here, since the config is not
    42  		// evaluated, and the provider is not needed to create delete actions
    43  		// for all instances.
    44  		log.Printf("[TRACE] NodeApplyableProvider: configuring %s", n.Addr)
    45  		return diags.Append(n.ConfigureProvider(ctx, provider, false))
    46  	case walkImport:
    47  		log.Printf("[TRACE] NodeApplyableProvider: configuring %s (requiring that configuration is wholly known)", n.Addr)
    48  		return diags.Append(n.ConfigureProvider(ctx, provider, true))
    49  	}
    50  	return diags
    51  }
    52  
    53  func (n *NodeApplyableProvider) ValidateProvider(ctx EvalContext, provider providers.Interface) (diags tfdiags.Diagnostics) {
    54  
    55  	configBody := buildProviderConfig(ctx, n.Addr, n.ProviderConfig())
    56  
    57  	// if a provider config is empty (only an alias), return early and don't continue
    58  	// validation. validate doesn't need to fully configure the provider itself, so
    59  	// skipping a provider with an implied configuration won't prevent other validation from completing.
    60  	_, noConfigDiags := configBody.Content(&hcl.BodySchema{})
    61  	if !noConfigDiags.HasErrors() {
    62  		return nil
    63  	}
    64  
    65  	schemaResp := provider.GetProviderSchema()
    66  	diags = diags.Append(schemaResp.Diagnostics.InConfigBody(configBody, n.Addr.String()))
    67  	if diags.HasErrors() {
    68  		return diags
    69  	}
    70  
    71  	configSchema := schemaResp.Provider.Block
    72  	if configSchema == nil {
    73  		// Should never happen in real code, but often comes up in tests where
    74  		// mock schemas are being used that tend to be incomplete.
    75  		log.Printf("[WARN] ValidateProvider: no config schema is available for %s, so using empty schema", n.Addr)
    76  		configSchema = &configschema.Block{}
    77  	}
    78  
    79  	configVal, _, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey)
    80  	if evalDiags.HasErrors() {
    81  		return diags.Append(evalDiags)
    82  	}
    83  	diags = diags.Append(evalDiags)
    84  
    85  	// If our config value contains any marked values, ensure those are
    86  	// stripped out before sending this to the provider
    87  	unmarkedConfigVal, _ := configVal.UnmarkDeep()
    88  
    89  	req := providers.ValidateProviderConfigRequest{
    90  		Config: unmarkedConfigVal,
    91  	}
    92  
    93  	validateResp := provider.ValidateProviderConfig(req)
    94  	diags = diags.Append(validateResp.Diagnostics.InConfigBody(configBody, n.Addr.String()))
    95  
    96  	return diags
    97  }
    98  
    99  // ConfigureProvider configures a provider that is already initialized and retrieved.
   100  // If verifyConfigIsKnown is true, ConfigureProvider will return an error if the
   101  // provider configVal is not wholly known and is meant only for use during import.
   102  func (n *NodeApplyableProvider) ConfigureProvider(ctx EvalContext, provider providers.Interface, verifyConfigIsKnown bool) (diags tfdiags.Diagnostics) {
   103  	config := n.ProviderConfig()
   104  
   105  	configBody := buildProviderConfig(ctx, n.Addr, config)
   106  
   107  	resp := provider.GetProviderSchema()
   108  	diags = diags.Append(resp.Diagnostics.InConfigBody(configBody, n.Addr.String()))
   109  	if diags.HasErrors() {
   110  		return diags
   111  	}
   112  
   113  	configSchema := resp.Provider.Block
   114  	configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey)
   115  	diags = diags.Append(evalDiags)
   116  	if evalDiags.HasErrors() {
   117  		return diags
   118  	}
   119  
   120  	if verifyConfigIsKnown && !configVal.IsWhollyKnown() {
   121  		diags = diags.Append(&hcl.Diagnostic{
   122  			Severity: hcl.DiagError,
   123  			Summary:  "Invalid provider configuration",
   124  			Detail:   fmt.Sprintf("The configuration for %s depends on values that cannot be determined until apply.", n.Addr),
   125  			Subject:  &config.DeclRange,
   126  		})
   127  		return diags
   128  	}
   129  
   130  	// If our config value contains any marked values, ensure those are
   131  	// stripped out before sending this to the provider
   132  	unmarkedConfigVal, _ := configVal.UnmarkDeep()
   133  
   134  	// Allow the provider to validate and insert any defaults into the full
   135  	// configuration.
   136  	req := providers.ValidateProviderConfigRequest{
   137  		Config: unmarkedConfigVal,
   138  	}
   139  
   140  	// ValidateProviderConfig is only used for validation. We are intentionally
   141  	// ignoring the PreparedConfig field to maintain existing behavior.
   142  	validateResp := provider.ValidateProviderConfig(req)
   143  	diags = diags.Append(validateResp.Diagnostics.InConfigBody(configBody, n.Addr.String()))
   144  	if diags.HasErrors() && config == nil {
   145  		// If there isn't an explicit "provider" block in the configuration,
   146  		// this error message won't be very clear. Add some detail to the error
   147  		// message in this case.
   148  		diags = diags.Append(tfdiags.Sourceless(
   149  			tfdiags.Error,
   150  			"Invalid provider configuration",
   151  			fmt.Sprintf(providerConfigErr, n.Addr.Provider),
   152  		))
   153  	}
   154  
   155  	if diags.HasErrors() {
   156  		return diags
   157  	}
   158  
   159  	// If the provider returns something different, log a warning to help
   160  	// indicate to provider developers that the value is not used.
   161  	preparedCfg := validateResp.PreparedConfig
   162  	if preparedCfg != cty.NilVal && !preparedCfg.IsNull() && !preparedCfg.RawEquals(unmarkedConfigVal) {
   163  		log.Printf("[WARN] ValidateProviderConfig from %q changed the config value, but that value is unused", n.Addr)
   164  	}
   165  
   166  	configDiags := ctx.ConfigureProvider(n.Addr, unmarkedConfigVal)
   167  	diags = diags.Append(configDiags.InConfigBody(configBody, n.Addr.String()))
   168  	if diags.HasErrors() && config == nil {
   169  		// If there isn't an explicit "provider" block in the configuration,
   170  		// this error message won't be very clear. Add some detail to the error
   171  		// message in this case.
   172  		diags = diags.Append(tfdiags.Sourceless(
   173  			tfdiags.Error,
   174  			"Invalid provider configuration",
   175  			fmt.Sprintf(providerConfigErr, n.Addr.Provider),
   176  		))
   177  	}
   178  	return diags
   179  }
   180  
   181  const providerConfigErr = `Provider %q requires explicit configuration. Add a provider block to the root module and configure the provider's required arguments as described in the provider documentation.
   182  `