Skip to content
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

add ValidateFunc to resourceTFEPolicySet to catch syntax errors at tf plan time #168

Merged
merged 5 commits into from
Aug 19, 2020
Merged

add ValidateFunc to resourceTFEPolicySet to catch syntax errors at tf plan time #168

merged 5 commits into from
Aug 19, 2020

Conversation

mathyourlife-fitbit
Copy link
Contributor

Description

When using terraform, it can be frustrating to have a plan complete successfully as part of PR validation processes, only to have it fail after merged and attempting to apply. In this case, using a name for tfe_policy_set that includes a space would pass PR validation but throw an error on apply as the name should only contain letters, numbers, dash, and underscore as specified in the UI.

Testing plan

TESTARGS="-run TestAccTFEPolicySet_invalidname" make testacc

Output from acceptance tests

Apologies for only running a targeted test here instead of a full suite, but I do not yet have a full acceptance test environment setup.

$ TESTARGS="-run TestAccTFEPolicySet_invalidname" make testacc
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test $(go list ./... |grep -v 'vendor') -v -run TestAccTFEPolicySet_invalidname -timeout 15m
?   	github.com/terraform-providers/terraform-provider-tfe	[no test files]
=== RUN   TestAccTFEPolicySet_invalidname
--- PASS: TestAccTFEPolicySet_invalidname (0.54s)
PASS
ok  	github.com/terraform-providers/terraform-provider-tfe/tfe	(cached)
?   	github.com/terraform-providers/terraform-provider-tfe/version	[no test files]

@ghost ghost added the size/S label May 7, 2020
@@ -22,6 +23,17 @@ func resourceTFEPolicySet() *schema.Resource {
"name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) {
value := v.(string)
matched, err := regexp.Match(`^[A-Za-z\d-_]+$`, []byte(value))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for submitting this PR. Having reviewed the contents I was wondering if any consideration was given to using one of the validators that are available in the validation package?

I think the use of the StringMatch validator will simplify things a great deal. As an example:

"name": {
	Type:         schema.TypeString,
	Required:     true,
	ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[\w\.\-]+$`), "The name of the policy set. Can only include letters, numbers, -, and _."),
},

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, makes sense. I'll adjust. Thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the validation function to the native validation call and updated the test to match the new error message

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests still show passing

$ TESTARGS="-run TestAccTFEPolicySet_invalidname" make testacc
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test $(go list ./... |grep -v 'vendor') -v -run TestAccTFEPolicySet_invalidname -timeout 15m
?   	github.com/terraform-providers/terraform-provider-tfe	[no test files]
=== RUN   TestAccTFEPolicySet_invalidname
--- PASS: TestAccTFEPolicySet_invalidname (0.01s)
PASS
ok  	github.com/terraform-providers/terraform-provider-tfe/tfe	(cached)
?   	github.com/terraform-providers/terraform-provider-tfe/version	[no test files]

Copy link
Contributor

@hcrhall hcrhall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to work on getting this merged. I recommend using the validation package within the SDK to ensure that naming requirements are fulfilled.

@@ -22,6 +23,17 @@ func resourceTFEPolicySet() *schema.Resource {
"name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) {
value := v.(string)
matched, err := regexp.Match(`^[A-Za-z\d-_]+$`, []byte(value))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for submitting this PR. Having reviewed the contents I was wondering if any consideration was given to using one of the validators that are available in the validation package?

I think the use of the StringMatch validator will simplify things a great deal. As an example:

"name": {
	Type:         schema.TypeString,
	Required:     true,
	ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[\w\.\-]+$`), "The name of the policy set. Can only include letters, numbers, -, and _."),
},

…atch and update tests to match new error message
Copy link
Contributor

@lafentres lafentres left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi there. This is a great idea! Thank you for opening up a PR to add this.
Overall this looks good. I requested some small changes to make sure the regexp you've added matches exactly what the API expects and to make your changes consistent with the rest of the repo.

Once these changes are made, please tag @hcrhall and myself so we can run this through our internal CI and get it merged and released :]

I'm also happy to make these changes myself by opening up a branch containing your changes and my requested changes. Just let me know what works best for you!

Required: true,
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[\w\.\-]+$`), "The name of the policy set. Can only include letters, numbers, -, and _."),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This regex allows ., which isn't allowed in policy set names. The regexp in my suggestion below will match exactly what the API accepts.

I think it would be good to adjust the error message we return here as well, so it is consistent with other error messages. This should result in an error message that look something like this:

"invalid value for name (can only include letters, numbers, -, and _.)"
Suggested change
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[\w\.\-]+$`), "The name of the policy set. Can only include letters, numbers, -, and _."),
ValidateFunc: validation.StringMatch(regexp.MustCompile(`\A[\w\_\-]+\z`), "can only include letters, numbers, -, and _."),

Comment on lines 449 to 461
func TestAccTFEPolicySet_invalidname(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFEPolicySetDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFEPolicySet_invalidname,
ExpectError: regexp.MustCompile(`The name of the policy set. Can only include letters, numbers, -, and _.`),
},
},
})
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There would need to be a change here as well, to make sure this lines up with my suggestions above.

This test should also be moved above the import test TestAccTFEPolicySetImport on line 295.

Suggested change
func TestAccTFEPolicySet_invalidname(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFEPolicySetDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFEPolicySet_invalidname,
ExpectError: regexp.MustCompile(`The name of the policy set. Can only include letters, numbers, -, and _.`),
},
},
})
}
func TestAccTFEPolicySet_invalidName(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFEPolicySetDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFEPolicySet_invalidName,
ExpectError: regexp.MustCompile(`can only include letters, numbers, -, and _.`),
},
},
})
}

Comment on lines 610 to 627
const testAccTFEPolicySet_invalidname = `
resource "tfe_organization" "foobar" {
name = "tst-terraform"
email = "admin@company.com"
}

resource "tfe_sentinel_policy" "foo" {
name = "policy-foo"
policy = "main = rule { true }"
organization = "${tfe_organization.foobar.id}"
}

resource "tfe_policy_set" "foobar" {
name = "not the right format"
description = "Policy Set"
organization = "${tfe_organization.foobar.id}"
policy_ids = ["${tfe_sentinel_policy.foo.id}"]
}`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small change here as well, for consistency.

Suggested change
const testAccTFEPolicySet_invalidname = `
resource "tfe_organization" "foobar" {
name = "tst-terraform"
email = "admin@company.com"
}
resource "tfe_sentinel_policy" "foo" {
name = "policy-foo"
policy = "main = rule { true }"
organization = "${tfe_organization.foobar.id}"
}
resource "tfe_policy_set" "foobar" {
name = "not the right format"
description = "Policy Set"
organization = "${tfe_organization.foobar.id}"
policy_ids = ["${tfe_sentinel_policy.foo.id}"]
}`
const testAccTFEPolicySet_invalidName = `
resource "tfe_organization" "foobar" {
name = "tst-terraform"
email = "admin@company.com"
}
resource "tfe_sentinel_policy" "foo" {
name = "policy-foo"
policy = "main = rule { true }"
organization = "${tfe_organization.foobar.id}"
}
resource "tfe_policy_set" "foobar" {
name = "not the right format"
description = "Policy Set"
organization = "${tfe_organization.foobar.id}"
policy_ids = ["${tfe_sentinel_policy.foo.id}"]
}`

@mathyourlife-fitbit
Copy link
Contributor Author

mathyourlife-fitbit commented Aug 14, 2020

Thanks for the detailed review @lafentres . Changes implemented. cc @hcrhall

Tests pass

$ TESTARGS="-run TestAccTFEPolicySet_invalidName" make testacc
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test $(go list ./... |grep -v 'vendor') -v -run TestAccTFEPolicySet_invalidName -timeout 15m
?   	github.com/terraform-providers/terraform-provider-tfe	[no test files]
=== RUN   TestAccTFEPolicySet_invalidName
--- PASS: TestAccTFEPolicySet_invalidName (0.01s)
PASS
ok  	github.com/terraform-providers/terraform-provider-tfe/tfe	(cached)
?   	github.com/terraform-providers/terraform-provider-tfe/version	[no test files]

@lafentres
Copy link
Contributor

Thanks @mathyourlife-fitbit! I've started the process of getting this through CI in #205 and will be working on getting this ready for merge this week.

Copy link
Contributor

@lafentres lafentres left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ 🎉 ✨

@lafentres lafentres merged commit 0798563 into hashicorp:master Aug 19, 2020
@lafentres
Copy link
Contributor

@mathyourlife-fitbit this has been released! It is available now as part of 0.21.0

@mathyourlife-fitbit
Copy link
Contributor Author

thanks for you help @lafentres @hcrhall 🥇

@mathyourlife-fitbit mathyourlife-fitbit deleted the tfe_policy_set-name-validation branch August 20, 2020 18:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants