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 plan-time validation of name on google_compute_instance #11886

Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/hashicorp/terraform-provider-google/google/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
"github.com/hashicorp/terraform-provider-google/google/verify"

{{ if eq $.TargetVersionName `ga` }}
"google.golang.org/api/compute/v1"
Expand Down Expand Up @@ -396,6 +397,7 @@ func ResourceComputeInstance() *schema.Resource {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: verify.ValidateRFC1035Name(1, 63),
Description: `The name of the instance. One of name or self_link must be provided.`,
},

Expand Down
35 changes: 21 additions & 14 deletions mmv1/third_party/terraform/verify/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const (

SubnetworkLinkRegex = "projects/(" + ProjectRegex + ")/regions/(" + RegionRegex + ")/subnetworks/(" + SubnetworkRegex + ")$"

RFC1035NameTemplate = "[a-z](?:[-a-z0-9]{%d,%d}[a-z0-9])"
RFC1035NameTemplate = "[a-z]([-a-z0-9]%v[a-z0-9])?"
CloudIoTIdRegex = "^[a-zA-Z][-a-zA-Z0-9._+~%]{2,254}$"

// Format of default Compute service accounts created by Google
Expand All @@ -41,7 +41,7 @@ var (
// The first and last characters have different restrictions, than
// the middle characters. The middle characters length must be between
// 4 and 28 since the first and last character are excluded.
ServiceAccountNameRegex = fmt.Sprintf(RFC1035NameTemplate, 4, 28)
ServiceAccountNameRegex = fmt.Sprintf(RFC1035NameTemplate, "{4,28}")

ServiceAccountLinkRegexPrefix = "projects/" + ProjectRegexWildCard + "/serviceAccounts/"
PossibleServiceAccountNames = []string{
Expand All @@ -54,7 +54,7 @@ var (
ServiceAccountKeyNameRegex = ServiceAccountLinkRegexPrefix + "(.+)/keys/(.+)"

// Format of service accounts created through the API
CreatedServiceAccountNameRegex = fmt.Sprintf(RFC1035NameTemplate, 4, 28) + "@" + ProjectNameInDNSFormRegex + "\\.iam\\.gserviceaccount\\.com$"
CreatedServiceAccountNameRegex = fmt.Sprintf(RFC1035NameTemplate, "{4,28}") + "@" + ProjectNameInDNSFormRegex + "\\.iam\\.gserviceaccount\\.com$"

// Format of service-created service account
// examples are:
Expand Down Expand Up @@ -194,19 +194,26 @@ func ValidateRFC3339Time(v interface{}, k string) (warnings []string, errors []e
}

func ValidateRFC1035Name(min, max int) schema.SchemaValidateFunc {
if min < 2 || max < min {
return func(i interface{}, k string) (s []string, errors []error) {
if min < 2 {
errors = append(errors, fmt.Errorf("min must be at least 2. Got: %d", min))
}
if max < min {
errors = append(errors, fmt.Errorf("max must greater than min. Got [%d, %d]", min, max))
}
return
return func(i interface{}, k string) (s []string, errors []error) {
value := i.(string)
re := fmt.Sprintf("^"+RFC1035NameTemplate+"$", "*")
if min < 1 {
errors = append(errors, fmt.Errorf("min must be at least 1. Got: %d", min))
}
if max < min {
errors = append(errors, fmt.Errorf("max must greater than min. Got [%d, %d]", min, max))
}

if len(value) < min || len(value) > max {
errors = append(errors, fmt.Errorf("%q (%q) must be between %d and %d characters long", k, value, min, max))
}

if !regexp.MustCompile(re).MatchString(value) {
errors = append(errors, fmt.Errorf("%q (%q) must match regex %q", k, value, re))
}
}

return ValidateRegexp(fmt.Sprintf("^"+RFC1035NameTemplate+"$", min-2, max-2))
return
}
}

func ValidateIpCidrRange(v interface{}, k string) (warnings []string, errors []error) {
Expand Down
8 changes: 7 additions & 1 deletion mmv1/third_party/terraform/verify/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,18 @@ func TestValidateRFC1035Name(t *testing.T) {
{TestName: "valid lower bound", Min: 12, Max: 30, Value: "a-valid-name"},
{TestName: "valid upper bound", Min: 6, Max: 12, Value: "a-valid-name"},
{TestName: "valid with numbers", Min: 6, Max: 30, Value: "valid000-name"},
{TestName: "valid shortest", Min: 1, Max: 63, Value: "a"},
{TestName: "valid longest", Min: 1, Max: 63, Value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
{TestName: "must start with a letter", Min: 6, Max: 10, Value: "0invalid", ExpectError: true},
{TestName: "cannot end with a dash", Min: 6, Max: 10, Value: "invalid-", ExpectError: true},
{TestName: "too short", Min: 6, Max: 10, Value: "short", ExpectError: true},
{TestName: "too long", Min: 6, Max: 10, Value: "toolooooong", ExpectError: true},
{TestName: "min too small", Min: 1, Max: 10, Value: "", ExpectError: true},
{TestName: "min too small", Min: 0, Max: 10, Value: "", ExpectError: true},
{TestName: "min < max", Min: 6, Max: 5, Value: "", ExpectError: true},
karolgorc marked this conversation as resolved.
Show resolved Hide resolved
{TestName: "min < max", Min: 6, Max: 5, Value: "", ExpectError: true},
{TestName: "invalid smallest possible w/ higher limit", Min: 2, Max: 63, Value: "a", ExpectError: true},
{TestName: "invalid smallest possible hyphen", Min: 1, Max: 1, Value: "-", ExpectError: true},
{TestName: "invalid smallest possible ends with hyphen", Min: 2, Max: 63, Value: "a-", ExpectError: true},
}

for _, c := range cases {
Expand Down