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_private_endpoint - add member_name property of ip_configuration block, support multiple ip_configuration blocks. #19389

Merged
merged 5 commits into from
Dec 12, 2022
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
17 changes: 15 additions & 2 deletions internal/services/network/private_endpoint_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/hashicorp/terraform-provider-azurerm/helpers/azure"
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/features"
"github.com/hashicorp/terraform-provider-azurerm/internal/locks"
cosmosParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/cosmos/parse"
mysqlParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/mysql/parse"
Expand Down Expand Up @@ -175,7 +176,6 @@ func resourcePrivateEndpoint() *pluginsdk.Resource {
"ip_configuration": {
Type: pluginsdk.TypeList,
Optional: true,
MaxItems: 1,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"name": {
Expand All @@ -196,6 +196,14 @@ func resourcePrivateEndpoint() *pluginsdk.Resource {
ForceNew: true,
ValidateFunc: validation.StringIsNotEmpty,
},
"member_name": {
Type: pluginsdk.TypeString,
Required: features.FourPointOhBeta(),
Optional: !features.FourPointOhBeta(),
Computed: !features.FourPointOhBeta(),
ForceNew: true,
ValidateFunc: validation.StringIsNotEmpty,
},
},
},
},
Expand Down Expand Up @@ -764,13 +772,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)
Expand All @@ -790,6 +802,7 @@ func flattenPrivateEndpointIPConfigurations(ipConfigurations *[]network.PrivateE
"name": item.Name,
"private_ip_address": item.PrivateIPAddress,
"subresource_name": item.GroupID,
"member_name": item.MemberName,
})
}

Expand Down
79 changes: 74 additions & 5 deletions internal/services/network/private_endpoint_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand All @@ -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"
}

Expand Down Expand Up @@ -501,7 +516,7 @@ provider "azurerm" {
}

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

Expand Down Expand Up @@ -581,7 +596,7 @@ provider "azurerm" {
}

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

Expand Down Expand Up @@ -656,7 +671,7 @@ provider "azurerm" {
}

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

Expand Down Expand Up @@ -741,7 +756,7 @@ provider "azurerm" {
}

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

Expand Down Expand Up @@ -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)
}
36 changes: 21 additions & 15 deletions website/docs/r/private_endpoint.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ The following arguments are supported:

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

* `ip_configuration` - (Optional) An `ip_configuration` block as defined below. This allows a static IP address to be set for this Private Endpoint, otherwise an address is dynamically allocated from the Subnet. At most one IP configuration is allowed. Changing this forces a new resource to be created.
* `ip_configuration` - (Optional) One or more `ip_configuration` blocks as defined below. This allows a static IP address to be set for this Private Endpoint, otherwise an address is dynamically allocated from the Subnet. Changing this forces a new resource to be created.

* `tags` - (Optional) A mapping of tags to assign to the resource.

Expand Down Expand Up @@ -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.

Expand All @@ -197,11 +199,15 @@ Some resource types (such as Storage Account) only support 1 subresource per pri

An `ip_configuration` supports the following:

* `name` - (Required) Specifies the Name of the IP Configuration. Changing this forces a new resource to be created.
* `name` - (Required) Specifies the Name of the IP Configuration. Changing this forces a new resource to be created.

* `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.
* `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

Expand Down