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
|
// A Terraform resource is something that represents some component that
|
||||||
// can be created and managed, and has some properties associated with it.
|
// can be created and managed, and has some properties associated with it.
|
||||||
type Resource struct {
|
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
|
Type string
|
||||||
Count int
|
|
||||||
RawConfig *RawConfig
|
RawConfig *RawConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -312,6 +312,10 @@ func loadResourcesLibucl(o *libucl.Object) ([]*Resource, error) {
|
||||||
// Remove the "count" from the config, since we treat that special
|
// Remove the "count" from the config, since we treat that special
|
||||||
delete(config, "count")
|
delete(config, "count")
|
||||||
|
|
||||||
|
// Delete the "provisioner" section from the config since
|
||||||
|
// that is treated specially.
|
||||||
|
delete(config, "provisioner")
|
||||||
|
|
||||||
rawConfig, err := NewRawConfig(config)
|
rawConfig, err := NewRawConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
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{
|
result = append(result, &Resource{
|
||||||
Name: r.Key(),
|
Name: r.Key(),
|
||||||
Type: t.Key(),
|
Type: t.Key(),
|
||||||
Count: count,
|
Count: count,
|
||||||
RawConfig: rawConfig,
|
RawConfig: rawConfig,
|
||||||
|
Provisioners: provisioners,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
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)
|
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
|
// This helper turns a provider configs field into a deterministic
|
||||||
// string value for comparison in tests.
|
// string value for comparison in tests.
|
||||||
func providerConfigsStr(pcs map[string]*ProviderConfig) string {
|
func providerConfigsStr(pcs map[string]*ProviderConfig) string {
|
||||||
|
@ -213,6 +229,23 @@ func resourcesStr(rs []*Resource) string {
|
||||||
result += fmt.Sprintf(" %s\n", k)
|
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 {
|
if len(r.RawConfig.Variables) > 0 {
|
||||||
result += fmt.Sprintf(" vars\n")
|
result += fmt.Sprintf(" vars\n")
|
||||||
|
|
||||||
|
@ -328,6 +361,18 @@ foo
|
||||||
bar
|
bar
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const provisionerResourcesStr = `
|
||||||
|
aws_instance[web]
|
||||||
|
ami
|
||||||
|
security_groups
|
||||||
|
provisioners
|
||||||
|
shell
|
||||||
|
path
|
||||||
|
vars
|
||||||
|
resource: aws_security_group.firewall.foo
|
||||||
|
user: var.foo
|
||||||
|
`
|
||||||
|
|
||||||
const variablesVariablesStr = `
|
const variablesVariablesStr = `
|
||||||
bar
|
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