config: understand "provisioner" blocks
This commit is contained in:
parent
305994036d
commit
e250a6f36c
|
@ -31,9 +31,16 @@ type ProviderConfig struct {
|
|||
// A Terraform resource is something that represents some component that
|
||||
// can be created and managed, and has some properties associated with it.
|
||||
type Resource struct {
|
||||
Name string
|
||||
Name string
|
||||
Type string
|
||||
Count int
|
||||
RawConfig *RawConfig
|
||||
Provisioners []*Provisioner
|
||||
}
|
||||
|
||||
// Provisioner is a configured provisioner step on a resource.
|
||||
type Provisioner struct {
|
||||
Type string
|
||||
Count int
|
||||
RawConfig *RawConfig
|
||||
}
|
||||
|
||||
|
|
|
@ -312,6 +312,10 @@ func loadResourcesLibucl(o *libucl.Object) ([]*Resource, error) {
|
|||
// Remove the "count" from the config, since we treat that special
|
||||
delete(config, "count")
|
||||
|
||||
// Delete the "provisioner" section from the config since
|
||||
// that is treated specially.
|
||||
delete(config, "provisioner")
|
||||
|
||||
rawConfig, err := NewRawConfig(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
|
@ -335,14 +339,86 @@ func loadResourcesLibucl(o *libucl.Object) ([]*Resource, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// If we have provisioners, then parse those out
|
||||
var provisioners []*Provisioner
|
||||
if po := r.Get("provisioner"); po != nil {
|
||||
var err error
|
||||
provisioners, err = loadProvisionersLibucl(po)
|
||||
po.Close()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error reading provisioners for %s[%s]: %s",
|
||||
t.Key(),
|
||||
r.Key(),
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, &Resource{
|
||||
Name: r.Key(),
|
||||
Type: t.Key(),
|
||||
Count: count,
|
||||
RawConfig: rawConfig,
|
||||
Name: r.Key(),
|
||||
Type: t.Key(),
|
||||
Count: count,
|
||||
RawConfig: rawConfig,
|
||||
Provisioners: provisioners,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func loadProvisionersLibucl(o *libucl.Object) ([]*Provisioner, error) {
|
||||
pos := make([]*libucl.Object, 0, int(o.Len()))
|
||||
|
||||
// Accumulate all the actual provisioner configuration objects. We
|
||||
// have to iterate twice here:
|
||||
//
|
||||
// 1. The first iteration is of the list of `provisioner` blocks.
|
||||
// 2. The second iteration is of the dictionary within the
|
||||
// provisioner which will have only one element which is the
|
||||
// type of provisioner to use along with tis config.
|
||||
//
|
||||
// In JSON it looks kind of like this:
|
||||
//
|
||||
// [
|
||||
// {
|
||||
// "shell": {
|
||||
// ...
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
//
|
||||
iter := o.Iterate(false)
|
||||
for o1 := iter.Next(); o1 != nil; o1 = iter.Next() {
|
||||
iter2 := o1.Iterate(true)
|
||||
for o2 := iter2.Next(); o2 != nil; o2 = iter2.Next() {
|
||||
pos = append(pos, o2)
|
||||
}
|
||||
|
||||
o1.Close()
|
||||
iter2.Close()
|
||||
}
|
||||
iter.Close()
|
||||
|
||||
result := make([]*Provisioner, 0, len(pos))
|
||||
for _, po := range pos {
|
||||
defer po.Close()
|
||||
|
||||
var config map[string]interface{}
|
||||
if err := po.Decode(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawConfig, err := NewRawConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = append(result, &Provisioner{
|
||||
Type: po.Key(),
|
||||
RawConfig: rawConfig,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
|
|
@ -131,6 +131,22 @@ func outputsStr(os map[string]*Output) string {
|
|||
return strings.TrimSpace(result)
|
||||
}
|
||||
|
||||
func TestLoad_provisioners(t *testing.T) {
|
||||
c, err := Load(filepath.Join(fixtureDir, "provisioners.tf"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if c == nil {
|
||||
t.Fatal("config should not be nil")
|
||||
}
|
||||
|
||||
actual := resourcesStr(c.Resources)
|
||||
if actual != strings.TrimSpace(provisionerResourcesStr) {
|
||||
t.Fatalf("bad:\n%s", actual)
|
||||
}
|
||||
}
|
||||
|
||||
// This helper turns a provider configs field into a deterministic
|
||||
// string value for comparison in tests.
|
||||
func providerConfigsStr(pcs map[string]*ProviderConfig) string {
|
||||
|
@ -213,6 +229,23 @@ func resourcesStr(rs []*Resource) string {
|
|||
result += fmt.Sprintf(" %s\n", k)
|
||||
}
|
||||
|
||||
if len(r.Provisioners) > 0 {
|
||||
result += fmt.Sprintf(" provisioners\n")
|
||||
for _, p := range r.Provisioners {
|
||||
result += fmt.Sprintf(" %s\n", p.Type)
|
||||
|
||||
ks := make([]string, 0, len(p.RawConfig.Raw))
|
||||
for k, _ := range p.RawConfig.Raw {
|
||||
ks = append(ks, k)
|
||||
}
|
||||
sort.Strings(ks)
|
||||
|
||||
for _, k := range ks {
|
||||
result += fmt.Sprintf(" %s\n", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.RawConfig.Variables) > 0 {
|
||||
result += fmt.Sprintf(" vars\n")
|
||||
|
||||
|
@ -328,6 +361,18 @@ foo
|
|||
bar
|
||||
`
|
||||
|
||||
const provisionerResourcesStr = `
|
||||
aws_instance[web]
|
||||
ami
|
||||
security_groups
|
||||
provisioners
|
||||
shell
|
||||
path
|
||||
vars
|
||||
resource: aws_security_group.firewall.foo
|
||||
user: var.foo
|
||||
`
|
||||
|
||||
const variablesVariablesStr = `
|
||||
bar
|
||||
<>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
resource "aws_instance" "web" {
|
||||
ami = "${var.foo}"
|
||||
security_groups = [
|
||||
"foo",
|
||||
"${aws_security_group.firewall.foo}"
|
||||
]
|
||||
|
||||
provisioner "shell" {
|
||||
path = "foo"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue