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 validation to label keys for cloud functions #2009

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
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