diff --git a/azurerm/internal/services/compute/validation.go b/azurerm/internal/services/compute/validation.go index 8456a8f7f6a1..0ac7280b5851 100644 --- a/azurerm/internal/services/compute/validation.go +++ b/azurerm/internal/services/compute/validation.go @@ -9,11 +9,85 @@ import ( ) func ValidateLinuxName(i interface{}, k string) (warnings []string, errors []error) { - return validateName(64)(i, k) + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("Expected %q to be a string but it wasn't!", k)) + return + } + + // The value must not be empty. + if strings.TrimSpace(v) == "" { + errors = append(errors, fmt.Errorf("%q must not be empty", k)) + return + } + + const maxLength = 64 + // The value must be between 1 and 64 (Linux) characters long. + if len(v) > maxLength { + errors = append(errors, fmt.Errorf("%q can be at most %d characters, got %d", k, maxLength, len(v))) + } + + if strings.HasPrefix(v, "_") { + errors = append(errors, fmt.Errorf("%q cannot begin with an underscore", k)) + } + + if strings.HasSuffix(v, ".") || strings.HasSuffix(v, "-") { + errors = append(errors, fmt.Errorf("%q cannot end with an period or dash", k)) + } + + // Azure resource names cannot contain special characters \/""[]:|<>+=;,?*@& or begin with '_' or end with '.' or '-' + specialCharacters := `\/""[]:|<>+=;,?*@&` + if strings.ContainsAny(v, specialCharacters) { + errors = append(errors, fmt.Errorf("%q cannot contain the special characters: `%s`", k, specialCharacters)) + } + + // The value can only contain alphanumeric characters and can start with a number. + if matched := regexp.MustCompile(`^[a-zA-Z0-9-_.]+$`).Match([]byte(v)); !matched { + errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters, dashes and underscores", k)) + } + + // Portal: Virtual machine name cannot contain only numbers. + if matched := regexp.MustCompile(`^\d+$`).Match([]byte(v)); matched { + errors = append(errors, fmt.Errorf("%q cannot contain only numbers", k)) + } + + return warnings, errors } func ValidateWindowsName(i interface{}, k string) (warnings []string, errors []error) { - return validateName(16)(i, k) + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("Expected %q to be a string but it wasn't!", k)) + return + } + + // The value must not be empty. + if strings.TrimSpace(v) == "" { + errors = append(errors, fmt.Errorf("%q must not be empty", k)) + return + } + + const maxLength = 15 + // The value must be between 1 and 15 (Windows) characters long. + if len(v) > maxLength { + errors = append(errors, fmt.Errorf("%q can be at most %d characters, got %d", k, maxLength, len(v))) + } + + if strings.HasSuffix(v, "-") { + errors = append(errors, fmt.Errorf("%q cannot end with dash", k)) + } + + // A windows computer name can only contain alphanumeric characters and hyphens + if matched := regexp.MustCompile(`^[a-zA-Z0-9-]+$`).Match([]byte(v)); !matched { + errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes", k)) + } + + // Portal: Virtual machine name cannot contain only numbers. + if matched := regexp.MustCompile(`^\d+$`).Match([]byte(v)); matched { + errors = append(errors, fmt.Errorf("%q cannot contain only numbers", k)) + } + + return warnings, errors } func ValidateScaleSetResourceID(i interface{}, k string) (s []string, es []error) { @@ -37,48 +111,6 @@ func ValidateScaleSetResourceID(i interface{}, k string) (s []string, es []error return } -func validateName(maxLength int) func(i interface{}, k string) (warnings []string, errors []error) { - return func(i interface{}, k string) (warnings []string, errors []error) { - v, ok := i.(string) - if !ok { - errors = append(errors, fmt.Errorf("Expected %q to be a string but it wasn't!", k)) - return - } - - // The value must not be empty. - if strings.TrimSpace(v) == "" { - errors = append(errors, fmt.Errorf("%q must not be empty", k)) - return - } - - // The value must be between 1 and 64 (Linux) or 16 (Windows) characters long. - if len(v) >= maxLength { - errors = append(errors, fmt.Errorf("%q can be at most %d characters, got %d", k, maxLength-1, len(v))) - } - - if strings.HasPrefix(v, "_") { - errors = append(errors, fmt.Errorf("%q cannot begin with an underscore", k)) - } - - if strings.HasSuffix(v, ".") || strings.HasSuffix(v, "-") { - errors = append(errors, fmt.Errorf("%q cannot end with an period or dash", k)) - } - - // Azure resource names cannot contain special characters \/""[]:|<>+=;,?*@& or begin with '_' or end with '.' or '-' - specialCharacters := `\/""[]:|<>+=;,?*@&` - if strings.ContainsAny(v, specialCharacters) { - errors = append(errors, fmt.Errorf("%q cannot contain the special characters: `%s`", k, specialCharacters)) - } - - // The value can only contain alphanumeric characters and cannot start with a number. - if matched := regexp.MustCompile(`^[a-zA-Z0-9-_]+$`).Match([]byte(v)); !matched { - errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters, dashes and underscores", k)) - } - - return - } -} - func validateDiskEncryptionSetName(i interface{}, k string) (warnings []string, errors []error) { v, ok := i.(string) if !ok { diff --git a/azurerm/internal/services/compute/validation_test.go b/azurerm/internal/services/compute/validation_test.go index 0eb577a0b0f2..e56f3a99e143 100644 --- a/azurerm/internal/services/compute/validation_test.go +++ b/azurerm/internal/services/compute/validation_test.go @@ -42,19 +42,34 @@ func TestValidateLinuxName(t *testing.T) { input: "hello.", expected: false, }, + { + // can have a dot in the middle + input: "hello.world", + expected: true, + }, + { + // start with a number + input: "0abc", + expected: true, + }, + { + // cannot contain only numbers + input: "12345", + expected: false, + }, { // 63 chars - input: "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij", + input: "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk", expected: true, }, { // 64 chars - input: "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk", + input: "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkj", expected: true, }, { // 65 chars - input: "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkj", + input: "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkjl", expected: false, }, } @@ -90,6 +105,11 @@ func TestValidateWindowsName(t *testing.T) { input: "_hello", expected: false, }, + { + // can't contain underscore + input: "hello_world", + expected: false, + }, { // can't end with a dash input: "hello-", @@ -110,6 +130,21 @@ func TestValidateWindowsName(t *testing.T) { input: "hello.", expected: false, }, + { + // can't contain dot + input: "hello.world", + expected: false, + }, + { + // start with a number + input: "0abc", + expected: true, + }, + { + // cannot contain only numbers + input: "12345", + expected: false, + }, { // 14 chars input: "abcdefghijklmn",