diff --git a/azurerm/data_source_private_endpoint.go b/azurerm/data_source_private_endpoint.go new file mode 100644 index 000000000000..2783e0f20b60 --- /dev/null +++ b/azurerm/data_source_private_endpoint.go @@ -0,0 +1,200 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file at +// https://github.com/Azure/magic-module-specs +// +// ---------------------------------------------------------------------------- + +package azurerm + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmPrivateEndpoint() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmPrivateEndpointRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "location": azure.SchemaLocationForDataSource(), + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "manual_private_link_service_connections": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "private_link_service_id": { + Type: schema.TypeString, + Computed: true, + }, + "group_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "request_message": { + Type: schema.TypeString, + Computed: true, + }, + "private_link_service_connection_state": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_required": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "network_interfaces": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "private_link_service_connections": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "private_link_service_id": { + Type: schema.TypeString, + Computed: true, + }, + "group_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "request_message": { + Type: schema.TypeString, + Computed: true, + }, + "private_link_service_connection_state": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_required": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "subnet_id": { + Type: schema.TypeString, + Computed: true, + }, + + "tags": tagsForDataSourceSchema(), + }, + } +} + +func dataSourceArmPrivateEndpointRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).network.PrivateEndpointClient + ctx := meta.(*ArmClient).StopContext + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + resp, err := client.Get(ctx, resourceGroup, name, "") + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Error: Private Endpoint %q (Resource Group %q) was not found", name, resourceGroup) + } + return fmt.Errorf("Error reading Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.SetId(*resp.ID) + + d.Set("name", resp.Name) + d.Set("resource_group_name", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + if privateEndpointProperties := resp.PrivateEndpointProperties; privateEndpointProperties != nil { + if err := d.Set("manual_private_link_service_connections", flattenArmPrivateEndpointPrivateLinkServiceConnection(privateEndpointProperties.ManualPrivateLinkServiceConnections)); err != nil { + return fmt.Errorf("Error setting `manual_private_link_service_connections`: %+v", err) + } + if err := d.Set("network_interfaces", flattenArmPrivateEndpointInterface(privateEndpointProperties.NetworkInterfaces)); err != nil { + return fmt.Errorf("Error setting `network_interfaces`: %+v", err) + } + if err := d.Set("private_link_service_connections", flattenArmPrivateEndpointPrivateLinkServiceConnection(privateEndpointProperties.PrivateLinkServiceConnections)); err != nil { + return fmt.Errorf("Error setting `private_link_service_connections`: %+v", err) + } + if subnet := privateEndpointProperties.Subnet; subnet != nil { + d.Set("subnet_id", subnet.ID) + } + } + tags.FlattenAndSet(d, resp.Tags) + + return nil +} diff --git a/azurerm/data_source_private_endpoint_test.go b/azurerm/data_source_private_endpoint_test.go new file mode 100644 index 000000000000..1c4449416743 --- /dev/null +++ b/azurerm/data_source_private_endpoint_test.go @@ -0,0 +1,124 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file at +// https://github.com/Azure/magic-module-specs +// +// ---------------------------------------------------------------------------- + +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" +) + +func TestAccDataSourceAzureRMPrivateEndpoint_basic(t *testing.T) { + dataSourceName := "data.azurerm_private_endpoint.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourcePrivateEndpoint_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "subnet_id"), + resource.TestCheckResourceAttr(dataSourceName, "private_link_service_connections.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "private_link_service_connections.0.name", "<%= get_resource_name('privatelinkservice', 'connection') -%>"), + ), + }, + }, + }) +} +func TestAccDataSourceAzureRMPrivateEndpoint_complete(t *testing.T) { + dataSourceName := "data.azurerm_private_endpoint.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourcePrivateEndpoint_complete(ri, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "subnet_id"), + resource.TestCheckResourceAttr(dataSourceName, "private_link_service_connections.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "private_link_service_connections.0.name", "<%= get_resource_name('privatelinkservice', 'connection') -%>"), + resource.TestCheckResourceAttr(dataSourceName, "private_link_service_connections.0.group_ids.#", "0"), + resource.TestCheckResourceAttr(dataSourceName, "private_link_service_connections.0.request_message", "plz approve my request"), + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(dataSourceName, "tags.env", "test"), + ), + }, + }, + }) +} +func TestAccDataSourceAzureRMPrivateEndpoint_update(t *testing.T) { + dataSourceName := "data.azurerm_private_endpoint.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourcePrivateEndpoint_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "subnet_id"), + resource.TestCheckResourceAttr(dataSourceName, "private_link_service_connections.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "private_link_service_connections.0.name", "<%= get_resource_name('privatelinkservice', 'connection') -%>"), + ), + }, + { + Config: testAccDataSourcePrivateEndpoint_complete(ri, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "subnet_id"), + resource.TestCheckResourceAttr(dataSourceName, "private_link_service_connections.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "private_link_service_connections.0.name", "<%= get_resource_name('privatelinkservice', 'connection') -%>"), + resource.TestCheckResourceAttr(dataSourceName, "private_link_service_connections.0.group_ids.#", "0"), + resource.TestCheckResourceAttr(dataSourceName, "private_link_service_connections.0.request_message", "plz approve my request"), + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(dataSourceName, "tags.env", "test"), + ), + }, + }, + }) +} + +func testAccDataSourcePrivateEndpoint_basic(rInt int, location string) string { + config := testAccAzureRMPrivateEndpoint_basic(rInt, location) + return fmt.Sprintf(` +%s + +data "azurerm_private_endpoint" "test" { + resource_group_name = "${azurerm_private_endpoint.test.resource_group_name}" + name = "${azurerm_private_endpoint.test.name}" +} +`, config) +} + +func testAccDataSourcePrivateEndpoint_complete(rInt int, location string) string { + config := testAccAzureRMPrivateEndpoint_complete(rInt, location) + return fmt.Sprintf(` +%s + +data "azurerm_private_endpoint" "test" { + resource_group_name = "${azurerm_private_endpoint.test.resource_group_name}" + name = "${azurerm_private_endpoint.test.name}" +} +`, config) +} diff --git a/azurerm/data_source_private_link_service.go b/azurerm/data_source_private_link_service.go new file mode 100644 index 000000000000..733cc4508689 --- /dev/null +++ b/azurerm/data_source_private_link_service.go @@ -0,0 +1,533 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file at +// https://github.com/Azure/magic-module-specs +// +// ---------------------------------------------------------------------------- + +package azurerm + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmPrivateLinkService() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmPrivateLinkServiceRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "location": azure.SchemaLocationForDataSource(), + + "resource_group": azure.SchemaResourceGroupNameForDataSource(), + + "alias": { + Type: schema.TypeString, + Computed: true, + }, + + "auto_approval": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subscriptions": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + + "fqdns": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "ip_configurations": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "private_ip_address": { + Type: schema.TypeString, + Computed: true, + }, + "private_ip_address_version": { + Type: schema.TypeString, + Computed: true, + }, + "private_ipallocation_method": { + Type: schema.TypeString, + Computed: true, + }, + "subnet": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "load_balancer_frontend_ip_configurations": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "private_ip_address": { + Type: schema.TypeString, + Computed: true, + }, + "public_ip_address": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "location": azure.SchemaLocationForDataSource(), + "tags": tagsForDataSourceSchema(), + "zones": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "public_ipprefix": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "subnet": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "private_ip_address_version": { + Type: schema.TypeString, + Computed: true, + }, + "private_ipallocation_method": { + Type: schema.TypeString, + Computed: true, + }, + "zones": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + + "network_interfaces": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dns_settings": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "applied_dns_servers": { + Type: schema.TypeString, + Computed: true, + }, + "dns_servers": { + Type: schema.TypeString, + Computed: true, + }, + "internal_dns_name_label": { + Type: schema.TypeString, + Computed: true, + }, + "internal_domain_name_suffix": { + Type: schema.TypeString, + Computed: true, + }, + "internal_fqdn": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "enable_accelerated_networking": { + Type: schema.TypeBool, + Computed: true, + }, + "enable_ipforwarding": { + Type: schema.TypeBool, + Computed: true, + }, + "etag": { + Type: schema.TypeString, + Computed: true, + }, + "hosted_workloads": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "ip_configurations": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "location": azure.SchemaLocationForDataSource(), + "mac_address": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "network_security_group": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "location": azure.SchemaLocationForDataSource(), + "name": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsForDataSourceSchema(), + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "primary": { + Type: schema.TypeBool, + Computed: true, + }, + "private_endpoint": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "location": azure.SchemaLocationForDataSource(), + "name": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsForDataSourceSchema(), + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "provisioning_state": { + Type: schema.TypeString, + Computed: true, + }, + "resource_guid": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsForDataSourceSchema(), + "tap_configurations": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "virtual_machine": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "private_endpoint_connections": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "private_endpoint": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "location": azure.SchemaLocationForDataSource(), + "tags": tagsForDataSourceSchema(), + }, + }, + }, + "private_link_service_connection_state": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_required": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "tags": tagsForDataSourceSchema(), + + "type": { + Type: schema.TypeString, + Computed: true, + }, + + "visibility": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subscriptions": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceArmPrivateLinkServiceRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).network.PrivateLinkServiceClient + ctx := meta.(*ArmClient).StopContext + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group").(string) + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Error: Private Link Service %q (Resource Group %q) was not found", name, resourceGroup) + } + return fmt.Errorf("Error reading Private Link Service %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.SetId(*resp.ID) + + d.Set("name", resp.Name) + d.Set("resource_group", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + if privateLinkServiceProperties := resp.PrivateLinkServiceProperties; privateLinkServiceProperties != nil { + d.Set("alias", privateLinkServiceProperties.Alias) + if err := d.Set("auto_approval", flattenArmPrivateLinkServicePrivateLinkServicePropertiesAutoApproval(privateLinkServiceProperties.AutoApproval)); err != nil { + return fmt.Errorf("Error setting `auto_approval`: %+v", err) + } + d.Set("fqdns", utils.FlattenStringSlice(privateLinkServiceProperties.Fqdns)) + if err := d.Set("ip_configurations", flattenArmPrivateLinkServicePrivateLinkServiceIPConfiguration(privateLinkServiceProperties.IPConfigurations)); err != nil { + return fmt.Errorf("Error setting `ip_configurations`: %+v", err) + } + if err := d.Set("load_balancer_frontend_ip_configurations", flattenArmPrivateLinkServiceFrontendIPConfiguration(privateLinkServiceProperties.LoadBalancerFrontendIPConfigurations)); err != nil { + return fmt.Errorf("Error setting `load_balancer_frontend_ip_configurations`: %+v", err) + } + if err := d.Set("network_interfaces", flattenArmPrivateLinkServiceInterface(privateLinkServiceProperties.NetworkInterfaces)); err != nil { + return fmt.Errorf("Error setting `network_interfaces`: %+v", err) + } + if err := d.Set("private_endpoint_connections", flattenArmPrivateLinkServicePrivateEndpointConnection(privateLinkServiceProperties.PrivateEndpointConnections)); err != nil { + return fmt.Errorf("Error setting `private_endpoint_connections`: %+v", err) + } + if err := d.Set("visibility", flattenArmPrivateLinkServicePrivateLinkServicePropertiesVisibility(privateLinkServiceProperties.Visibility)); err != nil { + return fmt.Errorf("Error setting `visibility`: %+v", err) + } + } + d.Set("type", resp.Type) + tags.FlattenAndSet(d, resp.Tags) + + return nil +} diff --git a/azurerm/data_source_private_link_service_test.go b/azurerm/data_source_private_link_service_test.go new file mode 100644 index 000000000000..222b03010773 --- /dev/null +++ b/azurerm/data_source_private_link_service_test.go @@ -0,0 +1,60 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file at +// https://github.com/Azure/magic-module-specs +// +// ---------------------------------------------------------------------------- + +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" +) + +func TestAccDataSourceAzureRMPrivateLinkService_basic(t *testing.T) { + dataSourceName := "data.azurerm_private_link_service.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourcePrivateLinkService_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "fqdns.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "fqdns.0", "testFqdns"), + resource.TestCheckResourceAttr(dataSourceName, "ip_configurations.%", "5"), + resource.TestCheckResourceAttr(dataSourceName, "ip_configurations.private_ip_address", "10.5.1.17"), + resource.TestCheckResourceAttr(dataSourceName, "ip_configurations.private_ip_address_version", "IPv4"), + resource.TestCheckResourceAttr(dataSourceName, "ip_configurations.private_ipallocation_method", "Static"), + resource.TestCheckResourceAttr(dataSourceName, "load_balancer_frontend_ip_configurations.%", "1"), + ), + }, + }, + }) +} + +func testAccDataSourcePrivateLinkService_basic(rInt int, location string) string { + config := testAccAzureRMPrivateLinkService_basic(rInt, location) + return fmt.Sprintf(` +%s + +data "azurerm_private_link_service" "test" { + resource_group = "${azurerm_private_link_service.test.resource_group}" + name = "${azurerm_private_link_service.test.name}" +} +`, config) +} diff --git a/azurerm/data_source_virtual_hub.go b/azurerm/data_source_virtual_hub.go new file mode 100644 index 000000000000..73acb31f86bd --- /dev/null +++ b/azurerm/data_source_virtual_hub.go @@ -0,0 +1,231 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file at +// https://github.com/Azure/magic-module-specs +// +// ---------------------------------------------------------------------------- + +package azurerm + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmVirtualHub() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmVirtualHubRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "location": azure.SchemaLocationForDataSource(), + + "resource_group": azure.SchemaResourceGroupNameForDataSource(), + + "address_prefix": { + Type: schema.TypeString, + Computed: true, + }, + + "etag": { + Type: schema.TypeString, + Computed: true, + }, + + "express_route_gateway": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "p2svpn_gateway": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "route_table": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "routes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address_prefixes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "next_hop_ip_address": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "tags": tagsForDataSourceSchema(), + + "type": { + Type: schema.TypeString, + Computed: true, + }, + + "virtual_network_connections": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allow_hub_to_remote_vnet_transit": { + Type: schema.TypeBool, + Computed: true, + }, + "allow_remote_vnet_to_use_hub_vnet_gateways": { + Type: schema.TypeBool, + Computed: true, + }, + "enable_internet_security": { + Type: schema.TypeBool, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "remote_virtual_network": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "virtual_wan": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "vpn_gateway": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceArmVirtualHubRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).network.VirtualHubClient + ctx := meta.(*ArmClient).StopContext + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group").(string) + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Error: Virtual Hub %q (Resource Group %q) was not found", name, resourceGroup) + } + return fmt.Errorf("Error reading Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.SetId(*resp.ID) + + d.Set("name", resp.Name) + d.Set("resource_group", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + if virtualHubProperties := resp.VirtualHubProperties; virtualHubProperties != nil { + d.Set("address_prefix", virtualHubProperties.AddressPrefix) + if err := d.Set("express_route_gateway", flattenArmVirtualHubSubResource(virtualHubProperties.ExpressRouteGateway)); err != nil { + return fmt.Errorf("Error setting `express_route_gateway`: %+v", err) + } + if err := d.Set("p2svpn_gateway", flattenArmVirtualHubSubResource(virtualHubProperties.P2SVpnGateway)); err != nil { + return fmt.Errorf("Error setting `p2svpn_gateway`: %+v", err) + } + if err := d.Set("route_table", flattenArmVirtualHubVirtualHubRouteTable(virtualHubProperties.RouteTable)); err != nil { + return fmt.Errorf("Error setting `route_table`: %+v", err) + } + if err := d.Set("virtual_network_connections", flattenArmVirtualHubHubVirtualNetworkConnection(virtualHubProperties.VirtualNetworkConnections)); err != nil { + return fmt.Errorf("Error setting `virtual_network_connections`: %+v", err) + } + if err := d.Set("virtual_wan", flattenArmVirtualHubSubResource(virtualHubProperties.VirtualWan)); err != nil { + return fmt.Errorf("Error setting `virtual_wan`: %+v", err) + } + if err := d.Set("vpn_gateway", flattenArmVirtualHubSubResource(virtualHubProperties.VpnGateway)); err != nil { + return fmt.Errorf("Error setting `vpn_gateway`: %+v", err) + } + } + d.Set("etag", resp.Etag) + d.Set("type", resp.Type) + tags.FlattenAndSet(d, resp.Tags) + + return nil +} diff --git a/azurerm/data_source_virtual_hub_test.go b/azurerm/data_source_virtual_hub_test.go new file mode 100644 index 000000000000..a3fb24ff501f --- /dev/null +++ b/azurerm/data_source_virtual_hub_test.go @@ -0,0 +1,60 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file at +// https://github.com/Azure/magic-module-specs +// +// ---------------------------------------------------------------------------- + +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" +) + +func TestAccDataSourceAzureRMVirtualHub_basic(t *testing.T) { + dataSourceName := "data.azurerm_virtual_hub.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceVirtualHub_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "address_prefix", "10.0.1.0/24"), + resource.TestCheckResourceAttr(dataSourceName, "virtual_wan.%", "1"), + resource.TestCheckResourceAttr(dataSourceName, "route_table.%", "1"), + resource.TestCheckResourceAttr(dataSourceName, "route_table.routes.address_prefixes.#", "2"), + resource.TestCheckResourceAttr(dataSourceName, "route_table.routes.address_prefixes.0", "10.0.2.0/24"), + resource.TestCheckResourceAttr(dataSourceName, "route_table.routes.address_prefixes.1", "10.0.3.0/24"), + resource.TestCheckResourceAttr(dataSourceName, "route_table.routes.next_hop_ip_address", "10.0.4.5"), + ), + }, + }, + }) +} + +func testAccDataSourceVirtualHub_basic(rInt int, location string) string { + config := testAccAzureRMVirtualHub_basic(rInt, location) + return fmt.Sprintf(` +%s + +data "azurerm_virtual_hub" "test" { + resource_group = "${azurerm_virtual_hub.test.resource_group}" + name = "${azurerm_virtual_hub.test.name}" +} +`, config) +} diff --git a/azurerm/resource_arm_private_endpoint.go b/azurerm/resource_arm_private_endpoint.go new file mode 100644 index 000000000000..c5bf2df3aaf5 --- /dev/null +++ b/azurerm/resource_arm_private_endpoint.go @@ -0,0 +1,396 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file at +// https://github.com/Azure/magic-module-specs +// +// ---------------------------------------------------------------------------- + +package azurerm + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/response" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmPrivateEndpoint() *schema.Resource { + return &schema.Resource{ + Create: resourceArmPrivateEndpointCreateUpdate, + Read: resourceArmPrivateEndpointRead, + Update: resourceArmPrivateEndpointCreateUpdate, + Delete: resourceArmPrivateEndpointDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "location": azure.SchemaLocation(), + + "resource_group_name": azure.SchemaResourceGroupNameDiffSuppress(), + + "subnet_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "manual_private_link_service_connections": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + "private_link_service_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + "group_ids": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "request_message": { + Type: schema.TypeString, + Optional: true, + }, + "private_link_service_connection_state": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_required": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "private_link_service_connections": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + "private_link_service_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + "group_ids": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "request_message": { + Type: schema.TypeString, + Optional: true, + }, + "private_link_service_connection_state": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_required": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "tags": tags.Schema(), + + "network_interfaces": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func resourceArmPrivateEndpointCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).network.PrivateEndpointClient + ctx := meta.(*ArmClient).StopContext + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + if features.ShouldResourcesBeImported() && d.IsNewResource() { + resp, err := client.Get(ctx, resourceGroup, name, "") + if err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Error checking for present of existing Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + if !utils.ResponseWasNotFound(resp.Response) { + return tf.ImportAsExistsError("azurerm_private_endpoint", *resp.ID) + } + } + + location := azure.NormalizeLocation(d.Get("location").(string)) + manualPrivateLinkServiceConnections := d.Get("manual_private_link_service_connections").([]interface{}) + privateLinkServiceConnections := d.Get("private_link_service_connections").([]interface{}) + subnetId := d.Get("subnet_id").(string) + t := d.Get("tags").(map[string]interface{}) + + parameters := network.PrivateEndpoint{ + Location: utils.String(location), + PrivateEndpointProperties: &network.PrivateEndpointProperties{ + ManualPrivateLinkServiceConnections: expandArmPrivateEndpointPrivateLinkServiceConnection(manualPrivateLinkServiceConnections), + PrivateLinkServiceConnections: expandArmPrivateEndpointPrivateLinkServiceConnection(privateLinkServiceConnections), + Subnet: &network.Subnet{ + ID: utils.String(subnetId), + }, + }, + Tags: tags.Expand(t), + } + + future, err := client.CreateOrUpdate(ctx, resourceGroup, name, parameters) + if err != nil { + return fmt.Errorf("Error creating Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) + } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for creation of Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + resp, err := client.Get(ctx, resourceGroup, name, "") + if err != nil { + return fmt.Errorf("Error retrieving Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) + } + if resp.ID == nil { + return fmt.Errorf("Cannot read Private Endpoint %q (Resource Group %q) ID", name, resourceGroup) + } + d.SetId(*resp.ID) + + return resourceArmPrivateEndpointRead(d, meta) +} + +func resourceArmPrivateEndpointRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).network.PrivateEndpointClient + ctx := meta.(*ArmClient).StopContext + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["privateEndpoints"] + + resp, err := client.Get(ctx, resourceGroup, name, "") + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Private Endpoint %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("Error reading Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.Set("name", resp.Name) + d.Set("resource_group_name", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + if privateEndpointProperties := resp.PrivateEndpointProperties; privateEndpointProperties != nil { + if err := d.Set("manual_private_link_service_connections", flattenArmPrivateEndpointPrivateLinkServiceConnection(privateEndpointProperties.ManualPrivateLinkServiceConnections)); err != nil { + return fmt.Errorf("Error setting `manual_private_link_service_connections`: %+v", err) + } + if err := d.Set("network_interfaces", flattenArmPrivateEndpointInterface(privateEndpointProperties.NetworkInterfaces)); err != nil { + return fmt.Errorf("Error setting `network_interfaces`: %+v", err) + } + if err := d.Set("private_link_service_connections", flattenArmPrivateEndpointPrivateLinkServiceConnection(privateEndpointProperties.PrivateLinkServiceConnections)); err != nil { + return fmt.Errorf("Error setting `private_link_service_connections`: %+v", err) + } + if subnet := privateEndpointProperties.Subnet; subnet != nil { + d.Set("subnet_id", subnet.ID) + } + } + tags.FlattenAndSet(d, resp.Tags) + + return nil +} + +func resourceArmPrivateEndpointDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).network.PrivateEndpointClient + ctx := meta.(*ArmClient).StopContext + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["privateEndpoints"] + + future, err := client.Delete(ctx, resourceGroup, name) + if err != nil { + if response.WasNotFound(future.Response()) { + return nil + } + return fmt.Errorf("Error deleting Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if !response.WasNotFound(future.Response()) { + return fmt.Errorf("Error waiting for deleting Private Endpoint %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + + return nil +} + +func expandArmPrivateEndpointPrivateLinkServiceConnection(input []interface{}) *[]network.PrivateLinkServiceConnection { + results := make([]network.PrivateLinkServiceConnection, 0) + for _, item := range input { + v := item.(map[string]interface{}) + privateLinkServiceID := v["private_link_service_id"].(string) + groupIds := v["group_ids"].([]interface{}) + requestMessage := v["request_message"].(string) + name := v["name"].(string) + + result := network.PrivateLinkServiceConnection{ + Name: utils.String(name), + PrivateLinkServiceConnectionProperties: &network.PrivateLinkServiceConnectionProperties{ + GroupIds: utils.ExpandStringSlice(groupIds), + PrivateLinkServiceID: utils.String(privateLinkServiceID), + RequestMessage: utils.String(requestMessage), + }, + } + + results = append(results, result) + } + return &results +} + +func flattenArmPrivateEndpointPrivateLinkServiceConnection(input *[]network.PrivateLinkServiceConnection) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + v := make(map[string]interface{}) + + if name := item.Name; name != nil { + v["name"] = *name + } + if privateLinkServiceConnectionProperties := item.PrivateLinkServiceConnectionProperties; privateLinkServiceConnectionProperties != nil { + v["group_ids"] = utils.FlattenStringSlice(privateLinkServiceConnectionProperties.GroupIds) + v["private_link_service_connection_state"] = flattenArmPrivateEndpointPrivateLinkServiceConnectionState(privateLinkServiceConnectionProperties.PrivateLinkServiceConnectionState) + if privateLinkServiceId := privateLinkServiceConnectionProperties.PrivateLinkServiceID; privateLinkServiceId != nil { + v["private_link_service_id"] = *privateLinkServiceId + } + if requestMessage := privateLinkServiceConnectionProperties.RequestMessage; requestMessage != nil { + v["request_message"] = *requestMessage + } + } + + results = append(results, v) + } + + return results +} + +func flattenArmPrivateEndpointInterface(input *[]network.Interface) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + v := make(map[string]interface{}) + + if id := item.ID; id != nil { + v["id"] = *id + } + + results = append(results, v) + } + + return results +} + +func flattenArmPrivateEndpointPrivateLinkServiceConnectionState(input *network.PrivateLinkServiceConnectionState) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + result := make(map[string]interface{}) + + if actionRequired := input.ActionRequired; actionRequired != nil { + result["action_required"] = *actionRequired + } + if description := input.Description; description != nil { + result["description"] = *description + } + if status := input.Status; status != nil { + result["status"] = *status + } + + return []interface{}{result} +} diff --git a/azurerm/resource_arm_private_endpoint_test.go b/azurerm/resource_arm_private_endpoint_test.go new file mode 100644 index 000000000000..645bcadcc638 --- /dev/null +++ b/azurerm/resource_arm_private_endpoint_test.go @@ -0,0 +1,335 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file at +// https://github.com/Azure/magic-module-specs +// +// ---------------------------------------------------------------------------- + +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMPrivateEndpoint_basic(t *testing.T) { + resourceName := "azurerm_private_endpoint.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPrivateEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMPrivateEndpoint_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateEndpointExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "subnet_id"), + resource.TestCheckResourceAttr(resourceName, "private_link_service_connections.#", "1"), + resource.TestCheckResourceAttr(resourceName, "private_link_service_connections.0.name", "<%= get_resource_name('privatelinkservice', 'connection') -%>"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMPrivateEndpoint_complete(t *testing.T) { + resourceName := "azurerm_private_endpoint.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPrivateEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMPrivateEndpoint_complete(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateEndpointExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "subnet_id"), + resource.TestCheckResourceAttr(resourceName, "private_link_service_connections.#", "1"), + resource.TestCheckResourceAttr(resourceName, "private_link_service_connections.0.name", "<%= get_resource_name('privatelinkservice', 'connection') -%>"), + resource.TestCheckResourceAttr(resourceName, "private_link_service_connections.0.group_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "private_link_service_connections.0.request_message", "plz approve my request"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.env", "test"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMPrivateEndpoint_update(t *testing.T) { + resourceName := "azurerm_private_endpoint.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPrivateEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMPrivateEndpoint_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateEndpointExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "subnet_id"), + resource.TestCheckResourceAttr(resourceName, "private_link_service_connections.#", "1"), + resource.TestCheckResourceAttr(resourceName, "private_link_service_connections.0.name", "<%= get_resource_name('privatelinkservice', 'connection') -%>"), + ), + }, + { + Config: testAccAzureRMPrivateEndpoint_complete(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateEndpointExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "subnet_id"), + resource.TestCheckResourceAttr(resourceName, "private_link_service_connections.#", "1"), + resource.TestCheckResourceAttr(resourceName, "private_link_service_connections.0.name", "<%= get_resource_name('privatelinkservice', 'connection') -%>"), + resource.TestCheckResourceAttr(resourceName, "private_link_service_connections.0.group_ids.#", "0"), + resource.TestCheckResourceAttr(resourceName, "private_link_service_connections.0.request_message", "plz approve my request"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.env", "test"), + ), + }, + }, + }) +} + +func testCheckAzureRMPrivateEndpointExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Private Endpoint not found: %s", resourceName) + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + client := testAccProvider.Meta().(*ArmClient).network.PrivateEndpointClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + if resp, err := client.Get(ctx, resourceGroup, name, ""); err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Private Endpoint %q (Resource Group %q) does not exist", name, resourceGroup) + } + return fmt.Errorf("Bad: Get on network.PrivateEndpointClient: %+v", err) + } + + return nil + } +} + +func testCheckAzureRMPrivateEndpointDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).network.PrivateEndpointClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_private_endpoint" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + if resp, err := client.Get(ctx, resourceGroup, name, ""); err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Get on network.PrivateEndpointClient: %+v", err) + } + } + + return nil + } + + return nil +} + +func testAccAzureRMPrivateEndpoint_basic(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvnet-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + address_space = ["10.5.0.0/16"] +} + +resource "azurerm_subnet" "test" { + name = "acctestsnet-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefix = "10.5.1.0/24" + private_endpoint_network_policies = "Disabled" + private_link_service_network_policies = "Disabled" +} + +resource "azurerm_public_ip" "test" { + name = "acctestpip-%d" + sku = "Standard" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + allocation_method = "Static" +} + +resource "azurerm_lb" "test" { + name = "acctestpip-%d" + sku = "Standard" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + frontend_ip_configuration { + name = "${azurerm_public_ip.test.name}" + public_ip_address_id = "${azurerm_public_ip.test.id}" + } +} + +resource "azurerm_private_link_service" "test" { + name = "acctestvirtualhub-%d" + location = "${azurerm_resource_group.test.location}" + resource_group = "${azurerm_resource_group.test.name}" + fqdns = ["testFqdns"] + + ip_configurations { + name = "${azurerm_public_ip.test.name}" + + subnet { + id = "${azurerm_subnet.test.id}" + } + + private_ip_address = "10.5.1.17" + private_ip_address_version = "IPv4" + private_ipallocation_method = "Static" + } + + load_balancer_frontend_ip_configurations { + id = "${azurerm_lb.test.frontend_ip_configuration.0.id}" + } +} + +resource "azurerm_private_endpoint" "test" { + name = "acctestendpoint-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + subnet_id = "${azurerm_subnet.test.id}" + + private_link_service_connections { + name = "acctestconnection-%d" + private_link_service_id = "${azurerm_private_link_service.test.id}" + } +} +`, rInt, location, rInt, rInt, rInt, rInt, rInt, rInt, rInt) +} + +func testAccAzureRMPrivateEndpoint_complete(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvnet-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + address_space = ["10.5.0.0/16"] +} + +resource "azurerm_subnet" "test" { + name = "acctestsnet-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefix = "10.5.1.0/24" + private_endpoint_network_policies = "Disabled" + private_link_service_network_policies = "Disabled" +} + +resource "azurerm_public_ip" "test" { + name = "acctestpip-%d" + sku = "Standard" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + allocation_method = "Static" +} + +resource "azurerm_lb" "test" { + name = "acctestpip-%d" + sku = "Standard" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + frontend_ip_configuration { + name = "${azurerm_public_ip.test.name}" + public_ip_address_id = "${azurerm_public_ip.test.id}" + } +} + +resource "azurerm_private_link_service" "test" { + name = "acctestvirtualhub-%d" + location = "${azurerm_resource_group.test.location}" + resource_group = "${azurerm_resource_group.test.name}" + fqdns = ["testFqdns"] + + ip_configurations { + name = "${azurerm_public_ip.test.name}" + + subnet { + id = "${azurerm_subnet.test.id}" + } + + private_ip_address = "10.5.1.17" + private_ip_address_version = "IPv4" + private_ipallocation_method = "Static" + } + + load_balancer_frontend_ip_configurations { + id = "${azurerm_lb.test.frontend_ip_configuration.0.id}" + } +} + +resource "azurerm_private_endpoint" "test" { + name = "acctestendpoint-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + subnet_id = "${azurerm_subnet.test.id}" + + private_link_service_connections { + name = "acctestconnection-%d" + private_link_service_id = "${azurerm_private_link_service.test.id}" + group_ids = [] + request_message = "plz approve my request" + } + + tags = { + env = "test" + } +} +`, rInt, location, rInt, rInt, rInt, rInt, rInt, rInt, rInt) +} diff --git a/azurerm/resource_arm_private_link_service.go b/azurerm/resource_arm_private_link_service.go new file mode 100644 index 000000000000..6e93a0c6dcaa --- /dev/null +++ b/azurerm/resource_arm_private_link_service.go @@ -0,0 +1,1114 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file at +// https://github.com/Azure/magic-module-specs +// +// ---------------------------------------------------------------------------- + +package azurerm + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/response" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmPrivateLinkService() *schema.Resource { + return &schema.Resource{ + Create: resourceArmPrivateLinkServiceCreateUpdate, + Read: resourceArmPrivateLinkServiceRead, + Update: resourceArmPrivateLinkServiceCreateUpdate, + Delete: resourceArmPrivateLinkServiceDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "location": azure.SchemaLocation(), + + "resource_group": azure.SchemaResourceGroupNameDiffSuppress(), + + "auto_approval": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subscriptions": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + + "fqdns": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "ip_configurations": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + }, + "private_ip_address": { + Type: schema.TypeString, + Optional: true, + }, + "private_ip_address_version": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(network.IPv4), + string(network.IPv6), + }, false), + Default: string(network.IPv4), + }, + "private_ipallocation_method": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(network.Static), + string(network.Dynamic), + }, false), + Default: string(network.Static), + }, + "subnet": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + + "load_balancer_frontend_ip_configurations": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "private_ip_address": { + Type: schema.TypeString, + Optional: true, + }, + "public_ip_address": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Optional: true, + }, + "location": azure.SchemaLocation(), + "tags": tags.Schema(), + "zones": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "public_ipprefix": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "subnet": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "private_ip_address_version": { + Type: schema.TypeString, + Computed: true, + }, + "private_ipallocation_method": { + Type: schema.TypeString, + Computed: true, + }, + "zones": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + + "private_endpoint_connections": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "private_endpoint": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Optional: true, + }, + "location": azure.SchemaLocation(), + "tags": tags.Schema(), + }, + }, + }, + "private_link_service_connection_state": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action_required": { + Type: schema.TypeString, + Optional: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "status": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + + "tags": tags.Schema(), + + "visibility": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subscriptions": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + + "alias": { + Type: schema.TypeString, + Computed: true, + }, + + "network_interfaces": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dns_settings": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "applied_dns_servers": { + Type: schema.TypeString, + Optional: true, + }, + "dns_servers": { + Type: schema.TypeString, + Optional: true, + }, + "internal_dns_name_label": { + Type: schema.TypeString, + Optional: true, + }, + "internal_domain_name_suffix": { + Type: schema.TypeString, + Optional: true, + }, + "internal_fqdn": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "enable_accelerated_networking": { + Type: schema.TypeBool, + Optional: true, + }, + "enable_ipforwarding": { + Type: schema.TypeBool, + Optional: true, + }, + "etag": { + Type: schema.TypeString, + Optional: true, + }, + "hosted_workloads": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Optional: true, + }, + "ip_configurations": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "location": azure.SchemaLocation(), + "mac_address": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "network_security_group": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Optional: true, + }, + "location": azure.SchemaLocation(), + "name": { + Type: schema.TypeString, + Optional: true, + }, + "tags": tags.Schema(), + "type": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "primary": { + Type: schema.TypeBool, + Optional: true, + }, + "private_endpoint": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Optional: true, + }, + "location": azure.SchemaLocation(), + "name": { + Type: schema.TypeString, + Optional: true, + }, + "tags": tags.Schema(), + "type": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "provisioning_state": { + Type: schema.TypeString, + Optional: true, + }, + "resource_guid": { + Type: schema.TypeString, + Optional: true, + }, + "tags": tags.Schema(), + "tap_configurations": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "etag": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "type": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "type": { + Type: schema.TypeString, + Optional: true, + }, + "virtual_machine": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceArmPrivateLinkServiceCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).network.PrivateLinkServiceClient + ctx := meta.(*ArmClient).StopContext + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group").(string) + + if features.ShouldResourcesBeImported() && d.IsNewResource() { + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Error checking for present of existing Private Link Service %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + if !utils.ResponseWasNotFound(resp.Response) { + return tf.ImportAsExistsError("azurerm_private_link_service", *resp.ID) + } + } + + location := azure.NormalizeLocation(d.Get("location").(string)) + autoApproval := d.Get("auto_approval").([]interface{}) + fqdns := d.Get("fqdns").([]interface{}) + ipConfigurations := d.Get("ip_configurations").([]interface{}) + loadBalancerFrontendIpConfigurations := d.Get("load_balancer_frontend_ip_configurations").([]interface{}) + privateEndpointConnections := d.Get("private_endpoint_connections").([]interface{}) + visibility := d.Get("visibility").([]interface{}) + t := d.Get("tags").(map[string]interface{}) + + parameters := network.PrivateLinkService{ + Location: utils.String(location), + PrivateLinkServiceProperties: &network.PrivateLinkServiceProperties{ + AutoApproval: expandArmPrivateLinkServicePrivateLinkServicePropertiesAutoApproval(autoApproval), + Fqdns: utils.ExpandStringSlice(fqdns), + IPConfigurations: expandArmPrivateLinkServicePrivateLinkServiceIPConfiguration(ipConfigurations), + LoadBalancerFrontendIPConfigurations: expandArmPrivateLinkServiceFrontendIPConfiguration(loadBalancerFrontendIpConfigurations), + PrivateEndpointConnections: expandArmPrivateLinkServicePrivateEndpointConnection(privateEndpointConnections), + Visibility: expandArmPrivateLinkServicePrivateLinkServicePropertiesVisibility(visibility), + }, + Tags: tags.Expand(t), + } + + future, err := client.CreateOrUpdate(ctx, resourceGroup, name, parameters) + if err != nil { + return fmt.Errorf("Error creating Private Link Service %q (Resource Group %q): %+v", name, resourceGroup, err) + } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for creation of Private Link Service %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Error retrieving Private Link Service %q (Resource Group %q): %+v", name, resourceGroup, err) + } + if resp.ID == nil { + return fmt.Errorf("Cannot read Private Link Service %q (Resource Group %q) ID", name, resourceGroup) + } + d.SetId(*resp.ID) + + return resourceArmPrivateLinkServiceRead(d, meta) +} + +func resourceArmPrivateLinkServiceRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).network.PrivateLinkServiceClient + ctx := meta.(*ArmClient).StopContext + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["privateLinkServices"] + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Private Link Service %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("Error reading Private Link Service %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.Set("name", resp.Name) + d.Set("resource_group", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + if privateLinkServiceProperties := resp.PrivateLinkServiceProperties; privateLinkServiceProperties != nil { + d.Set("alias", privateLinkServiceProperties.Alias) + if err := d.Set("auto_approval", flattenArmPrivateLinkServicePrivateLinkServicePropertiesAutoApproval(privateLinkServiceProperties.AutoApproval)); err != nil { + return fmt.Errorf("Error setting `auto_approval`: %+v", err) + } + d.Set("fqdns", utils.FlattenStringSlice(privateLinkServiceProperties.Fqdns)) + if err := d.Set("ip_configurations", flattenArmPrivateLinkServicePrivateLinkServiceIPConfiguration(privateLinkServiceProperties.IPConfigurations)); err != nil { + return fmt.Errorf("Error setting `ip_configurations`: %+v", err) + } + if err := d.Set("load_balancer_frontend_ip_configurations", flattenArmPrivateLinkServiceFrontendIPConfiguration(privateLinkServiceProperties.LoadBalancerFrontendIPConfigurations)); err != nil { + return fmt.Errorf("Error setting `load_balancer_frontend_ip_configurations`: %+v", err) + } + if err := d.Set("network_interfaces", flattenArmPrivateLinkServiceInterface(privateLinkServiceProperties.NetworkInterfaces)); err != nil { + return fmt.Errorf("Error setting `network_interfaces`: %+v", err) + } + if err := d.Set("private_endpoint_connections", flattenArmPrivateLinkServicePrivateEndpointConnection(privateLinkServiceProperties.PrivateEndpointConnections)); err != nil { + return fmt.Errorf("Error setting `private_endpoint_connections`: %+v", err) + } + if err := d.Set("visibility", flattenArmPrivateLinkServicePrivateLinkServicePropertiesVisibility(privateLinkServiceProperties.Visibility)); err != nil { + return fmt.Errorf("Error setting `visibility`: %+v", err) + } + } + d.Set("type", resp.Type) + tags.FlattenAndSet(d, resp.Tags) + + return nil +} + +func resourceArmPrivateLinkServiceDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).network.PrivateLinkServiceClient + ctx := meta.(*ArmClient).StopContext + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["privateLinkServices"] + + future, err := client.Delete(ctx, resourceGroup, name) + if err != nil { + if response.WasNotFound(future.Response()) { + return nil + } + return fmt.Errorf("Error deleting Private Link Service %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if !response.WasNotFound(future.Response()) { + return fmt.Errorf("Error waiting for deleting Private Link Service %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + + return nil +} + +func expandArmPrivateLinkServicePrivateLinkServicePropertiesAutoApproval(input []interface{}) *network.PrivateLinkServicePropertiesAutoApproval { + if len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + + subscriptions := v["subscriptions"].([]interface{}) + + result := network.PrivateLinkServicePropertiesAutoApproval{ + Subscriptions: utils.ExpandStringSlice(subscriptions), + } + return &result +} + +func expandArmPrivateLinkServicePrivateLinkServiceIPConfiguration(input []interface{}) *[]network.PrivateLinkServiceIPConfiguration { + results := make([]network.PrivateLinkServiceIPConfiguration, 0) + for _, item := range input { + v := item.(map[string]interface{}) + privateIpAddress := v["private_ip_address"].(string) + privateIpallocationMethod := v["private_ipallocation_method"].(string) + subnet := v["subnet"].([]interface{}) + privateIpAddressVersion := v["private_ip_address_version"].(string) + name := v["name"].(string) + + result := network.PrivateLinkServiceIPConfiguration{ + Name: utils.String(name), + PrivateLinkServiceIPConfigurationProperties: &network.PrivateLinkServiceIPConfigurationProperties{ + PrivateIPAddress: utils.String(privateIpAddress), + PrivateIPAddressVersion: network.IPVersion(privateIpAddressVersion), + PrivateIPAllocationMethod: network.IPAllocationMethod(privateIpallocationMethod), + Subnet: expandArmPrivateLinkServiceSubnet(subnet), + }, + } + + results = append(results, result) + } + return &results +} + +func expandArmPrivateLinkServiceFrontendIPConfiguration(input []interface{}) *[]network.FrontendIPConfiguration { + results := make([]network.FrontendIPConfiguration, 0) + for _, item := range input { + v := item.(map[string]interface{}) + id := v["id"].(string) + privateIpAddress := v["private_ip_address"].(string) + subnet := v["subnet"].([]interface{}) + publicIpAddress := v["public_ip_address"].([]interface{}) + publicIpprefix := v["public_ipprefix"].([]interface{}) + name := v["name"].(string) + etag := v["etag"].(string) + + result := network.FrontendIPConfiguration{ + Etag: utils.String(etag), + ID: utils.String(id), + Name: utils.String(name), + FrontendIPConfigurationPropertiesFormat: &network.FrontendIPConfigurationPropertiesFormat{ + PrivateIPAddress: utils.String(privateIpAddress), + PublicIPAddress: expandArmPrivateLinkServicePublicIPAddress(publicIpAddress), + PublicIPPrefix: expandArmPrivateLinkServiceSubResource(publicIpprefix), + Subnet: expandArmPrivateLinkServiceSubnet(subnet), + }, + } + + results = append(results, result) + } + return &results +} + +func expandArmPrivateLinkServicePrivateEndpointConnection(input []interface{}) *[]network.PrivateEndpointConnection { + results := make([]network.PrivateEndpointConnection, 0) + for _, item := range input { + v := item.(map[string]interface{}) + id := v["id"].(string) + privateEndpoint := v["private_endpoint"].([]interface{}) + privateLinkServiceConnectionState := v["private_link_service_connection_state"].([]interface{}) + name := v["name"].(string) + + result := network.PrivateEndpointConnection{ + ID: utils.String(id), + Name: utils.String(name), + PrivateEndpointConnectionProperties: &network.PrivateEndpointConnectionProperties{ + PrivateEndpoint: expandArmPrivateLinkServicePrivateEndpoint(privateEndpoint), + PrivateLinkServiceConnectionState: expandArmPrivateLinkServicePrivateLinkServiceConnectionState(privateLinkServiceConnectionState), + }, + } + + results = append(results, result) + } + return &results +} + +func expandArmPrivateLinkServicePrivateLinkServicePropertiesVisibility(input []interface{}) *network.PrivateLinkServicePropertiesVisibility { + if len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + + subscriptions := v["subscriptions"].([]interface{}) + + result := network.PrivateLinkServicePropertiesVisibility{ + Subscriptions: utils.ExpandStringSlice(subscriptions), + } + return &result +} + +func expandArmPrivateLinkServiceSubnet(input []interface{}) *network.Subnet { + if len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + + id := v["id"].(string) + name := v["name"].(string) + etag := v["etag"].(string) + + result := network.Subnet{ + Etag: utils.String(etag), + ID: utils.String(id), + Name: utils.String(name), + } + return &result +} + +func expandArmPrivateLinkServicePublicIPAddress(input []interface{}) *network.PublicIPAddress { + if len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + + id := v["id"].(string) + location := azure.NormalizeLocation(v["location"].(string)) + tags := v["tags"].(map[string]interface{}) + etag := v["etag"].(string) + zones := v["zones"].([]interface{}) + + result := network.PublicIPAddress{ + Etag: utils.String(etag), + ID: utils.String(id), + Location: utils.String(location), + Tags: tags.Expand(t), + Zones: utils.ExpandStringSlice(zones), + } + return &result +} + +func expandArmPrivateLinkServiceSubResource(input []interface{}) *network.SubResource { + if len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + + id := v["id"].(string) + + result := network.SubResource{ + ID: utils.String(id), + } + return &result +} + +func expandArmPrivateLinkServiceSubnet(input []interface{}) *network.Subnet { + if len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + + id := v["id"].(string) + name := v["name"].(string) + etag := v["etag"].(string) + + result := network.Subnet{ + Etag: utils.String(etag), + ID: utils.String(id), + Name: utils.String(name), + } + return &result +} + +func expandArmPrivateLinkServicePrivateEndpoint(input []interface{}) *network.PrivateEndpoint { + if len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + + id := v["id"].(string) + location := azure.NormalizeLocation(v["location"].(string)) + tags := v["tags"].(map[string]interface{}) + etag := v["etag"].(string) + + result := network.PrivateEndpoint{ + Etag: utils.String(etag), + ID: utils.String(id), + Location: utils.String(location), + Tags: tags.Expand(t), + } + return &result +} + +func expandArmPrivateLinkServicePrivateLinkServiceConnectionState(input []interface{}) *network.PrivateLinkServiceConnectionState { + if len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + + status := v["status"].(string) + description := v["description"].(string) + actionRequired := v["action_required"].(string) + + result := network.PrivateLinkServiceConnectionState{ + ActionRequired: utils.String(actionRequired), + Description: utils.String(description), + Status: utils.String(status), + } + return &result +} + +func flattenArmPrivateLinkServicePrivateLinkServicePropertiesAutoApproval(input *network.PrivateLinkServicePropertiesAutoApproval) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + result := make(map[string]interface{}) + + result["subscriptions"] = utils.FlattenStringSlice(input.Subscriptions) + + return []interface{}{result} +} + +func flattenArmPrivateLinkServicePrivateLinkServiceIPConfiguration(input *[]network.PrivateLinkServiceIPConfiguration) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + v := make(map[string]interface{}) + + if name := item.Name; name != nil { + v["name"] = *name + } + if privateLinkServiceIPConfigurationProperties := item.PrivateLinkServiceIPConfigurationProperties; privateLinkServiceIPConfigurationProperties != nil { + if privateIpAddress := privateLinkServiceIPConfigurationProperties.PrivateIPAddress; privateIpAddress != nil { + v["private_ip_address"] = *privateIpAddress + } + v["private_ip_address_version"] = string(privateLinkServiceIPConfigurationProperties.PrivateIPAddressVersion) + v["private_ipallocation_method"] = string(privateLinkServiceIPConfigurationProperties.PrivateIPAllocationMethod) + v["subnet"] = flattenArmPrivateLinkServiceSubnet(privateLinkServiceIPConfigurationProperties.Subnet) + } + + results = append(results, v) + } + + return results +} + +func flattenArmPrivateLinkServiceFrontendIPConfiguration(input *[]network.FrontendIPConfiguration) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + v := make(map[string]interface{}) + + if id := item.ID; id != nil { + v["id"] = *id + } + if etag := item.Etag; etag != nil { + v["etag"] = *etag + } + if frontendIPConfigurationPropertiesFormat := item.FrontendIPConfigurationPropertiesFormat; frontendIPConfigurationPropertiesFormat != nil { + if privateIpAddress := frontendIPConfigurationPropertiesFormat.PrivateIPAddress; privateIpAddress != nil { + v["private_ip_address"] = *privateIpAddress + } + v["private_ip_address_version"] = string(frontendIPConfigurationPropertiesFormat.PrivateIPAddressVersion) + v["private_ipallocation_method"] = string(frontendIPConfigurationPropertiesFormat.PrivateIPAllocationMethod) + v["public_ip_address"] = flattenArmPrivateLinkServicePublicIPAddress(frontendIPConfigurationPropertiesFormat.PublicIPAddress) + v["public_ipprefix"] = flattenArmPrivateLinkServiceSubResource(frontendIPConfigurationPropertiesFormat.PublicIPPrefix) + v["subnet"] = flattenArmPrivateLinkServiceSubnet(frontendIPConfigurationPropertiesFormat.Subnet) + } + v["zones"] = utils.FlattenStringSlice(item.Zones) + + results = append(results, v) + } + + return results +} + +func flattenArmPrivateLinkServiceInterface(input *[]network.Interface) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + v := make(map[string]interface{}) + + if id := item.ID; id != nil { + v["id"] = *id + } + + results = append(results, v) + } + + return results +} + +func flattenArmPrivateLinkServicePrivateEndpointConnection(input *[]network.PrivateEndpointConnection) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + v := make(map[string]interface{}) + + if id := item.ID; id != nil { + v["id"] = *id + } + if privateEndpointConnectionProperties := item.PrivateEndpointConnectionProperties; privateEndpointConnectionProperties != nil { + v["private_endpoint"] = flattenArmPrivateLinkServicePrivateEndpoint(privateEndpointConnectionProperties.PrivateEndpoint) + v["private_link_service_connection_state"] = flattenArmPrivateLinkServicePrivateLinkServiceConnectionState(privateEndpointConnectionProperties.PrivateLinkServiceConnectionState) + } + + results = append(results, v) + } + + return results +} + +func flattenArmPrivateLinkServicePrivateLinkServicePropertiesVisibility(input *network.PrivateLinkServicePropertiesVisibility) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + result := make(map[string]interface{}) + + result["subscriptions"] = utils.FlattenStringSlice(input.Subscriptions) + + return []interface{}{result} +} + +func flattenArmPrivateLinkServiceSubnet(input *network.Subnet) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + result := make(map[string]interface{}) + + if id := input.ID; id != nil { + result["id"] = *id + } + if etag := input.Etag; etag != nil { + result["etag"] = *etag + } + + return []interface{}{result} +} + +func flattenArmPrivateLinkServicePublicIPAddress(input *network.PublicIPAddress) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + result := make(map[string]interface{}) + + if id := input.ID; id != nil { + result["id"] = *id + } + if location := input.Location; location != nil { + result["location"] = azure.NormalizeLocation(*location) + } + if etag := input.Etag; etag != nil { + result["etag"] = *etag + } + result["zones"] = utils.FlattenStringSlice(input.Zones) + // TODO: setting tags to result is not supported + + return []interface{}{result} +} + +func flattenArmPrivateLinkServiceSubResource(input *network.SubResource) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + result := make(map[string]interface{}) + + if id := input.ID; id != nil { + result["id"] = *id + } + + return []interface{}{result} +} + +func flattenArmPrivateLinkServiceSubnet(input *network.Subnet) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + result := make(map[string]interface{}) + + if id := input.ID; id != nil { + result["id"] = *id + } + if etag := input.Etag; etag != nil { + result["etag"] = *etag + } + + return []interface{}{result} +} + +func flattenArmPrivateLinkServicePrivateEndpoint(input *network.PrivateEndpoint) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + result := make(map[string]interface{}) + + if id := input.ID; id != nil { + result["id"] = *id + } + if location := input.Location; location != nil { + result["location"] = azure.NormalizeLocation(*location) + } + if etag := input.Etag; etag != nil { + result["etag"] = *etag + } + // TODO: setting tags to result is not supported + + return []interface{}{result} +} + +func flattenArmPrivateLinkServicePrivateLinkServiceConnectionState(input *network.PrivateLinkServiceConnectionState) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + result := make(map[string]interface{}) + + if actionRequired := input.ActionRequired; actionRequired != nil { + result["action_required"] = *actionRequired + } + if description := input.Description; description != nil { + result["description"] = *description + } + if status := input.Status; status != nil { + result["status"] = *status + } + + return []interface{}{result} +} diff --git a/azurerm/resource_arm_private_link_service_test.go b/azurerm/resource_arm_private_link_service_test.go new file mode 100644 index 000000000000..d2d8f3582fea --- /dev/null +++ b/azurerm/resource_arm_private_link_service_test.go @@ -0,0 +1,287 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file at +// https://github.com/Azure/magic-module-specs +// +// ---------------------------------------------------------------------------- + +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMPrivateLinkService_basic(t *testing.T) { + resourceName := "azurerm_private_link_service.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPrivateLinkServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMPrivateLinkService_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateLinkServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "fqdns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "fqdns.0", "testFqdns"), + resource.TestCheckResourceAttr(resourceName, "ip_configurations.%", "5"), + resource.TestCheckResourceAttr(resourceName, "ip_configurations.private_ip_address", "10.5.1.17"), + resource.TestCheckResourceAttr(resourceName, "ip_configurations.private_ip_address_version", "IPv4"), + resource.TestCheckResourceAttr(resourceName, "ip_configurations.private_ipallocation_method", "Static"), + resource.TestCheckResourceAttr(resourceName, "load_balancer_frontend_ip_configurations.%", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMPrivateLinkService_update(t *testing.T) { + resourceName := "azurerm_private_link_service.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPrivateLinkServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMPrivateLinkService_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateLinkServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "fqdns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "fqdns.0", "testFqdns"), + resource.TestCheckResourceAttr(resourceName, "ip_configurations.%", "5"), + resource.TestCheckResourceAttr(resourceName, "ip_configurations.private_ip_address", "10.5.1.17"), + resource.TestCheckResourceAttr(resourceName, "ip_configurations.private_ip_address_version", "IPv4"), + resource.TestCheckResourceAttr(resourceName, "ip_configurations.private_ipallocation_method", "Static"), + resource.TestCheckResourceAttr(resourceName, "load_balancer_frontend_ip_configurations.%", "1"), + ), + }, + { + Config: testAccAzureRMPrivateLinkService_complete(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPrivateLinkServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "fqdns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "fqdns.0", "testFqdns2"), + resource.TestCheckResourceAttr(resourceName, "ip_configurations.%", "5"), + resource.TestCheckResourceAttr(resourceName, "ip_configurations.private_ip_address", "10.5.1.17"), + resource.TestCheckResourceAttr(resourceName, "ip_configurations.private_ip_address_version", "IPv4"), + resource.TestCheckResourceAttr(resourceName, "ip_configurations.private_ipallocation_method", "Static"), + resource.TestCheckResourceAttr(resourceName, "load_balancer_frontend_ip_configurations.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.env", "test"), + ), + }, + }, + }) +} + +func testCheckAzureRMPrivateLinkServiceExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Private Link Service not found: %s", resourceName) + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group"] + + client := testAccProvider.Meta().(*ArmClient).network.PrivateLinkServiceClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + if resp, err := client.Get(ctx, resourceGroup, name); err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Private Link Service %q (Resource Group %q) does not exist", name, resourceGroup) + } + return fmt.Errorf("Bad: Get on network.PrivateLinkServiceClient: %+v", err) + } + + return nil + } +} + +func testCheckAzureRMPrivateLinkServiceDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).network.PrivateLinkServiceClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_private_link_service" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group"] + + if resp, err := client.Get(ctx, resourceGroup, name); err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Get on network.PrivateLinkServiceClient: %+v", err) + } + } + + return nil + } + + return nil +} + +func testAccAzureRMPrivateLinkService_basic(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvnet-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + address_space = ["10.5.0.0/16"] +} + +resource "azurerm_subnet" "test" { + name = "acctestsnet-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefix = "10.5.1.0/24" + private_endpoint_network_policies = "Disabled" + private_link_service_network_policies = "Disabled" +} + +resource "azurerm_public_ip" "test" { + name = "acctestpip-%d" + sku = "Standard" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + allocation_method = "Static" +} + +resource "azurerm_lb" "test" { + name = "acctestpip-%d" + sku = "Standard" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + frontend_ip_configuration { + name = "${azurerm_public_ip.test.name}" + public_ip_address_id = "${azurerm_public_ip.test.id}" + } +} + +resource "azurerm_private_link_service" "test" { + name = "acctestvirtualhub-%d" + location = "${azurerm_resource_group.test.location}" + resource_group = "${azurerm_resource_group.test.name}" + fqdns = ["testFqdns"] + + ip_configurations { + name = "${azurerm_public_ip.test.name}" + + subnet { + id = "${azurerm_subnet.test.id}" + } + + private_ip_address = "10.5.1.17" + private_ip_address_version = "IPv4" + private_ipallocation_method = "Static" + } + + load_balancer_frontend_ip_configurations { + id = "${azurerm_lb.test.frontend_ip_configuration.0.id}" + } +} +`, rInt, location, rInt, rInt, rInt, rInt, rInt) +} + +func testAccAzureRMPrivateLinkService_complete(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvnet-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + address_space = ["10.5.0.0/16"] +} + +resource "azurerm_subnet" "test" { + name = "acctestsnet-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefix = "10.5.1.0/24" + private_endpoint_network_policies = "Disabled" + private_link_service_network_policies = "Disabled" +} + +resource "azurerm_public_ip" "test" { + name = "acctestpip-%d" + sku = "Standard" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + allocation_method = "Static" +} + +resource "azurerm_lb" "test" { + name = "acctestpip-%d" + sku = "Standard" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + frontend_ip_configuration { + name = "${azurerm_public_ip.test.name}" + public_ip_address_id = "${azurerm_public_ip.test.id}" + } +} + +resource "azurerm_private_link_service" "test" { + name = "acctestvirtualhub-%d" + location = "${azurerm_resource_group.test.location}" + resource_group = "${azurerm_resource_group.test.name}" + fqdns = ["testFqdns2"] + + ip_configurations { + name = "${azurerm_public_ip.test.name}" + + subnet { + id = "${azurerm_subnet.test.id}" + } + + private_ip_address = "10.5.1.17" + private_ip_address_version = "IPv4" + private_ipallocation_method = "Static" + } + + load_balancer_frontend_ip_configurations { + id = "${azurerm_lb.test.frontend_ip_configuration.0.id}" + } + + tags = { + env = "test" + } +} +`, rInt, location, rInt, rInt, rInt, rInt, rInt) +} diff --git a/azurerm/resource_arm_virtual_hub.go b/azurerm/resource_arm_virtual_hub.go new file mode 100644 index 000000000000..d04a8013f381 --- /dev/null +++ b/azurerm/resource_arm_virtual_hub.go @@ -0,0 +1,496 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file at +// https://github.com/Azure/magic-module-specs +// +// ---------------------------------------------------------------------------- + +package azurerm + +import ( + "fmt" + "log" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-12-01/network" + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/response" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmVirtualHub() *schema.Resource { + return &schema.Resource{ + Create: resourceArmVirtualHubCreateUpdate, + Read: resourceArmVirtualHubRead, + Update: resourceArmVirtualHubCreateUpdate, + Delete: resourceArmVirtualHubDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "location": azure.SchemaLocation(), + + "resource_group": azure.SchemaResourceGroupNameDiffSuppress(), + + "address_prefix": { + Type: schema.TypeString, + Optional: true, + }, + + "express_route_gateway": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + + "p2svpn_gateway": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + + "route_table": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "routes": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address_prefixes": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "next_hop_ip_address": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + + "tags": tags.Schema(), + + "virtual_network_connections": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allow_hub_to_remote_vnet_transit": { + Type: schema.TypeBool, + Optional: true, + }, + "allow_remote_vnet_to_use_hub_vnet_gateways": { + Type: schema.TypeBool, + Optional: true, + }, + "enable_internet_security": { + Type: schema.TypeBool, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "remote_virtual_network": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + + "virtual_wan": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + + "vpn_gateway": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + + "etag": { + Type: schema.TypeString, + Computed: true, + }, + + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceArmVirtualHubCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).network.VirtualHubClient + ctx := meta.(*ArmClient).StopContext + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group").(string) + + if features.ShouldResourcesBeImported() && d.IsNewResource() { + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Error checking for present of existing Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + if !utils.ResponseWasNotFound(resp.Response) { + return tf.ImportAsExistsError("azurerm_virtual_hub", *resp.ID) + } + } + + location := azure.NormalizeLocation(d.Get("location").(string)) + addressPrefix := d.Get("address_prefix").(string) + expressRouteGateway := d.Get("express_route_gateway").([]interface{}) + p2svpnGateway := d.Get("p2svpn_gateway").([]interface{}) + routeTable := d.Get("route_table").([]interface{}) + virtualNetworkConnections := d.Get("virtual_network_connections").([]interface{}) + virtualWan := d.Get("virtual_wan").([]interface{}) + vpnGateway := d.Get("vpn_gateway").([]interface{}) + t := d.Get("tags").(map[string]interface{}) + + virtualHubParameters := network.VirtualHub{ + Location: utils.String(location), + VirtualHubProperties: &network.VirtualHubProperties{ + AddressPrefix: utils.String(addressPrefix), + ExpressRouteGateway: expandArmVirtualHubSubResource(expressRouteGateway), + P2SVpnGateway: expandArmVirtualHubSubResource(p2svpnGateway), + RouteTable: expandArmVirtualHubVirtualHubRouteTable(routeTable), + VirtualNetworkConnections: expandArmVirtualHubHubVirtualNetworkConnection(virtualNetworkConnections), + VirtualWan: expandArmVirtualHubSubResource(virtualWan), + VpnGateway: expandArmVirtualHubSubResource(vpnGateway), + }, + Tags: tags.Expand(t), + } + + future, err := client.CreateOrUpdate(ctx, resourceGroup, name, virtualHubParameters) + if err != nil { + return fmt.Errorf("Error creating Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for creation of Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Error retrieving Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + if resp.ID == nil { + return fmt.Errorf("Cannot read Virtual Hub %q (Resource Group %q) ID", name, resourceGroup) + } + d.SetId(*resp.ID) + + return resourceArmVirtualHubRead(d, meta) +} + +func resourceArmVirtualHubRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).network.VirtualHubClient + ctx := meta.(*ArmClient).StopContext + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["virtualHubs"] + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Virtual Hub %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("Error reading Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.Set("name", resp.Name) + d.Set("resource_group", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + if virtualHubProperties := resp.VirtualHubProperties; virtualHubProperties != nil { + d.Set("address_prefix", virtualHubProperties.AddressPrefix) + if err := d.Set("express_route_gateway", flattenArmVirtualHubSubResource(virtualHubProperties.ExpressRouteGateway)); err != nil { + return fmt.Errorf("Error setting `express_route_gateway`: %+v", err) + } + if err := d.Set("p2svpn_gateway", flattenArmVirtualHubSubResource(virtualHubProperties.P2SVpnGateway)); err != nil { + return fmt.Errorf("Error setting `p2svpn_gateway`: %+v", err) + } + if err := d.Set("route_table", flattenArmVirtualHubVirtualHubRouteTable(virtualHubProperties.RouteTable)); err != nil { + return fmt.Errorf("Error setting `route_table`: %+v", err) + } + if err := d.Set("virtual_network_connections", flattenArmVirtualHubHubVirtualNetworkConnection(virtualHubProperties.VirtualNetworkConnections)); err != nil { + return fmt.Errorf("Error setting `virtual_network_connections`: %+v", err) + } + if err := d.Set("virtual_wan", flattenArmVirtualHubSubResource(virtualHubProperties.VirtualWan)); err != nil { + return fmt.Errorf("Error setting `virtual_wan`: %+v", err) + } + if err := d.Set("vpn_gateway", flattenArmVirtualHubSubResource(virtualHubProperties.VpnGateway)); err != nil { + return fmt.Errorf("Error setting `vpn_gateway`: %+v", err) + } + } + d.Set("etag", resp.Etag) + d.Set("type", resp.Type) + tags.FlattenAndSet(d, resp.Tags) + + return nil +} + +func resourceArmVirtualHubDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).network.VirtualHubClient + ctx := meta.(*ArmClient).StopContext + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["virtualHubs"] + + future, err := client.Delete(ctx, resourceGroup, name) + if err != nil { + if response.WasNotFound(future.Response()) { + return nil + } + return fmt.Errorf("Error deleting Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if !response.WasNotFound(future.Response()) { + return fmt.Errorf("Error waiting for deleting Virtual Hub %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + + return nil +} + +func expandArmVirtualHubSubResource(input []interface{}) *network.SubResource { + if len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + + id := v["id"].(string) + + result := network.SubResource{ + ID: utils.String(id), + } + return &result +} + +func expandArmVirtualHubVirtualHubRouteTable(input []interface{}) *network.VirtualHubRouteTable { + if len(input) == 0 { + return nil + } + v := input[0].(map[string]interface{}) + + routes := v["routes"].([]interface{}) + + result := network.VirtualHubRouteTable{ + Routes: expandArmVirtualHubVirtualHubRoute(routes), + } + return &result +} + +func expandArmVirtualHubHubVirtualNetworkConnection(input []interface{}) *[]network.HubVirtualNetworkConnection { + results := make([]network.HubVirtualNetworkConnection, 0) + for _, item := range input { + v := item.(map[string]interface{}) + id := v["id"].(string) + remoteVirtualNetwork := v["remote_virtual_network"].([]interface{}) + allowHubToRemoteVnetTransit := v["allow_hub_to_remote_vnet_transit"].(bool) + allowRemoteVnetToUseHubVnetGateways := v["allow_remote_vnet_to_use_hub_vnet_gateways"].(bool) + enableInternetSecurity := v["enable_internet_security"].(bool) + name := v["name"].(string) + + result := network.HubVirtualNetworkConnection{ + ID: utils.String(id), + Name: utils.String(name), + HubVirtualNetworkConnectionProperties: &network.HubVirtualNetworkConnectionProperties{ + AllowHubToRemoteVnetTransit: utils.Bool(allowHubToRemoteVnetTransit), + AllowRemoteVnetToUseHubVnetGateways: utils.Bool(allowRemoteVnetToUseHubVnetGateways), + EnableInternetSecurity: utils.Bool(enableInternetSecurity), + RemoteVirtualNetwork: expandArmVirtualHubSubResource(remoteVirtualNetwork), + }, + } + + results = append(results, result) + } + return &results +} + +func expandArmVirtualHubVirtualHubRoute(input []interface{}) *[]network.VirtualHubRoute { + results := make([]network.VirtualHubRoute, 0) + for _, item := range input { + v := item.(map[string]interface{}) + addressPrefixes := v["address_prefixes"].([]interface{}) + nextHopIpAddress := v["next_hop_ip_address"].(string) + + result := network.VirtualHubRoute{ + AddressPrefixes: utils.ExpandStringSlice(addressPrefixes), + NextHopIPAddress: utils.String(nextHopIpAddress), + } + + results = append(results, result) + } + return &results +} + +func flattenArmVirtualHubSubResource(input *network.SubResource) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + result := make(map[string]interface{}) + + if id := input.ID; id != nil { + result["id"] = *id + } + + return []interface{}{result} +} + +func flattenArmVirtualHubVirtualHubRouteTable(input *network.VirtualHubRouteTable) []interface{} { + if input == nil { + return make([]interface{}, 0) + } + + result := make(map[string]interface{}) + + result["routes"] = flattenArmVirtualHubVirtualHubRoute(input.Routes) + + return []interface{}{result} +} + +func flattenArmVirtualHubHubVirtualNetworkConnection(input *[]network.HubVirtualNetworkConnection) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + v := make(map[string]interface{}) + + if id := item.ID; id != nil { + v["id"] = *id + } + if name := item.Name; name != nil { + v["name"] = *name + } + if hubVirtualNetworkConnectionProperties := item.HubVirtualNetworkConnectionProperties; hubVirtualNetworkConnectionProperties != nil { + if allowHubToRemoteVnetTransit := hubVirtualNetworkConnectionProperties.AllowHubToRemoteVnetTransit; allowHubToRemoteVnetTransit != nil { + v["allow_hub_to_remote_vnet_transit"] = *allowHubToRemoteVnetTransit + } + if allowRemoteVnetToUseHubVnetGateways := hubVirtualNetworkConnectionProperties.AllowRemoteVnetToUseHubVnetGateways; allowRemoteVnetToUseHubVnetGateways != nil { + v["allow_remote_vnet_to_use_hub_vnet_gateways"] = *allowRemoteVnetToUseHubVnetGateways + } + if enableInternetSecurity := hubVirtualNetworkConnectionProperties.EnableInternetSecurity; enableInternetSecurity != nil { + v["enable_internet_security"] = *enableInternetSecurity + } + v["remote_virtual_network"] = flattenArmVirtualHubSubResource(hubVirtualNetworkConnectionProperties.RemoteVirtualNetwork) + } + + results = append(results, v) + } + + return results +} + +func flattenArmVirtualHubVirtualHubRoute(input *[]network.VirtualHubRoute) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + v := make(map[string]interface{}) + + v["address_prefixes"] = utils.FlattenStringSlice(item.AddressPrefixes) + if nextHopIpAddress := item.NextHopIPAddress; nextHopIpAddress != nil { + v["next_hop_ip_address"] = *nextHopIpAddress + } + + results = append(results, v) + } + + return results +} diff --git a/azurerm/resource_arm_virtual_hub_test.go b/azurerm/resource_arm_virtual_hub_test.go new file mode 100644 index 000000000000..f388194d493a --- /dev/null +++ b/azurerm/resource_arm_virtual_hub_test.go @@ -0,0 +1,289 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file at +// https://github.com/Azure/magic-module-specs +// +// ---------------------------------------------------------------------------- + +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMVirtualHub_basic(t *testing.T) { + resourceName := "azurerm_virtual_hub.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualHubDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMVirtualHub_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualHubExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "address_prefix", "10.0.1.0/24"), + resource.TestCheckResourceAttr(resourceName, "virtual_wan.%", "1"), + resource.TestCheckResourceAttr(resourceName, "route_table.%", "1"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.address_prefixes.#", "2"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.address_prefixes.0", "10.0.2.0/24"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.address_prefixes.1", "10.0.3.0/24"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.next_hop_ip_address", "10.0.4.5"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMVirtualHub_complete(t *testing.T) { + resourceName := "azurerm_virtual_hub.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualHubDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMVirtualHub_complete(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualHubExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "address_prefix", "10.0.1.0/24"), + resource.TestCheckResourceAttr(resourceName, "virtual_wan.%", "1"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connections.%", "5"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connections.name", "testConnection"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connections.allow_hub_to_remote_vnet_transit", "false"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connections.allow_remote_vnet_to_use_hub_vnet_gateways", "false"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connections.enable_internet_security", "false"), + resource.TestCheckResourceAttr(resourceName, "route_table.%", "1"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.address_prefixes.#", "2"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.address_prefixes.0", "10.0.2.0/24"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.address_prefixes.1", "10.0.3.0/24"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.next_hop_ip_address", "10.0.4.6"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.env", "test"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMVirtualHub_update(t *testing.T) { + resourceName := "azurerm_virtual_hub.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualHubDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMVirtualHub_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualHubExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "address_prefix", "10.0.1.0/24"), + resource.TestCheckResourceAttr(resourceName, "virtual_wan.%", "1"), + resource.TestCheckResourceAttr(resourceName, "route_table.%", "1"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.address_prefixes.#", "2"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.address_prefixes.0", "10.0.2.0/24"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.address_prefixes.1", "10.0.3.0/24"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.next_hop_ip_address", "10.0.4.5"), + ), + }, + { + Config: testAccAzureRMVirtualHub_complete(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualHubExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "address_prefix", "10.0.1.0/24"), + resource.TestCheckResourceAttr(resourceName, "virtual_wan.%", "1"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connections.%", "5"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connections.name", "testConnection"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connections.allow_hub_to_remote_vnet_transit", "false"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connections.allow_remote_vnet_to_use_hub_vnet_gateways", "false"), + resource.TestCheckResourceAttr(resourceName, "virtual_network_connections.enable_internet_security", "false"), + resource.TestCheckResourceAttr(resourceName, "route_table.%", "1"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.address_prefixes.#", "2"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.address_prefixes.0", "10.0.2.0/24"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.address_prefixes.1", "10.0.3.0/24"), + resource.TestCheckResourceAttr(resourceName, "route_table.routes.next_hop_ip_address", "10.0.4.6"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.env", "test"), + ), + }, + }, + }) +} + +func testCheckAzureRMVirtualHubExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Virtual Hub not found: %s", resourceName) + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group"] + + client := testAccProvider.Meta().(*ArmClient).network.VirtualHubClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + if resp, err := client.Get(ctx, resourceGroup, name); err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Virtual Hub %q (Resource Group %q) does not exist", name, resourceGroup) + } + return fmt.Errorf("Bad: Get on network.VirtualHubClient: %+v", err) + } + + return nil + } +} + +func testCheckAzureRMVirtualHubDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).network.VirtualHubClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_virtual_hub" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group"] + + if resp, err := client.Get(ctx, resourceGroup, name); err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Get on network.VirtualHubClient: %+v", err) + } + } + + return nil + } + + return nil +} + +func testAccAzureRMVirtualHub_basic(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_wan" "test" { + name = "acctestvwan-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" +} + +resource "azurerm_virtual_hub" "test" { + name = "acctestvirtualhub-%d" + resource_group = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + address_prefix = "10.0.1.0/24" + + virtual_wan { + id = "${azurerm_virtual_wan.test.id}" + } + + route_table { + routes { + address_prefixes = ["10.0.2.0/24", "10.0.3.0/24"] + next_hop_ip_address = "10.0.4.5" + } + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMVirtualHub_complete(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvnet-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + address_space = ["10.5.0.0/16"] +} + +resource "azurerm_subnet" "test" { + name = "acctestsnet-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefix = "10.5.1.0/24" + private_endpoint_network_policies = "Disabled" + private_link_service_network_policies = "Disabled" +} + +resource "azurerm_virtual_wan" "test" { + name = "acctestvwan-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" +} + +resource "azurerm_virtual_hub" "test" { + name = "acctestvirtualhub-%d" + resource_group = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + address_prefix = "10.0.1.0/24" + + virtual_wan { + id = "${azurerm_virtual_wan.test.id}" + } + + virtual_network_connections { + name = "testConnection" + + remote_virtual_network { + id = "${azurerm_virtual_network.test.id}" + } + + allow_hub_to_remote_vnet_transit = "false" + allow_remote_vnet_to_use_hub_vnet_gateways = "false" + enable_internet_security = "false" + } + + route_table { + routes { + address_prefixes = ["10.0.2.0/24", "10.0.3.0/24"] + next_hop_ip_address = "10.0.4.6" + } + } + + tags = { + env = "test" + } +} +`, rInt, location, rInt, rInt, rInt, rInt) +} diff --git a/website/docs/d/private_endpoint.html.markdown b/website/docs/d/private_endpoint.html.markdown new file mode 100644 index 000000000000..1ac738e4170d --- /dev/null +++ b/website/docs/d/private_endpoint.html.markdown @@ -0,0 +1,121 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file at +# https://github.com/Azure/magic-module-specs +# +# ---------------------------------------------------------------------------- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_private_endpoint" +sidebar_current: "docs-azurerm-datasource-private-endpoint" +description: |- + Gets information about an existing Private Endpoint +--- + +# Data Source: azurerm_private_endpoint + +Use this data source to access information about an existing Private Endpoint. + + +## Example Usage + +```hcl +data "azurerm_private_endpoint" "example" { + resource_group_name = "example-rg" + name = "example-private-endpoint" +} + +output "subnet_id" { + value = "${data.azurerm_private_endpoint.example.id}" +} +``` + + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the private endpoint. + +* `resource_group_name` - (Required) The Name of the Resource Group where the App Service exists. + + +## Attributes Reference + +The following attributes are exported: + +* `location` - Resource location. + +* `manual_private_link_service_connections` - One or more `manual_private_link_service_connection` block defined below. + +* `network_interfaces` - One or more `network_interface` block defined below. + +* `private_link_service_connections` - One or more `private_link_service_connection` block defined below. + +* `subnet_id` - The ID of the subnet from which the private IP will be allocated. + +* `tags` - Resource tags. + + +--- + +The `manual_private_link_service_connection` block contains the following: + +* `private_link_service_id` - The resource id of private link service. + +* `group_ids` - The ID(s) of the group(s) obtained from the remote resource that this private endpoint should connect to. + +* `request_message` - A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. + +* `name` - The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `private_link_service_connection_state` - One `private_link_service_connection_state` block defined below. + + +--- + +The `private_link_service_connection_state` block contains the following: + +* `status` - Indicates whether the connection has been Approved/Rejected/Removed by the owner of the service. + +* `description` - The reason for approval/rejection of the connection. + +* `action_required` - A message indicating if changes on the service provider require any updates on the consumer. + +--- + +The `network_interface` block contains the following: + +* `id` - Resource ID. + +--- + +The `private_link_service_connection` block contains the following: + +* `private_link_service_id` - The resource id of private link service. + +* `group_ids` - The ID(s) of the group(s) obtained from the remote resource that this private endpoint should connect to. + +* `request_message` - A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. + +* `name` - The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `private_link_service_connection_state` - One `private_link_service_connection_state` block defined below. + + +--- + +The `private_link_service_connection_state` block contains the following: + +* `status` - Indicates whether the connection has been Approved/Rejected/Removed by the owner of the service. + +* `description` - The reason for approval/rejection of the connection. + +* `action_required` - A message indicating if changes on the service provider require any updates on the consumer. diff --git a/website/docs/d/private_link_service.html.markdown b/website/docs/d/private_link_service.html.markdown new file mode 100644 index 000000000000..e7db7de007f0 --- /dev/null +++ b/website/docs/d/private_link_service.html.markdown @@ -0,0 +1,319 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file at +# https://github.com/Azure/magic-module-specs +# +# ---------------------------------------------------------------------------- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_private_link_service" +sidebar_current: "docs-azurerm-datasource-private-link-service" +description: |- + Gets information about an existing Private Link Service +--- + +# Data Source: azurerm_private_link_service + +Use this data source to access information about an existing Private Link Service. + + +## Private Link Service Usage + +```hcl +data "azurerm_private_link_service" "example" { + resource_group = "acctestRG" + // TODO: Unsupported property "name" value +} + +output "private_link_service_id" { + value = "${data.azurerm_private_link_service.example.id}" +} +``` + + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the private link service. + +* `resource_group` - (Required) The name of the resource group. + + +## Attributes Reference + +The following attributes are exported: + +* `location` - Resource location. + +* `alias` - The alias of the private link service. + +* `auto_approval` - One `auto_approval` block defined below. + +* `fqdns` - The list of Fqdn. + +* `ip_configurations` - One or more `ip_configuration` block defined below. + +* `load_balancer_frontend_ip_configurations` - One or more `load_balancer_frontend_ip_configuration` block defined below. + +* `network_interfaces` - One or more `network_interface` block defined below. + +* `private_endpoint_connections` - One or more `private_endpoint_connection` block defined below. + +* `type` - Resource type. + +* `visibility` - One `visibility` block defined below. + +* `tags` - Resource tags. + + +--- + +The `auto_approval` block contains the following: + +* `subscriptions` - The list of subscriptions. + +--- + +The `ip_configuration` block contains the following: + +* `private_ip_address` - The private IP address of the IP configuration. + +* `private_ipallocation_method` - The private IP address allocation method. + +* `subnet` - One `subnet` block defined below. + +* `private_ip_address_version` - Available from Api-Version 2016-03-30 onwards, it represents whether the specific ipconfiguration is IPv4 or IPv6. Default is taken as IPv4. + +* `name` - The name of private link service ip configuration. + + +--- + +The `subnet` block contains the following: + +* `id` - Resource ID. + +* `name` - The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `etag` - A unique read-only string that changes whenever the resource is updated. + +--- + +The `load_balancer_frontend_ip_configuration` block contains the following: + +* `id` - Resource ID. + +* `private_ip_address` - The private IP address of the IP configuration. + +* `private_ipallocation_method` - The Private IP allocation method. + +* `private_ip_address_version` - It represents whether the specific ipconfiguration is IPv4 or IPv6. Default is taken as IPv4. + +* `subnet` - One `subnet` block defined below. + +* `public_ip_address` - One `public_ip_address` block defined below. + +* `public_ipprefix` - One `public_ipprefix` block defined below. + +* `name` - The name of the resource that is unique within the set of frontend IP configurations used by the load balancer. This name can be used to access the resource. + +* `etag` - A unique read-only string that changes whenever the resource is updated. + +* `zones` - A list of availability zones denoting the IP allocated for the resource needs to come from. + + +--- + +The `subnet` block contains the following: + +* `id` - Resource ID. + +* `name` - The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `etag` - A unique read-only string that changes whenever the resource is updated. + +--- + +The `public_ip_address` block contains the following: + +* `id` - Resource ID. + +* `location` - Resource location. + +* `tags` - Resource tags. + +* `etag` - A unique read-only string that changes whenever the resource is updated. + +* `zones` - A list of availability zones denoting the IP allocated for the resource needs to come from. + +--- + +The `public_ipprefix` block contains the following: + +* `id` - Resource ID. + +--- + +The `network_interface` block contains the following: + +* `id` - Resource ID. + +* `name` - Resource name. + +* `type` - Resource type. + +* `location` - Resource location. + +* `tags` - Resource tags. + +* `virtual_machine` - One `virtual_machine` block defined below. + +* `network_security_group` - One `network_security_group` block defined below. + +* `private_endpoint` - One `private_endpoint` block defined below. + +* `ip_configurations` - One `ip_configuration` block defined below. + +* `tap_configurations` - One `tap_configuration` block defined below. + +* `dns_settings` - One `dns_setting` block defined below. + +* `mac_address` - The MAC address of the network interface. + +* `primary` - Gets whether this is a primary network interface on a virtual machine. + +* `enable_accelerated_networking` - If the network interface is accelerated networking enabled. + +* `enable_ipforwarding` - Indicates whether IP forwarding is enabled on this network interface. + +* `hosted_workloads` - A list of references to linked BareMetal resources. + +* `resource_guid` - The resource GUID property of the network interface resource. + +* `provisioning_state` - The provisioning state of the public IP resource. Possible values are: 'Updating', 'Deleting', and 'Failed'. + +* `etag` - A unique read-only string that changes whenever the resource is updated. + + +--- + +The `virtual_machine` block contains the following: + +* `id` - Resource ID. + +--- + +The `network_security_group` block contains the following: + +* `id` - Resource ID. + +* `name` - Resource name. + +* `type` - Resource type. + +* `location` - Resource location. + +* `tags` - Resource tags. + +* `etag` - A unique read-only string that changes whenever the resource is updated. + +--- + +The `private_endpoint` block contains the following: + +* `id` - Resource ID. + +* `name` - Resource name. + +* `type` - Resource type. + +* `location` - Resource location. + +* `tags` - Resource tags. + +* `etag` - A unique read-only string that changes whenever the resource is updated. + +--- + +The `ip_configuration` block contains the following: + +* `id` - Resource ID. + +* `name` - The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `etag` - A unique read-only string that changes whenever the resource is updated. + +--- + +The `tap_configuration` block contains the following: + +* `id` - Resource ID. + +* `name` - The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `etag` - A unique read-only string that changes whenever the resource is updated. + +* `type` - Sub Resource type. + +--- + +The `dns_setting` block contains the following: + +* `dns_servers` - List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection. + +* `applied_dns_servers` - If the VM that uses this NIC is part of an Availability Set, then this list will have the union of all DNS servers from all NICs that are part of the Availability Set. This property is what is configured on each of those VMs. + +* `internal_dns_name_label` - Relative DNS name for this NIC used for internal communications between VMs in the same virtual network. + +* `internal_fqdn` - Fully qualified DNS name supporting internal communications between VMs in the same virtual network. + +* `internal_domain_name_suffix` - Even if internalDnsNameLabel is not specified, a DNS entry is created for the primary NIC of the VM. This DNS name can be constructed by concatenating the VM name with the value of internalDomainNameSuffix. + +--- + +The `private_endpoint_connection` block contains the following: + +* `id` - Resource ID. + +* `private_endpoint` - One `private_endpoint` block defined below. + +* `private_link_service_connection_state` - One `private_link_service_connection_state` block defined below. + +* `name` - The name of the resource that is unique within a resource group. This name can be used to access the resource. + + +--- + +The `private_endpoint` block contains the following: + +* `id` - Resource ID. + +* `location` - Resource location. + +* `tags` - Resource tags. + +* `etag` - A unique read-only string that changes whenever the resource is updated. + +--- + +The `private_link_service_connection_state` block contains the following: + +* `status` - Indicates whether the connection has been Approved/Rejected/Removed by the owner of the service. + +* `description` - The reason for approval/rejection of the connection. + +* `action_required` - A message indicating if changes on the service provider require any updates on the consumer. + +--- + +The `visibility` block contains the following: + +* `subscriptions` - The list of subscriptions. diff --git a/website/docs/d/virtual_hub.html.markdown b/website/docs/d/virtual_hub.html.markdown new file mode 100644 index 000000000000..2224041e7b3d --- /dev/null +++ b/website/docs/d/virtual_hub.html.markdown @@ -0,0 +1,137 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file at +# https://github.com/Azure/magic-module-specs +# +# ---------------------------------------------------------------------------- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_virtual_hub" +sidebar_current: "docs-azurerm-datasource-virtual-hub" +description: |- + Gets information about an existing Virtual Hub +--- + +# Data Source: azurerm_virtual_hub + +Use this data source to access information about an existing Virtual Hub. + + +## Vitual Hub Usage + +```hcl +data "azurerm_virtual_hub" "example" { + resource_group = "acctestRG" + // TODO: Unsupported property "name" value +} + +output "virtual_hub_id" { + value = "${data.azurerm_virtual_hub.example.id}" +} +``` + + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the VirtualHub. + +* `resource_group` - (Required) The Name of the Resource Group where the App Service exists. + + +## Attributes Reference + +The following attributes are exported: + +* `location` - Resource location. + +* `address_prefix` - Address-prefix for this VirtualHub. + +* `etag` - Gets a unique read-only string that changes whenever the resource is updated. + +* `express_route_gateway` - One `express_route_gateway` block defined below. + +* `p2svpn_gateway` - One `p2svpn_gateway` block defined below. + +* `route_table` - One `route_table` block defined below. + +* `type` - Resource type. + +* `virtual_network_connections` - One or more `virtual_network_connection` block defined below. + +* `virtual_wan` - One `virtual_wan` block defined below. + +* `vpn_gateway` - One `vpn_gateway` block defined below. + +* `tags` - Resource tags. + + +--- + +The `express_route_gateway` block contains the following: + +* `id` - Resource ID. + +--- + +The `p2svpn_gateway` block contains the following: + +* `id` - Resource ID. + +--- + +The `route_table` block contains the following: + +* `routes` - One or more `route` block defined below. + + +--- + +The `route` block contains the following: + +* `address_prefixes` - List of all addressPrefixes. + +* `next_hop_ip_address` - NextHop ip address. + +--- + +The `virtual_network_connection` block contains the following: + +* `id` - Resource ID. + +* `remote_virtual_network` - One `remote_virtual_network` block defined below. + +* `allow_hub_to_remote_vnet_transit` - VirtualHub to RemoteVnet transit to enabled or not. + +* `allow_remote_vnet_to_use_hub_vnet_gateways` - Allow RemoteVnet to use Virtual Hub's gateways. + +* `enable_internet_security` - Enable internet security. + +* `name` - The name of the resource that is unique within a resource group. This name can be used to access the resource. + + +--- + +The `remote_virtual_network` block contains the following: + +* `id` - Resource ID. + +--- + +The `virtual_wan` block contains the following: + +* `id` - Resource ID. + +--- + +The `vpn_gateway` block contains the following: + +* `id` - Resource ID. diff --git a/website/docs/r/private_endpoint.html.markdown b/website/docs/r/private_endpoint.html.markdown new file mode 100644 index 000000000000..2c9cdd3c7e6e --- /dev/null +++ b/website/docs/r/private_endpoint.html.markdown @@ -0,0 +1,194 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file at +# https://github.com/Azure/magic-module-specs +# +# ---------------------------------------------------------------------------- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_private_endpoint" +sidebar_current: "docs-azurerm-resource-private-endpoint" +description: |- + Manage Azure PrivateEndpoint instance. +--- + +# azurerm_private_endpoint + +Manage Azure PrivateEndpoint instance. + + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-rg" + location = "West US2" +} + +resource "azurerm_virtual_network" "example" { + name = "acctestvnet-%d" + resource_group_name = "${azurerm_resource_group.example.name}" + location = "${azurerm_resource_group.example.location}" + address_space = ["10.5.0.0/16"] +} + +resource "azurerm_subnet" "example" { + name = "acctestsnet-%d" + resource_group_name = "${azurerm_resource_group.example.name}" + virtual_network_name = "${azurerm_virtual_network.example.name}" + address_prefix = "10.5.1.0/24" + private_endpoint_network_policies = "Disabled" + private_link_service_network_policies = "Disabled" +} + +resource "azurerm_public_ip" "example" { + name = "acctestpip-%d" + sku = "Standard" + location = "${azurerm_resource_group.example.location}" + resource_group_name = "${azurerm_resource_group.example.name}" + allocation_method = "Static" +} + +resource "azurerm_lb" "example" { + name = "acctestpip-%d" + sku = "Standard" + location = "${azurerm_resource_group.example.location}" + resource_group_name = "${azurerm_resource_group.example.name}" + + frontend_ip_configuration { + name = "${azurerm_public_ip.example.name}" + public_ip_address_id = "${azurerm_public_ip.example.id}" + } +} + +resource "azurerm_private_link_service" "example" { + name = "acctestvirtualhub-%d" + location = "${azurerm_resource_group.example.location}" + resource_group = "${azurerm_resource_group.example.name}" + fqdns = ["testFqdns"] + + ip_configurations { + name = "${azurerm_public_ip.example.name}" + + subnet { + id = "${azurerm_subnet.example.id}" + } + + private_ip_address = "10.5.1.17" + private_ip_address_version = "IPv4" + private_ipallocation_method = "Static" + } + + load_balancer_frontend_ip_configurations { + id = "${azurerm_lb.example.frontend_ip_configuration.0.id}" + } +} + +resource "azurerm_private_endpoint" "example" { + name = "acctestendpoint-%d" + resource_group_name = "${azurerm_resource_group.example.name}" + location = "${azurerm_resource_group.example.location}" + subnet_id = "${azurerm_subnet.example.id}" + + private_link_service_connections { + name = "acctestconnection-%d" + private_link_service_id = "${azurerm_private_link_service.example.id}" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the private endpoint. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the resource group. Changing this forces a new resource to be created. + +* `subnet_id` - (Required) The ID of the subnet from which the private IP will be allocated. + +* `location` - (Optional) Resource location. Changing this forces a new resource to be created. + +* `manual_private_link_service_connections` - (Optional) One or more `manual_private_link_service_connection` block defined below. + +* `private_link_service_connections` - (Optional) One or more `private_link_service_connection` block defined below. + +* `tags` - (Optional) Resource tags. Changing this forces a new resource to be created. + +--- + +The `manual_private_link_service_connection` block supports the following: + +* `private_link_service_id` - (Required) The resource id of private link service. + +* `group_ids` - (Optional) The ID(s) of the group(s) obtained from the remote resource that this private endpoint should connect to. + +* `request_message` - (Optional) A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. + +* `name` - (Required) The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `private_link_service_connection_state` - One `private_link_service_connection_state` block defined below. + + +--- + +The `private_link_service_connection_state` block contains the following: + +* `status` - Indicates whether the connection has been Approved/Rejected/Removed by the owner of the service. + +* `description` - The reason for approval/rejection of the connection. + +* `action_required` - A message indicating if changes on the service provider require any updates on the consumer. + +--- + +The `private_link_service_connection` block supports the following: + +* `private_link_service_id` - (Required) The resource id of private link service. + +* `group_ids` - (Optional) The ID(s) of the group(s) obtained from the remote resource that this private endpoint should connect to. + +* `request_message` - (Optional) A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars. + +* `name` - (Required) The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `private_link_service_connection_state` - One `private_link_service_connection_state` block defined below. + + +--- + +The `private_link_service_connection_state` block contains the following: + +* `status` - Indicates whether the connection has been Approved/Rejected/Removed by the owner of the service. + +* `description` - The reason for approval/rejection of the connection. + +* `action_required` - A message indicating if changes on the service provider require any updates on the consumer. + +## Attributes Reference + +The following attributes are exported: + +* `network_interfaces` - One or more `network_interface` block defined below. + + +--- + +The `network_interface` block contains the following: + +* `id` - Resource ID. + +## Import + +Private Endpoint can be imported using the `resource id`, e.g. + +```shell +$ terraform import azurerm_private_endpoint.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.Network/privateEndpoints/example-private-endpoint +``` diff --git a/website/docs/r/private_link_service.html.markdown b/website/docs/r/private_link_service.html.markdown new file mode 100644 index 000000000000..82bbe9ce4e51 --- /dev/null +++ b/website/docs/r/private_link_service.html.markdown @@ -0,0 +1,380 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file at +# https://github.com/Azure/magic-module-specs +# +# ---------------------------------------------------------------------------- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_private_link_service" +sidebar_current: "docs-azurerm-resource-private-link-service" +description: |- + Manage Azure PrivateLinkService instance. +--- + +# azurerm_private_link_service + +Manage Azure PrivateLinkService instance. + + +## Private Link Service Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "acctestRG" + location = "Eastus2" +} + +resource "azurerm_virtual_network" "example" { + name = "acctestvnet-%d" + resource_group_name = "${azurerm_resource_group.example.name}" + location = "${azurerm_resource_group.example.location}" + address_space = ["10.5.0.0/16"] +} + +resource "azurerm_subnet" "example" { + name = "acctestsnet-%d" + resource_group_name = "${azurerm_resource_group.example.name}" + virtual_network_name = "${azurerm_virtual_network.example.name}" + address_prefix = "10.5.1.0/24" + private_endpoint_network_policies = "Disabled" + private_link_service_network_policies = "Disabled" +} + +resource "azurerm_public_ip" "example" { + name = "acctestpip-%d" + sku = "Standard" + location = "${azurerm_resource_group.example.location}" + resource_group_name = "${azurerm_resource_group.example.name}" + allocation_method = "Static" +} + +resource "azurerm_lb" "example" { + name = "acctestpip-%d" + sku = "Standard" + location = "${azurerm_resource_group.example.location}" + resource_group_name = "${azurerm_resource_group.example.name}" + + frontend_ip_configuration { + name = "${azurerm_public_ip.example.name}" + public_ip_address_id = "${azurerm_public_ip.example.id}" + } +} + +resource "azurerm_private_link_service" "example" { + name = "acctestvirtualhub-%d" + location = "${azurerm_resource_group.example.location}" + resource_group = "${azurerm_resource_group.example.name}" + fqdns = ["testFqdns"] + + ip_configurations { + name = "${azurerm_public_ip.example.name}" + + subnet { + id = "${azurerm_subnet.example.id}" + } + + private_ip_address = "10.5.1.17" + private_ip_address_version = "IPv4" + private_ipallocation_method = "Static" + } + + load_balancer_frontend_ip_configurations { + id = "${azurerm_lb.example.frontend_ip_configuration.0.id}" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the private link service. Changing this forces a new resource to be created. + +* `resource_group` - (Required) The name of the resource group. Changing this forces a new resource to be created. + +* `location` - (Optional) Resource location. Changing this forces a new resource to be created. + +* `auto_approval` - (Optional) One `auto_approval` block defined below. + +* `fqdns` - (Optional) The list of Fqdn. + +* `ip_configurations` - (Optional) One or more `ip_configuration` block defined below. + +* `load_balancer_frontend_ip_configurations` - (Optional) One or more `load_balancer_frontend_ip_configuration` block defined below. + +* `private_endpoint_connections` - (Optional) One or more `private_endpoint_connection` block defined below. + +* `visibility` - (Optional) One `visibility` block defined below. + +* `tags` - (Optional) Resource tags. Changing this forces a new resource to be created. + +--- + +The `auto_approval` block supports the following: + +* `subscriptions` - (Optional) The list of subscriptions. + +--- + +The `ip_configuration` block supports the following: + +* `private_ip_address` - (Optional) The private IP address of the IP configuration. + +* `private_ipallocation_method` - (Optional) The private IP address allocation method. Defaults to `Static`. + +* `subnet` - (Optional) One `subnet` block defined below. + +* `private_ip_address_version` - (Optional) Available from Api-Version 2016-03-30 onwards, it represents whether the specific ipconfiguration is IPv4 or IPv6. Default is taken as IPv4. Defaults to `IPv4`. + +* `name` - (Optional) The name of private link service ip configuration. + + +--- + +The `subnet` block supports the following: + +* `id` - (Optional) Resource ID. + +* `name` - (Optional) The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `etag` - (Optional) A unique read-only string that changes whenever the resource is updated. + +--- + +The `load_balancer_frontend_ip_configuration` block supports the following: + +* `id` - (Optional) Resource ID. + +* `private_ip_address` - (Optional) The private IP address of the IP configuration. + +* `private_ipallocation_method` - The Private IP allocation method. + +* `private_ip_address_version` - It represents whether the specific ipconfiguration is IPv4 or IPv6. Default is taken as IPv4. + +* `subnet` - (Optional) One `subnet` block defined below. + +* `public_ip_address` - (Optional) One `public_ip_address` block defined below. + +* `public_ipprefix` - (Optional) One `public_ipprefix` block defined below. + +* `name` - (Optional) The name of the resource that is unique within the set of frontend IP configurations used by the load balancer. This name can be used to access the resource. + +* `etag` - (Optional) A unique read-only string that changes whenever the resource is updated. + +* `zones` - A list of availability zones denoting the IP allocated for the resource needs to come from. + + +--- + +The `subnet` block supports the following: + +* `id` - (Optional) Resource ID. + +* `name` - (Optional) The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `etag` - (Optional) A unique read-only string that changes whenever the resource is updated. + +--- + +The `public_ip_address` block supports the following: + +* `id` - (Optional) Resource ID. + +* `location` - (Optional) Resource location. Changing this forces a new resource to be created. + +* `tags` - (Optional) Resource tags. + +* `etag` - (Optional) A unique read-only string that changes whenever the resource is updated. + +* `zones` - (Optional) A list of availability zones denoting the IP allocated for the resource needs to come from. + +--- + +The `public_ipprefix` block supports the following: + +* `id` - (Optional) Resource ID. + +--- + +The `private_endpoint_connection` block supports the following: + +* `id` - (Optional) Resource ID. + +* `private_endpoint` - (Optional) One `private_endpoint` block defined below. + +* `private_link_service_connection_state` - (Optional) One `private_link_service_connection_state` block defined below. + +* `name` - (Optional) The name of the resource that is unique within a resource group. This name can be used to access the resource. + + +--- + +The `private_endpoint` block supports the following: + +* `id` - (Optional) Resource ID. + +* `location` - (Optional) Resource location. Changing this forces a new resource to be created. + +* `tags` - (Optional) Resource tags. + +* `etag` - (Optional) A unique read-only string that changes whenever the resource is updated. + +--- + +The `private_link_service_connection_state` block supports the following: + +* `status` - (Optional) Indicates whether the connection has been Approved/Rejected/Removed by the owner of the service. + +* `description` - (Optional) The reason for approval/rejection of the connection. + +* `action_required` - (Optional) A message indicating if changes on the service provider require any updates on the consumer. + +--- + +The `visibility` block supports the following: + +* `subscriptions` - (Optional) The list of subscriptions. + +## Attributes Reference + +The following attributes are exported: + +* `network_interfaces` - One or more `network_interface` block defined below. + +* `alias` - The alias of the private link service. + +* `type` - Resource type. + + +--- + +The `network_interface` block contains the following: + +* `id` - (Optional) Resource ID. + +* `name` - (Optional) Resource name. + +* `type` - (Optional) Resource type. + +* `location` - (Optional) Resource location. Changing this forces a new resource to be created. + +* `tags` - (Optional) Resource tags. + +* `virtual_machine` - (Optional) One `virtual_machine` block defined below. + +* `network_security_group` - (Optional) One `network_security_group` block defined below. + +* `private_endpoint` - (Optional) One `private_endpoint` block defined below. + +* `ip_configurations` - (Optional) One `ip_configuration` block defined below. + +* `tap_configurations` - (Optional) One `tap_configuration` block defined below. + +* `dns_settings` - (Optional) One `dns_setting` block defined below. + +* `mac_address` - (Optional) The MAC address of the network interface. + +* `primary` - (Optional) Gets whether this is a primary network interface on a virtual machine. + +* `enable_accelerated_networking` - (Optional) If the network interface is accelerated networking enabled. + +* `enable_ipforwarding` - (Optional) Indicates whether IP forwarding is enabled on this network interface. + +* `hosted_workloads` - (Optional) A list of references to linked BareMetal resources. + +* `resource_guid` - (Optional) The resource GUID property of the network interface resource. + +* `provisioning_state` - (Optional) The provisioning state of the public IP resource. Possible values are: 'Updating', 'Deleting', and 'Failed'. + +* `etag` - (Optional) A unique read-only string that changes whenever the resource is updated. + + +--- + +The `virtual_machine` block supports the following: + +* `id` - (Optional) Resource ID. + +--- + +The `network_security_group` block supports the following: + +* `id` - (Optional) Resource ID. + +* `name` - (Optional) Resource name. + +* `type` - (Optional) Resource type. + +* `location` - (Optional) Resource location. Changing this forces a new resource to be created. + +* `tags` - (Optional) Resource tags. + +* `etag` - (Optional) A unique read-only string that changes whenever the resource is updated. + +--- + +The `private_endpoint` block supports the following: + +* `id` - (Optional) Resource ID. + +* `name` - (Optional) Resource name. + +* `type` - (Optional) Resource type. + +* `location` - (Optional) Resource location. Changing this forces a new resource to be created. + +* `tags` - (Optional) Resource tags. + +* `etag` - (Optional) A unique read-only string that changes whenever the resource is updated. + +--- + +The `ip_configuration` block supports the following: + +* `id` - (Optional) Resource ID. + +* `name` - (Optional) The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `etag` - (Optional) A unique read-only string that changes whenever the resource is updated. + +--- + +The `tap_configuration` block supports the following: + +* `id` - (Optional) Resource ID. + +* `name` - (Optional) The name of the resource that is unique within a resource group. This name can be used to access the resource. + +* `etag` - (Optional) A unique read-only string that changes whenever the resource is updated. + +* `type` - (Optional) Sub Resource type. + +--- + +The `dns_setting` block supports the following: + +* `dns_servers` - (Optional) List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection. + +* `applied_dns_servers` - (Optional) If the VM that uses this NIC is part of an Availability Set, then this list will have the union of all DNS servers from all NICs that are part of the Availability Set. This property is what is configured on each of those VMs. + +* `internal_dns_name_label` - (Optional) Relative DNS name for this NIC used for internal communications between VMs in the same virtual network. + +* `internal_fqdn` - (Optional) Fully qualified DNS name supporting internal communications between VMs in the same virtual network. + +* `internal_domain_name_suffix` - (Optional) Even if internalDnsNameLabel is not specified, a DNS entry is created for the primary NIC of the VM. This DNS name can be constructed by concatenating the VM name with the value of internalDomainNameSuffix. + +## Import + +Private Link Service can be imported using the `resource id`, e.g. + +```shell +$ terraform import azurerm_private_link_service.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/acctestRG/providers/Microsoft.Network/privateLinkServices/ +``` diff --git a/website/docs/r/virtual_hub.html.markdown b/website/docs/r/virtual_hub.html.markdown new file mode 100644 index 000000000000..46008ad34b1b --- /dev/null +++ b/website/docs/r/virtual_hub.html.markdown @@ -0,0 +1,163 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file at +# https://github.com/Azure/magic-module-specs +# +# ---------------------------------------------------------------------------- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_virtual_hub" +sidebar_current: "docs-azurerm-resource-virtual-hub" +description: |- + Manage Azure VirtualHub instance. +--- + +# azurerm_virtual_hub + +Manage Azure VirtualHub instance. + + +## Vitual Hub Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "acctestRG" + location = "Eastus2" +} + +resource "azurerm_virtual_wan" "example" { + name = "acctestvwan-%d" + resource_group_name = "${azurerm_resource_group.example.name}" + location = "${azurerm_resource_group.example.location}" +} + +resource "azurerm_virtual_hub" "example" { + name = "acctestvirtualhub-%d" + resource_group = "${azurerm_resource_group.example.name}" + location = "${azurerm_resource_group.example.location}" + address_prefix = "10.0.1.0/24" + + virtual_wan { + id = "${azurerm_virtual_wan.example.id}" + } + + route_table { + routes { + address_prefixes = ["10.0.2.0/24", "10.0.3.0/24"] + next_hop_ip_address = "10.0.4.5" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the VirtualHub. Changing this forces a new resource to be created. + +* `resource_group` - (Required) The resource group name of the VirtualHub. Changing this forces a new resource to be created. + +* `location` - (Optional) Resource location. Changing this forces a new resource to be created. + +* `address_prefix` - (Optional) Address-prefix for this VirtualHub. + +* `express_route_gateway` - (Optional) One `express_route_gateway` block defined below. + +* `p2svpn_gateway` - (Optional) One `p2svpn_gateway` block defined below. + +* `route_table` - (Optional) One `route_table` block defined below. + +* `virtual_network_connections` - (Optional) One or more `virtual_network_connection` block defined below. + +* `virtual_wan` - (Optional) One `virtual_wan` block defined below. + +* `vpn_gateway` - (Optional) One `vpn_gateway` block defined below. + +* `tags` - (Optional) Resource tags. Changing this forces a new resource to be created. + +--- + +The `express_route_gateway` block supports the following: + +* `id` - (Optional) Resource ID. + +--- + +The `p2svpn_gateway` block supports the following: + +* `id` - (Optional) Resource ID. + +--- + +The `route_table` block supports the following: + +* `routes` - (Optional) One or more `route` block defined below. + + +--- + +The `route` block supports the following: + +* `address_prefixes` - (Optional) List of all addressPrefixes. + +* `next_hop_ip_address` - (Optional) NextHop ip address. + +--- + +The `virtual_network_connection` block supports the following: + +* `id` - (Optional) Resource ID. + +* `remote_virtual_network` - (Optional) One `remote_virtual_network` block defined below. + +* `allow_hub_to_remote_vnet_transit` - (Optional) VirtualHub to RemoteVnet transit to enabled or not. + +* `allow_remote_vnet_to_use_hub_vnet_gateways` - (Optional) Allow RemoteVnet to use Virtual Hub's gateways. + +* `enable_internet_security` - (Optional) Enable internet security. + +* `name` - (Optional) The name of the resource that is unique within a resource group. This name can be used to access the resource. + + +--- + +The `remote_virtual_network` block supports the following: + +* `id` - (Optional) Resource ID. + +--- + +The `virtual_wan` block supports the following: + +* `id` - (Optional) Resource ID. + +--- + +The `vpn_gateway` block supports the following: + +* `id` - (Optional) Resource ID. + +## Attributes Reference + +The following attributes are exported: + +* `type` - Resource type. + +* `etag` - Gets a unique read-only string that changes whenever the resource is updated. + + +## Import + +Virtual Hub can be imported using the `resource id`, e.g. + +```shell +$ terraform import azurerm_virtual_hub.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/acctestRG/providers/Microsoft.Network/virtualHubs/ +```