Skip to content

Commit d33174f

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 e50a57b commit d33174f

File tree

4 files changed

+135
-16
lines changed

4 files changed

+135
-16
lines changed

Diff for: command/apply.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,8 @@ Options:
351351
352352
-target=resource Resource to target. Operation will be limited to this
353353
resource and its dependencies. This flag can be used
354-
multiple times.
354+
multiple times. Prefixing the resource with ! will
355+
exclude the resource.
355356
356357
-var 'foo=bar' Set a variable in the Terraform configuration. This
357358
flag can be set multiple times.

Diff for: command/plan.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ Options:
171171
172172
-target=resource Resource to target. Operation will be limited to this
173173
resource and its dependencies. This flag can be used
174-
multiple times.
174+
multiple times. Prefixing the resource with ! will
175+
exclude the resource.
175176
176177
-var 'foo=bar' Set a variable in the Terraform configuration. This
177178
flag can be set multiple times.

Diff for: terraform/transform_targets.go

+36-14
Original file line numberDiff line numberDiff line change
@@ -41,27 +41,36 @@ type TargetsTransformer struct {
4141
// that already have the targets parsed
4242
ParsedTargets []ResourceAddress
4343

44+
// List of parsed excludes, provided by callers like ResourceCountTransform
45+
// that already have the targets parsed
46+
ParsedExcludes []ResourceAddress
47+
4448
// Set to true when we're in a `terraform destroy` or a
4549
// `terraform plan -destroy`
4650
Destroy bool
4751
}
4852

4953
func (t *TargetsTransformer) Transform(g *Graph) error {
5054
if len(t.Targets) > 0 && len(t.ParsedTargets) == 0 {
51-
addrs, err := t.parseTargetAddresses()
55+
targeted, excluded, err := t.parseTargetAddresses()
5256
if err != nil {
5357
return err
5458
}
55-
56-
t.ParsedTargets = addrs
59+
t.ParsedTargets = targeted
60+
t.ParsedExcludes = excluded
5761
}
5862

59-
if len(t.ParsedTargets) > 0 {
63+
if len(t.ParsedTargets) > 0 || len(t.ParsedExcludes) > 0 {
6064
targetedNodes, err := t.selectTargetedNodes(g, t.ParsedTargets)
6165
if err != nil {
6266
return err
6367
}
6468

69+
excludedNodes, err := t.selectTargetedNodes(g, t.ParsedExcludes)
70+
if err != nil {
71+
return err
72+
}
73+
6574
for _, v := range g.Vertices() {
6675
removable := false
6776
if _, ok := v.(GraphNodeResource); ok {
@@ -70,27 +79,40 @@ func (t *TargetsTransformer) Transform(g *Graph) error {
7079
if vr, ok := v.(RemovableIfNotTargeted); ok {
7180
removable = vr.RemoveIfNotTargeted()
7281
}
73-
if removable && !targetedNodes.Include(v) {
74-
log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v))
75-
g.Remove(v)
82+
if removable {
83+
if targetedNodes.Len() > 0 && !targetedNodes.Include(v) {
84+
log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v))
85+
g.Remove(v)
86+
} else if excludedNodes.Len() > 0 && excludedNodes.Include(v) {
87+
log.Printf("[DEBUG] Removing %s, filtered by excluding.", dag.VertexName(v))
88+
g.Remove(v)
89+
}
7690
}
7791
}
7892
}
7993

8094
return nil
8195
}
8296

83-
func (t *TargetsTransformer) parseTargetAddresses() ([]ResourceAddress, error) {
84-
addrs := make([]ResourceAddress, len(t.Targets))
85-
for i, target := range t.Targets {
97+
func (t *TargetsTransformer) parseTargetAddresses() ([]ResourceAddress, []ResourceAddress, error) {
98+
var targeted, excluded []ResourceAddress
99+
for _, target := range t.Targets {
100+
exclude := string(target[0]) == "!"
101+
if exclude {
102+
target = target[1:]
103+
log.Printf("[DEBUG] Excluding %s", target)
104+
}
86105
ta, err := ParseResourceAddress(target)
87106
if err != nil {
88-
return nil, err
107+
return nil, nil, err
108+
}
109+
if exclude {
110+
excluded = append(excluded, *ta)
111+
} else {
112+
targeted = append(targeted, *ta)
89113
}
90-
addrs[i] = *ta
91114
}
92-
93-
return addrs, nil
115+
return targeted, excluded, nil
94116
}
95117

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

Diff for: terraform/transform_targets_test.go

+95
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,98 @@ aws_instance.metoo
160160
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
161161
}
162162
}
163+
164+
func TestTargetsTransformer_exclude(t *testing.T) {
165+
mod := testModule(t, "transform-targets-basic")
166+
167+
g := Graph{Path: RootModulePath}
168+
{
169+
tf := &ConfigTransformer{Module: mod}
170+
if err := tf.Transform(&g); err != nil {
171+
t.Fatalf("err: %s", err)
172+
}
173+
}
174+
175+
{
176+
transform := &TargetsTransformer{Targets: []string{"!aws_instance.me"}}
177+
if err := transform.Transform(&g); err != nil {
178+
t.Fatalf("err: %s", err)
179+
}
180+
}
181+
182+
actual := strings.TrimSpace(g.String())
183+
expected := strings.TrimSpace(`
184+
aws_instance.notme
185+
aws_instance.notmeeither
186+
aws_subnet.notme
187+
aws_vpc.notme
188+
`)
189+
if actual != expected {
190+
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
191+
}
192+
}
193+
194+
func TestTargetsTransformer_exclude_destroy(t *testing.T) {
195+
mod := testModule(t, "transform-targets-destroy")
196+
197+
g := Graph{Path: RootModulePath}
198+
{
199+
tf := &ConfigTransformer{Module: mod}
200+
if err := tf.Transform(&g); err != nil {
201+
t.Fatalf("err: %s", err)
202+
}
203+
}
204+
205+
{
206+
transform := &TargetsTransformer{
207+
Targets: []string{"!aws_instance.me"},
208+
Destroy: true,
209+
}
210+
if err := transform.Transform(&g); err != nil {
211+
t.Fatalf("err: %s", err)
212+
}
213+
}
214+
215+
actual := strings.TrimSpace(g.String())
216+
expected := strings.TrimSpace(`
217+
aws_instance.notme
218+
aws_subnet.notme
219+
aws_vpc.notme
220+
aws_vpc.notme
221+
`)
222+
if actual != expected {
223+
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
224+
}
225+
}
226+
227+
func TestTargetsTransformer_include_exclude(t *testing.T) {
228+
mod := testModule(t, "transform-targets-basic")
229+
230+
g := Graph{Path: RootModulePath}
231+
{
232+
tf := &ConfigTransformer{Module: mod}
233+
if err := tf.Transform(&g); err != nil {
234+
t.Fatalf("err: %s", err)
235+
}
236+
}
237+
238+
{
239+
transform := &TargetsTransformer{
240+
Targets: []string{
241+
"aws_instance.me",
242+
"!aws_subnet.me",
243+
},
244+
}
245+
if err := transform.Transform(&g); err != nil {
246+
t.Fatalf("err: %s", err)
247+
}
248+
}
249+
250+
actual := strings.TrimSpace(g.String())
251+
expected := strings.TrimSpace(`
252+
aws_instance.me
253+
`)
254+
if actual != expected {
255+
t.Fatalf("bad:\n\nexpected:\n%s\n\ngot:\n%s\n", expected, actual)
256+
}
257+
}

0 commit comments

Comments
 (0)