terraform: start apply-based graph builder, basic diff transform
This commit is contained in:
parent
361bc5a8df
commit
3f090df26e
|
@ -0,0 +1,44 @@
|
||||||
|
package terraform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/terraform/config/module"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ApplyGraphBuilder implements GraphBuilder and is responsible for building
|
||||||
|
// a graph for applying a Terraform diff.
|
||||||
|
//
|
||||||
|
// Because the graph is built from the diff (vs. the config or state),
|
||||||
|
// this helps ensure that the apply-time graph doesn't modify any resources
|
||||||
|
// that aren't explicitly in the diff. There are other scenarios where the
|
||||||
|
// diff can be deviated, so this is just one layer of protection.
|
||||||
|
type ApplyGraphBuilder struct {
|
||||||
|
// Config is the root module for the graph to build.
|
||||||
|
Config *module.Tree
|
||||||
|
|
||||||
|
// Diff is the diff to apply.
|
||||||
|
Diff *Diff
|
||||||
|
|
||||||
|
// Providers is the list of providers supported.
|
||||||
|
Providers []string
|
||||||
|
|
||||||
|
// Provisioners is the list of provisioners supported.
|
||||||
|
Provisioners []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// See GraphBuilder
|
||||||
|
func (b *ApplyGraphBuilder) Build(path []string) (*Graph, error) {
|
||||||
|
return (&BasicGraphBuilder{
|
||||||
|
Steps: b.Steps(),
|
||||||
|
Validate: true,
|
||||||
|
}).Build(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// See GraphBuilder
|
||||||
|
func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
|
||||||
|
steps := []GraphTransformer{
|
||||||
|
// Creates all the nodes represented in the diff.
|
||||||
|
&DiffTransformer{Diff: b.Diff},
|
||||||
|
}
|
||||||
|
|
||||||
|
return steps
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package terraform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestApplyGraphBuilder_impl(t *testing.T) {
|
||||||
|
var _ GraphBuilder = new(ApplyGraphBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApplyGraphBuilder(t *testing.T) {
|
||||||
|
diff := &Diff{
|
||||||
|
Modules: []*ModuleDiff{
|
||||||
|
&ModuleDiff{
|
||||||
|
Path: []string{"root"},
|
||||||
|
Resources: map[string]*InstanceDiff{
|
||||||
|
// Verify noop doesn't show up in graph
|
||||||
|
"aws_instance.noop": &InstanceDiff{},
|
||||||
|
|
||||||
|
"aws_instance.create": &InstanceDiff{
|
||||||
|
Attributes: map[string]*ResourceAttrDiff{
|
||||||
|
"name": &ResourceAttrDiff{
|
||||||
|
Old: "",
|
||||||
|
New: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
b := &ApplyGraphBuilder{
|
||||||
|
Diff: diff,
|
||||||
|
}
|
||||||
|
|
||||||
|
g, err := b.Build(RootModulePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(g.Path, RootModulePath) {
|
||||||
|
t.Fatalf("bad: %#v", g.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := strings.TrimSpace(g.String())
|
||||||
|
expected := strings.TrimSpace(testApplyGraphBuilderStr)
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("bad: %s", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testApplyGraphBuilderStr = `
|
||||||
|
aws_instance.create
|
||||||
|
`
|
|
@ -0,0 +1,10 @@
|
||||||
|
package terraform
|
||||||
|
|
||||||
|
// NodeResource is a graph node for referencing a resource.
|
||||||
|
type NodeResource struct {
|
||||||
|
Addr *ResourceAddress // Addr is the address for this resource
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NodeResource) Name() string {
|
||||||
|
return n.Addr.String()
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package terraform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DiffTransformer is a GraphTransformer that adds the elements of
|
||||||
|
// the diff to the graph.
|
||||||
|
//
|
||||||
|
// This transform is used for example by the ApplyGraphBuilder to ensure
|
||||||
|
// that only resources that are being modified are represented in the graph.
|
||||||
|
type DiffTransformer struct {
|
||||||
|
Diff *Diff
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *DiffTransformer) Transform(g *Graph) error {
|
||||||
|
// If the diff is nil or empty (nil is empty) then do nothing
|
||||||
|
if t.Diff.Empty() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go through all the modules in the diff.
|
||||||
|
for _, m := range t.Diff.Modules {
|
||||||
|
// TODO: If this is a destroy diff then add a module destroy node
|
||||||
|
|
||||||
|
// Go through all the resources in this module.
|
||||||
|
for name, inst := range m.Resources {
|
||||||
|
// TODO: Destroy diff
|
||||||
|
|
||||||
|
// If this diff has no attribute changes, then we have
|
||||||
|
// nothing to do and therefore won't add it to the graph.
|
||||||
|
if len(inst.Attributes) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have changes! This is a create or update operation.
|
||||||
|
// First grab the address so we have a unique way to
|
||||||
|
// reference this resource.
|
||||||
|
addr, err := parseResourceAddressInternal(name)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Error parsing internal name, this is a bug: %q", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the resource to the graph
|
||||||
|
g.Add(&NodeResource{
|
||||||
|
Addr: addr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue