Skip to content

Commit b33cc53

Browse files
nevins-bjosephholsten
authored andcommitted
adding exclude flag to plan and apply to exclude specified resource from map
reverting changes, changing target to exclude when using ! cleanup
1 parent 316d473 commit b33cc53

File tree

4 files changed

+132
-12
lines changed

4 files changed

+132
-12
lines changed

command/apply.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,8 @@ Options:
357357
358358
-target=resource Resource to target. Operation will be limited to this
359359
resource and its dependencies. This flag can be used
360-
multiple times.
360+
multiple times. Prefixing the resource with ! will
361+
exclude the resource.
361362
362363
-var 'foo=bar' Set a variable in the Terraform configuration. This
363364
flag can be set multiple times.

command/plan.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,8 @@ Options:
198198
199199
-target=resource Resource to target. Operation will be limited to this
200200
resource and its dependencies. This flag can be used
201-
multiple times.
201+
multiple times. Prefixing the resource with ! will
202+
exclude the resource.
202203
203204
-var 'foo=bar' Set a variable in the Terraform configuration. This
204205
flag can be set multiple times.

terraform/transform_targets.go

+33-10
Original file line numberDiff line numberDiff line change
@@ -17,47 +17,70 @@ type TargetsTransformer struct {
1717
// that already have the targets parsed
1818
ParsedTargets []ResourceAddress
1919

20+
// List of parsed excludes, provided by callers like ResourceCountTransform
21+
// that already have the targets parsed
22+
ParsedExcludes []ResourceAddress
23+
2024
// Set to true when we're in a `terraform destroy` or a
2125
// `terraform plan -destroy`
2226
Destroy bool
2327
}
2428

2529
func (t *TargetsTransformer) Transform(g *Graph) error {
2630
if len(t.Targets) > 0 && len(t.ParsedTargets) == 0 {
27-
addrs, err := t.parseTargetAddresses()
31+
targeted, excluded, err := t.parseTargetAddresses()
2832
if err != nil {
2933
return err
3034
}
31-
t.ParsedTargets = addrs
35+
t.ParsedTargets = targeted
36+
t.ParsedExcludes = excluded
3237
}
33-
if len(t.ParsedTargets) > 0 {
38+
39+
if len(t.ParsedTargets) > 0 || len(t.ParsedExcludes) > 0 {
3440
targetedNodes, err := t.selectTargetedNodes(g, t.ParsedTargets)
3541
if err != nil {
3642
return err
3743
}
3844

45+
excludedNodes, err := t.selectTargetedNodes(g, t.ParsedExcludes)
46+
if err != nil {
47+
return err
48+
}
49+
3950
for _, v := range g.Vertices() {
4051
if _, ok := v.(GraphNodeAddressable); ok {
41-
if !targetedNodes.Include(v) {
52+
if targetedNodes.Len() > 0 && !targetedNodes.Include(v) {
4253
log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v))
4354
g.Remove(v)
55+
} else if excludedNodes.Len() > 0 && excludedNodes.Include(v) {
56+
log.Printf("[DEBUG] Removing %s, filtered by excluding.", dag.VertexName(v))
57+
g.Remove(v)
4458
}
4559
}
4660
}
4761
}
4862
return nil
4963
}
5064

51-
func (t *TargetsTransformer) parseTargetAddresses() ([]ResourceAddress, error) {
52-
addrs := make([]ResourceAddress, len(t.Targets))
53-
for i, target := range t.Targets {
65+
func (t *TargetsTransformer) parseTargetAddresses() ([]ResourceAddress, []ResourceAddress, error) {
66+
var targeted, excluded []ResourceAddress
67+
for _, target := range t.Targets {
68+
exclude := string(target[0]) == "!"
69+
if exclude {
70+
target = target[1:]
71+
log.Printf("[DEBUG] Excluding %s", target)
72+
}
5473
ta, err := ParseResourceAddress(target)
5574
if err != nil {
56-
return nil, err
75+
return nil, nil, err
76+
}
77+
if exclude {
78+
excluded = append(excluded, *ta)
79+
} else {
80+
targeted = append(targeted, *ta)
5781
}
58-
addrs[i] = *ta
5982
}
60-
return addrs, nil
83+
return targeted, excluded, nil
6184
}
6285

6386
// Returns the list of targeted nodes. A targeted node is either addressed

terraform/transform_targets_test.go

+95
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,98 @@ aws_instance.metoo
6969
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
7070
}
7171
}
72+
73+
func TestTargetsTransformer_exclude(t *testing.T) {
74+
mod := testModule(t, "transform-targets-basic")
75+
76+
g := Graph{Path: RootModulePath}
77+
{
78+
tf := &ConfigTransformer{Module: mod}
79+
if err := tf.Transform(&g); err != nil {
80+
t.Fatalf("err: %s", err)
81+
}
82+
}
83+
84+
{
85+
transform := &TargetsTransformer{Targets: []string{"!aws_instance.me"}}
86+
if err := transform.Transform(&g); err != nil {
87+
t.Fatalf("err: %s", err)
88+
}
89+
}
90+
91+
actual := strings.TrimSpace(g.String())
92+
expected := strings.TrimSpace(`
93+
aws_instance.notme
94+
aws_instance.notmeeither
95+
aws_subnet.notme
96+
aws_vpc.notme
97+
`)
98+
if actual != expected {
99+
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
100+
}
101+
}
102+
103+
func TestTargetsTransformer_exclude_destroy(t *testing.T) {
104+
mod := testModule(t, "transform-targets-destroy")
105+
106+
g := Graph{Path: RootModulePath}
107+
{
108+
tf := &ConfigTransformer{Module: mod}
109+
if err := tf.Transform(&g); err != nil {
110+
t.Fatalf("err: %s", err)
111+
}
112+
}
113+
114+
{
115+
transform := &TargetsTransformer{
116+
Targets: []string{"!aws_instance.me"},
117+
Destroy: true,
118+
}
119+
if err := transform.Transform(&g); err != nil {
120+
t.Fatalf("err: %s", err)
121+
}
122+
}
123+
124+
actual := strings.TrimSpace(g.String())
125+
expected := strings.TrimSpace(`
126+
aws_instance.notme
127+
aws_subnet.notme
128+
aws_vpc.notme
129+
aws_vpc.notme
130+
`)
131+
if actual != expected {
132+
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
133+
}
134+
}
135+
136+
func TestTargetsTransformer_include_exclude(t *testing.T) {
137+
mod := testModule(t, "transform-targets-basic")
138+
139+
g := Graph{Path: RootModulePath}
140+
{
141+
tf := &ConfigTransformer{Module: mod}
142+
if err := tf.Transform(&g); err != nil {
143+
t.Fatalf("err: %s", err)
144+
}
145+
}
146+
147+
{
148+
transform := &TargetsTransformer{
149+
Targets: []string{
150+
"aws_instance.me",
151+
"!aws_subnet.me",
152+
},
153+
}
154+
if err := transform.Transform(&g); err != nil {
155+
t.Fatalf("err: %s", err)
156+
}
157+
}
158+
159+
actual := strings.TrimSpace(g.String())
160+
expected := strings.TrimSpace(`
161+
aws_instance.me
162+
`)
163+
if actual != expected {
164+
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
165+
}
166+
}

0 commit comments

Comments
 (0)