From 5cacb634bb1943e7ee7dffe4c05cd82a1bc7b88b Mon Sep 17 00:00:00 2001 From: Chris Stephens Date: Mon, 27 Apr 2020 15:03:01 -0700 Subject: [PATCH 1/2] Add validation to label keys for cloud functions --- .../resource_cloudfunctions_function.go | 24 +++++++++- ...source_cloudfunctions_function_test.go.erb | 45 +++++++++++++++++++ .../r/cloudfunctions_function.html.markdown | 4 +- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/third_party/terraform/resources/resource_cloudfunctions_function.go b/third_party/terraform/resources/resource_cloudfunctions_function.go index 5023aaba6164..f1547094bb5d 100644 --- a/third_party/terraform/resources/resource_cloudfunctions_function.go +++ b/third_party/terraform/resources/resource_cloudfunctions_function.go @@ -1,6 +1,8 @@ package google import ( + "regexp" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "google.golang.org/api/cloudfunctions/v1" @@ -50,6 +52,23 @@ func (s *cloudFunctionId) cloudFunctionId() string { return fmt.Sprintf("projects/%s/locations/%s/functions/%s", s.Project, s.Region, s.Name) } +// matches all international lower case letters, number, underscores and dashes. +var labelKeyRegex = regexp.MustCompile(`^[\p{Ll}0-9_-]+$`) + +func labelKeyValidator(val interface{}, key string) (warns []string, errs []error) { + if val == nil { + return + } + + m := val.(map[string]interface{}) + for k := range m { + if !labelKeyRegex.MatchString(k) { + errs = append(errs, fmt.Errorf("%q is an invlaid label key. See https://cloud.google.com/resource-manager/docs/creating-managing-labels#requirements", k)) + } + } + return +} + func (s *cloudFunctionId) locationId() string { return fmt.Sprintf("projects/%s/locations/%s", s.Project, s.Region) } @@ -193,8 +212,9 @@ func resourceCloudFunctionsFunction() *schema.Resource { }, "labels": { - Type: schema.TypeMap, - Optional: true, + Type: schema.TypeMap, + ValidateFunc: labelKeyValidator, + Optional: true, }, "runtime": { diff --git a/third_party/terraform/tests/resource_cloudfunctions_function_test.go.erb b/third_party/terraform/tests/resource_cloudfunctions_function_test.go.erb index 6f63a3795d73..e3af7df8159b 100644 --- a/third_party/terraform/tests/resource_cloudfunctions_function_test.go.erb +++ b/third_party/terraform/tests/resource_cloudfunctions_function_test.go.erb @@ -70,6 +70,51 @@ func TestCloudFunctionsFunction_nameValidator(t *testing.T) { } } +func TestValidLabelKeys(t *testing.T) { + testCases := []struct { + labelKey string + valid bool + }{ + { + "test-label", true, + }, + { + "test_label", true, + }, + { + "MixedCase", false, + }, + { + "number-09-dash", true, + }, + { + "", false, + }, + { + "test-label", true, + }, + { + "mixed*symbol", false, + }, + { + "intérnätional", true, + }, + } + + for _, tc := range testCases { + labels := make(map[string]interface{}) + labels[tc.labelKey] = "test value" + + _, errs := labelKeyValidator(labels, "") + if tc.valid && len(errs) > 0 { + t.Errorf("Validation failure, key: '%s' should be valid but actual errors were %q", tc.labelKey, errs) + } + if !tc.valid && len(errs) < 1 { + t.Errorf("Validation failure, key: '%s' should fail but actual errors were %q", tc.labelKey, errs) + } + } +} + func TestAccCloudFunctionsFunction_basic(t *testing.T) { t.Parallel() diff --git a/third_party/terraform/website/docs/r/cloudfunctions_function.html.markdown b/third_party/terraform/website/docs/r/cloudfunctions_function.html.markdown index 13aa62af6a50..d2766fa4bd6c 100644 --- a/third_party/terraform/website/docs/r/cloudfunctions_function.html.markdown +++ b/third_party/terraform/website/docs/r/cloudfunctions_function.html.markdown @@ -125,7 +125,7 @@ Eg. `"nodejs8"`, `"nodejs10"`, `"python37"`, `"go111"`. * `ingress_settings` - (Optional) String value that controls what traffic can reach the function. Allowed values are ALLOW_ALL and ALLOW_INTERNAL_ONLY. Changes to this field will recreate the cloud function. -* `labels` - (Optional) A set of key/value label pairs to assign to the function. +* `labels` - (Optional) A set of key/value label pairs to assign to the function. Label keys must follow the requirements at https://cloud.google.com/resource-manager/docs/creating-managing-labels#requirements. * `service_account_email` - (Optional) If provided, the self-provided service account to run the function with. @@ -147,7 +147,7 @@ Eg. `"nodejs8"`, `"nodejs10"`, `"python37"`, `"go111"`. The `event_trigger` block supports: * `event_type` - (Required) The type of event to observe. For example: `"google.storage.object.finalize"`. -See the documentation on [calling Cloud Functions](https://cloud.google.com/functions/docs/calling/) for a +See the documentation on [calling Cloud Functions](https://cloud.google.com/functions/docs/calling/) for a full reference of accepted triggers. * `resource` - (Required) Required. The name or partial URI of the resource from From 90579b0270d720b5fd83d9d122dc573fcc66dcb4 Mon Sep 17 00:00:00 2001 From: Chris Stephens Date: Mon, 27 Apr 2020 17:01:56 -0700 Subject: [PATCH 2/2] speling errors --- .../terraform/resources/resource_cloudfunctions_function.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/terraform/resources/resource_cloudfunctions_function.go b/third_party/terraform/resources/resource_cloudfunctions_function.go index f1547094bb5d..212633ecea9e 100644 --- a/third_party/terraform/resources/resource_cloudfunctions_function.go +++ b/third_party/terraform/resources/resource_cloudfunctions_function.go @@ -63,7 +63,7 @@ func labelKeyValidator(val interface{}, key string) (warns []string, errs []erro m := val.(map[string]interface{}) for k := range m { if !labelKeyRegex.MatchString(k) { - errs = append(errs, fmt.Errorf("%q is an invlaid label key. See https://cloud.google.com/resource-manager/docs/creating-managing-labels#requirements", k)) + errs = append(errs, fmt.Errorf("%q is an invalid label key. See https://cloud.google.com/resource-manager/docs/creating-managing-labels#requirements", k)) } } return