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

     1  package configs
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/hcl/v2"
     7  	"github.com/hashicorp/hcl/v2/gohcl"
     8  	"github.com/hashicorp/hcl/v2/hclsyntax"
     9  
    10  	"github.com/hashicorp/terraform-plugin-sdk/internal/addrs"
    11  )
    12  
    13  // Provider represents a "provider" block in a module or file. A provider
    14  // block is a provider configuration, and there can be zero or more
    15  // configurations for each actual provider.
    16  type Provider struct {
    17  	Name       string
    18  	NameRange  hcl.Range
    19  	Alias      string
    20  	AliasRange *hcl.Range // nil if no alias set
    21  
    22  	Version VersionConstraint
    23  
    24  	Config hcl.Body
    25  
    26  	DeclRange hcl.Range
    27  }
    28  
    29  func decodeProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) {
    30  	content, config, diags := block.Body.PartialContent(providerBlockSchema)
    31  
    32  	provider := &Provider{
    33  		Name:      block.Labels[0],
    34  		NameRange: block.LabelRanges[0],
    35  		Config:    config,
    36  		DeclRange: block.DefRange,
    37  	}
    38  
    39  	if attr, exists := content.Attributes["alias"]; exists {
    40  		valDiags := gohcl.DecodeExpression(attr.Expr, nil, &provider.Alias)
    41  		diags = append(diags, valDiags...)
    42  		provider.AliasRange = attr.Expr.Range().Ptr()
    43  
    44  		if !hclsyntax.ValidIdentifier(provider.Alias) {
    45  			diags = append(diags, &hcl.Diagnostic{
    46  				Severity: hcl.DiagError,
    47  				Summary:  "Invalid provider configuration alias",
    48  				Detail:   fmt.Sprintf("An alias must be a valid name. %s", badIdentifierDetail),
    49  			})
    50  		}
    51  	}
    52  
    53  	if attr, exists := content.Attributes["version"]; exists {
    54  		var versionDiags hcl.Diagnostics
    55  		provider.Version, versionDiags = decodeVersionConstraint(attr)
    56  		diags = append(diags, versionDiags...)
    57  	}
    58  
    59  	// Reserved attribute names
    60  	for _, name := range []string{"count", "depends_on", "for_each", "source"} {
    61  		if attr, exists := content.Attributes[name]; exists {
    62  			diags = append(diags, &hcl.Diagnostic{
    63  				Severity: hcl.DiagError,
    64  				Summary:  "Reserved argument name in provider block",
    65  				Detail:   fmt.Sprintf("The provider argument name %q is reserved for use by Terraform in a future version.", name),
    66  				Subject:  &attr.NameRange,
    67  			})
    68  		}
    69  	}
    70  
    71  	// Reserved block types (all of them)
    72  	for _, block := range content.Blocks {
    73  		diags = append(diags, &hcl.Diagnostic{
    74  			Severity: hcl.DiagError,
    75  			Summary:  "Reserved block type name in provider block",
    76  			Detail:   fmt.Sprintf("The block type name %q is reserved for use by Terraform in a future version.", block.Type),
    77  			Subject:  &block.TypeRange,
    78  		})
    79  	}
    80  
    81  	return provider, diags
    82  }
    83  
    84  // Addr returns the address of the receiving provider configuration, relative
    85  // to its containing module.
    86  func (p *Provider) Addr() addrs.ProviderConfig {
    87  	return addrs.ProviderConfig{
    88  		Type:  p.Name,
    89  		Alias: p.Alias,
    90  	}
    91  }
    92  
    93  func (p *Provider) moduleUniqueKey() string {
    94  	if p.Alias != "" {
    95  		return fmt.Sprintf("%s.%s", p.Name, p.Alias)
    96  	}
    97  	return p.Name
    98  }
    99  
   100  // ProviderRequirement represents a declaration of a dependency on a particular
   101  // provider version without actually configuring that provider. This is used in
   102  // child modules that expect a provider to be passed in from their parent.
   103  type ProviderRequirement struct {
   104  	Name        string
   105  	Requirement VersionConstraint
   106  }
   107  
   108  func decodeRequiredProvidersBlock(block *hcl.Block) ([]*ProviderRequirement, hcl.Diagnostics) {
   109  	attrs, diags := block.Body.JustAttributes()
   110  	var reqs []*ProviderRequirement
   111  	for name, attr := range attrs {
   112  		req, reqDiags := decodeVersionConstraint(attr)
   113  		diags = append(diags, reqDiags...)
   114  		if !diags.HasErrors() {
   115  			reqs = append(reqs, &ProviderRequirement{
   116  				Name:        name,
   117  				Requirement: req,
   118  			})
   119  		}
   120  	}
   121  	return reqs, diags
   122  }
   123  
   124  var providerBlockSchema = &hcl.BodySchema{
   125  	Attributes: []hcl.AttributeSchema{
   126  		{
   127  			Name: "alias",
   128  		},
   129  		{
   130  			Name: "version",
   131  		},
   132  
   133  		// Attribute names reserved for future expansion.
   134  		{Name: "count"},
   135  		{Name: "depends_on"},
   136  		{Name: "for_each"},
   137  		{Name: "source"},
   138  	},
   139  	Blocks: []hcl.BlockHeaderSchema{
   140  		// _All_ of these are reserved for future expansion.
   141  		{Type: "lifecycle"},
   142  		{Type: "locals"},
   143  	},
   144  }