Skip to content
This repository has been archived by the owner on Nov 29, 2022. It is now read-only.

Commit

Permalink
feat: terraform0.12 part2: checks
Browse files Browse the repository at this point in the history
  • Loading branch information
thazelart committed Aug 3, 2019
1 parent 9d7945e commit 5cef6d2
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 0 deletions.
68 changes: 68 additions & 0 deletions internal/checks/checks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package checks

import (
"fmt"
"github.com/thazelart/terraform-validator/internal/hcl"
"github.com/thazelart/terraform-validator/pkg/utils"
"regexp"
)

// VerifyBlockNames ensure that all the terraform blocks are well named
func verifyBlockNames(blocks map[string][]string, pattern string) (errs []error) {
for blockType, blockNames := range blocks {
if blockType == "provider" {
// provider names are not choosen by the user
continue
}
for _, blockName := range blockNames {
matched, _ := regexp.MatchString(pattern, blockName)
if !matched {
errs = append(errs, fmt.Errorf("%s (%s)", blockName, blockType))
}
}
}
return errs
}

// VerifyBlockNames ensure that all the terraform blocks are well named
func verifyAuthorizedBlocktypes(blocks map[string][]string, authorizedBlocks []string) (errs []error) {
for blockType := range blocks {
if utils.Contains(authorizedBlocks, blockType) {
continue
}
errs = append(errs, fmt.Errorf("%s", blockType))
}
return errs
}

// VerifyFile launch every check that are file dependant (block names and
// authorized blocks)
func VerifyFile(parsedFile hcl.ParsedFile, pattern string,
authorizedBlocks []string) bool {

blocks := parsedFile.GetBlockNamesByType()

bnErrs := verifyBlockNames(blocks, pattern)
btErrs := verifyAuthorizedBlocktypes(blocks, authorizedBlocks)

hasBnErrs := len(bnErrs) > 0
hasBtErrs := len(btErrs) > 0

if hasBnErrs || hasBtErrs {
fmt.Printf("\nERROR: %s misformed:\n", parsedFile.Name)
if hasBnErrs {
fmt.Printf(" Unmatching \"%s\" pattern blockname(s):\n", pattern)
for _, err := range bnErrs {
fmt.Printf(" - %s\n", err.Error())
}
}
if hasBtErrs {
fmt.Println(" Unauthorized block(s):")
for _, err := range btErrs {
fmt.Printf(" - %s\n", err.Error())
}
}
return false
}
return true
}
3 changes: 3 additions & 0 deletions internal/checks/checks_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package checks_test

import ()
95 changes: 95 additions & 0 deletions internal/checks/checks_private_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package checks

import (
"fmt"
"github.com/google/go-cmp/cmp"
"sort"
"testing"
)

func TestVerifyBlockNames(t *testing.T) {
var testMap = map[string][]string{
"data": []string{"a_data"},
"locals": []string{"a_local", "another_local", "third_local"},
"module": []string{"consul", "network"},
"output": []string{"out_with_description", "out_without_description"},
"provider": []string{"google"},
"resource": []string{"a_resource"},
"terraform": []string{},
"variable": []string{"var_with_description", "var_without_description"},
}

var expectedResult []error
testResult := verifyBlockNames(testMap, "^[a-z0-9_]*$")
if diff := cmp.Diff(expectedResult, testResult); diff != "" {
t.Errorf("verifyBlockNames() mismatch (-want +got):\n%s", diff)
}

// test2 with errors
testMap["output"] = []string{"out_with_description", "out-description"}
testMap["resource"] = []string{"a-resource"}

expectedResult = append(expectedResult, fmt.Errorf("out-description (output)"))
expectedResult = append(expectedResult, fmt.Errorf("a-resource (resource)"))
testResult = verifyBlockNames(testMap, "^[a-z0-9_]*$")

var stringExpectedResult, stringTestResult []string
for i := range expectedResult {
stringExpectedResult = append(stringExpectedResult, expectedResult[i].Error())
stringTestResult = append(stringTestResult, testResult[i].Error())
}
sort.Strings(stringExpectedResult)
sort.Strings(stringTestResult)
if diff := cmp.Diff(stringExpectedResult, stringTestResult); diff != "" {
t.Errorf("verifyAuthorizedBlocktypes(error) mismatch (-want +got):\n%s", diff)
}
}

func TestVerifyAuthorizedBlocktypes(t *testing.T) {
var testMap = map[string][]string{
"data": []string{"a_data"},
"locals": []string{"a_local", "another_local", "third_local"},
"module": []string{"consul", "network"},
}
authorizedBlocks := []string{"data", "locals", "module"}

var expectedResult []error
testResult := verifyAuthorizedBlocktypes(testMap, authorizedBlocks)
if diff := cmp.Diff(expectedResult, testResult); diff != "" {
t.Errorf("verifyBlockNames() mismatch (-want +got):\n%s", diff)
}

// test2 with errors
authorizedBlocks = []string{"module", "locals"}

expectedResult = append(expectedResult, fmt.Errorf("data"))
testResult = verifyAuthorizedBlocktypes(testMap, authorizedBlocks)

var stringExpectedResult, stringTestResult []string
for i := range expectedResult {
stringExpectedResult = append(stringExpectedResult, expectedResult[i].Error())
stringTestResult = append(stringTestResult, testResult[i].Error())
}
sort.Strings(stringExpectedResult)
sort.Strings(stringTestResult)
if diff := cmp.Diff(stringExpectedResult, stringTestResult); diff != "" {
t.Errorf("verifyAuthorizedBlocktypes(error) mismatch (-want +got):\n%s", diff)
}

// test3 with errors because no blocks authorized
authorizedBlocks = []string{}

expectedResult = append(expectedResult, fmt.Errorf("locals"))
expectedResult = append(expectedResult, fmt.Errorf("module"))
testResult = verifyAuthorizedBlocktypes(testMap, authorizedBlocks)

for i := range expectedResult {
stringExpectedResult = append(stringExpectedResult, expectedResult[i].Error())
stringTestResult = append(stringTestResult, testResult[i].Error())
}
sort.Strings(stringExpectedResult)
sort.Strings(stringTestResult)
if diff := cmp.Diff(stringExpectedResult, stringTestResult); diff != "" {
t.Errorf("verifyAuthorizedBlocktypes(error) mismatch (-want +got):\n%s", diff)
}
}
79 changes: 79 additions & 0 deletions internal/checks/checks_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package checks_test

import (
"github.com/google/go-cmp/cmp"
"github.com/kami-zh/go-capturer"
"github.com/thazelart/terraform-validator/internal/checks"
"github.com/thazelart/terraform-validator/internal/hcl"
"testing"
)

var parsedFile = hcl.ParsedFile{
Name: "main.tf",
Blocks: hcl.TerraformBlocks{
Variables: []hcl.Variable{
hcl.Variable{Name: "var_with_description", Description: "a var description"},
hcl.Variable{Name: "var_without_description", Description: ""},
},
Outputs: []hcl.Output{
hcl.Output{Name: "out_with_description", Description: "a output description"},
hcl.Output{Name: "out_without_description", Description: ""},
},
Resources: []hcl.Resource{
hcl.Resource{Name: "a_resource", Type: "google_sql_database"},
},
Locals: []hcl.Locals{
hcl.Locals{"a_local", "another_local"},
hcl.Locals{"third_local"},
},
Data: []hcl.Data{
hcl.Data{Name: "a_data", Type: "consul_key_prefix"},
},
Providers: []hcl.Provider{
hcl.Provider{Name: "google", Version: "=1.28.0"},
},
Terraform: hcl.Terraform{Version: "> 0.12.0", Backend: "gcs"},
Modules: []hcl.Module{
hcl.Module{Name: "consul", Version: "0.0.5"},
hcl.Module{Name: "network", Version: "1.2.3"},
},
},
}

func TestVerifyFile(t *testing.T) {
// test1 well formed ParsedFile
parsedFileTest := parsedFile
authorizedBocks := []string{"module", "locals", "provider", "data",
"variable", "resource", "output", "terraform"}
expectedOut := ""
testOut := capturer.CaptureStdout(func() {
checks.VerifyFile(parsedFileTest, "^[a-z0-9_]*$", authorizedBocks)
})

if diff := cmp.Diff(expectedOut, testOut); diff != "" {
t.Errorf("VerifyFile(ok) mismatch (-want +got):\n%s", diff)
}

// test2 with unwanted blocks and misnamed bloc
parsedFileTest.Blocks.Data = []hcl.Data{
hcl.Data{Name: "a-data", Type: "consul_key_prefix"},
}
authorizedBocks = []string{"module", "locals", "provider", "data",
"variable", "output", "terraform"}

expectedOut = `
ERROR: main.tf misformed:
Unmatching "^[a-z0-9_]*$" pattern blockname(s):
- a-data (data)
Unauthorized block(s):
- resource
`

testOut = capturer.CaptureStdout(func() {
checks.VerifyFile(parsedFileTest, "^[a-z0-9_]*$", authorizedBocks)
})

if diff := cmp.Diff(expectedOut, testOut); diff != "" {
t.Errorf("VerifyFile(ko) mismatch (-want +got):\n%s", diff)
}
}

0 comments on commit 5cef6d2

Please sign in to comment.