Skip to content

Commit

Permalink
adding exclude flag to plan and apply to exclude specified resource f…
Browse files Browse the repository at this point in the history
…rom map

reverting changes, changing target to exclude when using !

cleanup
  • Loading branch information
nevins-b authored and josephholsten committed Feb 4, 2016
1 parent 316d473 commit b33cc53
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 12 deletions.
3 changes: 2 additions & 1 deletion command/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,8 @@ Options:
-target=resource Resource to target. Operation will be limited to this
resource and its dependencies. This flag can be used
multiple times.
multiple times. Prefixing the resource with ! will
exclude the resource.
-var 'foo=bar' Set a variable in the Terraform configuration. This
flag can be set multiple times.
Expand Down
3 changes: 2 additions & 1 deletion command/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ Options:
-target=resource Resource to target. Operation will be limited to this
resource and its dependencies. This flag can be used
multiple times.
multiple times. Prefixing the resource with ! will
exclude the resource.
-var 'foo=bar' Set a variable in the Terraform configuration. This
flag can be set multiple times.
Expand Down
43 changes: 33 additions & 10 deletions terraform/transform_targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,47 +17,70 @@ type TargetsTransformer struct {
// that already have the targets parsed
ParsedTargets []ResourceAddress

// List of parsed excludes, provided by callers like ResourceCountTransform
// that already have the targets parsed
ParsedExcludes []ResourceAddress

// Set to true when we're in a `terraform destroy` or a
// `terraform plan -destroy`
Destroy bool
}

func (t *TargetsTransformer) Transform(g *Graph) error {
if len(t.Targets) > 0 && len(t.ParsedTargets) == 0 {
addrs, err := t.parseTargetAddresses()
targeted, excluded, err := t.parseTargetAddresses()
if err != nil {
return err
}
t.ParsedTargets = addrs
t.ParsedTargets = targeted
t.ParsedExcludes = excluded
}
if len(t.ParsedTargets) > 0 {

if len(t.ParsedTargets) > 0 || len(t.ParsedExcludes) > 0 {
targetedNodes, err := t.selectTargetedNodes(g, t.ParsedTargets)
if err != nil {
return err
}

excludedNodes, err := t.selectTargetedNodes(g, t.ParsedExcludes)
if err != nil {
return err
}

for _, v := range g.Vertices() {
if _, ok := v.(GraphNodeAddressable); ok {
if !targetedNodes.Include(v) {
if targetedNodes.Len() > 0 && !targetedNodes.Include(v) {
log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v))
g.Remove(v)
} else if excludedNodes.Len() > 0 && excludedNodes.Include(v) {
log.Printf("[DEBUG] Removing %s, filtered by excluding.", dag.VertexName(v))
g.Remove(v)
}
}
}
}
return nil
}

func (t *TargetsTransformer) parseTargetAddresses() ([]ResourceAddress, error) {
addrs := make([]ResourceAddress, len(t.Targets))
for i, target := range t.Targets {
func (t *TargetsTransformer) parseTargetAddresses() ([]ResourceAddress, []ResourceAddress, error) {
var targeted, excluded []ResourceAddress
for _, target := range t.Targets {
exclude := string(target[0]) == "!"
if exclude {
target = target[1:]
log.Printf("[DEBUG] Excluding %s", target)
}
ta, err := ParseResourceAddress(target)
if err != nil {
return nil, err
return nil, nil, err
}
if exclude {
excluded = append(excluded, *ta)
} else {
targeted = append(targeted, *ta)
}
addrs[i] = *ta
}
return addrs, nil
return targeted, excluded, nil
}

// Returns the list of targeted nodes. A targeted node is either addressed
Expand Down
95 changes: 95 additions & 0 deletions terraform/transform_targets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,98 @@ aws_instance.metoo
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
}
}

func TestTargetsTransformer_exclude(t *testing.T) {
mod := testModule(t, "transform-targets-basic")

g := Graph{Path: RootModulePath}
{
tf := &ConfigTransformer{Module: mod}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}

{
transform := &TargetsTransformer{Targets: []string{"!aws_instance.me"}}
if err := transform.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}

actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(`
aws_instance.notme
aws_instance.notmeeither
aws_subnet.notme
aws_vpc.notme
`)
if actual != expected {
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
}
}

func TestTargetsTransformer_exclude_destroy(t *testing.T) {
mod := testModule(t, "transform-targets-destroy")

g := Graph{Path: RootModulePath}
{
tf := &ConfigTransformer{Module: mod}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}

{
transform := &TargetsTransformer{
Targets: []string{"!aws_instance.me"},
Destroy: true,
}
if err := transform.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}

actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(`
aws_instance.notme
aws_subnet.notme
aws_vpc.notme
aws_vpc.notme
`)
if actual != expected {
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
}
}

func TestTargetsTransformer_include_exclude(t *testing.T) {
mod := testModule(t, "transform-targets-basic")

g := Graph{Path: RootModulePath}
{
tf := &ConfigTransformer{Module: mod}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}

{
transform := &TargetsTransformer{
Targets: []string{
"aws_instance.me",
"!aws_subnet.me",
},
}
if err := transform.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}

actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(`
aws_instance.me
`)
if actual != expected {
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
}
}

0 comments on commit b33cc53

Please sign in to comment.