diff --git a/azurerm/internal/services/containers/resource_arm_kubernetes_cluster.go b/azurerm/internal/services/containers/resource_arm_kubernetes_cluster.go index b872747e43d2..ce56f91aab67 100644 --- a/azurerm/internal/services/containers/resource_arm_kubernetes_cluster.go +++ b/azurerm/internal/services/containers/resource_arm_kubernetes_cluster.go @@ -226,6 +226,18 @@ func resourceArmKubernetesCluster() *schema.Resource { }, true), DiffSuppressFunc: suppress.CaseDifference, }, + + "outbound_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: string(containerservice.LoadBalancer), + ValidateFunc: validation.StringInSlice([]string{ + string(containerservice.LoadBalancer), + string(containerservice.UserDefinedRouting), + }, false), + }, + "load_balancer_profile": { Type: schema.TypeList, MaxItems: 1, @@ -1118,6 +1130,7 @@ func expandKubernetesClusterNetworkProfile(input []interface{}) (*containerservi networkPlugin := config["network_plugin"].(string) networkPolicy := config["network_policy"].(string) loadBalancerSku := config["load_balancer_sku"].(string) + outboundType := config["outbound_type"].(string) loadBalancerProfile, err := expandLoadBalancerProfile(config["load_balancer_profile"].([]interface{}), loadBalancerSku) if err != nil { @@ -1129,6 +1142,7 @@ func expandKubernetesClusterNetworkProfile(input []interface{}) (*containerservi NetworkPolicy: containerservice.NetworkPolicy(networkPolicy), LoadBalancerSku: containerservice.LoadBalancerSku(loadBalancerSku), LoadBalancerProfile: loadBalancerProfile, + OutboundType: containerservice.OutboundType(outboundType), } if v, ok := config["dns_service_ip"]; ok && v.(string) != "" { @@ -1291,6 +1305,7 @@ func flattenKubernetesClusterNetworkProfile(profile *containerservice.NetworkPro "network_policy": string(profile.NetworkPolicy), "pod_cidr": podCidr, "service_cidr": serviceCidr, + "outbound_type": string(profile.OutboundType), }, } } diff --git a/azurerm/internal/services/containers/tests/resource_arm_kubernetes_cluster_network_test.go b/azurerm/internal/services/containers/tests/resource_arm_kubernetes_cluster_network_test.go index a37cb36f7628..209c1a71948b 100644 --- a/azurerm/internal/services/containers/tests/resource_arm_kubernetes_cluster_network_test.go +++ b/azurerm/internal/services/containers/tests/resource_arm_kubernetes_cluster_network_test.go @@ -282,6 +282,54 @@ func testAccAzureRMKubernetesCluster_internalNetwork(t *testing.T) { }) } +func TestAccAzureRMKubernetesCluster_outboundTypeLoadBalancer(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccAzureRMKubernetesCluster_outboundTypeLoadBalancer(t) +} + +func testAccAzureRMKubernetesCluster_outboundTypeLoadBalancer(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMKubernetesClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMKubernetesCluster_outboundTypeLoadBalancerConfig(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKubernetesClusterExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMKubernetesCluster_outboundTypeUserDefinedRouting(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccAzureRMKubernetesCluster_outboundTypeUserDefinedRouting(t) +} + +func testAccAzureRMKubernetesCluster_outboundTypeUserDefinedRouting(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMKubernetesClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMKubernetesCluster_outboundTypeUserDefinedRoutingConfig(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKubernetesClusterExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + func TestAccAzureRMKubernetesCluster_privateLinkOn(t *testing.T) { checkIfShouldRunTestsIndividually(t) testAccAzureRMKubernetesCluster_privateLinkOn(t) @@ -842,6 +890,130 @@ resource "azurerm_kubernetes_cluster" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) } +func testAccAzureRMKubernetesCluster_outboundTypeLoadBalancerConfig(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" + + default_node_pool { + name = "default" + node_count = 2 + vm_size = "Standard_DS2_v2" + max_pods = 60 + } + + identity { + type = "SystemAssigned" + } + + network_profile { + network_plugin = "kubenet" + load_balancer_sku = "Basic" + pod_cidr = "10.244.0.0/16" + service_cidr = "10.0.0.0/16" + dns_service_ip = "10.0.0.10" + docker_bridge_cidr = "172.17.0.1/16" + outbound_type = "loadBalancer" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func testAccAzureRMKubernetesCluster_outboundTypeUserDefinedRoutingConfig(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-aks-%d" + location = "%s" +} + + + +resource "azurerm_route_table" "test" { + name = "akc-routetable-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + route { + name = "first" + address_prefix = "10.100.0.0/14" + next_hop_type = "VirtualAppliance" + next_hop_in_ip_address = "10.10.1.1" + } + + route { + name = "second" + address_prefix = "0.0.0.0/0" + next_hop_type = "VirtualAppliance" + next_hop_in_ip_address = "10.10.1.1" + } +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvirtnet%d" + address_space = ["10.1.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "internal" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefix = "10.1.0.0/24" +} + +resource "azurerm_subnet_route_table_association" "test" { + subnet_id = azurerm_subnet.test.id + route_table_id = azurerm_route_table.test.id +} + +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" + + default_node_pool { + name = "default" + node_count = 2 + vm_size = "Standard_DS2_v2" + vnet_subnet_id = azurerm_subnet.test.id + max_pods = 60 + } + + identity { + type = "SystemAssigned" + } + + network_profile { + network_plugin = "kubenet" + load_balancer_sku = "Standard" + pod_cidr = "10.244.0.0/16" + service_cidr = "10.0.0.0/16" + dns_service_ip = "10.0.0.10" + docker_bridge_cidr = "172.17.0.1/16" + outbound_type = "userDefinedRouting" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + func testAccAzureRMKubernetesCluster_privateLinkConfig(data acceptance.TestData, enablePrivateLink bool) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/azurerm/internal/services/containers/tests/resource_arm_kubernetes_cluster_test.go b/azurerm/internal/services/containers/tests/resource_arm_kubernetes_cluster_test.go index c9a9a9c18753..dcd02eedd7b9 100644 --- a/azurerm/internal/services/containers/tests/resource_arm_kubernetes_cluster_test.go +++ b/azurerm/internal/services/containers/tests/resource_arm_kubernetes_cluster_test.go @@ -79,18 +79,20 @@ func TestAccAzureRMKubernetes_all(t *testing.T) { "windowsAndLinux": testAccAzureRMKubernetesClusterNodePool_windowsAndLinux, }, "other": { - "basicAvailabilitySet": testAccAzureRMKubernetesCluster_basicAvailabilitySet, - "basicVMSS": testAccAzureRMKubernetesCluster_basicVMSS, - "requiresImport": testAccAzureRMKubernetesCluster_requiresImport, - "linuxProfile": testAccAzureRMKubernetesCluster_linuxProfile, - "nodeLabels": testAccAzureRMKubernetesCluster_nodeLabels, - "nodeTaints": testAccAzureRMKubernetesCluster_nodeTaints, - "nodeResourceGroup": testAccAzureRMKubernetesCluster_nodeResourceGroup, - "upgradeConfig": testAccAzureRMKubernetesCluster_upgrade, - "tags": testAccAzureRMKubernetesCluster_tags, - "windowsProfile": testAccAzureRMKubernetesCluster_windowsProfile, - "privateLinkOn": testAccAzureRMKubernetesCluster_privateLinkOn, - "privateLinkOff": testAccAzureRMKubernetesCluster_privateLinkOff, + "basicAvailabilitySet": testAccAzureRMKubernetesCluster_basicAvailabilitySet, + "basicVMSS": testAccAzureRMKubernetesCluster_basicVMSS, + "requiresImport": testAccAzureRMKubernetesCluster_requiresImport, + "linuxProfile": testAccAzureRMKubernetesCluster_linuxProfile, + "nodeLabels": testAccAzureRMKubernetesCluster_nodeLabels, + "nodeTaints": testAccAzureRMKubernetesCluster_nodeTaints, + "nodeResourceGroup": testAccAzureRMKubernetesCluster_nodeResourceGroup, + "upgradeConfig": testAccAzureRMKubernetesCluster_upgrade, + "tags": testAccAzureRMKubernetesCluster_tags, + "windowsProfile": testAccAzureRMKubernetesCluster_windowsProfile, + "outboundTypeLoadBalancer": testAccAzureRMKubernetesCluster_outboundTypeLoadBalancer, + "outboundTypeUserDefinedRouting": testAccAzureRMKubernetesCluster_outboundTypeUserDefinedRouting, + "privateLinkOn": testAccAzureRMKubernetesCluster_privateLinkOn, + "privateLinkOff": testAccAzureRMKubernetesCluster_privateLinkOff, }, "scaling": { "addAgent": testAccAzureRMKubernetesCluster_addAgent, diff --git a/website/docs/r/kubernetes_cluster.html.markdown b/website/docs/r/kubernetes_cluster.html.markdown index d64576d1f85c..922ae976404e 100644 --- a/website/docs/r/kubernetes_cluster.html.markdown +++ b/website/docs/r/kubernetes_cluster.html.markdown @@ -271,6 +271,8 @@ A `network_profile` block supports the following: * `docker_bridge_cidr` - (Optional) IP address (in CIDR notation) used as the Docker bridge IP address on nodes. This is required when `network_plugin` is set to `azure`. Changing this forces a new resource to be created. +* `outbound_type` - (Optional) The outbound (egress) routing method which should be used for this Kubernetes Cluster. Possible values are `loadBalancer` and `userDefinedRouting`. Defaults to `loadBalancer`. + * `pod_cidr` - (Optional) The CIDR to use for pod IP addresses. This field can only be set when `network_plugin` is set to `kubenet`. Changing this forces a new resource to be created. * `service_cidr` - (Optional) The Network Range used by the Kubernetes service. This is required when `network_plugin` is set to `azure`. Changing this forces a new resource to be created.