From f14017b452d5c8c14e6124e600a662abe4ea60fe Mon Sep 17 00:00:00 2001 From: aristosvo <8375124+aristosvo@users.noreply.github.com> Date: Thu, 15 Dec 2022 23:09:04 +0100 Subject: [PATCH] New data source - `azurerm_lb_outbound_rule` (#19345) Fixes https://github.com/hashicorp/terraform-provider-azurerm/issues/19301 --- ...balancer_outbound_rule_data_source_test.go | 160 +++++++++++++++++ .../loadbalancer/outbound_rule_data_source.go | 161 ++++++++++++++++++ .../services/loadbalancer/registration.go | 1 + website/docs/d/lb_outbound_rule.html.markdown | 64 +++++++ 4 files changed, 386 insertions(+) create mode 100644 internal/services/loadbalancer/loadbalancer_outbound_rule_data_source_test.go create mode 100644 internal/services/loadbalancer/outbound_rule_data_source.go create mode 100644 website/docs/d/lb_outbound_rule.html.markdown diff --git a/internal/services/loadbalancer/loadbalancer_outbound_rule_data_source_test.go b/internal/services/loadbalancer/loadbalancer_outbound_rule_data_source_test.go new file mode 100644 index 000000000000..c79708e510ee --- /dev/null +++ b/internal/services/loadbalancer/loadbalancer_outbound_rule_data_source_test.go @@ -0,0 +1,160 @@ +package loadbalancer_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +func TestAccAzureRMDataSourceLoadBalancerOutboundRule_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_lb_outbound_rule", "test") + r := LoadBalancerOutboundRule{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basicDataSource(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("id").Exists(), + check.That(data.ResourceName).Key("frontend_ip_configuration.0.name").Exists(), + check.That(data.ResourceName).Key("protocol").Exists(), + ), + }, + }) +} + +func TestAccAzureRMDataSourceLoadBalancerOutboundRule_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_lb_outbound_rule", "test") + r := LoadBalancerOutboundRule{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.completeDataSource(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("id").Exists(), + check.That(data.ResourceName).Key("frontend_ip_configuration.0.name").Exists(), + check.That(data.ResourceName).Key("protocol").Exists(), + check.That(data.ResourceName).Key("backend_address_pool_id").Exists(), + check.That(data.ResourceName).Key("idle_timeout_in_minutes").Exists(), + check.That(data.ResourceName).Key("tcp_reset_enabled").Exists(), + ), + }, + }) +} + +func (r LoadBalancerOutboundRule) basicDataSource(data acceptance.TestData) string { + template := r.basic(data) + return fmt.Sprintf(` +%s + +data "azurerm_lb_outbound_rule" "test" { + name = azurerm_lb_outbound_rule.test.name + loadbalancer_id = azurerm_lb_outbound_rule.test.loadbalancer_id +} +`, template) +} + +func (r LoadBalancerOutboundRule) completeDataSource(data acceptance.TestData) string { + return fmt.Sprintf(` + provider "azurerm" { + features {} + } + + resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" + } + + resource "azurerm_public_ip" "test1" { + name = "test-ip-1-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" + sku = "Standard" + } + + resource "azurerm_public_ip" "test2" { + name = "test-ip-2-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" + sku = "Standard" + } + + resource "azurerm_public_ip" "test3" { + name = "test-ip-3-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" + sku = "Standard" + } + + resource "azurerm_lb" "test" { + name = "arm-test-loadbalancer-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Standard" + + frontend_ip_configuration { + name = "fe1-%d" + public_ip_address_id = azurerm_public_ip.test1.id + } + + frontend_ip_configuration { + name = "fe2-%d" + public_ip_address_id = azurerm_public_ip.test2.id + } + + frontend_ip_configuration { + name = "fe3-%d" + public_ip_address_id = azurerm_public_ip.test3.id + } + } + + resource "azurerm_lb_backend_address_pool" "test" { + loadbalancer_id = azurerm_lb.test.id + name = "be-%d" + } + + resource "azurerm_lb_outbound_rule" "test" { + loadbalancer_id = azurerm_lb.test.id + name = "OutboundRule1-%d" + protocol = "All" + backend_address_pool_id = azurerm_lb_backend_address_pool.test.id + + frontend_ip_configuration { + name = "fe1-%d" + } + } + + resource "azurerm_lb_outbound_rule" "test2" { + loadbalancer_id = azurerm_lb.test.id + name = "OutboundRule2-%d" + protocol = "Tcp" + backend_address_pool_id = azurerm_lb_backend_address_pool.test.id + enable_tcp_reset = true + idle_timeout_in_minutes = 5 + + frontend_ip_configuration { + name = "fe2-%d" + } + } + + resource "azurerm_lb_outbound_rule" "test3" { + loadbalancer_id = azurerm_lb.test.id + name = "OutboundRule3-%d" + protocol = "Udp" + backend_address_pool_id = azurerm_lb_backend_address_pool.test.id + + frontend_ip_configuration { + name = "fe3-%d" + } + } + + data "azurerm_lb_outbound_rule" "test" { + name = azurerm_lb_outbound_rule.test2.name + loadbalancer_id = azurerm_lb_outbound_rule.test.loadbalancer_id + } +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/loadbalancer/outbound_rule_data_source.go b/internal/services/loadbalancer/outbound_rule_data_source.go new file mode 100644 index 000000000000..8bc706fe5127 --- /dev/null +++ b/internal/services/loadbalancer/outbound_rule_data_source.go @@ -0,0 +1,161 @@ +package loadbalancer + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/loadbalancer/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/loadbalancer/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func dataSourceArmLoadBalancerOutboundRule() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceArmLoadBalancerOutboundRuleRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "loadbalancer_id": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validate.LoadBalancerID, + }, + + "frontend_ip_configuration": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + }, + }, + }, + + "backend_address_pool_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "protocol": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "tcp_reset_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "allocated_outbound_ports": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "idle_timeout_in_minutes": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + }, + } +} + +func dataSourceArmLoadBalancerOutboundRuleRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).LoadBalancers.LoadBalancersClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + loadBalancerId, err := parse.LoadBalancerID(d.Get("loadbalancer_id").(string)) + if err != nil { + return err + } + + loadBalancer, err := client.Get(ctx, loadBalancerId.ResourceGroup, loadBalancerId.Name, "") + if err != nil { + if utils.ResponseWasNotFound(loadBalancer.Response) { + d.SetId("") + log.Printf("[INFO] Load Balancer %q not found. Removing from state", loadBalancerId.Name) + return nil + } + return fmt.Errorf("failed to retrieve Load Balancer %q (resource group %q) for Outbound Rule %q: %+v", loadBalancerId.Name, loadBalancerId.ResourceGroup, name, err) + } + + id := parse.NewLoadBalancerOutboundRuleID(loadBalancerId.SubscriptionId, loadBalancerId.ResourceGroup, loadBalancerId.Name, name) + config, _, exists := FindLoadBalancerOutboundRuleByName(&loadBalancer, id.OutboundRuleName) + if !exists { + d.SetId("") + log.Printf("[INFO] Load Balancer Outbound Rule %q not found. Removing from state", name) + return fmt.Errorf("%s was not found", id) + } + + d.SetId(id.ID()) + if props := config.OutboundRulePropertiesFormat; props != nil { + allocatedOutboundPorts := 0 + if props.AllocatedOutboundPorts != nil { + allocatedOutboundPorts = int(*props.AllocatedOutboundPorts) + } + d.Set("allocated_outbound_ports", allocatedOutboundPorts) + + backendAddressPoolId := "" + if props.BackendAddressPool != nil && props.BackendAddressPool.ID != nil { + bapid, err := parse.LoadBalancerBackendAddressPoolID(*props.BackendAddressPool.ID) + if err != nil { + return err + } + + backendAddressPoolId = bapid.ID() + } + d.Set("backend_address_pool_id", backendAddressPoolId) + d.Set("tcp_reset_enabled", props.EnableTCPReset) + + frontendIpConfigurations := make([]interface{}, 0) + if configs := props.FrontendIPConfigurations; configs != nil { + for _, feConfig := range *configs { + if feConfig.ID == nil { + continue + } + feid, err := parse.LoadBalancerFrontendIpConfigurationID(*feConfig.ID) + if err != nil { + return err + } + + frontendIpConfigurations = append(frontendIpConfigurations, map[string]interface{}{ + "id": feid.ID(), + "name": feid.FrontendIPConfigurationName, + }) + } + } + d.Set("frontend_ip_configuration", frontendIpConfigurations) + + idleTimeoutInMinutes := 0 + if props.IdleTimeoutInMinutes != nil { + idleTimeoutInMinutes = int(*props.IdleTimeoutInMinutes) + } + d.Set("idle_timeout_in_minutes", idleTimeoutInMinutes) + d.Set("protocol", string(props.Protocol)) + } + + return nil +} diff --git a/internal/services/loadbalancer/registration.go b/internal/services/loadbalancer/registration.go index 5d9a5c41c55e..f288716285a2 100644 --- a/internal/services/loadbalancer/registration.go +++ b/internal/services/loadbalancer/registration.go @@ -39,6 +39,7 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { "azurerm_lb": dataSourceArmLoadBalancer(), "azurerm_lb_backend_address_pool": dataSourceArmLoadBalancerBackendAddressPool(), "azurerm_lb_rule": dataSourceArmLoadBalancerRule(), + "azurerm_lb_outbound_rule": dataSourceArmLoadBalancerOutboundRule(), } } diff --git a/website/docs/d/lb_outbound_rule.html.markdown b/website/docs/d/lb_outbound_rule.html.markdown new file mode 100644 index 000000000000..c3102c097553 --- /dev/null +++ b/website/docs/d/lb_outbound_rule.html.markdown @@ -0,0 +1,64 @@ +--- +subcategory: "Load Balancer" +layout: "azurerm" +page_title: "Azure Resource Manager: Data Source: azurerm_lb_outbound_rule" +description: |- + Gets information about an existing Load Balancer Outbound Rule. +--- + +# Data Source: azurerm_lb_outbound_rule + +Use this data source to access information about an existing Load Balancer Outbound Rule. + +## Example Usage + +```hcl +data "azurerm_lb_outbound_rule" "example" { + name = "existing_lb_outbound_rule" + loadbalancer_id = "existing_load_balancer_id" +} + +output "id" { + value = data.azurerm_lb_outbound_rule.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name of this Load Balancer Outbound Rule. + +* `loadbalancer_id` - (Required) The ID of the Load Balancer in which the Outbound Rule exists. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Load Balancer Outbound Rule. + +* `allocated_outbound_ports` - The number of outbound ports used for NAT. + +* `backend_address_pool_id` - The ID of the Backend Address Pool. Outbound traffic is randomly load balanced across IPs in the backend IPs. + +* `frontend_ip_configuration` - A `frontend_ip_configuration` block as defined below. + +* `idle_timeout_in_minutes` - The timeout for the TCP idle connection. + +* `protocol` - The transport protocol for the external endpoint. + +* `tcp_reset_enabled` - Is the bidirectional TCP Reset on TCP flow idle timeout or unexpected connection termination enabled? This value is useful when the protocol is set to TCP. + +--- + +A `frontend_ip_configuration` block exports the following: + +* `id` - The ID of the Frontend IP Configuration. + +* `name` - The name of the Frontend IP Configuration. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +* `read` - (Defaults to 5 minutes) Used when retrieving the Load Balancer Outbound Rule. \ No newline at end of file