configs/configupgrade: Upgrade the bodies of "provisioner" blocks
Aside from the two special meta-arguments "connection" and "provisioner" this is just our standard mapping from schema to conversion rules, using the provisioner's configuration schema.
This commit is contained in:
parent
cdca8fbfe8
commit
e2ef51800a
|
@ -3,7 +3,7 @@ resource "test_instance" "example" {
|
||||||
connection {
|
connection {
|
||||||
host = "127.0.0.1"
|
host = "127.0.0.1"
|
||||||
}
|
}
|
||||||
provisioner "local-exec" {
|
provisioner "test" {
|
||||||
connection {
|
connection {
|
||||||
host = "127.0.0.2"
|
host = "127.0.0.2"
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ resource "test_instance" "example" {
|
||||||
connection {
|
connection {
|
||||||
host = "127.0.0.1"
|
host = "127.0.0.1"
|
||||||
}
|
}
|
||||||
provisioner "local-exec" {
|
provisioner "test" {
|
||||||
connection {
|
connection {
|
||||||
host = "127.0.0.2"
|
host = "127.0.0.2"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
resource "test_instance" "foo" {
|
||||||
|
provisioner "test" {
|
||||||
|
commands = "${list("a", "b", "c")}"
|
||||||
|
|
||||||
|
when = "create"
|
||||||
|
on_failure = "fail"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
resource "test_instance" "foo" {
|
||||||
|
provisioner "test" {
|
||||||
|
commands = ["a", "b", "c"]
|
||||||
|
|
||||||
|
when = create
|
||||||
|
on_failure = fail
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
terraform {
|
||||||
|
required_version = ">= 0.12"
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
hcl1ast "github.com/hashicorp/hcl/hcl/ast"
|
hcl1ast "github.com/hashicorp/hcl/hcl/ast"
|
||||||
|
hcl1printer "github.com/hashicorp/hcl/hcl/printer"
|
||||||
hcl1token "github.com/hashicorp/hcl/hcl/token"
|
hcl1token "github.com/hashicorp/hcl/hcl/token"
|
||||||
hcl2 "github.com/hashicorp/hcl2/hcl"
|
hcl2 "github.com/hashicorp/hcl2/hcl"
|
||||||
hcl2syntax "github.com/hashicorp/hcl2/hcl/hclsyntax"
|
hcl2syntax "github.com/hashicorp/hcl2/hcl/hclsyntax"
|
||||||
|
@ -554,3 +555,69 @@ func lifecycleBlockBodyRules(filename string, an *analysis) bodyContentRules {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func provisionerBlockRule(filename string, an *analysis, adhocComments *commentQueue) bodyItemRule {
|
||||||
|
// Unlike some other examples above, this is a rule for the entire
|
||||||
|
// provisioner block, rather than just for its contents. Therefore it must
|
||||||
|
// also produce the block header and body delimiters.
|
||||||
|
return func(buf *bytes.Buffer, blockAddr string, item *hcl1ast.ObjectItem) tfdiags.Diagnostics {
|
||||||
|
var diags tfdiags.Diagnostics
|
||||||
|
body := item.Val.(*hcl1ast.ObjectType)
|
||||||
|
declRange := hcl1PosRange(filename, item.Keys[0].Pos())
|
||||||
|
|
||||||
|
if len(item.Keys) < 2 {
|
||||||
|
diags = diags.Append(&hcl2.Diagnostic{
|
||||||
|
Severity: hcl2.DiagError,
|
||||||
|
Summary: "Invalid provisioner block",
|
||||||
|
Detail: "A provisioner block must have one label: the provisioner type.",
|
||||||
|
Subject: &declRange,
|
||||||
|
})
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
|
||||||
|
typeName := item.Keys[1].Token.Value().(string)
|
||||||
|
schema := an.ProvisionerSchemas[typeName]
|
||||||
|
if schema == nil {
|
||||||
|
// This message is assuming that if the user _is_ using a third-party
|
||||||
|
// provisioner plugin they already know how to install it for normal
|
||||||
|
// use and so we don't need to spell out those instructions in detail
|
||||||
|
// here.
|
||||||
|
diags = diags.Append(&hcl2.Diagnostic{
|
||||||
|
Severity: hcl2.DiagError,
|
||||||
|
Summary: "Unknown provisioner type",
|
||||||
|
Detail: fmt.Sprintf("The provisioner type %q is not supported. If this is a third-party plugin, make sure its plugin executable is available in one of the usual plugin search paths.", typeName),
|
||||||
|
Subject: &declRange,
|
||||||
|
})
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
|
||||||
|
rules := schemaDefaultBodyRules(filename, schema, an, adhocComments)
|
||||||
|
rules["when"] = maybeBareTraversalAttributeRule(filename, an)
|
||||||
|
rules["on_failure"] = maybeBareTraversalAttributeRule(filename, an)
|
||||||
|
rules["connection"] = connectionBlockRule(filename, an, adhocComments)
|
||||||
|
|
||||||
|
printComments(buf, item.LeadComment)
|
||||||
|
printBlockOpen(buf, "provisioner", []string{typeName}, item.LineComment)
|
||||||
|
bodyDiags := upgradeBlockBody(filename, fmt.Sprintf("%s.provisioner[%q]", blockAddr, typeName), buf, body.List.Items, body.Rbrace, rules, adhocComments)
|
||||||
|
diags = diags.Append(bodyDiags)
|
||||||
|
buf.WriteString("}\n")
|
||||||
|
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func connectionBlockRule(filename string, an *analysis, adhocComments *commentQueue) bodyItemRule {
|
||||||
|
// Unlike some other examples above, this is a rule for the entire
|
||||||
|
// connection block, rather than just for its contents. Therefore it must
|
||||||
|
// also produce the block header and body delimiters.
|
||||||
|
return func(buf *bytes.Buffer, blockAddr string, item *hcl1ast.ObjectItem) tfdiags.Diagnostics {
|
||||||
|
// TODO: For the few resource types that were setting ConnInfo in
|
||||||
|
// state after create/update in prior versions, generate the additional
|
||||||
|
// explicit connection settings that are now required if and only if
|
||||||
|
// there's at least one provisioner block.
|
||||||
|
// For now, we just pass this through as-is.
|
||||||
|
hcl1printer.Fprint(buf, item)
|
||||||
|
buf.WriteByte('\n')
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -329,24 +329,8 @@ func (u *Upgrader) upgradeNativeSyntaxResource(filename string, buf *bytes.Buffe
|
||||||
rules["depends_on"] = dependsOnAttributeRule(filename, an)
|
rules["depends_on"] = dependsOnAttributeRule(filename, an)
|
||||||
rules["provider"] = maybeBareTraversalAttributeRule(filename, an)
|
rules["provider"] = maybeBareTraversalAttributeRule(filename, an)
|
||||||
rules["lifecycle"] = nestedBlockRule(filename, lifecycleBlockBodyRules(filename, an), an, adhocComments)
|
rules["lifecycle"] = nestedBlockRule(filename, lifecycleBlockBodyRules(filename, an), an, adhocComments)
|
||||||
rules["connection"] = func(buf *bytes.Buffer, blockAddr string, item *hcl1ast.ObjectItem) tfdiags.Diagnostics {
|
rules["connection"] = connectionBlockRule(filename, an, adhocComments)
|
||||||
// TODO: For the few resource types that were setting ConnInfo in
|
rules["provisioner"] = provisionerBlockRule(filename, an, adhocComments)
|
||||||
// state after create/update in prior versions, generate the additional
|
|
||||||
// explicit connection settings that are now required if and only if
|
|
||||||
// there's at least one provisioner block.
|
|
||||||
// For now, we just pass this through as-is.
|
|
||||||
hcl1printer.Fprint(buf, item)
|
|
||||||
buf.WriteByte('\n')
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
rules["provisioner"] = func(buf *bytes.Buffer, blockAddr string, item *hcl1ast.ObjectItem) tfdiags.Diagnostics {
|
|
||||||
// TODO: Look up the provisioner schema and map this properly to ensure
|
|
||||||
// any references get properly updated.
|
|
||||||
// For now, we just pass this through as-is.
|
|
||||||
hcl1printer.Fprint(buf, item)
|
|
||||||
buf.WriteByte('\n')
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
printComments(buf, item.LeadComment)
|
printComments(buf, item.LeadComment)
|
||||||
printBlockOpen(buf, blockType, labels, item.LineComment)
|
printBlockOpen(buf, blockType, labels, item.LineComment)
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/hashicorp/terraform/configs/configschema"
|
"github.com/hashicorp/terraform/configs/configschema"
|
||||||
"github.com/hashicorp/terraform/helper/logging"
|
"github.com/hashicorp/terraform/helper/logging"
|
||||||
"github.com/hashicorp/terraform/providers"
|
"github.com/hashicorp/terraform/providers"
|
||||||
|
"github.com/hashicorp/terraform/provisioners"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,7 +40,8 @@ func TestUpgradeValid(t *testing.T) {
|
||||||
inputDir := filepath.Join(fixtureDir, entry.Name(), "input")
|
inputDir := filepath.Join(fixtureDir, entry.Name(), "input")
|
||||||
wantDir := filepath.Join(fixtureDir, entry.Name(), "want")
|
wantDir := filepath.Join(fixtureDir, entry.Name(), "want")
|
||||||
u := &Upgrader{
|
u := &Upgrader{
|
||||||
Providers: providers.ResolverFixed(testProviders),
|
Providers: providers.ResolverFixed(testProviders),
|
||||||
|
Provisioners: testProvisioners,
|
||||||
}
|
}
|
||||||
|
|
||||||
inputSrc, err := LoadModule(inputDir)
|
inputSrc, err := LoadModule(inputDir)
|
||||||
|
@ -250,6 +252,21 @@ var testProviders = map[string]providers.Factory{
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var testProvisioners = map[string]provisioners.Factory{
|
||||||
|
"test": provisioners.Factory(func() (provisioners.Interface, error) {
|
||||||
|
p := &terraform.MockProvisioner{}
|
||||||
|
p.GetSchemaResponse = provisioners.GetSchemaResponse{
|
||||||
|
Provisioner: &configschema.Block{
|
||||||
|
Attributes: map[string]*configschema.Attribute{
|
||||||
|
"commands": {Type: cty.List(cty.String), Optional: true},
|
||||||
|
"interpreter": {Type: cty.String, Optional: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Initialize the backends
|
// Initialize the backends
|
||||||
backendinit.Init(nil)
|
backendinit.Init(nil)
|
||||||
|
|
Loading…
Reference in New Issue