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 }