diff --git a/google/data_source_google_compute_zones.go b/google/data_source_google_compute_zones.go index a200aba5cd3..e9485a44d90 100644 --- a/google/data_source_google_compute_zones.go +++ b/google/data_source_google_compute_zones.go @@ -7,6 +7,7 @@ import ( "time" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" compute "google.golang.org/api/compute/v1" ) @@ -24,15 +25,9 @@ func dataSourceGoogleComputeZones() *schema.Resource { Elem: &schema.Schema{Type: schema.TypeString}, }, "status": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: func(v interface{}, k string) (ws []string, es []error) { - value := v.(string) - if value != "UP" && value != "DOWN" { - es = append(es, fmt.Errorf("%q can only be 'UP' or 'DOWN' (%q given)", k, value)) - } - return - }, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"UP", "DOWN"}, false), }, }, } diff --git a/google/data_source_storage_object_signed_url.go b/google/data_source_storage_object_signed_url.go index fced990cf4d..21497a57204 100644 --- a/google/data_source_storage_object_signed_url.go +++ b/google/data_source_storage_object_signed_url.go @@ -23,6 +23,7 @@ import ( "github.com/hashicorp/errwrap" "github.com/hashicorp/terraform/helper/pathorcontents" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" "golang.org/x/oauth2/google" "golang.org/x/oauth2/jwt" ) @@ -68,7 +69,7 @@ func dataSourceGoogleSignedUrl() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "GET", - ValidateFunc: validateHttpMethod, + ValidateFunc: validation.StringInSlice([]string{"GET", "HEAD", "PUT", "DELETE"}, true), }, "path": &schema.Schema{ Type: schema.TypeString, @@ -93,15 +94,6 @@ func validateExtensionHeaders(v interface{}, k string) (ws []string, errors []er return } -func validateHttpMethod(v interface{}, k string) (ws []string, errs []error) { - value := v.(string) - value = strings.ToUpper(value) - if value != "GET" && value != "HEAD" && value != "PUT" && value != "DELETE" { - errs = append(errs, errors.New("http_method must be one of [GET|HEAD|PUT|DELETE]")) - } - return -} - func dataSourceGoogleSignedUrlRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) diff --git a/google/resource_compute_backend_bucket.go b/google/resource_compute_backend_bucket.go index 9849402e8f3..c437dcfb685 100644 --- a/google/resource_compute_backend_bucket.go +++ b/google/resource_compute_backend_bucket.go @@ -3,7 +3,6 @@ package google import ( "fmt" "log" - "regexp" "github.com/hashicorp/terraform/helper/schema" "google.golang.org/api/compute/v1" @@ -18,18 +17,10 @@ func resourceComputeBackendBucket() *schema.Resource { Schema: map[string]*schema.Schema{ "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - re := `^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$` - if !regexp.MustCompile(re).MatchString(value) { - errors = append(errors, fmt.Errorf( - "%q (%q) doesn't match regexp %q", k, value, re)) - } - return - }, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateGCPName, }, "bucket_name": &schema.Schema{ diff --git a/google/resource_compute_backend_service.go b/google/resource_compute_backend_service.go index d18ef7c6d9a..ccdbb66ca1b 100644 --- a/google/resource_compute_backend_service.go +++ b/google/resource_compute_backend_service.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "log" - "regexp" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" @@ -23,18 +22,10 @@ func resourceComputeBackendService() *schema.Resource { Schema: map[string]*schema.Schema{ "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - re := `^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$` - if !regexp.MustCompile(re).MatchString(value) { - errors = append(errors, fmt.Errorf( - "%q (%q) doesn't match regexp %q", k, value, re)) - } - return - }, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateGCPName, }, "health_checks": &schema.Schema{ diff --git a/google/resource_compute_instance_template.go b/google/resource_compute_instance_template.go index 32b3d524605..98043f077d8 100644 --- a/google/resource_compute_instance_template.go +++ b/google/resource_compute_instance_template.go @@ -26,15 +26,7 @@ func resourceComputeInstanceTemplate() *schema.Resource { Computed: true, ForceNew: true, ConflictsWith: []string{"name_prefix"}, - ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { - // https://cloud.google.com/compute/docs/reference/latest/instanceTemplates#resource - value := v.(string) - if len(value) > 63 { - errors = append(errors, fmt.Errorf( - "%q cannot be longer than 63 characters", k)) - } - return - }, + ValidateFunc: validateGCPName, }, "name_prefix": &schema.Schema{ diff --git a/google/resource_compute_region_backend_service.go b/google/resource_compute_region_backend_service.go index 894961de980..f78a458cba6 100644 --- a/google/resource_compute_region_backend_service.go +++ b/google/resource_compute_region_backend_service.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "log" - "regexp" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" @@ -20,18 +19,10 @@ func resourceComputeRegionBackendService() *schema.Resource { Schema: map[string]*schema.Schema{ "name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - re := `^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$` - if !regexp.MustCompile(re).MatchString(value) { - errors = append(errors, fmt.Errorf( - "%q (%q) doesn't match regexp %q", k, value, re)) - } - return - }, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateGCPName, }, "health_checks": &schema.Schema{ diff --git a/google/resource_compute_ssl_certificate.go b/google/resource_compute_ssl_certificate.go index 5b64ebbf753..bbe07d593f3 100644 --- a/google/resource_compute_ssl_certificate.go +++ b/google/resource_compute_ssl_certificate.go @@ -28,15 +28,7 @@ func resourceComputeSslCertificate() *schema.Resource { Computed: true, ForceNew: true, ConflictsWith: []string{"name_prefix"}, - ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { - // https://cloud.google.com/compute/docs/reference/latest/sslCertificates#resource - value := v.(string) - if len(value) > 63 { - errors = append(errors, fmt.Errorf( - "%q cannot be longer than 63 characters", k)) - } - return - }, + ValidateFunc: validateGCPName, }, "name_prefix": &schema.Schema{ diff --git a/google/resource_sql_database_instance.go b/google/resource_sql_database_instance.go index 42db6af6c90..1bb76fcd0e6 100644 --- a/google/resource_sql_database_instance.go +++ b/google/resource_sql_database_instance.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" "google.golang.org/api/googleapi" "google.golang.org/api/sqladmin/v1beta4" @@ -167,18 +168,14 @@ func resourceSqlDatabaseInstance() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "day": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { - return validateNumericRange(v, k, 1, 7) - }, + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 7), }, "hour": &schema.Schema{ - Type: schema.TypeInt, - Optional: true, - ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { - return validateNumericRange(v, k, 0, 23) - }, + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 23), }, "update_track": &schema.Schema{ Type: schema.TypeString, @@ -1179,15 +1176,6 @@ func resourceSqlDatabaseInstanceDelete(d *schema.ResourceData, meta interface{}) return nil } -func validateNumericRange(v interface{}, k string, min int, max int) (ws []string, errors []error) { - value := v.(int) - if min > value || value > max { - errors = append(errors, fmt.Errorf( - "%q outside range %d-%d.", k, min, max)) - } - return -} - func instanceMutexKey(project, instance_name string) string { return fmt.Sprintf("google-sql-database-instance-%s-%s", project, instance_name) } diff --git a/google/validation.go b/google/validation.go new file mode 100644 index 00000000000..4191b6e8692 --- /dev/null +++ b/google/validation.go @@ -0,0 +1,24 @@ +package google + +import ( + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "regexp" +) + +func validateGCPName(v interface{}, k string) (ws []string, errors []error) { + re := `^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$` + return validateRegexp(re)(v, k) +} + +func validateRegexp(re string) schema.SchemaValidateFunc { + return func(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + if !regexp.MustCompile(re).MatchString(value) { + errors = append(errors, fmt.Errorf( + "%q (%q) doesn't match regexp %q", k, value, re)) + } + + return + } +} diff --git a/google/validation_test.go b/google/validation_test.go new file mode 100644 index 00000000000..e76b954e022 --- /dev/null +++ b/google/validation_test.go @@ -0,0 +1,57 @@ +package google + +import ( + "fmt" + "testing" +) + +func TestValidateGCPName(t *testing.T) { + x := []GCPNameTestCase{ + // No errors + {TestName: "basic", Value: "foobar"}, + {TestName: "with numbers", Value: "foobar123"}, + {TestName: "short", Value: "f"}, + {TestName: "long", Value: "foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoo"}, + {TestName: "has a hyphen", Value: "foo-bar"}, + + // With errors + {TestName: "empty", Value: "", ExpectError: true}, + {TestName: "starts with a capital", Value: "Foobar", ExpectError: true}, + {TestName: "starts with a number", Value: "1foobar", ExpectError: true}, + {TestName: "has an underscore", Value: "foo_bar", ExpectError: true}, + {TestName: "too long", Value: "foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoob", ExpectError: true}, + } + + es := testGCPNames(x) + if len(es) > 0 { + t.Errorf("Failed to validate GCP names: %v", es) + } +} + +type GCPNameTestCase struct { + TestName string + Value string + ExpectError bool +} + +func testGCPNames(cases []GCPNameTestCase) []error { + es := make([]error, 0) + for _, c := range cases { + es = append(es, testGCPName(c)...) + } + + return es +} + +func testGCPName(testCase GCPNameTestCase) []error { + _, es := validateGCPName(testCase.Value, testCase.TestName) + if testCase.ExpectError { + if len(es) > 0 { + return nil + } else { + return []error{fmt.Errorf("Didn't see expected error in case \"%s\" with string \"%s\"", testCase.TestName, testCase.Value)} + } + } + + return es +}