config: can parse outputs

This commit is contained in:
Mitchell Hashimoto 2014-07-04 10:43:06 -07:00
parent b444f5a171
commit cc2bb950a1
4 changed files with 113 additions and 0 deletions

View File

@ -15,6 +15,7 @@ type Config struct {
ProviderConfigs map[string]*ProviderConfig ProviderConfigs map[string]*ProviderConfig
Resources []*Resource Resources []*Resource
Variables map[string]*Variable Variables map[string]*Variable
Outputs map[string]*Output
} }
// ProviderConfig is the configuration for a resource provider. // ProviderConfig is the configuration for a resource provider.
@ -42,6 +43,13 @@ type Variable struct {
defaultSet bool defaultSet bool
} }
// Output is an output defined within the configuration. An output is
// resulting data that is highlighted by Terraform when finished.
type Output struct {
Name string
RawConfig *RawConfig
}
// An InterpolatedVariable is a variable that is embedded within a string // An InterpolatedVariable is a variable that is embedded within a string
// in the configuration, such as "hello ${world}" (world in this case is // in the configuration, such as "hello ${world}" (world in this case is
// an interpolated variable). // an interpolated variable).

View File

@ -78,6 +78,16 @@ func (t *libuclConfigurable) Config() (*Config, error) {
} }
} }
// Build the outputs
if outputs := t.Object.Get("output"); outputs != nil {
var err error
config.Outputs, err = loadOutputsLibucl(outputs)
outputs.Close()
if err != nil {
return nil, err
}
}
return config, nil return config, nil
} }
@ -145,6 +155,52 @@ func loadFileLibucl(root string) (configurable, []string, error) {
return result, importPaths, nil return result, importPaths, nil
} }
// LoadOutputsLibucl recurses into the given libucl object and turns
// it into a mapping of outputs.
func loadOutputsLibucl(o *libucl.Object) (map[string]*Output, error) {
objects := make(map[string]*libucl.Object)
// Iterate over all the "output" blocks and get the keys along with
// their raw configuration objects. We'll parse those later.
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() {
objects[o2.Key()] = o2
defer o2.Close()
}
o1.Close()
iter2.Close()
}
iter.Close()
// Go through each object and turn it into an actual result.
result := make(map[string]*Output)
for n, o := range objects {
var config map[string]interface{}
if err := o.Decode(&config); err != nil {
return nil, err
}
rawConfig, err := NewRawConfig(config)
if err != nil {
return nil, fmt.Errorf(
"Error reading config for output %s: %s",
n,
err)
}
result[n] = &Output{
Name: n,
RawConfig: rawConfig,
}
}
return result, nil
}
// LoadProvidersLibucl recurses into the given libucl object and turns // LoadProvidersLibucl recurses into the given libucl object and turns
// it into a mapping of provider configs. // it into a mapping of provider configs.
func loadProvidersLibucl(o *libucl.Object) (map[string]*ProviderConfig, error) { func loadProvidersLibucl(o *libucl.Object) (map[string]*ProviderConfig, error) {

View File

@ -39,6 +39,11 @@ func TestLoadBasic(t *testing.T) {
if actual != strings.TrimSpace(basicResourcesStr) { if actual != strings.TrimSpace(basicResourcesStr) {
t.Fatalf("bad:\n%s", actual) t.Fatalf("bad:\n%s", actual)
} }
actual = outputsStr(c.Outputs)
if actual != strings.TrimSpace(basicOutputsStr) {
t.Fatalf("bad:\n%s", actual)
}
} }
func TestLoadBasic_import(t *testing.T) { func TestLoadBasic_import(t *testing.T) {
@ -92,6 +97,40 @@ func TestLoad_variables(t *testing.T) {
} }
} }
func outputsStr(os map[string]*Output) string {
ns := make([]string, 0, len(os))
for n, _ := range os {
ns = append(ns, n)
}
sort.Strings(ns)
result := ""
for _, n := range ns {
o := os[n]
result += fmt.Sprintf("%s\n", n)
if len(o.RawConfig.Variables) > 0 {
result += fmt.Sprintf(" vars\n")
for _, rawV := range o.RawConfig.Variables {
kind := "unknown"
str := rawV.FullKey()
switch rawV.(type) {
case *ResourceVariable:
kind = "resource"
case *UserVariable:
kind = "user"
}
result += fmt.Sprintf(" %s: %s\n", kind, str)
}
}
}
return strings.TrimSpace(result)
}
// 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 {
@ -219,6 +258,12 @@ func variablesStr(vs map[string]*Variable) string {
return strings.TrimSpace(result) return strings.TrimSpace(result)
} }
const basicOutputsStr = `
web_ip
vars
resource: aws_instance.web.private_ip
`
const basicProvidersStr = ` const basicProvidersStr = `
aws aws
access_key access_key

View File

@ -32,3 +32,7 @@ resource aws_instance "web" {
resource "aws_instance" "db" { resource "aws_instance" "db" {
security_groups = "${aws_security_group.firewall.*.id}" security_groups = "${aws_security_group.firewall.*.id}"
} }
output "web_ip" {
value = "${aws_instance.web.private_ip}"
}