Remove all traces of libucl
This commit is contained in:
parent
47ddd197f5
commit
04975827ac
49
Makefile
49
Makefile
|
@ -1,69 +1,34 @@
|
||||||
CGO_CFLAGS:=-I$(CURDIR)/vendor/libucl/include
|
|
||||||
CGO_LDFLAGS:=-L$(CURDIR)/vendor/libucl
|
|
||||||
LIBUCL_NAME=libucl.a
|
|
||||||
TEST?=./...
|
TEST?=./...
|
||||||
|
|
||||||
# Windows-only
|
|
||||||
ifeq ($(OS), Windows_NT)
|
|
||||||
# The Libucl library is named libucl.dll
|
|
||||||
LIBUCL_NAME=libucl.dll
|
|
||||||
|
|
||||||
# Add the current directory on the path so the DLL is available.
|
|
||||||
export PATH := $(CURDIR):$(PATH)
|
|
||||||
endif
|
|
||||||
|
|
||||||
export CGO_CFLAGS CGO_LDFLAGS PATH
|
|
||||||
|
|
||||||
default: test
|
default: test
|
||||||
|
|
||||||
bin: config/y.go libucl
|
bin: config/y.go
|
||||||
@sh -c "$(CURDIR)/scripts/build.sh"
|
@sh -c "$(CURDIR)/scripts/build.sh"
|
||||||
|
|
||||||
dev: config/y.go libucl
|
dev: config/y.go
|
||||||
@TF_DEV=1 sh -c "$(CURDIR)/scripts/build.sh"
|
@TF_DEV=1 sh -c "$(CURDIR)/scripts/build.sh"
|
||||||
|
|
||||||
libucl: vendor/libucl/$(LIBUCL_NAME)
|
test: config/y.go
|
||||||
|
|
||||||
test: config/y.go libucl
|
|
||||||
TF_ACC= go test $(TEST) $(TESTARGS) -timeout=10s
|
TF_ACC= go test $(TEST) $(TESTARGS) -timeout=10s
|
||||||
|
|
||||||
testacc: config/y.go libucl
|
testacc: config/y.go
|
||||||
@if [ "$(TEST)" = "./..." ]; then \
|
@if [ "$(TEST)" = "./..." ]; then \
|
||||||
echo "ERROR: Set TEST to a specific package"; \
|
echo "ERROR: Set TEST to a specific package"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 30m
|
TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 30m
|
||||||
|
|
||||||
testrace: config/y.go libucl
|
testrace: config/y.go
|
||||||
TF_ACC= go test -race $(TEST) $(TESTARGS)
|
TF_ACC= go test -race $(TEST) $(TESTARGS)
|
||||||
|
|
||||||
updatedeps: config/y.go libucl
|
updatedeps: config/y.go
|
||||||
go get -u -v ./...
|
go get -u -v ./...
|
||||||
|
|
||||||
config/y.go: config/expr.y
|
config/y.go: config/expr.y
|
||||||
cd config/ && \
|
cd config/ && \
|
||||||
go tool yacc -p "expr" expr.y
|
go tool yacc -p "expr" expr.y
|
||||||
|
|
||||||
vendor/libucl/libucl.a: vendor/libucl
|
|
||||||
cd vendor/libucl && \
|
|
||||||
cmake cmake/ && \
|
|
||||||
make
|
|
||||||
|
|
||||||
vendor/libucl/libucl.dll: vendor/libucl
|
|
||||||
cd vendor/libucl && \
|
|
||||||
$(MAKE) -f Makefile.w32 && \
|
|
||||||
cp .obj/libucl.dll . && \
|
|
||||||
cp libucl.dll $(CURDIR)
|
|
||||||
|
|
||||||
vendor/libucl:
|
|
||||||
rm -rf vendor/libucl
|
|
||||||
mkdir -p vendor/libucl
|
|
||||||
git clone https://github.com/hashicorp/libucl.git vendor/libucl
|
|
||||||
cd vendor/libucl && \
|
|
||||||
git checkout fix-win32-compile
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm config/y.go
|
rm config/y.go
|
||||||
rm -rf vendor
|
|
||||||
|
|
||||||
.PHONY: clean default libucl test updatedeps
|
.PHONY: clean default test updatedeps
|
||||||
|
|
|
@ -2,9 +2,10 @@ package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mitchellh/go-libucl"
|
"github.com/hashicorp/hcl"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FlagVar is a flag.Value implementation for parsing user variables
|
// FlagVar is a flag.Value implementation for parsing user variables
|
||||||
|
@ -55,25 +56,23 @@ func (v *FlagVarFile) Set(raw string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const libuclParseFlags = libucl.ParserNoTime
|
|
||||||
|
|
||||||
func loadVarFile(path string) (map[string]string, error) {
|
func loadVarFile(path string) (map[string]string, error) {
|
||||||
var obj *libucl.Object
|
// Read the HCL file and prepare for parsing
|
||||||
|
d, err := ioutil.ReadFile(path)
|
||||||
parser := libucl.NewParser(libuclParseFlags)
|
|
||||||
err := parser.AddFile(path)
|
|
||||||
if err == nil {
|
|
||||||
obj = parser.Object()
|
|
||||||
defer obj.Close()
|
|
||||||
}
|
|
||||||
defer parser.Close()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf(
|
||||||
|
"Error reading %s: %s", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse it
|
||||||
|
obj, err := hcl.Parse(string(d))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"Error parsing %s: %s", path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var result map[string]string
|
var result map[string]string
|
||||||
if err := obj.Decode(&result); err != nil {
|
if err := hcl.DecodeObject(&result, obj); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
35
config.go
35
config.go
|
@ -1,13 +1,15 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/hashicorp/hcl"
|
||||||
"github.com/hashicorp/terraform/plugin"
|
"github.com/hashicorp/terraform/plugin"
|
||||||
"github.com/hashicorp/terraform/rpc"
|
"github.com/hashicorp/terraform/rpc"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
"github.com/mitchellh/go-libucl"
|
|
||||||
"github.com/mitchellh/osext"
|
"github.com/mitchellh/osext"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,10 +29,6 @@ var BuiltinConfig Config
|
||||||
// ContextOpts are the global ContextOpts we use to initialize the CLI.
|
// ContextOpts are the global ContextOpts we use to initialize the CLI.
|
||||||
var ContextOpts terraform.ContextOpts
|
var ContextOpts terraform.ContextOpts
|
||||||
|
|
||||||
// Put the parse flags we use for libucl in a constant so we can get
|
|
||||||
// equally behaving parsing everywhere.
|
|
||||||
const libuclParseFlags = libucl.ParserNoTime
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
BuiltinConfig.Providers = map[string]string{
|
BuiltinConfig.Providers = map[string]string{
|
||||||
"aws": "terraform-provider-aws",
|
"aws": "terraform-provider-aws",
|
||||||
|
@ -49,26 +47,23 @@ func init() {
|
||||||
|
|
||||||
// LoadConfig loads the CLI configuration from ".terraformrc" files.
|
// LoadConfig loads the CLI configuration from ".terraformrc" files.
|
||||||
func LoadConfig(path string) (*Config, error) {
|
func LoadConfig(path string) (*Config, error) {
|
||||||
var obj *libucl.Object
|
// Read the HCL file and prepare for parsing
|
||||||
|
d, err := ioutil.ReadFile(path)
|
||||||
// Parse the file and get the root object.
|
|
||||||
parser := libucl.NewParser(libuclParseFlags)
|
|
||||||
err := parser.AddFile(path)
|
|
||||||
if err == nil {
|
|
||||||
obj = parser.Object()
|
|
||||||
defer obj.Close()
|
|
||||||
}
|
|
||||||
defer parser.Close()
|
|
||||||
|
|
||||||
// If there was an error parsing, return now.
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf(
|
||||||
|
"Error reading %s: %s", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse it
|
||||||
|
obj, err := hcl.Parse(string(d))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"Error parsing %s: %s", path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build up the result
|
// Build up the result
|
||||||
var result Config
|
var result Config
|
||||||
|
if err := hcl.DecodeObject(&result, obj); err != nil {
|
||||||
if err := obj.Decode(&result); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,538 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/mitchellh/go-libucl"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Put the parse flags we use for libucl in a constant so we can get
|
|
||||||
// equally behaving parsing everywhere.
|
|
||||||
const libuclParseFlags = libucl.ParserNoTime
|
|
||||||
|
|
||||||
// libuclConfigurable is an implementation of configurable that knows
|
|
||||||
// how to turn libucl configuration into a *Config object.
|
|
||||||
type libuclConfigurable struct {
|
|
||||||
Object *libucl.Object
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *libuclConfigurable) Close() error {
|
|
||||||
return t.Object.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *libuclConfigurable) Config() (*Config, error) {
|
|
||||||
validKeys := map[string]struct{}{
|
|
||||||
"output": struct{}{},
|
|
||||||
"provider": struct{}{},
|
|
||||||
"resource": struct{}{},
|
|
||||||
"variable": struct{}{},
|
|
||||||
}
|
|
||||||
|
|
||||||
type LibuclVariable struct {
|
|
||||||
Default interface{}
|
|
||||||
Description string
|
|
||||||
Fields []string `libucl:",decodedFields"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var rawConfig struct {
|
|
||||||
Variable map[string]*LibuclVariable
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := t.Object.Decode(&rawConfig); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start building up the actual configuration. We start with
|
|
||||||
// variables.
|
|
||||||
// TODO(mitchellh): Make function like loadVariablesLibucl so that
|
|
||||||
// duplicates aren't overridden
|
|
||||||
config := new(Config)
|
|
||||||
if len(rawConfig.Variable) > 0 {
|
|
||||||
config.Variables = make([]*Variable, 0, len(rawConfig.Variable))
|
|
||||||
for k, v := range rawConfig.Variable {
|
|
||||||
// Defaults turn into a slice of map[string]interface{} and
|
|
||||||
// we need to make sure to convert that down into the
|
|
||||||
// proper type for Config.
|
|
||||||
if ms, ok := v.Default.([]map[string]interface{}); ok {
|
|
||||||
def := make(map[string]interface{})
|
|
||||||
for _, m := range ms {
|
|
||||||
for k, v := range m {
|
|
||||||
def[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
v.Default = def
|
|
||||||
}
|
|
||||||
|
|
||||||
newVar := &Variable{
|
|
||||||
Name: k,
|
|
||||||
Default: v.Default,
|
|
||||||
Description: v.Description,
|
|
||||||
}
|
|
||||||
|
|
||||||
config.Variables = append(config.Variables, newVar)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the provider configs
|
|
||||||
providers := t.Object.Get("provider")
|
|
||||||
if providers != nil {
|
|
||||||
var err error
|
|
||||||
config.ProviderConfigs, err = loadProvidersLibucl(providers)
|
|
||||||
providers.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the resources
|
|
||||||
resources := t.Object.Get("resource")
|
|
||||||
if resources != nil {
|
|
||||||
var err error
|
|
||||||
config.Resources, err = loadResourcesLibucl(resources)
|
|
||||||
resources.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for invalid keys
|
|
||||||
iter := t.Object.Iterate(true)
|
|
||||||
defer iter.Close()
|
|
||||||
for o := iter.Next(); o != nil; o = iter.Next() {
|
|
||||||
k := o.Key()
|
|
||||||
o.Close()
|
|
||||||
|
|
||||||
if _, ok := validKeys[k]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
config.unknownKeys = append(config.unknownKeys, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadFileLibucl is a fileLoaderFunc that knows how to read libucl
|
|
||||||
// files and turn them into libuclConfigurables.
|
|
||||||
func loadFileLibucl(root string) (configurable, []string, error) {
|
|
||||||
var obj *libucl.Object = nil
|
|
||||||
|
|
||||||
// Parse and store the object. We don't use a defer here so that
|
|
||||||
// we clear resources right away rather than stack them up all the
|
|
||||||
// way through our recursive calls.
|
|
||||||
parser := libucl.NewParser(libuclParseFlags)
|
|
||||||
err := parser.AddFile(root)
|
|
||||||
if err == nil {
|
|
||||||
obj = parser.Object()
|
|
||||||
defer obj.Close()
|
|
||||||
}
|
|
||||||
parser.Close()
|
|
||||||
|
|
||||||
// If there was an error, return early
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start building the result
|
|
||||||
result := &libuclConfigurable{
|
|
||||||
Object: obj,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, dive in, find the imports.
|
|
||||||
imports := obj.Get("import")
|
|
||||||
if imports == nil {
|
|
||||||
result.Object.Ref()
|
|
||||||
return result, nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if imports.Type() != libucl.ObjectTypeString {
|
|
||||||
imports.Close()
|
|
||||||
|
|
||||||
return nil, nil, fmt.Errorf(
|
|
||||||
"Error in %s: all 'import' declarations should be in the format\n"+
|
|
||||||
"`import \"foo\"` (Got type %s)",
|
|
||||||
root,
|
|
||||||
imports.Type())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gather all the import paths
|
|
||||||
importPaths := make([]string, 0, imports.Len())
|
|
||||||
iter := imports.Iterate(false)
|
|
||||||
for imp := iter.Next(); imp != nil; imp = iter.Next() {
|
|
||||||
path := imp.ToString()
|
|
||||||
if !filepath.IsAbs(path) {
|
|
||||||
// Relative paths are relative to the Terraform file itself
|
|
||||||
dir := filepath.Dir(root)
|
|
||||||
path = filepath.Join(dir, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
importPaths = append(importPaths, path)
|
|
||||||
imp.Close()
|
|
||||||
}
|
|
||||||
iter.Close()
|
|
||||||
imports.Close()
|
|
||||||
|
|
||||||
result.Object.Ref()
|
|
||||||
return result, importPaths, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadOutputsLibucl recurses into the given libucl object and turns
|
|
||||||
// it into a mapping of outputs.
|
|
||||||
func loadOutputsLibucl(o *libucl.Object) ([]*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()
|
|
||||||
|
|
||||||
// If we have none, just return nil
|
|
||||||
if len(objects) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through each object and turn it into an actual result.
|
|
||||||
result := make([]*Output, 0, len(objects))
|
|
||||||
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 = append(result, &Output{
|
|
||||||
Name: n,
|
|
||||||
RawConfig: rawConfig,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadProvidersLibucl recurses into the given libucl object and turns
|
|
||||||
// it into a mapping of provider configs.
|
|
||||||
func loadProvidersLibucl(o *libucl.Object) ([]*ProviderConfig, error) {
|
|
||||||
objects := make(map[string]*libucl.Object)
|
|
||||||
|
|
||||||
// Iterate over all the "provider" 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()
|
|
||||||
|
|
||||||
if len(objects) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through each object and turn it into an actual result.
|
|
||||||
result := make([]*ProviderConfig, 0, len(objects))
|
|
||||||
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 provider config %s: %s",
|
|
||||||
n,
|
|
||||||
err)
|
|
||||||
}
|
|
||||||
|
|
||||||
result = append(result, &ProviderConfig{
|
|
||||||
Name: n,
|
|
||||||
RawConfig: rawConfig,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a handle to a libucl object, this recurses into the structure
|
|
||||||
// and pulls out a list of resources.
|
|
||||||
//
|
|
||||||
// The resulting resources may not be unique, but each resource
|
|
||||||
// represents exactly one resource definition in the libucl configuration.
|
|
||||||
// We leave it up to another pass to merge them together.
|
|
||||||
func loadResourcesLibucl(o *libucl.Object) ([]*Resource, error) {
|
|
||||||
var allTypes []*libucl.Object
|
|
||||||
|
|
||||||
// Libucl 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".
|
|
||||||
iter := o.Iterate(false)
|
|
||||||
for o1 := iter.Next(); o1 != nil; o1 = iter.Next() {
|
|
||||||
// Iterate the inner to get the list of types
|
|
||||||
iter2 := o1.Iterate(true)
|
|
||||||
for o2 := iter2.Next(); o2 != nil; o2 = iter2.Next() {
|
|
||||||
// Iterate all of this type to get _all_ the types
|
|
||||||
iter3 := o2.Iterate(false)
|
|
||||||
for o3 := iter3.Next(); o3 != nil; o3 = iter3.Next() {
|
|
||||||
allTypes = append(allTypes, o3)
|
|
||||||
}
|
|
||||||
|
|
||||||
o2.Close()
|
|
||||||
iter3.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
o1.Close()
|
|
||||||
iter2.Close()
|
|
||||||
}
|
|
||||||
iter.Close()
|
|
||||||
|
|
||||||
// Where all the results will go
|
|
||||||
var result []*Resource
|
|
||||||
|
|
||||||
// Now go over all the types and their children in order to get
|
|
||||||
// all of the actual resources.
|
|
||||||
for _, t := range allTypes {
|
|
||||||
// Release the resources for this raw type since we don't need it.
|
|
||||||
// Note that this makes it unsafe now to use allTypes again.
|
|
||||||
defer t.Close()
|
|
||||||
|
|
||||||
iter := t.Iterate(true)
|
|
||||||
defer iter.Close()
|
|
||||||
for r := iter.Next(); r != nil; r = iter.Next() {
|
|
||||||
defer r.Close()
|
|
||||||
|
|
||||||
var config map[string]interface{}
|
|
||||||
if err := r.Decode(&config); err != nil {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"Error reading config for %s[%s]: %s",
|
|
||||||
t.Key(),
|
|
||||||
r.Key(),
|
|
||||||
err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the fields we handle specially
|
|
||||||
delete(config, "connection")
|
|
||||||
delete(config, "count")
|
|
||||||
delete(config, "depends_on")
|
|
||||||
delete(config, "provisioner")
|
|
||||||
|
|
||||||
rawConfig, err := NewRawConfig(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"Error reading config for %s[%s]: %s",
|
|
||||||
t.Key(),
|
|
||||||
r.Key(),
|
|
||||||
err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a count, then figure it out
|
|
||||||
var count int = 1
|
|
||||||
if o := r.Get("count"); o != nil {
|
|
||||||
err = o.Decode(&count)
|
|
||||||
o.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"Error parsing count for %s[%s]: %s",
|
|
||||||
t.Key(),
|
|
||||||
r.Key(),
|
|
||||||
err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have connection info, then parse those out
|
|
||||||
var connInfo map[string]interface{}
|
|
||||||
if conn := r.Get("connection"); conn != nil {
|
|
||||||
var err error
|
|
||||||
connInfo, err = loadConnInfoLibucl(conn)
|
|
||||||
conn.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"Error reading connection info for %s[%s]: %s",
|
|
||||||
t.Key(),
|
|
||||||
r.Key(),
|
|
||||||
err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have depends fields, then add those in
|
|
||||||
var dependsOn []string
|
|
||||||
if deps := r.Get("depends_on"); deps != nil {
|
|
||||||
err := deps.Decode(&dependsOn)
|
|
||||||
deps.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"Error reading depends_on for %s[%s]: %s",
|
|
||||||
t.Key(),
|
|
||||||
r.Key(),
|
|
||||||
err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, connInfo)
|
|
||||||
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,
|
|
||||||
Provisioners: provisioners,
|
|
||||||
DependsOn: dependsOn,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadProvisionersLibucl(o *libucl.Object, connInfo map[string]interface{}) ([]*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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the "connection" section, handle separately
|
|
||||||
delete(config, "connection")
|
|
||||||
|
|
||||||
rawConfig, err := NewRawConfig(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we have a provisioner-level connection
|
|
||||||
// block that overrides the resource-level
|
|
||||||
var subConnInfo map[string]interface{}
|
|
||||||
if conn := po.Get("connection"); conn != nil {
|
|
||||||
var err error
|
|
||||||
subConnInfo, err = loadConnInfoLibucl(conn)
|
|
||||||
conn.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inherit from the resource connInfo any keys
|
|
||||||
// that are not explicitly overridden.
|
|
||||||
if connInfo != nil && subConnInfo != nil {
|
|
||||||
for k, v := range connInfo {
|
|
||||||
if _, ok := subConnInfo[k]; !ok {
|
|
||||||
subConnInfo[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if subConnInfo == nil {
|
|
||||||
subConnInfo = connInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the connInfo
|
|
||||||
connRaw, err := NewRawConfig(subConnInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
result = append(result, &Provisioner{
|
|
||||||
Type: po.Key(),
|
|
||||||
RawConfig: rawConfig,
|
|
||||||
ConnInfo: connRaw,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadConnInfoLibucl(o *libucl.Object) (map[string]interface{}, error) {
|
|
||||||
var config map[string]interface{}
|
|
||||||
if err := o.Decode(&config); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return config, nil
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLibuclConfigurableCloser(t *testing.T) {
|
|
||||||
var _ io.Closer = new(libuclConfigurable)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLibuclConfigurableConfigurable(t *testing.T) {
|
|
||||||
var _ configurable = new(libuclConfigurable)
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
providers {
|
providers {
|
||||||
"aws" = "foo"
|
aws = "foo"
|
||||||
"do" = "bar"
|
do = "bar"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue