config: use new HCL lib and structure
This commit is contained in:
parent
ca5be43519
commit
2fd545bca1
|
@ -5,14 +5,14 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/hashicorp/hcl"
|
"github.com/hashicorp/hcl"
|
||||||
"github.com/hashicorp/hcl/ast"
|
hclobj "github.com/hashicorp/hcl/hcl"
|
||||||
)
|
)
|
||||||
|
|
||||||
// hclConfigurable is an implementation of configurable that knows
|
// hclConfigurable is an implementation of configurable that knows
|
||||||
// how to turn HCL configuration into a *Config object.
|
// how to turn HCL configuration into a *Config object.
|
||||||
type hclConfigurable struct {
|
type hclConfigurable struct {
|
||||||
File string
|
File string
|
||||||
Object *ast.ObjectNode
|
Object *hclobj.Object
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *hclConfigurable) Config() (*Config, error) {
|
func (t *hclConfigurable) Config() (*Config, error) {
|
||||||
|
@ -33,7 +33,7 @@ func (t *hclConfigurable) Config() (*Config, error) {
|
||||||
Variable map[string]*hclVariable
|
Variable map[string]*hclVariable
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := hcl.DecodeAST(&rawConfig, t.Object); err != nil {
|
if err := hcl.DecodeObject(&rawConfig, t.Object); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,8 +97,8 @@ func (t *hclConfigurable) Config() (*Config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for invalid keys
|
// Check for invalid keys
|
||||||
for _, elem := range t.Object.Elem {
|
for _, elem := range t.Object.Elem(true) {
|
||||||
k := elem.Key()
|
k := elem.Key
|
||||||
if _, ok := validKeys[k]; ok {
|
if _, ok := validKeys[k]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ func (t *hclConfigurable) Config() (*Config, error) {
|
||||||
// loadFileHcl is a fileLoaderFunc that knows how to read HCL
|
// loadFileHcl is a fileLoaderFunc that knows how to read HCL
|
||||||
// files and turn them into hclConfigurables.
|
// files and turn them into hclConfigurables.
|
||||||
func loadFileHcl(root string) (configurable, []string, error) {
|
func loadFileHcl(root string) (configurable, []string, error) {
|
||||||
var obj *ast.ObjectNode = nil
|
var obj *hclobj.Object = nil
|
||||||
|
|
||||||
// Read the HCL file and prepare for parsing
|
// Read the HCL file and prepare for parsing
|
||||||
d, err := ioutil.ReadFile(root)
|
d, err := ioutil.ReadFile(root)
|
||||||
|
@ -179,8 +179,17 @@ func loadFileHcl(root string) (configurable, []string, error) {
|
||||||
|
|
||||||
// LoadOutputsHcl recurses into the given HCL object and turns
|
// LoadOutputsHcl recurses into the given HCL object and turns
|
||||||
// it into a mapping of outputs.
|
// it into a mapping of outputs.
|
||||||
func loadOutputsHcl(ns []ast.Node) ([]*Output, error) {
|
func loadOutputsHcl(os *hclobj.Object) ([]*Output, error) {
|
||||||
objects := hclObjectMap(ns)
|
objects := make(map[string]*hclobj.Object)
|
||||||
|
|
||||||
|
// Iterate over all the "output" blocks and get the keys along with
|
||||||
|
// their raw configuration objects. We'll parse those later.
|
||||||
|
for _, o1 := range os.Elem(false) {
|
||||||
|
for _, o2 := range o1.Elem(true) {
|
||||||
|
objects[o2.Key] = o2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(objects) == 0 {
|
if len(objects) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -190,7 +199,7 @@ func loadOutputsHcl(ns []ast.Node) ([]*Output, error) {
|
||||||
for n, o := range objects {
|
for n, o := range objects {
|
||||||
var config map[string]interface{}
|
var config map[string]interface{}
|
||||||
|
|
||||||
if err := hcl.DecodeAST(&config, o); err != nil {
|
if err := hcl.DecodeObject(&config, o); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,8 +222,17 @@ func loadOutputsHcl(ns []ast.Node) ([]*Output, error) {
|
||||||
|
|
||||||
// LoadProvidersHcl recurses into the given HCL object and turns
|
// LoadProvidersHcl recurses into the given HCL object and turns
|
||||||
// it into a mapping of provider configs.
|
// it into a mapping of provider configs.
|
||||||
func loadProvidersHcl(ns []ast.Node) ([]*ProviderConfig, error) {
|
func loadProvidersHcl(os *hclobj.Object) ([]*ProviderConfig, error) {
|
||||||
objects := hclObjectMap(ns)
|
objects := make(map[string]*hclobj.Object)
|
||||||
|
|
||||||
|
// Iterate over all the "provider" blocks and get the keys along with
|
||||||
|
// their raw configuration objects. We'll parse those later.
|
||||||
|
for _, o1 := range os.Elem(false) {
|
||||||
|
for _, o2 := range o1.Elem(true) {
|
||||||
|
objects[o2.Key] = o2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(objects) == 0 {
|
if len(objects) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -224,7 +242,7 @@ func loadProvidersHcl(ns []ast.Node) ([]*ProviderConfig, error) {
|
||||||
for n, o := range objects {
|
for n, o := range objects {
|
||||||
var config map[string]interface{}
|
var config map[string]interface{}
|
||||||
|
|
||||||
if err := hcl.DecodeAST(&config, o); err != nil {
|
if err := hcl.DecodeObject(&config, o); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,25 +269,40 @@ func loadProvidersHcl(ns []ast.Node) ([]*ProviderConfig, error) {
|
||||||
// The resulting resources may not be unique, but each resource
|
// The resulting resources may not be unique, but each resource
|
||||||
// represents exactly one resource definition in the HCL configuration.
|
// represents exactly one resource definition in the HCL configuration.
|
||||||
// We leave it up to another pass to merge them together.
|
// We leave it up to another pass to merge them together.
|
||||||
func loadResourcesHcl(ns []ast.Node) ([]*Resource, error) {
|
func loadResourcesHcl(os *hclobj.Object) ([]*Resource, error) {
|
||||||
typeMap := hclObjectMap(ns)
|
var allTypes []*hclobj.Object
|
||||||
|
|
||||||
|
// HCL object iteration is really nasty. Below is likely to make
|
||||||
|
// no sense to anyone approaching this code. Luckily, it is very heavily
|
||||||
|
// tested. If working on a bug fix or feature, we recommend writing a
|
||||||
|
// test first then doing whatever you want to the code below. If you
|
||||||
|
// break it, the tests will catch it. Likewise, if you change this,
|
||||||
|
// MAKE SURE you write a test for your change, because its fairly impossible
|
||||||
|
// to reason about this mess.
|
||||||
|
//
|
||||||
|
// Functionally, what the code does below is get the libucl.Objects
|
||||||
|
// for all the TYPES, such as "aws_security_group".
|
||||||
|
for _, o1 := range os.Elem(false) {
|
||||||
|
// Iterate the inner to get the list of types
|
||||||
|
for _, o2 := range o1.Elem(true) {
|
||||||
|
// Iterate all of this type to get _all_ the types
|
||||||
|
for _, o3 := range o2.Elem(false) {
|
||||||
|
allTypes = append(allTypes, o3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Where all the results will go
|
// Where all the results will go
|
||||||
var result []*Resource
|
var result []*Resource
|
||||||
|
|
||||||
// Now go over all the types and their children in order to get
|
// Now go over all the types and their children in order to get
|
||||||
// all of the actual resources.
|
// all of the actual resources.
|
||||||
for t, rs := range typeMap {
|
for _, t := range allTypes {
|
||||||
resourceMap := hclObjectMap([]ast.Node{rs})
|
for _, obj := range t.Elem(true) {
|
||||||
for k, o := range resourceMap {
|
k := obj.Key
|
||||||
for _, o := range o.Elem {
|
|
||||||
obj, ok := o.(ast.ObjectNode)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var config map[string]interface{}
|
var config map[string]interface{}
|
||||||
if err := hcl.DecodeAST(&config, o); err != nil {
|
if err := hcl.DecodeObject(&config, obj); err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"Error reading config for %s[%s]: %s",
|
"Error reading config for %s[%s]: %s",
|
||||||
t,
|
t,
|
||||||
|
@ -294,9 +327,8 @@ func loadResourcesHcl(ns []ast.Node) ([]*Resource, error) {
|
||||||
|
|
||||||
// If we have a count, then figure it out
|
// If we have a count, then figure it out
|
||||||
var count int = 1
|
var count int = 1
|
||||||
if os := obj.Get("count", false); os != nil {
|
if o := obj.Get("count", false); o != nil {
|
||||||
for _, o := range os {
|
err = hcl.DecodeObject(&count, o)
|
||||||
err = hcl.DecodeAST(&count, o)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"Error parsing count for %s[%s]: %s",
|
"Error parsing count for %s[%s]: %s",
|
||||||
|
@ -305,13 +337,11 @@ func loadResourcesHcl(ns []ast.Node) ([]*Resource, error) {
|
||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If we have depends fields, then add those in
|
// If we have depends fields, then add those in
|
||||||
var dependsOn []string
|
var dependsOn []string
|
||||||
if os := obj.Get("depends_on", false); os != nil {
|
if o := obj.Get("depends_on", false); o != nil {
|
||||||
for _, o := range os {
|
err := hcl.DecodeObject(&dependsOn, o)
|
||||||
err := hcl.DecodeAST(&dependsOn, o)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"Error reading depends_on for %s[%s]: %s",
|
"Error reading depends_on for %s[%s]: %s",
|
||||||
|
@ -320,13 +350,11 @@ func loadResourcesHcl(ns []ast.Node) ([]*Resource, error) {
|
||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If we have connection info, then parse those out
|
// If we have connection info, then parse those out
|
||||||
var connInfo map[string]interface{}
|
var connInfo map[string]interface{}
|
||||||
if os := obj.Get("connection", false); os != nil {
|
if o := obj.Get("connection", false); o != nil {
|
||||||
for _, o := range os {
|
err := hcl.DecodeObject(&connInfo, o)
|
||||||
err := hcl.DecodeAST(&connInfo, o)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"Error reading connection info for %s[%s]: %s",
|
"Error reading connection info for %s[%s]: %s",
|
||||||
|
@ -335,7 +363,6 @@ func loadResourcesHcl(ns []ast.Node) ([]*Resource, error) {
|
||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If we have provisioners, then parse those out
|
// If we have provisioners, then parse those out
|
||||||
var provisioners []*Provisioner
|
var provisioners []*Provisioner
|
||||||
|
@ -353,7 +380,7 @@ func loadResourcesHcl(ns []ast.Node) ([]*Resource, error) {
|
||||||
|
|
||||||
result = append(result, &Resource{
|
result = append(result, &Resource{
|
||||||
Name: k,
|
Name: k,
|
||||||
Type: t,
|
Type: t.Key,
|
||||||
Count: count,
|
Count: count,
|
||||||
RawConfig: rawConfig,
|
RawConfig: rawConfig,
|
||||||
Provisioners: provisioners,
|
Provisioners: provisioners,
|
||||||
|
@ -361,13 +388,12 @@ func loadResourcesHcl(ns []ast.Node) ([]*Resource, error) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadProvisionersHcl(ns []ast.Node, connInfo map[string]interface{}) ([]*Provisioner, error) {
|
func loadProvisionersHcl(os *hclobj.Object, connInfo map[string]interface{}) ([]*Provisioner, error) {
|
||||||
pos := make([]ast.AssignmentNode, 0, len(ns))
|
pos := make([]*hclobj.Object, 0, int(os.Len()))
|
||||||
|
|
||||||
// Accumulate all the actual provisioner configuration objects. We
|
// Accumulate all the actual provisioner configuration objects. We
|
||||||
// have to iterate twice here:
|
// have to iterate twice here:
|
||||||
|
@ -387,14 +413,9 @@ func loadProvisionersHcl(ns []ast.Node, connInfo map[string]interface{}) ([]*Pro
|
||||||
// }
|
// }
|
||||||
// ]
|
// ]
|
||||||
//
|
//
|
||||||
for _, n := range ns {
|
for _, o1 := range os.Elem(false) {
|
||||||
obj, ok := n.(ast.ObjectNode)
|
for _, o2 := range o1.Elem(true) {
|
||||||
if !ok {
|
pos = append(pos, o2)
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, elem := range obj.Elem {
|
|
||||||
pos = append(pos, elem)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,13 +426,8 @@ func loadProvisionersHcl(ns []ast.Node, connInfo map[string]interface{}) ([]*Pro
|
||||||
|
|
||||||
result := make([]*Provisioner, 0, len(pos))
|
result := make([]*Provisioner, 0, len(pos))
|
||||||
for _, po := range pos {
|
for _, po := range pos {
|
||||||
obj, ok := po.Value.(ast.ObjectNode)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var config map[string]interface{}
|
var config map[string]interface{}
|
||||||
if err := hcl.DecodeAST(&config, obj); err != nil {
|
if err := hcl.DecodeObject(&config, po); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,14 +442,12 @@ func loadProvisionersHcl(ns []ast.Node, connInfo map[string]interface{}) ([]*Pro
|
||||||
// Check if we have a provisioner-level connection
|
// Check if we have a provisioner-level connection
|
||||||
// block that overrides the resource-level
|
// block that overrides the resource-level
|
||||||
var subConnInfo map[string]interface{}
|
var subConnInfo map[string]interface{}
|
||||||
if os := obj.Get("connection", false); os != nil {
|
if o := po.Get("connection", false); o != nil {
|
||||||
for _, o := range os {
|
err := hcl.DecodeObject(&subConnInfo, o)
|
||||||
err := hcl.DecodeAST(&subConnInfo, o)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Inherit from the resource connInfo any keys
|
// Inherit from the resource connInfo any keys
|
||||||
// that are not explicitly overriden.
|
// that are not explicitly overriden.
|
||||||
|
@ -454,7 +468,7 @@ func loadProvisionersHcl(ns []ast.Node, connInfo map[string]interface{}) ([]*Pro
|
||||||
}
|
}
|
||||||
|
|
||||||
result = append(result, &Provisioner{
|
result = append(result, &Provisioner{
|
||||||
Type: po.Key(),
|
Type: po.Key,
|
||||||
RawConfig: rawConfig,
|
RawConfig: rawConfig,
|
||||||
ConnInfo: connRaw,
|
ConnInfo: connRaw,
|
||||||
})
|
})
|
||||||
|
@ -463,32 +477,22 @@ func loadProvisionersHcl(ns []ast.Node, connInfo map[string]interface{}) ([]*Pro
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func hclObjectMap(ns []ast.Node) map[string]ast.ListNode {
|
/*
|
||||||
objects := make(map[string]ast.ListNode)
|
func hclObjectMap(os *hclobj.Object) map[string]ast.ListNode {
|
||||||
|
objects := make(map[string][]*hclobj.Object)
|
||||||
|
|
||||||
for _, n := range ns {
|
for _, o := range os.Elem(false) {
|
||||||
ns := []ast.Node{n}
|
for _, elem := range o.Elem(true) {
|
||||||
if ln, ok := n.(ast.ListNode); ok {
|
val, ok := objects[elem.Key]
|
||||||
ns = ln.Elem
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, n := range ns {
|
|
||||||
obj, ok := n.(ast.ObjectNode)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
val = make([]*hclobj.Object, 0, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, elem := range obj.Elem {
|
val = append(val, elem)
|
||||||
val, ok := objects[elem.Key()]
|
objects[elem.Key] = val
|
||||||
if !ok {
|
|
||||||
val = ast.ListNode{}
|
|
||||||
}
|
|
||||||
|
|
||||||
val.Elem = append(val.Elem, elem.Value)
|
|
||||||
objects[elem.Key()] = val
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return objects
|
return objects
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
Loading…
Reference in New Issue