Skip to content

Add invalid machine type rules #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,19 @@ This documentation describes a list of rules available by enabling this ruleset.

## Basic Rules

No rules
### Invalid machine types

These rules warn you if a machine type not listed at https://cloud.google.com/compute/docs/machine-types is being used. Please note that custom machine types cannot be detected correctly. These rules consider all machine types starting with `custom-` to be valid.

|Name|Severity|Enabled|
| --- | --- | --- |
|google_composer_environment_invalid_machine_type|ERROR|✔|
|google_compute_instance_invalid_machine_type|ERROR|✔|
|google_compute_instance_template_invalid_machine_type|ERROR|✔|
|google_compute_reservation_invalid_machine_type|ERROR|✔|
|google_container_cluster_invalid_machine_type|ERROR|✔|
|google_container_node_pool_invalid_machine_type|ERROR|✔|
|google_dataflow_job_invalid_machine_type|ERROR|✔|

## Magic Modules Rules

Expand Down
86 changes: 86 additions & 0 deletions rules/google_composer_environment_invalid_machine_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package rules

import (
"fmt"
"strings"

hcl "github.com/hashicorp/hcl/v2"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
)

// GoogleComposerEnvironmentInvalidMachineTypeRule checks whether the machine type is invalid
type GoogleComposerEnvironmentInvalidMachineTypeRule struct{}

// NewGoogleComposerEnvironmentInvalidMachineTypeRule returns a new rule
func NewGoogleComposerEnvironmentInvalidMachineTypeRule() *GoogleComposerEnvironmentInvalidMachineTypeRule {
return &GoogleComposerEnvironmentInvalidMachineTypeRule{}
}

// Name returns the rule name
func (r *GoogleComposerEnvironmentInvalidMachineTypeRule) Name() string {
return "google_composer_environment_invalid_machine_type"
}

// Enabled returns whether the rule is enabled by default
func (r *GoogleComposerEnvironmentInvalidMachineTypeRule) Enabled() bool {
return true
}

// Severity returns the rule severity
func (r *GoogleComposerEnvironmentInvalidMachineTypeRule) Severity() string {
return tflint.ERROR
}

// Link returns the rule reference link
func (r *GoogleComposerEnvironmentInvalidMachineTypeRule) Link() string {
return ""
}

// Check checks whether the machine type is invalid
func (r *GoogleComposerEnvironmentInvalidMachineTypeRule) Check(runner tflint.Runner) error {
return runner.WalkResourceBlocks("google_composer_environment", "config", func(block *hcl.Block) error {
content, _, diags := block.Body.PartialContent(&hcl.BodySchema{
Blocks: []hcl.BlockHeaderSchema{
{Type: "node_config"},
},
})
if diags.HasErrors() {
return diags
}

for _, block := range content.Blocks {
content, _, diags := block.Body.PartialContent(&hcl.BodySchema{
Attributes: []hcl.AttributeSchema{
{Name: "machine_type"},
},
})

if diags.HasErrors() {
return diags
}

if attribute, exists := content.Attributes["machine_type"]; exists {
var machineType string
err := runner.EvaluateExpr(attribute.Expr, &machineType)

err = runner.EnsureNoError(err, func() error {
if validMachineTypes[machineType] || strings.HasPrefix(machineType, "custom-") {
return nil
}

return runner.EmitIssueOnExpr(
r,
fmt.Sprintf(`"%s" is an invalid as machine type`, machineType),
attribute.Expr,
)
})

if err != nil {
return err
}
}
}

return nil
})
}
111 changes: 111 additions & 0 deletions rules/google_composer_environment_invalid_machine_type_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package rules

import (
"testing"

hcl "github.com/hashicorp/hcl/v2"
"github.com/terraform-linters/tflint-plugin-sdk/helper"
)

func Test_GoogleComposerEnvironmentInvalidMachineType(t *testing.T) {
cases := []struct {
Name string
Content string
Expected helper.Issues
}{
{
Name: "invalid type",
Content: `
resource "google_composer_environment" "test" {
name = "mycomposer"
region = "us-central1"
config {
node_count = 4

node_config {
zone = "us-central1-a"
machine_type = "n1-standard-11"

network = google_compute_network.test.id
subnetwork = google_compute_subnetwork.test.id

service_account = google_service_account.test.name
}
}

depends_on = [google_project_iam_member.composer-worker]
}`,
Expected: helper.Issues{
{
Rule: NewGoogleComposerEnvironmentInvalidMachineTypeRule(),
Message: `"n1-standard-11" is an invalid as machine type`,
Range: hcl.Range{
Filename: "resource.tf",
Start: hcl.Pos{Line: 10, Column: 22},
End: hcl.Pos{Line: 10, Column: 38},
},
},
},
},
{
Name: "valid type",
Content: `
resource "google_composer_environment" "test" {
name = "mycomposer"
region = "us-central1"
config {
node_count = 4

node_config {
zone = "us-central1-a"
machine_type = "n2-standard-2"

network = google_compute_network.test.id
subnetwork = google_compute_subnetwork.test.id

service_account = google_service_account.test.name
}
}

depends_on = [google_project_iam_member.composer-worker]
}`,
Expected: helper.Issues{},
},
{
Name: "custom type",
Content: `
resource "google_composer_environment" "test" {
name = "mycomposer"
region = "us-central1"
config {
node_count = 4

node_config {
zone = "us-central1-a"
machine_type = "custom-6-20480"

network = google_compute_network.test.id
subnetwork = google_compute_subnetwork.test.id

service_account = google_service_account.test.name
}
}

depends_on = [google_project_iam_member.composer-worker]
}`,
Expected: helper.Issues{},
},
}

rule := NewGoogleComposerEnvironmentInvalidMachineTypeRule()

for _, tc := range cases {
runner := helper.TestRunner(t, map[string]string{"resource.tf": tc.Content})

if err := rule.Check(runner); err != nil {
t.Fatalf("Unexpected error occurred: %s", err)
}

helper.AssertIssues(t, tc.Expected, runner.Issues)
}
}
57 changes: 57 additions & 0 deletions rules/google_compute_instance_invalid_machine_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package rules

import (
"fmt"
"strings"

hcl "github.com/hashicorp/hcl/v2"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
)

// GoogleComputeInstanceInvalidMachineTypeRule checks whether the machine type is invalid
type GoogleComputeInstanceInvalidMachineTypeRule struct {}

// NewGoogleComputeInstanceInvalidMachineTypeRule returns a new rule
func NewGoogleComputeInstanceInvalidMachineTypeRule() *GoogleComputeInstanceInvalidMachineTypeRule {
return &GoogleComputeInstanceInvalidMachineTypeRule{}
}

// Name returns the rule name
func (r *GoogleComputeInstanceInvalidMachineTypeRule) Name() string {
return "google_compute_instance_invalid_machine_type"
}

// Enabled returns whether the rule is enabled by default
func (r *GoogleComputeInstanceInvalidMachineTypeRule) Enabled() bool {
return true
}

// Severity returns the rule severity
func (r *GoogleComputeInstanceInvalidMachineTypeRule) Severity() string {
return tflint.ERROR
}

// Link returns the rule reference link
func (r *GoogleComputeInstanceInvalidMachineTypeRule) Link() string {
return ""
}

// Check checks whether the machine type is invalid
func (r *GoogleComputeInstanceInvalidMachineTypeRule) Check(runner tflint.Runner) error {
return runner.WalkResourceAttributes("google_compute_instance", "machine_type", func(attribute *hcl.Attribute) error {
var machineType string
err := runner.EvaluateExpr(attribute.Expr, &machineType)

return runner.EnsureNoError(err, func() error {
if validMachineTypes[machineType] || strings.HasPrefix(machineType, "custom-") {
return nil
}

return runner.EmitIssueOnExpr(
r,
fmt.Sprintf(`"%s" is an invalid as machine type`, machineType),
attribute.Expr,
)
})
})
}
63 changes: 63 additions & 0 deletions rules/google_compute_instance_invalid_machine_type_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package rules

import (
"testing"

hcl "github.com/hashicorp/hcl/v2"
"github.com/terraform-linters/tflint-plugin-sdk/helper"
)

func Test_GoogleComputeInstanceInvalidMachineType(t *testing.T) {
cases := []struct {
Name string
Content string
Expected helper.Issues
}{
{
Name: "invalid type",
Content: `
resource "google_compute_instance" "vm_instance" {
machine_type = "n2-standard-1"
}`,
Expected: helper.Issues{
{
Rule: NewGoogleComputeInstanceInvalidMachineTypeRule(),
Message: `"n2-standard-1" is an invalid as machine type`,
Range: hcl.Range{
Filename: "resource.tf",
Start: hcl.Pos{Line: 3, Column: 20},
End: hcl.Pos{Line: 3, Column: 35},
},
},
},
},
{
Name: "valid type",
Content: `
resource "google_compute_instance" "vm_instance" {
machine_type = "n2-standard-2"
}`,
Expected: helper.Issues{},
},
{
Name: "custom type",
Content: `
resource "google_compute_instance" "vm_instance" {
machine_type = "custom-6-20480"
}`,
Expected: helper.Issues{},
},
}

rule := NewGoogleComputeInstanceInvalidMachineTypeRule()

for _, tc := range cases {
runner := helper.TestRunner(t, map[string]string{"resource.tf": tc.Content})

if err := rule.Check(runner); err != nil {
t.Fatalf("Unexpected error occurred: %s", err)
}

helper.AssertIssues(t, tc.Expected, runner.Issues)
}
}
57 changes: 57 additions & 0 deletions rules/google_compute_instance_template_invalid_machine_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package rules

import (
"fmt"
"strings"

hcl "github.com/hashicorp/hcl/v2"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
)

// GoogleComputeInstanceTemplateInvalidMachineTypeRule checks whether the machine type is invalid
type GoogleComputeInstanceTemplateInvalidMachineTypeRule struct {}

// NewGoogleComputeInstanceTemplateInvalidMachineTypeRule returns a new rule
func NewGoogleComputeInstanceTemplateInvalidMachineTypeRule() *GoogleComputeInstanceTemplateInvalidMachineTypeRule {
return &GoogleComputeInstanceTemplateInvalidMachineTypeRule{}
}

// Name returns the rule name
func (r *GoogleComputeInstanceTemplateInvalidMachineTypeRule) Name() string {
return "google_compute_instance_template_invalid_machine_type"
}

// Enabled returns whether the rule is enabled by default
func (r *GoogleComputeInstanceTemplateInvalidMachineTypeRule) Enabled() bool {
return true
}

// Severity returns the rule severity
func (r *GoogleComputeInstanceTemplateInvalidMachineTypeRule) Severity() string {
return tflint.ERROR
}

// Link returns the rule reference link
func (r *GoogleComputeInstanceTemplateInvalidMachineTypeRule) Link() string {
return ""
}

// Check checks whether the machine type is invalid
func (r *GoogleComputeInstanceTemplateInvalidMachineTypeRule) Check(runner tflint.Runner) error {
return runner.WalkResourceAttributes("google_compute_instance_template", "machine_type", func(attribute *hcl.Attribute) error {
var machineType string
err := runner.EvaluateExpr(attribute.Expr, &machineType)

return runner.EnsureNoError(err, func() error {
if validMachineTypes[machineType] || strings.HasPrefix(machineType, "custom-") {
return nil
}

return runner.EmitIssueOnExpr(
r,
fmt.Sprintf(`"%s" is an invalid as machine type`, machineType),
attribute.Expr,
)
})
})
}
Loading