diff --git a/internal/services/machinelearning/machine_learning_compute_cluster_resource.go b/internal/services/machinelearning/machine_learning_compute_cluster_resource.go index 5193ca81381e..a8107149c9e4 100644 --- a/internal/services/machinelearning/machine_learning_compute_cluster_resource.go +++ b/internal/services/machinelearning/machine_learning_compute_cluster_resource.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/machinelearning/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -41,9 +42,10 @@ func resourceComputeCluster() *pluginsdk.Resource { Schema: map[string]*pluginsdk.Schema{ "name": { - Type: pluginsdk.TypeString, - Required: true, - ForceNew: true, + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ComputeClusterName, }, "machine_learning_workspace_id": { diff --git a/internal/services/machinelearning/validate/compute_cluster_name.go b/internal/services/machinelearning/validate/compute_cluster_name.go new file mode 100644 index 000000000000..a00c68e96a8a --- /dev/null +++ b/internal/services/machinelearning/validate/compute_cluster_name.go @@ -0,0 +1,24 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validate + +import ( + "fmt" + "regexp" +) + +func ComputeClusterName(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + // The portal says: It can include letters, digits and dashes. It must start with a letter, end with a letter or digit, and be between 3 and 32 characters in length. + // If you provide invalid name, the rest api will return an error with the following regex. + if matched := regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9-]{1,30}[a-zA-Z0-9]$`).Match([]byte(v)); !matched { + errors = append(errors, fmt.Errorf("%s must be between 3 and 32 characters, may only include alphanumeric characters and '-' and must start with a letter, end with a letter or digit", k)) + } + return +} diff --git a/internal/services/machinelearning/validate/compute_cluster_name_test.go b/internal/services/machinelearning/validate/compute_cluster_name_test.go new file mode 100644 index 000000000000..ae729346b3c9 --- /dev/null +++ b/internal/services/machinelearning/validate/compute_cluster_name_test.go @@ -0,0 +1,89 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validate + +import "testing" + +func TestComputeClusterName(t *testing.T) { + testData := []struct { + input string + expected bool + }{ + { + // empty + input: "", + expected: false, + }, + { + // basic example + input: "hello", + expected: true, + }, + { + // cannot start with a hyphen + input: "-hello", + expected: false, + }, + { + // cannot start with a digit + input: "1hello", + expected: false, + }, + { + // can end with a digit + input: "hello2", + expected: true, + }, + { + // cannot end with a hyphen + input: "hello-", + expected: false, + }, + { + // cannot contain other special symbols other than hyphens + input: "hello.world", + expected: false, + }, + { + // cannot contain underscore + input: "hello_world", + expected: false, + }, + { + // hyphen in the middle + input: "hello-world", + expected: true, + }, + { + // 2 chars + input: "ab", + expected: false, + }, + { + // 3 chars + input: "abc", + expected: true, + }, + { + // 32 chars + input: "abcdefghijklmnopqrstuvwxyzabcdef", + expected: true, + }, + { + // 33 chars + input: "abcdefghijklmnopqrstuvwxyzabcdefg", + expected: false, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.input) + + _, errors := ComputeClusterName(v.input, "name") + actual := len(errors) == 0 + if v.expected != actual { + t.Fatalf("Expected %t but got %t", v.expected, actual) + } + } +}