Skip to content

Commit

Permalink
Adds a rule to check that the name of a windows virtual machine is va…
Browse files Browse the repository at this point in the history
…lid (#332)

* Adds a rule to check that the name of a windows virtual machine is valid

* Adds azurerm_windows_virtual_machine_invalid_name to doc_README.md.tmpl

* fix(azurerm_windows_virtual_machine_invalid_name): corrects regex inside error message
  • Loading branch information
JannoTjarks committed May 12, 2024
1 parent 9ef01fb commit 793a327
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This documentation describes a list of rules available by enabling this ruleset.
|[azurerm_linux_virtual_machine_scale_set_invalid_sku](rules/azurerm_linux_virtual_machine_scale_set_invalid_sku.md)||
|[azurerm_resource_missing_tags](rules/azurerm_resource_missing_tags.md)||
|[azurerm_virtual_machine_invalid_vm_size](rules/azurerm_virtual_machine_invalid_vm_size.md)||
|[azurerm_windows_virtual_machine_invalid_name](rules/azurerm_windows_virtual_machine_invalid_name.md)||
|[azurerm_windows_virtual_machine_invalid_size](rules/azurerm_windows_virtual_machine_invalid_size.md)||
|[azurerm_windows_virtual_machine_scale_set_invalid_sku](rules/azurerm_windows_virtual_machine_scale_set_invalid_sku.md)||

Expand Down
32 changes: 32 additions & 0 deletions docs/rules/azurerm_windows_virtual_machine_invalid_name.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# azurerm_windows_virtual_machine_invalid_name

Warns about values that appear to be invalid based on [Naming rules and restrictions for Azure resources](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules#microsoftcompute).

In this rule, the string must match the regular expression `^[a-zA-Z0-9]{0,1}[a-zA-Z0-9-]{0,13}[a-zA-Z0-9]$`.

## Example

```hcl
resource "azurerm_windows_virtual_machine" "foo" {
name = "dummy-" // invalid value
}
```

```
$ tflint
1 issue(s) found:
Error: "dummy-" does not match valid pattern ^[a-zA-Z0-9]{0,1}[a-zA-Z0-9-]{0,13}[a-zA-Z0-9]$ (azurerm_windows_virtual_machine_invalid_name)
on template.tf line 2:
2: name = "dummy-" // invalid value
```

## Why

Requests containing invalid values will return an error when calling the API by `terraform apply`.

## How To Fix

Replace the warned value with a valid value. In this example a valid name could be "dummy-1", because it matches the valid pattern ^[a-zA-Z0-9]{0,1}[a-zA-Z0-9-]{0,13}[a-zA-Z0-9]$.
90 changes: 90 additions & 0 deletions rules/azurerm_windows_virtual_machine_invalid_name.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package rules

import (
"fmt"
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
"github.com/terraform-linters/tflint-ruleset-azurerm/project"
"regexp"
)

// AzurermWindowsVirtualMachineInvalidNameRule checks the hostname is valid
type AzurermWindowsVirtualMachineInvalidNameRule struct {
tflint.DefaultRule

pattern *regexp.Regexp
resourceType string
attributeName string
attributeComputerName string
}

// NewAzurermWindowsVirtualMachineInvalidNameRule returns new rule with default attributes
func NewAzurermWindowsVirtualMachineInvalidNameRule() *AzurermWindowsVirtualMachineInvalidNameRule {
return &AzurermWindowsVirtualMachineInvalidNameRule{
resourceType: "azurerm_windows_virtual_machine",
attributeName: "name",
attributeComputerName: "computer_name",
pattern: regexp.MustCompile(`^[a-zA-Z0-9]{0,1}[a-zA-Z0-9-]{0,13}[a-zA-Z0-9]$`),
}
}

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

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

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

// Link returns the rule reference link
func (r *AzurermWindowsVirtualMachineInvalidNameRule) Link() string {
return project.ReferenceLink(r.Name())
}

// Check checks the name is valid
func (r *AzurermWindowsVirtualMachineInvalidNameRule) Check(runner tflint.Runner) error {
resources, err := runner.GetResourceContent(r.resourceType, &hclext.BodySchema{
Attributes: []hclext.AttributeSchema{
{Name: r.attributeName},
{Name: r.attributeComputerName},
},
}, nil)
if err != nil {
return err
}

for _, resource := range resources.Blocks {
_, exists := resource.Body.Attributes[r.attributeComputerName]
if exists {
continue
}

primaryAttribute, exists := resource.Body.Attributes[r.attributeName]
if !exists {
continue
}

err := runner.EvaluateExpr(primaryAttribute.Expr, func(val string) error {
if !r.pattern.MatchString(val) {
runner.EmitIssue(
r,
fmt.Sprintf(`"%s" does not match valid pattern %s`, val, `^[a-zA-Z0-9]{0,1}[a-zA-Z0-9-]{0,13}[a-zA-Z0-9]$`),
primaryAttribute.Expr.Range(),
)
}
return nil
}, nil)
if err != nil {
return err
}
}

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

import (
"testing"

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

func Test_AzurermWindowsVirtualMachineInvalidName(t *testing.T) {
cases := []struct {
Name string
Content string
Expected helper.Issues
}{
{
Name: "InvalidName - Ends with hyphen",
Content: `
resource "azurerm_windows_virtual_machine" "vm" {
name = "dummy-"
}`,
Expected: helper.Issues{
{
Rule: NewAzurermWindowsVirtualMachineInvalidNameRule(),
Message: `"dummy-" does not match valid pattern ^[a-zA-Z0-9]{0,1}[a-zA-Z0-9-]{0,13}[a-zA-Z0-9]$`,
Range: hcl.Range{
Filename: "resource.tf",
Start: hcl.Pos{Line: 3, Column: 10},
End: hcl.Pos{Line: 3, Column: 18},
},
},
},
},
{
Name: "InvalidName - too long",
Content: `
resource "azurerm_windows_virtual_machine" "vm" {
name = "dummyhostname123"
}`,
Expected: helper.Issues{
{
Rule: NewAzurermWindowsVirtualMachineInvalidNameRule(),
Message: `"dummyhostname123" does not match valid pattern ^[a-zA-Z0-9]{0,1}[a-zA-Z0-9-]{0,13}[a-zA-Z0-9]$`,
Range: hcl.Range{
Filename: "resource.tf",
Start: hcl.Pos{Line: 3, Column: 10},
End: hcl.Pos{Line: 3, Column: 28},
},
},
},
},
{
Name: "ValidName - Name is valid",
Content: `
resource "azurerm_windows_virtual_machine" "vm" {
name = "dummyhostname1"
}`,
Expected: helper.Issues{},
},
{
Name: "ValidName - Hostname is specified",
Content: `
resource "azurerm_windows_virtual_machine" "vm" {
name = "dummy-"
computer_name = "dummyhostname1"
}`,
Expected: helper.Issues{},
},
}

rule := NewAzurermWindowsVirtualMachineInvalidNameRule()

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)
}
}
1 change: 1 addition & 0 deletions rules/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ var Rules = append([]tflint.Rule{
NewAzurermLinuxVirtualMachineInvalidSizeRule(),
NewAzurermLinuxVirtualMachineScaleSetInvalidSkuRule(),
NewAzurermVirtualMachineInvalidVMSizeRule(),
NewAzurermWindowsVirtualMachineInvalidNameRule(),
NewAzurermWindowsVirtualMachineInvalidSizeRule(),
NewAzurermWindowsVirtualMachineScaleSetInvalidSkuRule(),
NewAzurermResourceMissingTagsRule(),
Expand Down
1 change: 1 addition & 0 deletions tools/apispec-rule-gen/doc_README.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This documentation describes a list of rules available by enabling this ruleset.
|[azurerm_linux_virtual_machine_scale_set_invalid_sku](rules/azurerm_linux_virtual_machine_scale_set_invalid_sku.md)|✔|
|[azurerm_resource_missing_tags](rules/azurerm_resource_missing_tags.md)||
|[azurerm_virtual_machine_invalid_vm_size](rules/azurerm_virtual_machine_invalid_vm_size.md)|✔|
|[azurerm_windows_virtual_machine_invalid_name](rules/azurerm_windows_virtual_machine_invalid_name.md)|✔|
|[azurerm_windows_virtual_machine_invalid_size](rules/azurerm_windows_virtual_machine_invalid_size.md)|✔|
|[azurerm_windows_virtual_machine_scale_set_invalid_sku](rules/azurerm_windows_virtual_machine_scale_set_invalid_sku.md)|✔|

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mapping "azurerm_windows_virtual_machine" {
admin_password = any //OSProfile.adminPassword
admin_username = any //OSProfile.adminUsername
size = any //HardwareProfile.vmSize
name = any
allow_extension_operations = OSProfile.allowExtensionOperations
computer_name = OSProfile.computerName
custom_data = OSProfile.customData
Expand Down

0 comments on commit 793a327

Please sign in to comment.