terraform: build resource graph, validate
This commit is contained in:
parent
9480783ee4
commit
d731d033f1
|
@ -9,6 +9,10 @@ import (
|
||||||
"github.com/hashicorp/terraform/depgraph"
|
"github.com/hashicorp/terraform/depgraph"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ResourceGraphRoot is the name of the resource graph root that should be
|
||||||
|
// ignored since it doesn't map to an exact resource.
|
||||||
|
const ResourceGraphRoot = "root"
|
||||||
|
|
||||||
// Config is the configuration that comes from loading a collection
|
// Config is the configuration that comes from loading a collection
|
||||||
// of Terraform templates.
|
// of Terraform templates.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -116,7 +120,7 @@ func (c *Config) ResourceGraph() *depgraph.Graph {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a root that just depends on everything else finishing.
|
// Create a root that just depends on everything else finishing.
|
||||||
root := &depgraph.Noun{Name: "root"}
|
root := &depgraph.Noun{Name: ResourceGraphRoot}
|
||||||
for _, n := range nounsList {
|
for _, n := range nounsList {
|
||||||
root.Deps = append(root.Deps, &depgraph.Dependency{
|
root.Deps = append(root.Deps, &depgraph.Dependency{
|
||||||
Name: n.Name,
|
Name: n.Name,
|
||||||
|
|
|
@ -4,17 +4,5 @@ package terraform
|
||||||
// can use to keep track of what real world resources it is actually
|
// can use to keep track of what real world resources it is actually
|
||||||
// managing.
|
// managing.
|
||||||
type State struct {
|
type State struct {
|
||||||
resources map[string]resourceState
|
resources map[string]ResourceState
|
||||||
}
|
|
||||||
|
|
||||||
// resourceState is the state of a single resource.
|
|
||||||
//
|
|
||||||
// The ID is required and is some opaque string used to recognize
|
|
||||||
// the realized resource.
|
|
||||||
//
|
|
||||||
// Extra is arbitrary extra metadata that the resource provider returns
|
|
||||||
// that is sent back into the resource provider when it is needed.
|
|
||||||
type resourceState struct {
|
|
||||||
ID string
|
|
||||||
Extra map[string]interface{}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
|
"github.com/hashicorp/terraform/depgraph"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Terraform is the primary structure that is used to interact with
|
// Terraform is the primary structure that is used to interact with
|
||||||
|
@ -12,6 +13,7 @@ import (
|
||||||
// all resources, a resource tree, a specific resource, etc.
|
// all resources, a resource tree, a specific resource, etc.
|
||||||
type Terraform struct {
|
type Terraform struct {
|
||||||
config *config.Config
|
config *config.Config
|
||||||
|
graph *depgraph.Graph
|
||||||
mapping map[*config.Resource]ResourceProvider
|
mapping map[*config.Resource]ResourceProvider
|
||||||
variables map[string]string
|
variables map[string]string
|
||||||
}
|
}
|
||||||
|
@ -98,6 +100,13 @@ func New(c *Config) (*Terraform, error) {
|
||||||
mapping[r] = provider
|
mapping[r] = provider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build the resource graph
|
||||||
|
graph := c.Config.ResourceGraph()
|
||||||
|
if err := graph.Validate(); err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf(
|
||||||
|
"Resource graph has an error: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
// If we accumulated any errors, then return them all
|
// If we accumulated any errors, then return them all
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return nil, &MultiError{Errors: errs}
|
return nil, &MultiError{Errors: errs}
|
||||||
|
@ -105,6 +114,7 @@ func New(c *Config) (*Terraform, error) {
|
||||||
|
|
||||||
return &Terraform{
|
return &Terraform{
|
||||||
config: c.Config,
|
config: c.Config,
|
||||||
|
graph: graph,
|
||||||
mapping: mapping,
|
mapping: mapping,
|
||||||
variables: c.Variables,
|
variables: c.Variables,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
|
@ -80,6 +80,24 @@ func TestNew(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNew_graphCycle(t *testing.T) {
|
||||||
|
config := testConfig(t, "new-graph-cycle")
|
||||||
|
tfConfig := &Config{
|
||||||
|
Config: config,
|
||||||
|
Providers: map[string]ResourceProviderFactory{
|
||||||
|
"aws": testProviderFunc("aws", []string{"aws_instance"}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tf, err := New(tfConfig)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("should error")
|
||||||
|
}
|
||||||
|
if tf != nil {
|
||||||
|
t.Fatalf("should not return tf")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNew_variables(t *testing.T) {
|
func TestNew_variables(t *testing.T) {
|
||||||
config := testConfig(t, "new-variables")
|
config := testConfig(t, "new-variables")
|
||||||
tfConfig := &Config{
|
tfConfig := &Config{
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
ami = "${aws_instance.bar.id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "bar" {
|
||||||
|
ami = "${aws_instance.foo.id}"
|
||||||
|
}
|
Loading…
Reference in New Issue