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

azurerm_kubernetes_cluster - fix validation logic for dns_prefix #20813

Merged
merged 4 commits into from
Mar 7, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,24 @@ func (KubernetesClusterResource) updateDefaultNodePoolAgentCount(nodeCount int)
}
}

func TestAccKubernetesCluster_dnsPrefix(t *testing.T) {
// regression test case for issue #20806
data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test")
dnsPrefix := fmt.Sprintf("1stCluster%d", data.RandomInteger)

r := KubernetesClusterResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.dnsPrefix(data, currentKubernetesVersion),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("dns_prefix").HasValue(dnsPrefix),
),
},
})
}

func (KubernetesClusterResource) hostEncryption(data acceptance.TestData, controlPlaneVersion string) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down Expand Up @@ -652,3 +670,34 @@ resource "azurerm_kubernetes_cluster" "test" {
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, controlPlaneVersion)
}

func (KubernetesClusterResource) dnsPrefix(data acceptance.TestData, controlPlaneVersion string) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}

resource "azurerm_resource_group" "test" {
name = "acctestRG-aks-%d"
location = "%s"
}

resource "azurerm_kubernetes_cluster" "test" {
name = "acctestaks%d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
dns_prefix = "1stCluster%d"
kubernetes_version = %q

default_node_pool {
name = "default"
node_count = 1
vm_size = "Standard_DS2_v2"
}

identity {
type = "SystemAssigned"
}
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, controlPlaneVersion)
}
38 changes: 28 additions & 10 deletions internal/services/containers/validate/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,51 @@ import (
)

func KubernetesAdminUserName(i interface{}, k string) (warnings []string, errors []error) {
adminUserName := i.(string)
adminUserName, ok := i.(string)
if !ok {
return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
}

re := regexp.MustCompile(`^[A-Za-z][-A-Za-z0-9_]*$`)
re := regexp.MustCompile(`^[A-Za-z][-A-Za-z\d_]*$`)
if re != nil && !re.MatchString(adminUserName) {
errors = append(errors, fmt.Errorf("%s must start with alphabet and/or continue with alphanumeric characters, underscores, hyphens. Got %q.", k, adminUserName))
errors = append(errors, fmt.Errorf("the %q must begin with a letter, contain only letters, numbers, underscores and hyphens, got %q", k, adminUserName))
}

return warnings, errors
}

func KubernetesAgentPoolName(i interface{}, k string) (warnings []string, errors []error) {
agentPoolName := i.(string)
agentPoolName, ok := i.(string)
if !ok {
return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
}

re := regexp.MustCompile(`^[a-z]{1}[a-z0-9]{0,11}$`)
re := regexp.MustCompile(`^[a-z]{1}[a-z\d]{0,11}$`)
if re != nil && !re.MatchString(agentPoolName) {
errors = append(errors, fmt.Errorf("%s must start with a lowercase letter, have max length of 12, and only have characters a-z0-9. Got %q.", k, agentPoolName))
errors = append(errors, fmt.Errorf("the %q must begin with a lowercase letter, contain only lowercase letters and numbers and be between 1 and 12 characters in length, got %q", k, agentPoolName))
}

return warnings, errors
}

func KubernetesDNSPrefix(i interface{}, k string) (warnings []string, errors []error) {
dnsPrefix := i.(string)
dnsPrefix, ok := i.(string)
if !ok {
return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
}

re := regexp.MustCompile(`^[a-zA-Z][-a-zA-Z0-9]{0,43}[a-zA-Z0-9]$`)
if re != nil && !re.MatchString(dnsPrefix) {
errors = append(errors, fmt.Errorf("%s must contain between 2 and 45 characters. The name can contain only letters, numbers, and hyphens. The name must start with a letter and must end with an alphanumeric character.. Got %q.", k, dnsPrefix))
errMsg := fmt.Sprintf("the %q must begin and end with a letter or number, contain only letters, numbers, and hyphens and be between 1 and 54 characters in length, got", k)

if len(dnsPrefix) < 2 {
re := regexp.MustCompile(`^[a-zA-Z\d]`)
if re != nil && !re.MatchString(dnsPrefix) {
errors = append(errors, fmt.Errorf("%s %q", errMsg, dnsPrefix))
}
} else {
re := regexp.MustCompile(`^[a-zA-Z\d][-a-zA-Z\d]{0,52}[a-zA-Z\d]$`)
if re != nil && !re.MatchString(dnsPrefix) {
errors = append(errors, fmt.Errorf("%s %q", errMsg, dnsPrefix))
}
}

return warnings, errors
Expand Down
30 changes: 29 additions & 1 deletion internal/services/containers/validate/kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,41 @@ func TestKubernetesDNSPrefix(t *testing.T) {
Errors: 1,
},
{
DNSPrefix: "a",
DNSPrefix: "aBc-123ab-",
Errors: 1,
},
{
DNSPrefix: "-aBc-123abc",
Errors: 1,
},
{
DNSPrefix: "a",
Errors: 0,
},
{
DNSPrefix: "aBc-123abc",
Errors: 0,
},
{
DNSPrefix: "ThisIsAKubernetesDNSPrefixThatIsExactlyFiftyFourCharac",
Errors: 0,
},
{
DNSPrefix: "ThisIsAKubernetesDNSPrefixThatIsNotExactlyFiftyFourChar",
Errors: 1,
},
{
DNSPrefix: "2",
Errors: 0,
},
{
DNSPrefix: "2ndCluster",
Errors: 0,
},
{
DNSPrefix: "aBc-123abc2",
Errors: 0,
},
}

for _, tc := range cases {
Expand Down
18 changes: 8 additions & 10 deletions website/docs/r/kubernetes_cluster.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,11 @@ The following arguments are supported:

* `default_node_pool` - (Required) A `default_node_pool` block as defined below.

* `dns_prefix` - (Optional) DNS prefix specified when creating the managed cluster. Changing this forces a new resource to be created.
* `dns_prefix` - (Optional) DNS prefix specified when creating the managed cluster. Possible values must begin and end with a letter or number, contain only letters, numbers, and hyphens and be between 1 and 54 characters in length. Changing this forces a new resource to be created.

* `dns_prefix_private_cluster` - (Optional) Specifies the DNS prefix to use with private clusters. Changing this forces a new resource to be created.

-> **Note:** One of `dns_prefix` or `dns_prefix_private_cluster` must be specified.

-> **Note:** The `dns_prefix` must contain between 3 and 45 characters, and can contain only letters, numbers, and hyphens. It must start with a letter and must end with a letter or a number.
-> **Note:** You must define either a `dns_prefix` or a `dns_prefix_private_cluster` field.

In addition, one of either `identity` or `service_principal` blocks must be specified.

Expand Down Expand Up @@ -219,9 +217,9 @@ resource "azurerm_kubernetes_cluster" "example" {

* `workload_identity_enabled` - (Optional) Specifies whether Azure AD Workload Identity should be enabled for the Cluster. Defaults to `false`.

-> **Note** To enable Azure AD Workload Identity `oidc_issuer_enabled` must be set to `true`.
-> **Note:** To enable Azure AD Workload Identity `oidc_issuer_enabled` must be set to `true`.

-> **Note** This requires that the Preview Feature `Microsoft.ContainerService/EnableWorkloadIdentityPreview` is enabled and the Resource Provider is re-registered, see [the documentation](https://learn.microsoft.com/en-us/azure/aks/workload-identity-deploy-cluster#register-the-enableworkloadidentitypreview-feature-flag) for more information.
-> **Note:** This requires that the Preview Feature `Microsoft.ContainerService/EnableWorkloadIdentityPreview` is enabled and the Resource Provider is re-registered, see [the documentation](https://learn.microsoft.com/en-us/azure/aks/workload-identity-deploy-cluster#register-the-enableworkloadidentitypreview-feature-flag) for more information.

* `public_network_access_enabled` - (Optional) Whether public network access is allowed for this Kubernetes Cluster. Defaults to `true`. Changing this forces a new resource to be created.

Expand Down Expand Up @@ -470,7 +468,7 @@ An `identity` block supports the following:

* `identity_ids` - (Optional) Specifies a list of User Assigned Managed Identity IDs to be assigned to this Kubernetes Cluster.

~> **NOTE:** This is required when `type` is set to `UserAssigned`.
~> **Note:** This is required when `type` is set to `UserAssigned`.

---

Expand All @@ -488,7 +486,7 @@ A `key_vault_secrets_provider` block supports the following:

* `secret_rotation_interval` - (Optional) The interval to poll for secret rotation. This attribute is only set when `secret_rotation` is true and defaults to `2m`.

-> **NOTE:** To enable`key_vault_secrets_provider` either `secret_rotation_enabled` or `secret_rotation_interval` must be specified.
-> **Note:** To enable`key_vault_secrets_provider` either `secret_rotation_enabled` or `secret_rotation_interval` must be specified.

---

Expand Down Expand Up @@ -524,7 +522,7 @@ The `kubelet_identity` block supports the following:

* `user_assigned_identity_id` - (Optional) The ID of the User Assigned Identity assigned to the Kubelets. If not specified a Managed Identity is created automatically. Changing this forces a new resource to be created.

-> **NOTE:** When `kubelet_identity` is enabled - The `type` field in the `identity` block must be set to `UserAssigned` and `identity_ids` must be set.
-> **Note:** When `kubelet_identity` is enabled - The `type` field in the `identity` block must be set to `UserAssigned` and `identity_ids` must be set.

---

Expand Down Expand Up @@ -722,7 +720,7 @@ A `storage_profile` block supports the following:

* `disk_driver_version` - (Optional) Disk CSI Driver version to be used. Possible values are `v1` and `v2`. Defaults to `v1`.

-> **NOTE:** `Azure Disk CSI driver v2` is currently in [Public Preview](https://azure.microsoft.com/en-us/updates/public-preview-azure-disk-csi-driver-v2-in-aks/) on an opt-in basis. To use it, the feature `EnableAzureDiskCSIDriverV2` for namespace `Microsoft.ContainerService` must be requested.
-> **Note:** `Azure Disk CSI driver v2` is currently in [Public Preview](https://azure.microsoft.com/en-us/updates/public-preview-azure-disk-csi-driver-v2-in-aks/) on an opt-in basis. To use it, the feature `EnableAzureDiskCSIDriverV2` for namespace `Microsoft.ContainerService` must be requested.

* `file_driver_enabled` - (Optional) Is the File CSI driver enabled? Defaults to `true`.

Expand Down