From 8038e49503b5f1ee2057d478ec7026d6871a61db Mon Sep 17 00:00:00 2001 From: Even Holthe Date: Fri, 24 Jan 2020 21:40:07 +0100 Subject: [PATCH] Improvement: `azurerm_kubernetes_cluster` - Add support for `load_balancer_profile` (#5394) --- .../resource_arm_kubernetes_cluster.go | 194 +++++++- ...rce_arm_kubernetes_cluster_network_test.go | 466 ++++++++++++++++++ .../resource_arm_kubernetes_cluster_test.go | 5 + .../docs/r/kubernetes_cluster.html.markdown | 20 + 4 files changed, 670 insertions(+), 15 deletions(-) diff --git a/azurerm/internal/services/containers/resource_arm_kubernetes_cluster.go b/azurerm/internal/services/containers/resource_arm_kubernetes_cluster.go index ee48956fbca0..e0ca72a6cd5f 100644 --- a/azurerm/internal/services/containers/resource_arm_kubernetes_cluster.go +++ b/azurerm/internal/services/containers/resource_arm_kubernetes_cluster.go @@ -415,6 +415,54 @@ func resourceArmKubernetesCluster() *schema.Resource { }, true), DiffSuppressFunc: suppress.CaseDifference, }, + "load_balancer_profile": { + Type: schema.TypeList, + MaxItems: 1, + ForceNew: true, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "managed_outbound_ip_count": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(1, 100), + ConflictsWith: []string{"network_profile.0.load_balancer_profile.0.outbound_ip_prefix_ids", "network_profile.0.load_balancer_profile.0.outbound_ip_address_ids"}, + }, + "outbound_ip_prefix_ids": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ConfigMode: schema.SchemaConfigModeAttr, + ConflictsWith: []string{"network_profile.0.load_balancer_profile.0.managed_outbound_ip_count", "network_profile.0.load_balancer_profile.0.outbound_ip_address_ids"}, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: azure.ValidateResourceID, + }, + }, + "outbound_ip_address_ids": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + ConfigMode: schema.SchemaConfigModeAttr, + ConflictsWith: []string{"network_profile.0.load_balancer_profile.0.managed_outbound_ip_count", "network_profile.0.load_balancer_profile.0.outbound_ip_prefix_ids"}, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: azure.ValidateResourceID, + }, + }, + "effective_outbound_ips": { + Type: schema.TypeSet, + Computed: true, + ConfigMode: schema.SchemaConfigModeAttr, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, }, }, }, @@ -650,7 +698,10 @@ func resourceArmKubernetesClusterCreate(d *schema.ResourceData, meta interface{} addonProfiles := ExpandKubernetesAddOnProfiles(addOnProfilesRaw) networkProfileRaw := d.Get("network_profile").([]interface{}) - networkProfile := expandKubernetesClusterNetworkProfile(networkProfileRaw) + networkProfile, err := expandKubernetesClusterNetworkProfile(networkProfileRaw) + if err != nil { + return err + } rbacRaw := d.Get("role_based_access_control").([]interface{}) rbacEnabled, azureADProfile := expandKubernetesClusterRoleBasedAccessControl(rbacRaw, tenantId) @@ -844,7 +895,11 @@ func resourceArmKubernetesClusterUpdate(d *schema.ResourceData, meta interface{} if d.HasChange("network_profile") { updateCluster = true networkProfileRaw := d.Get("network_profile").([]interface{}) - networkProfile := expandKubernetesClusterNetworkProfile(networkProfileRaw) + networkProfile, err := expandKubernetesClusterNetworkProfile(networkProfileRaw) + if err != nil { + return err + } + existing.ManagedClusterProperties.NetworkProfile = networkProfile } @@ -1376,9 +1431,9 @@ func flattenKubernetesClusterWindowsProfile(profile *containerservice.ManagedClu } } -func expandKubernetesClusterNetworkProfile(input []interface{}) *containerservice.NetworkProfileType { +func expandKubernetesClusterNetworkProfile(input []interface{}) (*containerservice.NetworkProfileType, error) { if len(input) == 0 { - return nil + return nil, nil } config := input[0].(map[string]interface{}) @@ -1387,10 +1442,16 @@ func expandKubernetesClusterNetworkProfile(input []interface{}) *containerservic networkPolicy := config["network_policy"].(string) loadBalancerSku := config["load_balancer_sku"].(string) + loadBalancerProfile, err := expandLoadBalancerProfile(config["load_balancer_profile"].([]interface{}), loadBalancerSku) + if err != nil { + return nil, err + } + networkProfile := containerservice.NetworkProfileType{ - NetworkPlugin: containerservice.NetworkPlugin(networkPlugin), - NetworkPolicy: containerservice.NetworkPolicy(networkPolicy), - LoadBalancerSku: containerservice.LoadBalancerSku(loadBalancerSku), + NetworkPlugin: containerservice.NetworkPlugin(networkPlugin), + NetworkPolicy: containerservice.NetworkPolicy(networkPolicy), + LoadBalancerSku: containerservice.LoadBalancerSku(loadBalancerSku), + LoadBalancerProfile: loadBalancerProfile, } if v, ok := config["dns_service_ip"]; ok && v.(string) != "" { @@ -1413,7 +1474,83 @@ func expandKubernetesClusterNetworkProfile(input []interface{}) *containerservic networkProfile.ServiceCidr = utils.String(serviceCidr) } - return &networkProfile + return &networkProfile, nil +} + +func expandLoadBalancerProfile(d []interface{}, loadBalancerType string) (*containerservice.ManagedClusterLoadBalancerProfile, error) { + if len(d) == 0 || d[0] == nil { + return nil, nil + } + + if strings.ToLower(loadBalancerType) != "standard" { + return nil, fmt.Errorf("Only load balancer SKU 'Standard' supports load balancer profiles. Provided load balancer type: %s", loadBalancerType) + } + + config := d[0].(map[string]interface{}) + + var managedOutboundIps *containerservice.ManagedClusterLoadBalancerProfileManagedOutboundIPs + var outboundIpPrefixes *containerservice.ManagedClusterLoadBalancerProfileOutboundIPPrefixes + var outboundIps *containerservice.ManagedClusterLoadBalancerProfileOutboundIPs + + if ipCount := config["managed_outbound_ip_count"]; ipCount != nil { + if c := int32(ipCount.(int)); c > 0 { + managedOutboundIps = &containerservice.ManagedClusterLoadBalancerProfileManagedOutboundIPs{Count: &c} + } + } + + if ipPrefixes := idsToResourceReferences(config["outbound_ip_prefix_ids"]); ipPrefixes != nil { + outboundIpPrefixes = &containerservice.ManagedClusterLoadBalancerProfileOutboundIPPrefixes{PublicIPPrefixes: ipPrefixes} + } + + if outIps := idsToResourceReferences(config["outbound_ip_address_ids"]); outIps != nil { + outboundIps = &containerservice.ManagedClusterLoadBalancerProfileOutboundIPs{PublicIPs: outIps} + } + + return &containerservice.ManagedClusterLoadBalancerProfile{ + ManagedOutboundIPs: managedOutboundIps, + OutboundIPPrefixes: outboundIpPrefixes, + OutboundIPs: outboundIps, + }, nil +} + +func idsToResourceReferences(set interface{}) *[]containerservice.ResourceReference { + if set == nil { + return nil + } + + s := set.(*schema.Set) + results := make([]containerservice.ResourceReference, 0) + + for _, element := range s.List() { + id := element.(string) + results = append(results, containerservice.ResourceReference{ID: &id}) + } + + if len(results) > 0 { + return &results + } + + return nil +} + +func resourceReferencesToIds(refs *[]containerservice.ResourceReference) []string { + if refs == nil { + return nil + } + + ids := make([]string, 0) + + for _, ref := range *refs { + if ref.ID != nil { + ids = append(ids, *ref.ID) + } + } + + if len(ids) > 0 { + return ids + } + + return nil } func flattenKubernetesClusterNetworkProfile(profile *containerservice.NetworkProfileType) []interface{} { @@ -1441,15 +1578,42 @@ func flattenKubernetesClusterNetworkProfile(profile *containerservice.NetworkPro podCidr = *profile.PodCidr } + lbProfiles := make([]interface{}, 0) + if lbp := profile.LoadBalancerProfile; lbp != nil { + lb := make(map[string]interface{}) + + if ips := lbp.ManagedOutboundIPs; ips != nil { + if count := ips.Count; count != nil { + lb["managed_outbound_ip_count"] = count + } + } + + if oip := lbp.OutboundIPs; oip != nil { + if poip := oip.PublicIPs; poip != nil { + lb["outbound_ip_address_ids"] = resourceReferencesToIds(poip) + } + } + + if oip := lbp.OutboundIPPrefixes; oip != nil { + if pip := oip.PublicIPPrefixes; pip != nil { + lb["outbound_ip_prefix_ids"] = resourceReferencesToIds(pip) + } + } + + lb["effective_outbound_ips"] = resourceReferencesToIds(profile.LoadBalancerProfile.EffectiveOutboundIPs) + lbProfiles = append(lbProfiles, lb) + } + return []interface{}{ map[string]interface{}{ - "dns_service_ip": dnsServiceIP, - "docker_bridge_cidr": dockerBridgeCidr, - "load_balancer_sku": string(profile.LoadBalancerSku), - "network_plugin": string(profile.NetworkPlugin), - "network_policy": string(profile.NetworkPolicy), - "pod_cidr": podCidr, - "service_cidr": serviceCidr, + "dns_service_ip": dnsServiceIP, + "docker_bridge_cidr": dockerBridgeCidr, + "load_balancer_sku": string(profile.LoadBalancerSku), + "load_balancer_profile": lbProfiles, + "network_plugin": string(profile.NetworkPlugin), + "network_policy": string(profile.NetworkPolicy), + "pod_cidr": podCidr, + "service_cidr": serviceCidr, }, } } 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 c2dd1a2facc1..1e40fe777f51 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 @@ -3,6 +3,7 @@ package tests import ( "fmt" "os" + "regexp" "testing" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" @@ -435,6 +436,146 @@ func testAccAzureRMKubernetesCluster_standardLoadBalancerComplete(t *testing.T) }) } +func TestAccAzureRMKubernetesCluster_standardLoadBalancerProfile(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccAzureRMKubernetesCluster_standardLoadBalancerProfile(t) +} + +func testAccAzureRMKubernetesCluster_standardLoadBalancerProfile(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + clientId := os.Getenv("ARM_CLIENT_ID") + clientSecret := os.Getenv("ARM_CLIENT_SECRET") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMKubernetesClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMKubernetesCluster_standardLoadBalancerProfileConfig(data, clientId, clientSecret), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKubernetesClusterExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "network_profile.0.load_balancer_sku", "Standard"), + resource.TestCheckResourceAttr(data.ResourceName, "network_profile.0.load_balancer_profile.0.managed_outbound_ip_count", "3"), + resource.TestCheckResourceAttr(data.ResourceName, "network_profile.0.load_balancer_profile.0.effective_outbound_ips.#", "3"), + ), + }, + }, + }) +} + +func TestAccAzureRMKubernetesCluster_standardLoadBalancerProfileComplete(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccAzureRMKubernetesCluster_standardLoadBalancerProfileComplete(t) +} + +func testAccAzureRMKubernetesCluster_standardLoadBalancerProfileComplete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + clientId := os.Getenv("ARM_CLIENT_ID") + clientSecret := os.Getenv("ARM_CLIENT_SECRET") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMKubernetesClusterDestroy, + PreventPostDestroyRefresh: true, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMKubernetesCluster_standardLoadBalancerProfileCompleteConfig(data, clientId, clientSecret), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKubernetesClusterExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "network_profile.0.load_balancer_sku", "Standard"), + resource.TestCheckResourceAttr(data.ResourceName, "network_profile.0.load_balancer_profile.0.effective_outbound_ips.#", "1"), + ), + }, + }, + }) +} + +func TestAccAzureRMKubernetesCluster_basicLoadBalancerProfile(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccAzureRMKubernetesCluster_basicLoadBalancerProfile(t) +} + +func testAccAzureRMKubernetesCluster_basicLoadBalancerProfile(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + clientId := os.Getenv("ARM_CLIENT_ID") + clientSecret := os.Getenv("ARM_CLIENT_SECRET") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMKubernetesClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMKubernetesCluster_basicLoadBalancerProfileConfig(data, clientId, clientSecret), + ExpectError: regexp.MustCompile("errors during apply: Only load balancer SKU 'Standard' supports load balancer profiles. Provided load balancer type: basic"), + }, + }, + }) +} + +func TestAccAzureRMKubernetesCluster_conflictingLoadBalancerProfile(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccAzureRMKubernetesCluster_conflictingLoadBalancerProfile(t) +} + +func testAccAzureRMKubernetesCluster_conflictingLoadBalancerProfile(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + clientId := os.Getenv("ARM_CLIENT_ID") + clientSecret := os.Getenv("ARM_CLIENT_SECRET") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMKubernetesClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMKubernetesCluster_conflictingLoadBalancerProfileConfig(data, clientId, clientSecret), + ExpectError: regexp.MustCompile(`- "network_profile.0.load_balancer_profile.0.managed_outbound_ip_count": conflicts with network_profile.0.load_balancer_profile.0.outbound_ip_address_ids`), + }, + { + ResourceName: "azurerm_public_ip.test", + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: "azurerm_public_ip.test2", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMKubernetesCluster_prefixedLoadBalancerProfile(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccAzureRMKubernetesCluster_prefixedLoadBalancerProfile(t) +} + +func testAccAzureRMKubernetesCluster_prefixedLoadBalancerProfile(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + clientId := os.Getenv("ARM_CLIENT_ID") + clientSecret := os.Getenv("ARM_CLIENT_SECRET") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMKubernetesClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMKubernetesCluster_prefixedLoadBalancerProfileConfig(data, clientId, clientSecret), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMKubernetesClusterExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "network_profile.0.load_balancer_sku", "Standard"), + resource.TestCheckResourceAttr(data.ResourceName, "network_profile.0.load_balancer_profile.0.outbound_ip_prefix_ids.#", "1"), + resource.TestCheckResourceAttr(data.ResourceName, "network_profile.0.load_balancer_profile.0.effective_outbound_ips.#", "1"), + ), + }, + }, + }) +} + func testAccAzureRMKubernetesCluster_advancedNetworkingConfig(data acceptance.TestData, clientId string, clientSecret string, location string, networkPlugin string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { @@ -966,3 +1107,328 @@ resource "azurerm_kubernetes_cluster" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, currentKubernetesVersion, data.RandomInteger, clientId, clientSecret) } + +func testAccAzureRMKubernetesCluster_standardLoadBalancerProfileConfig(data acceptance.TestData, clientId string, clientSecret string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +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 = "acctestsubnet%d" + 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_kubernetes_cluster" "test" { + name = "acctestaks%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + dns_prefix = "acctestaks%d" + kubernetes_version = "%s" + + 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 = 2 + vm_size = "Standard_DS2_v2" + vnet_subnet_id = azurerm_subnet.test.id + } + + service_principal { + client_id = "%s" + client_secret = "%s" + } + + network_profile { + network_plugin = "azure" + load_balancer_sku = "Standard" + load_balancer_profile { + managed_outbound_ip_count = 3 + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, currentKubernetesVersion, data.RandomInteger, clientId, clientSecret) +} + +func testAccAzureRMKubernetesCluster_standardLoadBalancerProfileCompleteConfig(data acceptance.TestData, clientId string, clientSecret string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +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 = "acctestsubnet%d" + 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_public_ip" "test" { + name = "acctestip%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" + sku = "Standard" +} + +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" + kubernetes_version = "%s" + + 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 = 2 + vm_size = "Standard_DS2_v2" + vnet_subnet_id = azurerm_subnet.test.id + } + + service_principal { + client_id = "%s" + client_secret = "%s" + } + + network_profile { + network_plugin = "azure" + load_balancer_sku = "Standard" + load_balancer_profile { + outbound_ip_address_ids = [azurerm_public_ip.test.id] + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, currentKubernetesVersion, data.RandomInteger, clientId, clientSecret) +} + +func testAccAzureRMKubernetesCluster_basicLoadBalancerProfileConfig(data acceptance.TestData, clientId string, clientSecret string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +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 = "acctestsubnet%d" + 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_kubernetes_cluster" "test" { + name = "acctestaks%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + dns_prefix = "acctestaks%d" + kubernetes_version = "%s" + + 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 = 2 + vm_size = "Standard_DS2_v2" + vnet_subnet_id = azurerm_subnet.test.id + } + + service_principal { + client_id = "%s" + client_secret = "%s" + } + + network_profile { + network_plugin = "azure" + load_balancer_sku = "basic" + load_balancer_profile { + managed_outbound_ip_count = 3 + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, currentKubernetesVersion, data.RandomInteger, clientId, clientSecret) +} + +func testAccAzureRMKubernetesCluster_conflictingLoadBalancerProfileConfig(data acceptance.TestData, clientId string, clientSecret string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +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 = "acctestsubnet%d" + 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_public_ip" "test" { + name = "acctestipone%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" +} + +resource "azurerm_public_ip" "test2" { + name = "acctestiptwo%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" +} + +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" + kubernetes_version = "%s" + + 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 = 2 + vm_size = "Standard_DS2_v2" + vnet_subnet_id = azurerm_subnet.test.id + } + + service_principal { + client_id = "%s" + client_secret = "%s" + } + + network_profile { + network_plugin = "azure" + load_balancer_sku = "standard" + load_balancer_profile { + managed_outbound_ip_count = 3 + outbound_ip_address_ids = [azurerm_public_ip.test.id, azurerm_public_ip.test2.id] + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, currentKubernetesVersion, data.RandomInteger, clientId, clientSecret) +} + +func testAccAzureRMKubernetesCluster_prefixedLoadBalancerProfileConfig(data acceptance.TestData, clientId string, clientSecret string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +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 = "acctestsubnet%d" + 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_public_ip_prefix" "test" { + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + name = "acctestipprefix%d" + prefix_length = 31 +} + +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" + kubernetes_version = "%s" + + 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 = 2 + vm_size = "Standard_DS2_v2" + vnet_subnet_id = azurerm_subnet.test.id + } + + service_principal { + client_id = "%s" + client_secret = "%s" + } + + network_profile { + network_plugin = "azure" + load_balancer_sku = "Standard" + load_balancer_profile { + outbound_ip_prefix_ids = [azurerm_public_ip_prefix.test.id] + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, currentKubernetesVersion, data.RandomInteger, clientId, clientSecret) +} 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 33c64ef8cc59..0b947d9648ce 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 @@ -52,8 +52,13 @@ func TestAccAzureRMKubernetes_all(t *testing.T) { "advancedNetworkingAzureNPMPolicyComplete": testAccAzureRMKubernetesCluster_advancedNetworkingAzureNPMPolicyComplete, "enableNodePublicIP": testAccAzureRMKubernetesCluster_enableNodePublicIP, "internalNetwork": testAccAzureRMKubernetesCluster_internalNetwork, + "basicLoadBalancerProfile": testAccAzureRMKubernetesCluster_basicLoadBalancerProfile, + "conflictingLoadBalancerProfile": testAccAzureRMKubernetesCluster_conflictingLoadBalancerProfile, + "prefixedLoadBalancerProfile": testAccAzureRMKubernetesCluster_prefixedLoadBalancerProfile, "standardLoadBalancer": testAccAzureRMKubernetesCluster_standardLoadBalancer, "standardLoadBalancerComplete": testAccAzureRMKubernetesCluster_standardLoadBalancerComplete, + "standardLoadBalancerProfile": testAccAzureRMKubernetesCluster_standardLoadBalancerProfile, + "standardLoadBalancerProfileComplete": testAccAzureRMKubernetesCluster_standardLoadBalancerProfileComplete, }, "nodePool": { "autoScale": testAccAzureRMKubernetesClusterNodePool_autoScale, diff --git a/website/docs/r/kubernetes_cluster.html.markdown b/website/docs/r/kubernetes_cluster.html.markdown index f420c64a59fa..eb93dc80d709 100644 --- a/website/docs/r/kubernetes_cluster.html.markdown +++ b/website/docs/r/kubernetes_cluster.html.markdown @@ -315,6 +315,20 @@ Examples of how to use [AKS with Advanced Networking](https://docs.microsoft.com * `load_balancer_sku` - (Optional) Specifies the SKU of the Load Balancer used for this Kubernetes Cluster. Possible values are `basic` and `standard`. Defaults to `basic`. +* `load_balancer_profile` - (Optional) A `load_balancer_profile` block. This can only be specified when `load_balancer_sku` is set to `standard`. + +--- + +A `load_balancer_profile` block supports the following: + +~> **NOTE:** These options are mutually exclusive. Note that when specifying `outbound_ip_address_ids` ([azurerm_public_ip](/docs/providers/azurerm/r/public_ip.html)) the SKU must be `Standard`. + +* `managed_outbound_ip_count` - (Optional) Count of desired managed outbound IPs for the cluster load balancer. Must be in the range of [1, 100]. + +* `outbound_ip_prefix_ids` - (Optional) The ID of the outbound Public IP Address Prefixes which should be used for the cluster load balancer. + +* `outbound_ip_address_ids` - (Optional) The ID of the Public IP Addresses which should be used for outbound communication for the cluster load balancer. + --- A `oms_agent` block supports the following: @@ -386,6 +400,12 @@ A `http_application_routing` block exports the following: --- +A `load_balancer_profile` block exports the following: + +* `effective_outbound_ips` - The outcome (resource IDs) of the specified arguments. + +--- + The `identity` block exports the following: * `principal_id` - The principal id of the system assigned identity which is used by master components.