Skip to content

Commit f12527f

Browse files
authored
Merge pull request #8 from terraform-linters/migrate_remain_rules
Migrate the aws_route rules from TFLint core
2 parents afbdb19 + 630b878 commit f12527f

7 files changed

+408
-3
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ require (
1313
github.com/onsi/ginkgo v1.14.2 // indirect
1414
github.com/onsi/gomega v1.10.3 // indirect
1515
github.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e
16-
github.com/terraform-linters/tflint-plugin-sdk v0.6.1-0.20201214165213-827cf110e0a9
16+
github.com/terraform-linters/tflint-plugin-sdk v0.6.1-0.20201219154003-09b2270d9de5
1717
github.com/terraform-providers/terraform-provider-aws v1.60.1-0.20201118192700-9cc6324740c9
1818
github.com/zclconf/go-cty v1.7.0
1919
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
326326
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
327327
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
328328
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
329-
github.com/terraform-linters/tflint-plugin-sdk v0.6.1-0.20201214165213-827cf110e0a9 h1:ADqZANXUwQzsBtG4nuaz8qGjXsetvHgk67Fr2OmRJs4=
330-
github.com/terraform-linters/tflint-plugin-sdk v0.6.1-0.20201214165213-827cf110e0a9/go.mod h1:EMiQwq0IiBwylbSgx53sdPBRhOHEXrjXhrD0x5C8SjY=
329+
github.com/terraform-linters/tflint-plugin-sdk v0.6.1-0.20201219154003-09b2270d9de5 h1:PCwAYfajRygdxp9gtEu6SDfbN9jm2X/TjDgetlf9fck=
330+
github.com/terraform-linters/tflint-plugin-sdk v0.6.1-0.20201219154003-09b2270d9de5/go.mod h1:EMiQwq0IiBwylbSgx53sdPBRhOHEXrjXhrD0x5C8SjY=
331331
github.com/terraform-providers/terraform-provider-aws v1.60.1-0.20201118192700-9cc6324740c9 h1:0u9SqTq2nbof0t+7xqfI8Ejhmooe3Qqe09fobOCZY6g=
332332
github.com/terraform-providers/terraform-provider-aws v1.60.1-0.20201118192700-9cc6324740c9/go.mod h1:sToOUnPCXFPwMljH57zM6uOI3q1YVREy4GSlg1Wm8/Y=
333333
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package rules
2+
3+
import (
4+
hcl "github.com/hashicorp/hcl/v2"
5+
"github.com/terraform-linters/tflint-plugin-sdk/terraform/configs"
6+
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
7+
"github.com/terraform-linters/tflint-ruleset-aws/project"
8+
)
9+
10+
// AwsRouteNotSpecifiedTargetRule checks whether a route definition has a routing target
11+
type AwsRouteNotSpecifiedTargetRule struct {
12+
resourceType string
13+
}
14+
15+
// NewAwsRouteNotSpecifiedTargetRule returns new rule with default attributes
16+
func NewAwsRouteNotSpecifiedTargetRule() *AwsRouteNotSpecifiedTargetRule {
17+
return &AwsRouteNotSpecifiedTargetRule{
18+
resourceType: "aws_route",
19+
}
20+
}
21+
22+
// Name returns the rule name
23+
func (r *AwsRouteNotSpecifiedTargetRule) Name() string {
24+
return "aws_route_not_specified_target"
25+
}
26+
27+
// Enabled returns whether the rule is enabled by default
28+
func (r *AwsRouteNotSpecifiedTargetRule) Enabled() bool {
29+
return true
30+
}
31+
32+
// Severity returns the rule severity
33+
func (r *AwsRouteNotSpecifiedTargetRule) Severity() string {
34+
return tflint.ERROR
35+
}
36+
37+
// Link returns the rule reference link
38+
func (r *AwsRouteNotSpecifiedTargetRule) Link() string {
39+
return project.ReferenceLink(r.Name())
40+
}
41+
42+
// Check checks whether `gateway_id`, `egress_only_gateway_id`, `nat_gateway_id`, `instance_id`
43+
// `vpc_peering_connection_id`, `network_interface_id` or `vpc_endpoint_id` is defined in a resource
44+
func (r *AwsRouteNotSpecifiedTargetRule) Check(runner tflint.Runner) error {
45+
return runner.WalkResources(r.resourceType, func(resource *configs.Resource) error {
46+
body, _, diags := resource.Config.PartialContent(&hcl.BodySchema{
47+
Attributes: []hcl.AttributeSchema{
48+
{
49+
Name: "gateway_id",
50+
},
51+
{
52+
Name: "egress_only_gateway_id",
53+
},
54+
{
55+
Name: "nat_gateway_id",
56+
},
57+
{
58+
Name: "instance_id",
59+
},
60+
{
61+
Name: "vpc_peering_connection_id",
62+
},
63+
{
64+
Name: "network_interface_id",
65+
},
66+
{
67+
Name: "transit_gateway_id",
68+
},
69+
{
70+
Name: "vpc_endpoint_id",
71+
},
72+
},
73+
})
74+
if diags.HasErrors() {
75+
return diags
76+
}
77+
78+
var nullAttributes int
79+
for _, attribute := range body.Attributes {
80+
isNull, err := runner.IsNullExpr(attribute.Expr)
81+
if err != nil {
82+
return err
83+
}
84+
85+
if isNull {
86+
nullAttributes = nullAttributes + 1
87+
}
88+
}
89+
90+
if len(body.Attributes)-nullAttributes == 0 {
91+
runner.EmitIssue(
92+
r,
93+
"The routing target is not specified, each aws_route must contain either egress_only_gateway_id, gateway_id, instance_id, nat_gateway_id, network_interface_id, transit_gateway_id, vpc_peering_connection_id or vpc_endpoint_id.",
94+
resource.DeclRange,
95+
)
96+
}
97+
98+
return nil
99+
})
100+
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package rules
2+
3+
import (
4+
"testing"
5+
6+
hcl "github.com/hashicorp/hcl/v2"
7+
"github.com/terraform-linters/tflint-plugin-sdk/helper"
8+
)
9+
10+
func Test_AwsRouteNotSpecifiedTarget(t *testing.T) {
11+
cases := []struct {
12+
Name string
13+
Content string
14+
Expected helper.Issues
15+
}{
16+
{
17+
Name: "route target is not specified",
18+
Content: `
19+
resource "aws_route" "foo" {
20+
route_table_id = "rtb-1234abcd"
21+
}`,
22+
Expected: helper.Issues{
23+
{
24+
Rule: NewAwsRouteNotSpecifiedTargetRule(),
25+
Message: "The routing target is not specified, each aws_route must contain either egress_only_gateway_id, gateway_id, instance_id, nat_gateway_id, network_interface_id, transit_gateway_id, vpc_peering_connection_id or vpc_endpoint_id.",
26+
Range: hcl.Range{
27+
Filename: "resource.tf",
28+
Start: hcl.Pos{Line: 2, Column: 1},
29+
End: hcl.Pos{Line: 2, Column: 27},
30+
},
31+
},
32+
},
33+
},
34+
{
35+
Name: "gateway_id is specified",
36+
Content: `
37+
resource "aws_route" "foo" {
38+
route_table_id = "rtb-1234abcd"
39+
gateway_id = "igw-1234abcd"
40+
}`,
41+
Expected: helper.Issues{},
42+
},
43+
{
44+
Name: "egress_only_gateway_id is specified",
45+
Content: `
46+
resource "aws_route" "foo" {
47+
route_table_id = "rtb-1234abcd"
48+
egress_only_gateway_id = "eigw-1234abcd"
49+
}`,
50+
Expected: helper.Issues{},
51+
},
52+
{
53+
Name: "nat_gateway_id is specified",
54+
Content: `
55+
resource "aws_route" "foo" {
56+
route_table_id = "rtb-1234abcd"
57+
nat_gateway_id = "nat-1234abcd"
58+
}`,
59+
Expected: helper.Issues{},
60+
},
61+
{
62+
Name: "instance_id is specified",
63+
Content: `
64+
resource "aws_route" "foo" {
65+
route_table_id = "rtb-1234abcd"
66+
instance_id = "i-1234abcd"
67+
}`,
68+
Expected: helper.Issues{},
69+
},
70+
{
71+
Name: "vpc_peering_connection_id is specified",
72+
Content: `
73+
resource "aws_route" "foo" {
74+
route_table_id = "rtb-1234abcd"
75+
vpc_peering_connection_id = "pcx-1234abcd"
76+
}`,
77+
Expected: helper.Issues{},
78+
},
79+
{
80+
Name: "network_interface_id is specified",
81+
Content: `
82+
resource "aws_route" "foo" {
83+
route_table_id = "rtb-1234abcd"
84+
network_interface_id = "eni-1234abcd"
85+
}`,
86+
Expected: helper.Issues{},
87+
},
88+
{
89+
Name: "transit_gateway_id is specified",
90+
Content: `
91+
resource "aws_route" "foo" {
92+
route_table_id = "rtb-1234abcd"
93+
transit_gateway_id = "tgw-1234abcd"
94+
}`,
95+
Expected: helper.Issues{},
96+
},
97+
{
98+
Name: "transit_gateway_id is specified, but the value is null",
99+
Content: `
100+
resource "aws_route" "foo" {
101+
route_table_id = "rtb-1234abcd"
102+
transit_gateway_id = null
103+
}`,
104+
Expected: helper.Issues{
105+
{
106+
Rule: NewAwsRouteNotSpecifiedTargetRule(),
107+
Message: "The routing target is not specified, each aws_route must contain either egress_only_gateway_id, gateway_id, instance_id, nat_gateway_id, network_interface_id, transit_gateway_id, vpc_peering_connection_id or vpc_endpoint_id.",
108+
Range: hcl.Range{
109+
Filename: "resource.tf",
110+
Start: hcl.Pos{Line: 2, Column: 1},
111+
End: hcl.Pos{Line: 2, Column: 27},
112+
},
113+
},
114+
},
115+
},
116+
{
117+
Name: "vpc_endpoint_id is specified",
118+
Content: `
119+
resource "aws_route" "foo" {
120+
route_table_id = "rtb-1234abcd"
121+
vpc_endpoint_id = "vpce-12345678abcdefgh"
122+
}`,
123+
Expected: helper.Issues{},
124+
},
125+
}
126+
127+
rule := NewAwsRouteNotSpecifiedTargetRule()
128+
129+
for _, tc := range cases {
130+
runner := helper.TestRunner(t, map[string]string{"resource.tf": tc.Content})
131+
132+
if err := rule.Check(runner); err != nil {
133+
t.Fatalf("Unexpected error occurred: %s", err)
134+
}
135+
136+
helper.AssertIssues(t, tc.Expected, runner.Issues)
137+
}
138+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package rules
2+
3+
import (
4+
hcl "github.com/hashicorp/hcl/v2"
5+
"github.com/terraform-linters/tflint-plugin-sdk/terraform/configs"
6+
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
7+
"github.com/terraform-linters/tflint-ruleset-aws/project"
8+
)
9+
10+
// AwsRouteSpecifiedMultipleTargetsRule checks whether a route definition has multiple routing targets
11+
type AwsRouteSpecifiedMultipleTargetsRule struct {
12+
resourceType string
13+
}
14+
15+
// NewAwsRouteSpecifiedMultipleTargetsRule returns new rule with default attributes
16+
func NewAwsRouteSpecifiedMultipleTargetsRule() *AwsRouteSpecifiedMultipleTargetsRule {
17+
return &AwsRouteSpecifiedMultipleTargetsRule{
18+
resourceType: "aws_route",
19+
}
20+
}
21+
22+
// Name returns the rule name
23+
func (r *AwsRouteSpecifiedMultipleTargetsRule) Name() string {
24+
return "aws_route_specified_multiple_targets"
25+
}
26+
27+
// Enabled returns whether the rule is enabled by default
28+
func (r *AwsRouteSpecifiedMultipleTargetsRule) Enabled() bool {
29+
return true
30+
}
31+
32+
// Severity returns the rule severity
33+
func (r *AwsRouteSpecifiedMultipleTargetsRule) Severity() string {
34+
return tflint.ERROR
35+
}
36+
37+
// Link returns the rule reference link
38+
func (r *AwsRouteSpecifiedMultipleTargetsRule) Link() string {
39+
return project.ReferenceLink(r.Name())
40+
}
41+
42+
// Check checks whether a resource defines `gateway_id`, `egress_only_gateway_id`, `nat_gateway_id`
43+
// `instance_id`, `vpc_peering_connection_id` or `network_interface_id` at the same time
44+
func (r *AwsRouteSpecifiedMultipleTargetsRule) Check(runner tflint.Runner) error {
45+
return runner.WalkResources(r.resourceType, func(resource *configs.Resource) error {
46+
body, _, diags := resource.Config.PartialContent(&hcl.BodySchema{
47+
Attributes: []hcl.AttributeSchema{
48+
{
49+
Name: "gateway_id",
50+
},
51+
{
52+
Name: "egress_only_gateway_id",
53+
},
54+
{
55+
Name: "nat_gateway_id",
56+
},
57+
{
58+
Name: "instance_id",
59+
},
60+
{
61+
Name: "vpc_peering_connection_id",
62+
},
63+
{
64+
Name: "network_interface_id",
65+
},
66+
{
67+
Name: "transit_gateway_id",
68+
},
69+
},
70+
})
71+
if diags.HasErrors() {
72+
return diags
73+
}
74+
75+
var nullAttributes int
76+
for _, attribute := range body.Attributes {
77+
isNull, err := runner.IsNullExpr(attribute.Expr)
78+
if err != nil {
79+
return err
80+
}
81+
82+
if isNull {
83+
nullAttributes = nullAttributes + 1
84+
}
85+
}
86+
87+
if len(body.Attributes)-nullAttributes > 1 {
88+
runner.EmitIssue(
89+
r,
90+
"More than one routing target specified. It must be one.",
91+
resource.DeclRange,
92+
)
93+
}
94+
95+
return nil
96+
})
97+
}

0 commit comments

Comments
 (0)