Skip to content

Commit

Permalink
Add validation to label keys for cloud functions (#3431) (#2009)
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <magic-modules@google.com>
  • Loading branch information
modular-magician authored Apr 28, 2020
1 parent 65f6a66 commit d561dff
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .changelog/3431.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
cloudfunctions: Added validation to label keys for `google_cloudfunctions_function` as API errors aren't useful.
```
24 changes: 22 additions & 2 deletions google-beta/resource_cloudfunctions_function.go
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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 invalid 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)
}
Expand Down Expand Up @@ -193,8 +212,9 @@ func resourceCloudFunctionsFunction() *schema.Resource {
},

"labels": {
Type: schema.TypeMap,
Optional: true,
Type: schema.TypeMap,
ValidateFunc: labelKeyValidator,
Optional: true,
},

"runtime": {
Expand Down
45 changes: 45 additions & 0 deletions google-beta/resource_cloudfunctions_function_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,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()

Expand Down
4 changes: 2 additions & 2 deletions website/docs/r/cloudfunctions_function.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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
Expand Down

0 comments on commit d561dff

Please sign in to comment.