From 5389c518bb3d4f78421582d2d45e0f4c5054cbd8 Mon Sep 17 00:00:00 2001 From: ziyeqf Date: Tue, 22 Nov 2022 14:47:43 +0800 Subject: [PATCH] `azurerm_private_endpoint` - add `member_name` property of `ip_configuration` block, support multiple `ip_configuration` blocks. --- .../network/private_endpoint_resource.go | 15 +++- .../network/private_endpoint_resource_test.go | 79 +++++++++++++++++-- website/docs/r/private_endpoint.html.markdown | 30 ++++--- 3 files changed, 105 insertions(+), 19 deletions(-) diff --git a/internal/services/network/private_endpoint_resource.go b/internal/services/network/private_endpoint_resource.go index 95e80f476bb3..36d111cf11e7 100644 --- a/internal/services/network/private_endpoint_resource.go +++ b/internal/services/network/private_endpoint_resource.go @@ -175,7 +175,6 @@ func resourcePrivateEndpoint() *pluginsdk.Resource { "ip_configuration": { Type: pluginsdk.TypeList, Optional: true, - MaxItems: 1, Elem: &pluginsdk.Resource{ Schema: map[string]*pluginsdk.Schema{ "name": { @@ -196,6 +195,13 @@ func resourcePrivateEndpoint() *pluginsdk.Resource { ForceNew: true, ValidateFunc: validation.StringIsNotEmpty, }, + "member_name": { // TODO: set to Required, remove Computed in v4.0 + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, // to avoid breaking change, set it to `Computed`. + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, }, }, }, @@ -764,13 +770,17 @@ func expandPrivateEndpointIPConfigurations(input []interface{}) *[]network.Priva v := item.(map[string]interface{}) privateIPAddress := v["private_ip_address"].(string) subResourceName := v["subresource_name"].(string) + memberName := v["member_name"].(string) + if memberName == "" { + memberName = subResourceName + } name := v["name"].(string) result := network.PrivateEndpointIPConfiguration{ Name: utils.String(name), PrivateEndpointIPConfigurationProperties: &network.PrivateEndpointIPConfigurationProperties{ PrivateIPAddress: utils.String(privateIPAddress), GroupID: utils.String(subResourceName), - MemberName: utils.String(subResourceName), + MemberName: utils.String(memberName), }, } results = append(results, result) @@ -790,6 +800,7 @@ func flattenPrivateEndpointIPConfigurations(ipConfigurations *[]network.PrivateE "name": item.Name, "private_ip_address": item.PrivateIPAddress, "subresource_name": item.GroupID, + "member_name": item.MemberName, }) } diff --git a/internal/services/network/private_endpoint_resource_test.go b/internal/services/network/private_endpoint_resource_test.go index a7bd55273e00..d00d022ea053 100644 --- a/internal/services/network/private_endpoint_resource_test.go +++ b/internal/services/network/private_endpoint_resource_test.go @@ -307,6 +307,21 @@ func TestAccPrivateEndpoint_multipleInstances(t *testing.T) { }) } +func TestAccPrivateEndpoint_multipleIpConfigurations(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_private_endpoint", "test") + r := PrivateEndpointResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.recoveryServiceVaultWithMultiIpConfig(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (PrivateEndpointResource) template(data acceptance.TestData, seviceCfg string) string { return fmt.Sprintf(` provider "azurerm" { @@ -316,7 +331,7 @@ provider "azurerm" { data "azurerm_subscription" "current" {} resource "azurerm_resource_group" "test" { - name = "zjhe-acctestRG-privatelink-%d" + name = "acctestRG-privatelink-%d" location = "%s" } @@ -501,7 +516,7 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "zjhe-acctestRG-privatelink-%d" + name = "acctestRG-privatelink-%d" location = "%s" } @@ -581,7 +596,7 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "zjhe-acctestRG-privatelink-%d" + name = "acctestRG-privatelink-%d" location = "%s" } @@ -656,7 +671,7 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "zjhe-acctestRG-privatelink-%d" + name = "acctestRG-privatelink-%d" location = "%s" } @@ -741,7 +756,7 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "zjhe-acctestRG-privatelink-%d" + name = "acctestRG-privatelink-%d" location = "%s" } @@ -862,3 +877,57 @@ resource "azurerm_private_endpoint" "test" { } `, r.template(data, r.serviceAutoApprove(data)), count, data.RandomInteger) } + +func (r PrivateEndpointResource) recoveryServiceVaultWithMultiIpConfig(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +locals { + ip_configs = { + "SiteRecovery-prot2" = "10.5.2.24" + "SiteRecovery-srs1" = "10.5.2.25" + "SiteRecovery-id1" = "10.5.2.26" + "SiteRecovery-tel1" = "10.5.2.27" + "SiteRecovery-rcm1" = "10.5.2.28" + } +} + +resource "azurerm_recovery_services_vault" "test" { + name = "acctest-vault-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Standard" + + soft_delete_enabled = false + + identity { + type = "SystemAssigned" + } +} + +resource "azurerm_private_endpoint" "test" { + name = "acctest-privatelink-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + subnet_id = azurerm_subnet.endpoint.id + + private_service_connection { + name = "acctest-privatelink-%[2]d" + is_manual_connection = false + subresource_names = ["AzureSiteRecovery"] + private_connection_resource_id = azurerm_recovery_services_vault.test.id + } + + dynamic "ip_configuration" { + for_each = local.ip_configs + + content { + name = ip_configuration.key + private_ip_address = ip_configuration.value + subresource_name = "AzureSiteRecovery" + member_name = ip_configuration.key + } + } +} +`, r.template(data, r.serviceAutoApprove(data)), data.RandomInteger) +} diff --git a/website/docs/r/private_endpoint.html.markdown b/website/docs/r/private_endpoint.html.markdown index 2fb4cbbb9a40..e4325120ea6c 100644 --- a/website/docs/r/private_endpoint.html.markdown +++ b/website/docs/r/private_endpoint.html.markdown @@ -176,18 +176,20 @@ A `private_service_connection` supports the following: -> Several possible values for this field are shown below, however this is not extensive: -| Resource Type | SubResource Name | Secondary SubResource Name | -| ----------------------------- | ---------------- | -------------------------- | -| Data Lake File System Gen2 | dfs | dfs_secondary | -| SQL Database / Data Warehouse | sqlServer | | -| SQL Managed Instance | managedInstance | | -| Storage Account | blob | blob_secondary | -| Storage Account | file | file_secondary | -| Storage Account | queue | queue_secondary | -| Storage Account | table | table_secondary | -| Storage Account | web | web_secondary | -| Web App / Function App | sites | | +| Resource Type | SubResource Name | Secondary SubResource Name | +|-------------------------------|------------------------|----------------------------| +| Data Lake File System Gen2 | dfs | dfs_secondary | +| SQL Database / Data Warehouse | sqlServer | | +| SQL Managed Instance | managedInstance | | +| Storage Account | blob | blob_secondary | +| Storage Account | file | file_secondary | +| Storage Account | queue | queue_secondary | +| Storage Account | table | table_secondary | +| Storage Account | web | web_secondary | +| Web App / Function App | sites | | | Web App / Function App Slots | sites-<slotName> | | +| Recovery Services Vault | AzureBackup | | +| Recovery Services Vault | AzureSiteRecovery | | Some resource types (such as Storage Account) only support 1 subresource per private endpoint. See the product [documentation](https://docs.microsoft.com/azure/private-link/private-endpoint-overview#private-link-resource) for more information. @@ -201,7 +203,11 @@ An `ip_configuration` supports the following: * `private_ip_address` - (Required) Specifies the static IP address within the private endpoint's subnet to be used. Changing this forces a new resource to be created. -* `subresource_name` - (Required) Specifies the subresource this IP address applies to. `subresource_names` corresponds to `group_id` and in this context is also used for `member_name`. Changing this forces a new resource to be created. +* `subresource_name` - (Required) Specifies the subresource this IP address applies to. `subresource_names` corresponds to `group_id`. Changing this forces a new resource to be created. + +* `member_name` - (Optional) Specifies the member name this IP address applies to. If it is not specified, it will use the value of `subresource_name`. Changing this forces a new resource to be created. + +-> **NOTE:** `member_name` will be required and will not take the value of `subresource_name` in the next major version. ## Attributes Reference