diff --git a/azurerm/internal/services/containers/kubernetes_addons.go b/azurerm/internal/services/containers/kubernetes_addons.go index bd8444bf4a1e..d804de022ee4 100644 --- a/azurerm/internal/services/containers/kubernetes_addons.go +++ b/azurerm/internal/services/containers/kubernetes_addons.go @@ -8,7 +8,10 @@ import ( "github.com/Azure/go-autorest/autorest/azure" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + commonValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" logAnalyticsValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/loganalytics/validate" + applicationGatewayValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/validate" + subnetValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" laparse "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/loganalytics/parse" @@ -16,11 +19,12 @@ import ( const ( // note: the casing on these keys is important - aciConnectorKey = "aciConnectorLinux" - azurePolicyKey = "azurepolicy" - kubernetesDashboardKey = "kubeDashboard" - httpApplicationRoutingKey = "httpApplicationRouting" - omsAgentKey = "omsagent" + aciConnectorKey = "aciConnectorLinux" + azurePolicyKey = "azurepolicy" + kubernetesDashboardKey = "kubeDashboard" + httpApplicationRoutingKey = "httpApplicationRouting" + omsAgentKey = "omsagent" + ingressApplicationGatewayKey = "ingressApplicationGateway" ) // The AKS API hard-codes which add-ons are supported in which environment @@ -155,6 +159,42 @@ func schemaKubernetesAddOnProfiles() *schema.Schema { }, }, }, + + "ingress_application_gateway": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Required: true, + }, + "gateway_id": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"addon_profile.0.ingress_application_gateway.0.subnet_cidr", "addon_profile.0.ingress_application_gateway.0.subnet_id"}, + ValidateFunc: applicationGatewayValidate.ApplicationGatewayID, + }, + "subnet_cidr": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"addon_profile.0.ingress_application_gateway.0.gateway_id", "addon_profile.0.ingress_application_gateway.0.subnet_id"}, + ValidateFunc: commonValidate.CIDR, + }, + "subnet_id": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"addon_profile.0.ingress_application_gateway.0.gateway_id", "addon_profile.0.ingress_application_gateway.0.subnet_cidr"}, + ValidateFunc: subnetValidate.SubnetID, + }, + "effective_gateway_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, }, }, } @@ -166,11 +206,12 @@ func expandKubernetesAddOnProfiles(input []interface{}, env azure.Environment) ( } profiles := map[string]*containerservice.ManagedClusterAddonProfile{ - aciConnectorKey: &disabled, - azurePolicyKey: &disabled, - kubernetesDashboardKey: &disabled, - httpApplicationRoutingKey: &disabled, - omsAgentKey: &disabled, + aciConnectorKey: &disabled, + azurePolicyKey: &disabled, + kubernetesDashboardKey: &disabled, + httpApplicationRoutingKey: &disabled, + omsAgentKey: &disabled, + ingressApplicationGatewayKey: &disabled, } if len(input) == 0 || input[0] == nil { @@ -249,6 +290,30 @@ func expandKubernetesAddOnProfiles(input []interface{}, env azure.Environment) ( } } + ingressApplicationGateway := profile["ingress_application_gateway"].([]interface{}) + if len(ingressApplicationGateway) > 0 && ingressApplicationGateway[0] != nil { + value := ingressApplicationGateway[0].(map[string]interface{}) + config := make(map[string]*string) + enabled := value["enabled"].(bool) + + if gatewayId, ok := value["gateway_id"]; ok && gatewayId != "" { + config["applicationGatewayId"] = utils.String(gatewayId.(string)) + } + + if subnetCIDR, ok := value["subnet_cidr"]; ok && subnetCIDR != "" { + config["subnetCIDR"] = utils.String(subnetCIDR.(string)) + } + + if subnetId, ok := value["subnet_id"]; ok && subnetId != "" { + config["subnetId"] = utils.String(subnetId.(string)) + } + + addonProfiles[ingressApplicationGatewayKey] = &containerservice.ManagedClusterAddonProfile{ + Enabled: utils.Bool(enabled), + Config: config, + } + } + return filterUnsupportedKubernetesAddOns(addonProfiles, env) } @@ -365,18 +430,55 @@ func flattenKubernetesAddOnProfiles(profile map[string]*containerservice.Managed }) } + ingressApplicationGateways := make([]interface{}, 0) + if ingressApplicationGateway := kubernetesAddonProfileLocate(profile, ingressApplicationGatewayKey); ingressApplicationGateway != nil { + enabled := false + if enabledVal := ingressApplicationGateway.Enabled; enabledVal != nil { + enabled = *enabledVal + } + + gatewayId := "" + if v := kubernetesAddonProfilelocateInConfig(ingressApplicationGateway.Config, "applicationGatewayId"); v != nil { + gatewayId = *v + } + + effectiveGatewayId := "" + if v := kubernetesAddonProfilelocateInConfig(ingressApplicationGateway.Config, "effectiveApplicationGatewayId"); v != nil { + effectiveGatewayId = *v + } + + subnetCIDR := "" + if v := kubernetesAddonProfilelocateInConfig(ingressApplicationGateway.Config, "subnetCIDR"); v != nil { + subnetCIDR = *v + } + + subnetId := "" + if v := kubernetesAddonProfilelocateInConfig(ingressApplicationGateway.Config, "subnetId"); v != nil { + subnetId = *v + } + + ingressApplicationGateways = append(ingressApplicationGateways, map[string]interface{}{ + "enabled": enabled, + "gateway_id": gatewayId, + "effective_gateway_id": effectiveGatewayId, + "subnet_cidr": subnetCIDR, + "subnet_id": subnetId, + }) + } + // this is a UX hack, since if the top level block isn't defined everything should be turned off - if len(aciConnectors) == 0 && len(azurePolicies) == 0 && len(httpApplicationRoutes) == 0 && len(kubeDashboards) == 0 && len(omsAgents) == 0 { + if len(aciConnectors) == 0 && len(azurePolicies) == 0 && len(httpApplicationRoutes) == 0 && len(kubeDashboards) == 0 && len(omsAgents) == 0 && len(ingressApplicationGateways) == 0 { return []interface{}{} } return []interface{}{ map[string]interface{}{ - "aci_connector_linux": aciConnectors, - "azure_policy": azurePolicies, - "http_application_routing": httpApplicationRoutes, - "kube_dashboard": kubeDashboards, - "oms_agent": omsAgents, + "aci_connector_linux": aciConnectors, + "azure_policy": azurePolicies, + "http_application_routing": httpApplicationRoutes, + "kube_dashboard": kubeDashboards, + "oms_agent": omsAgents, + "ingress_application_gateway": ingressApplicationGateways, }, } } diff --git a/azurerm/internal/services/containers/kubernetes_cluster_addons_resource_test.go b/azurerm/internal/services/containers/kubernetes_cluster_addons_resource_test.go index 2155dccad0e2..bb6f1410e7b5 100644 --- a/azurerm/internal/services/containers/kubernetes_cluster_addons_resource_test.go +++ b/azurerm/internal/services/containers/kubernetes_cluster_addons_resource_test.go @@ -17,8 +17,13 @@ var kubernetesAddOnTests = map[string]func(t *testing.T){ "addonProfileOMS": testAccKubernetesCluster_addonProfileOMS, "addonProfileOMSToggle": testAccKubernetesCluster_addonProfileOMSToggle, "addonProfileRouting": testAccKubernetesCluster_addonProfileRoutingToggle, + "addonProfileAppGatewayAppGatewayId": testAccKubernetesCluster_addonProfileIngressApplicationGateway_appGatewayId, + "addonProfileAppGatewaySubnetCIDR": testAccKubernetesCluster_addonProfileIngressApplicationGateway_subnetCIDR, + "addonProfileAppGatewaySubnetID": testAccKubernetesCluster_addonProfileIngressApplicationGateway_subnetId, } +var addOnAppGatewaySubnetCIDR string = "10.241.0.0/16" // AKS will use 10.240.0.0/16 for the aks subnet so use 10.241.0.0/16 for the app gateway subnet + func TestAccKubernetesCluster_addonProfileAciConnectorLinux(t *testing.T) { checkIfShouldRunTestsIndividually(t) testAccKubernetesCluster_addonProfileAciConnectorLinux(t) @@ -256,6 +261,82 @@ func testAccKubernetesCluster_addonProfileRoutingToggle(t *testing.T) { }) } +func TestAccKubernetesCluster_addonProfileIngressApplicationGateway_appGatewayId(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccKubernetesCluster_addonProfileIngressApplicationGateway_appGatewayId(t) +} + +func testAccKubernetesCluster_addonProfileIngressApplicationGateway_appGatewayId(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + r := KubernetesClusterResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.addonProfileIngressApplicationGatewayAppGatewayConfig(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.effective_gateway_id").Exists(), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.effective_gateway_id").MatchesOtherKey( + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.gateway_id"), + ), + ), + }, + data.ImportStep(), + }) +} + +func TestAccKubernetesCluster_addonProfileIngressApplicationGateway_subnetCIDR(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccKubernetesCluster_addonProfileIngressApplicationGateway_subnetCIDR(t) +} + +func testAccKubernetesCluster_addonProfileIngressApplicationGateway_subnetCIDR(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + r := KubernetesClusterResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.addonProfileIngressApplicationGatewaySubnetCIDRConfig(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.effective_gateway_id").Exists(), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.subnet_cidr").HasValue(addOnAppGatewaySubnetCIDR), + ), + }, + data.ImportStep(), + { + Config: r.addonProfileIngressApplicationGatewayDisabledConfig(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.#").HasValue("1"), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.enabled").HasValue("false"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccKubernetesCluster_addonProfileIngressApplicationGateway_subnetId(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccKubernetesCluster_addonProfileIngressApplicationGateway_subnetId(t) +} + +func testAccKubernetesCluster_addonProfileIngressApplicationGateway_subnetId(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + r := KubernetesClusterResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.addonProfileIngressApplicationGatewaySubnetIdConfig(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.effective_gateway_id").Exists(), + ), + }, + data.ImportStep(), + }) +} + func (KubernetesClusterResource) addonProfileAciConnectorLinuxConfig(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { @@ -727,3 +808,284 @@ resource "azurerm_kubernetes_cluster" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) } + +func (KubernetesClusterResource) addonProfileIngressApplicationGatewayAppGatewayConfig(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-aks-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvirtnet%d" + address_space = ["172.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "acctestsubnet%d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["172.0.2.0/24"] +} + +resource "azurerm_public_ip" "test" { + name = "acctestpublicip%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + sku = "Standard" + allocation_method = "Static" +} + +resource "azurerm_application_gateway" "test" { + name = "acctestappgw%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + sku { + name = "Standard_V2" + tier = "Standard_V2" + capacity = 2 + } + + gateway_ip_configuration { + name = "gwipcfg" + subnet_id = azurerm_subnet.test.id + } + + frontend_port { + name = "frontendport" + port = 80 + } + + frontend_ip_configuration { + name = "frontendipcfg" + public_ip_address_id = azurerm_public_ip.test.id + } + + backend_address_pool { + name = "backendaddresspool" + } + + backend_http_settings { + name = "backendhttpsettings" + cookie_based_affinity = "Disabled" + port = 80 + protocol = "Http" + request_timeout = 60 + } + + http_listener { + name = "httplistener" + frontend_ip_configuration_name = "frontendipcfg" + frontend_port_name = "frontendport" + protocol = "Http" + } + + request_routing_rule { + name = "requestroutingrule" + rule_type = "Basic" + http_listener_name = "httplistener" + backend_address_pool_name = "backendaddresspool" + backend_http_settings_name = "backendhttpsettings" + } +} + +resource "azurerm_kubernetes_cluster" "test" { + name = "acctestaks%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + dns_prefix = "acctestaks%d" + + linux_profile { + admin_username = "acctestuser%d" + + ssh_key { + key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld" + } + } + + default_node_pool { + name = "default" + node_count = 1 + vm_size = "Standard_DS2_v2" + } + + addon_profile { + ingress_application_gateway { + enabled = true + gateway_id = azurerm_application_gateway.test.id + } + kube_dashboard { + enabled = false + } + } + + identity { + type = "SystemAssigned" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + +func (KubernetesClusterResource) addonProfileIngressApplicationGatewaySubnetCIDRConfig(data acceptance.TestData) 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 = "acctestaks%d" + + linux_profile { + admin_username = "acctestuser%d" + + ssh_key { + key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld" + } + } + + default_node_pool { + name = "default" + node_count = 1 + vm_size = "Standard_DS2_v2" + } + + addon_profile { + ingress_application_gateway { + enabled = true + subnet_cidr = "%s" + } + kube_dashboard { + enabled = false + } + } + + identity { + type = "SystemAssigned" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, addOnAppGatewaySubnetCIDR) +} + +func (KubernetesClusterResource) addonProfileIngressApplicationGatewayDisabledConfig(data acceptance.TestData) 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 = "acctestaks%d" + + linux_profile { + admin_username = "acctestuser%d" + + ssh_key { + key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld" + } + } + + default_node_pool { + name = "default" + node_count = 1 + vm_size = "Standard_DS2_v2" + } + + addon_profile { + ingress_application_gateway { + enabled = false + } + kube_dashboard { + enabled = false + } + } + + identity { + type = "SystemAssigned" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + +func (KubernetesClusterResource) addonProfileIngressApplicationGatewaySubnetIdConfig(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-aks-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvirtnet%d" + address_space = ["172.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "acctestsubnet%d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["172.0.2.0/24"] +} + +resource "azurerm_kubernetes_cluster" "test" { + name = "acctestaks%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + dns_prefix = "acctestaks%d" + + linux_profile { + admin_username = "acctestuser%d" + + ssh_key { + key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld" + } + } + + default_node_pool { + name = "default" + node_count = 1 + vm_size = "Standard_DS2_v2" + } + + addon_profile { + ingress_application_gateway { + enabled = true + subnet_id = azurerm_subnet.test.id + } + kube_dashboard { + enabled = false + } + } + + identity { + type = "SystemAssigned" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} diff --git a/azurerm/internal/services/containers/kubernetes_cluster_data_source.go b/azurerm/internal/services/containers/kubernetes_cluster_data_source.go index 0c992dd08f24..eab61a05bb33 100644 --- a/azurerm/internal/services/containers/kubernetes_cluster_data_source.go +++ b/azurerm/internal/services/containers/kubernetes_cluster_data_source.go @@ -118,6 +118,35 @@ func dataSourceKubernetesCluster() *schema.Resource { }, }, }, + + "ingress_application_gateway": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "gateway_id": { + Type: schema.TypeString, + Computed: true, + }, + "effective_gateway_id": { + Type: schema.TypeString, + Computed: true, + }, + "subnet_cidr": { + Type: schema.TypeString, + Computed: true, + }, + "subnet_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, }, }, }, @@ -827,6 +856,44 @@ func flattenKubernetesClusterDataSourceAddonProfiles(profile map[string]*contain } values["azure_policy"] = azurePolicies + ingressApplicationGateways := make([]interface{}, 0) + if ingressApplicationGateway := kubernetesAddonProfileLocate(profile, ingressApplicationGatewayKey); ingressApplicationGateway != nil { + enabled := false + if enabledVal := ingressApplicationGateway.Enabled; enabledVal != nil { + enabled = *enabledVal + } + + gatewayId := "" + if v := kubernetesAddonProfilelocateInConfig(ingressApplicationGateway.Config, "applicationGatewayId"); v != nil { + gatewayId = *v + } + + effectiveGatewayId := "" + if v := kubernetesAddonProfilelocateInConfig(ingressApplicationGateway.Config, "effectiveApplicationGatewayId"); v != nil { + effectiveGatewayId = *v + } + + subnetCIDR := "" + if v := kubernetesAddonProfilelocateInConfig(ingressApplicationGateway.Config, "subnetCIDR"); v != nil { + subnetCIDR = *v + } + + subnetId := "" + if v := kubernetesAddonProfilelocateInConfig(ingressApplicationGateway.Config, "subnetId"); v != nil { + subnetId = *v + } + + output := map[string]interface{}{ + "enabled": enabled, + "gateway_id": gatewayId, + "effective_gateway_id": effectiveGatewayId, + "subnet_cidr": subnetCIDR, + "subnet_id": subnetId, + } + ingressApplicationGateways = append(ingressApplicationGateways, output) + } + values["ingress_application_gateway"] = ingressApplicationGateways + return []interface{}{values} } diff --git a/azurerm/internal/services/containers/kubernetes_cluster_data_source_test.go b/azurerm/internal/services/containers/kubernetes_cluster_data_source_test.go index d6dbaf2f3b43..5bbeb9f0f2fc 100644 --- a/azurerm/internal/services/containers/kubernetes_cluster_data_source_test.go +++ b/azurerm/internal/services/containers/kubernetes_cluster_data_source_test.go @@ -14,27 +14,30 @@ type KubernetesClusterDataSource struct { } var kubernetesDataSourceTests = map[string]func(t *testing.T){ - "basic": testAccDataSourceKubernetesCluster_basic, - "roleBasedAccessControl": testAccDataSourceKubernetesCluster_roleBasedAccessControl, - "roleBasedAccessControlAAD": testAccDataSourceKubernetesCluster_roleBasedAccessControlAAD, - "internalNetwork": testAccDataSourceKubernetesCluster_internalNetwork, - "advancedNetworkingAzure": testAccDataSourceKubernetesCluster_advancedNetworkingAzure, - "advancedNetworkingAzureCalicoPolicy": testAccDataSourceKubernetesCluster_advancedNetworkingAzureCalicoPolicy, - "advancedNetworkingAzureNPMPolicy": testAccDataSourceKubernetesCluster_advancedNetworkingAzureNPMPolicy, - "advancedNetworkingAzureComplete": testAccDataSourceKubernetesCluster_advancedNetworkingAzureComplete, - "advancedNetworkingAzureCalicoPolicyComplete": testAccDataSourceKubernetesCluster_advancedNetworkingAzureCalicoPolicyComplete, - "advancedNetworkingAzureNPMPolicyComplete": testAccDataSourceKubernetesCluster_advancedNetworkingAzureNPMPolicyComplete, - "advancedNetworkingKubenet": testAccDataSourceKubernetesCluster_advancedNetworkingKubenet, - "advancedNetworkingKubenetComplete": testAccDataSourceKubernetesCluster_advancedNetworkingKubenetComplete, - "addOnProfileOMS": testAccDataSourceKubernetesCluster_addOnProfileOMS, - "addOnProfileKubeDashboard": testAccDataSourceKubernetesCluster_addOnProfileKubeDashboard, - "addOnProfileAzurePolicy": testAccDataSourceKubernetesCluster_addOnProfileAzurePolicy, - "addOnProfileRouting": testAccDataSourceKubernetesCluster_addOnProfileRouting, - "autoscalingNoAvailabilityZones": testAccDataSourceKubernetesCluster_autoscalingNoAvailabilityZones, - "autoscalingWithAvailabilityZones": testAccDataSourceKubernetesCluster_autoscalingWithAvailabilityZones, - "nodeLabels": testAccDataSourceKubernetesCluster_nodeLabels, - "enableNodePublicIP": testAccDataSourceKubernetesCluster_enableNodePublicIP, - "privateCluster": testAccDataSourceKubernetesCluster_privateCluster, + "basic": testAccDataSourceKubernetesCluster_basic, + "roleBasedAccessControl": testAccDataSourceKubernetesCluster_roleBasedAccessControl, + "roleBasedAccessControlAAD": testAccDataSourceKubernetesCluster_roleBasedAccessControlAAD, + "internalNetwork": testAccDataSourceKubernetesCluster_internalNetwork, + "advancedNetworkingAzure": testAccDataSourceKubernetesCluster_advancedNetworkingAzure, + "advancedNetworkingAzureCalicoPolicy": testAccDataSourceKubernetesCluster_advancedNetworkingAzureCalicoPolicy, + "advancedNetworkingAzureNPMPolicy": testAccDataSourceKubernetesCluster_advancedNetworkingAzureNPMPolicy, + "advancedNetworkingAzureComplete": testAccDataSourceKubernetesCluster_advancedNetworkingAzureComplete, + "advancedNetworkingAzureCalicoPolicyComplete": testAccDataSourceKubernetesCluster_advancedNetworkingAzureCalicoPolicyComplete, + "advancedNetworkingAzureNPMPolicyComplete": testAccDataSourceKubernetesCluster_advancedNetworkingAzureNPMPolicyComplete, + "advancedNetworkingKubenet": testAccDataSourceKubernetesCluster_advancedNetworkingKubenet, + "advancedNetworkingKubenetComplete": testAccDataSourceKubernetesCluster_advancedNetworkingKubenetComplete, + "addOnProfileOMS": testAccDataSourceKubernetesCluster_addOnProfileOMS, + "addOnProfileKubeDashboard": testAccDataSourceKubernetesCluster_addOnProfileKubeDashboard, + "addOnProfileAzurePolicy": testAccDataSourceKubernetesCluster_addOnProfileAzurePolicy, + "addOnProfileRouting": testAccDataSourceKubernetesCluster_addOnProfileRouting, + "addOnProfileIngressApplicationGateewayAppGateway": testAccDataSourceKubernetesCluster_addOnProfileIngressApplicationGatewayAppGateway, + "addOnProfileIngressApplicationGateewaySubnetCIDR": testAccDataSourceKubernetesCluster_addOnProfileIngressApplicationGatewaySubnetCIDR, + "addOnProfileIngressApplicationGateewaySubnetId": testAccDataSourceKubernetesCluster_addOnProfileIngressApplicationGatewaySubnetId, + "autoscalingNoAvailabilityZones": testAccDataSourceKubernetesCluster_autoscalingNoAvailabilityZones, + "autoscalingWithAvailabilityZones": testAccDataSourceKubernetesCluster_autoscalingWithAvailabilityZones, + "nodeLabels": testAccDataSourceKubernetesCluster_nodeLabels, + "enableNodePublicIP": testAccDataSourceKubernetesCluster_enableNodePublicIP, + "privateCluster": testAccDataSourceKubernetesCluster_privateCluster, } func TestAccDataSourceKubernetesCluster_basic(t *testing.T) { @@ -450,6 +453,79 @@ func testAccDataSourceKubernetesCluster_addOnProfileRouting(t *testing.T) { }) } +func TestAccDataSourceKubernetesCluster_addOnProfileIngressApplicationGatewayAppGateway(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccDataSourceKubernetesCluster_addOnProfileIngressApplicationGatewayAppGateway(t) +} + +func testAccDataSourceKubernetesCluster_addOnProfileIngressApplicationGatewayAppGateway(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_kubernetes_cluster", "test") + r := KubernetesClusterDataSource{} + + data.DataSourceTest(t, []resource.TestStep{ + { + Config: r.addOnProfileIngressApplicationGatewayAppGatewayConfig(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("addon_profile.#").HasValue("1"), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.#").HasValue("1"), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.enabled").HasValue("true"), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.effective_gateway_id").MatchesOtherKey( + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.gateway_id"), + ), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.subnet_cidr").IsEmpty(), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.subnet_id").IsEmpty(), + ), + }, + }) +} + +func TestAccDataSourceKubernetesCluster_addOnProfileIngressApplicationGatewaySubnetCIDR(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccDataSourceKubernetesCluster_addOnProfileIngressApplicationGatewaySubnetCIDR(t) +} + +func testAccDataSourceKubernetesCluster_addOnProfileIngressApplicationGatewaySubnetCIDR(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_kubernetes_cluster", "test") + r := KubernetesClusterDataSource{} + + data.DataSourceTest(t, []resource.TestStep{ + { + Config: r.addOnProfileIngressApplicationGatewaySubnetCIDRConfig(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("addon_profile.#").HasValue("1"), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.#").HasValue("1"), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.enabled").HasValue("true"), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.gateway_id").IsEmpty(), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.subnet_cidr").HasValue(addOnAppGatewaySubnetCIDR), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.subnet_id").IsEmpty(), + ), + }, + }) +} + +func TestAccDataSourceKubernetesCluster_addOnProfileIngressApplicationGatewaySubnetId(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccDataSourceKubernetesCluster_addOnProfileIngressApplicationGatewaySubnetId(t) +} + +func testAccDataSourceKubernetesCluster_addOnProfileIngressApplicationGatewaySubnetId(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_kubernetes_cluster", "test") + r := KubernetesClusterDataSource{} + + data.DataSourceTest(t, []resource.TestStep{ + { + Config: r.addOnProfileIngressApplicationGatewaySubnetIdConfig(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("addon_profile.#").HasValue("1"), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.#").HasValue("1"), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.enabled").HasValue("true"), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.gateway_id").IsEmpty(), + check.That(data.ResourceName).Key("addon_profile.0.ingress_application_gateway.0.subnet_cidr").IsEmpty(), + ), + }, + }) +} + func TestAccDataSourceKubernetesCluster_autoscalingNoAvailabilityZones(t *testing.T) { checkIfShouldRunTestsIndividually(t) testAccDataSourceKubernetesCluster_autoscalingNoAvailabilityZones(t) @@ -713,6 +789,39 @@ data "azurerm_kubernetes_cluster" "test" { `, KubernetesClusterResource{}.addonProfileRoutingConfig(data)) } +func (KubernetesClusterDataSource) addOnProfileIngressApplicationGatewayAppGatewayConfig(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_kubernetes_cluster" "test" { + name = azurerm_kubernetes_cluster.test.name + resource_group_name = azurerm_kubernetes_cluster.test.resource_group_name +} +`, KubernetesClusterResource{}.addonProfileIngressApplicationGatewayAppGatewayConfig(data)) +} + +func (KubernetesClusterDataSource) addOnProfileIngressApplicationGatewaySubnetCIDRConfig(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_kubernetes_cluster" "test" { + name = azurerm_kubernetes_cluster.test.name + resource_group_name = azurerm_kubernetes_cluster.test.resource_group_name +} +`, KubernetesClusterResource{}.addonProfileIngressApplicationGatewaySubnetCIDRConfig(data)) +} + +func (KubernetesClusterDataSource) addOnProfileIngressApplicationGatewaySubnetIdConfig(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_kubernetes_cluster" "test" { + name = azurerm_kubernetes_cluster.test.name + resource_group_name = azurerm_kubernetes_cluster.test.resource_group_name +} +`, KubernetesClusterResource{}.addonProfileIngressApplicationGatewaySubnetIdConfig(data)) +} + func (KubernetesClusterDataSource) autoScalingNoAvailabilityZonesConfig(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/website/docs/d/kubernetes_cluster.html.markdown b/website/docs/d/kubernetes_cluster.html.markdown index c7f24dcf5edb..7c59b1a7a415 100644 --- a/website/docs/d/kubernetes_cluster.html.markdown +++ b/website/docs/d/kubernetes_cluster.html.markdown @@ -98,6 +98,8 @@ A `addon_profile` block exports the following: * `azure_policy` - A `azure_policy` block. +* `ingress_application_gateway` - An `ingress_application_gateway` block. + --- A `agent_pool_profile` block exports the following: @@ -256,6 +258,18 @@ A `azure_policy` block supports the following: * `enabled` - Is Azure Policy for Kubernetes enabled? +An `ingress_application_gateway` block supports the following: + +* `enabled` - Is the Application Gateway ingress controller integrated with this Kubernetes Cluster? + +* `effective_gateway_id` - The ID of the Application Gateway associated with the ingress controller deployed to this Kubernetes Cluster. + +* `gateway_id` - The ID of the Application Gateway integrated with the ingress controller of this Kubernetes Cluster. This attribute is only set when gateway_id is specified when configuring the `ingress_application_gateway` addon. + +* `subnet_cidr` - The subnet CIDR used to create an Application Gateway, which in turn will be integrated with the ingress controller of this Kubernetes Cluster. This attribute is only set when `subnet_cidr` is specified when configuring the `ingress_application_gateway` addon. + +* `subnet_id` - The ID of the subnet on which to create an Application Gateway, which in turn will be integrated with the ingress controller of this Kubernetes Cluster. This attribute is only set when `subnet_id` is specified when configuring the `ingress_application_gateway` addon. + --- A `role_based_access_control` block exports the following: diff --git a/website/docs/r/kubernetes_cluster.html.markdown b/website/docs/r/kubernetes_cluster.html.markdown index 4955d28487e3..9badcfb789f8 100644 --- a/website/docs/r/kubernetes_cluster.html.markdown +++ b/website/docs/r/kubernetes_cluster.html.markdown @@ -215,6 +215,8 @@ A `addon_profile` block supports the following: * `oms_agent` - (Optional) A `oms_agent` block as defined below. For more details, please visit [How to onboard Azure Monitor for containers](https://docs.microsoft.com/en-us/azure/monitoring/monitoring-container-insights-onboard). +* `ingress_application_gateway` - (Optional) An `ingress_application_gateway` block as defined below. + --- A `auto_scaler_profile` block supports the following: @@ -432,6 +434,18 @@ A `oms_agent` block supports the following: --- +An `ingress_application_gateway` block supports the following: + +* `enabled` - (Required) Whether to deploy the Application Gateway ingress controller to this Kubernetes Cluster? + +* `gateway_id` - (Optional) The ID of the Application Gateway to integrate with the ingress controller of this Kubernetes Cluster. See [this](https://docs.microsoft.com/en-us/azure/application-gateway/tutorial-ingress-controller-add-on-existing) page for further details. + +* `subnet_cidr` - (Optional) The subnet CIDR to be used to create an Application Gateway, which in turn will be integrated with the ingress controller of this Kubernetes Cluster. See [this](https://docs.microsoft.com/en-us/azure/application-gateway/tutorial-ingress-controller-add-on-new) page for further details. + +* `subnet_id` - (Optional) The ID of the subnet on which to create an Application Gateway, which in turn will be integrated with the ingress controller of this Kubernetes Cluster. See [this](https://docs.microsoft.com/en-us/azure/application-gateway/tutorial-ingress-controller-add-on-new) page for further details. + +--- + A `role_based_access_control` block supports the following: * `azure_active_directory` - (Optional) An `azure_active_directory` block. @@ -492,6 +506,8 @@ The following attributes are exported: * `kubelet_identity` - A `kubelet_identity` block as defined below. +* `addon_profile` - An `addon_profile` block as defined below. + --- A `http_application_routing` block exports the following: @@ -567,6 +583,18 @@ provider "kubernetes" { } ``` +--- + +The `addon_profile` block exports the following: + +* `ingress_application_gateway` - An `ingress_application_gateway` block as defined below. + +--- + +The `ingress_application_gateway` block exports the following: + +* `effective_gateway_id` - The ID of the Application Gateway associated with the ingress controller deployed to this Kubernetes Cluster. + ## Timeouts The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: