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 Jun 11, 2017
1 parent e50a57b commit 17eb5c4
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 16 deletions.
3 changes: 2 additions & 1 deletion command/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,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 @@ -171,7 +171,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
50 changes: 36 additions & 14 deletions terraform/transform_targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,36 @@ 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() {
removable := false
if _, ok := v.(GraphNodeResource); ok {
Expand All @@ -70,27 +79,40 @@ func (t *TargetsTransformer) Transform(g *Graph) error {
if vr, ok := v.(RemovableIfNotTargeted); ok {
removable = vr.RemoveIfNotTargeted()
}
if removable && !targetedNodes.Include(v) {
log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v))
g.Remove(v)
if removable {
if len(t.ParsedTargets) > 0 && !targetedNodes.Include(v) {
log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v))
g.Remove(v)
} else if len(t.ParsedExcludes) > 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
98 changes: 98 additions & 0 deletions terraform/transform_targets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,101 @@ 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.me
aws_subnet.notme
aws_vpc.me
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_elb.me
aws_instance.metoo
aws_instance.notme
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_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 17eb5c4

Please sign in to comment.