From 656be2bd89a24245da893636079e8cfdb8bde4f1 Mon Sep 17 00:00:00 2001 From: Kyler Middleton Date: Tue, 23 Jan 2024 02:57:55 -0600 Subject: [PATCH] New data source `azurerm_ip_groups` (#24540) * New data source ip_groups * Fix website linting * Fix website linting, part deux * Add IP, update tests * Fix names, add more IP groups for test case * Fix tests * Update to List type so hash codes match (thanks Stephy!) Co-authored-by: stephybun --------- Co-authored-by: stephybun --- .../network/ip_group_resource_test.go | 27 ++++- .../services/network/ip_groups_data_source.go | 113 ++++++++++++++++++ .../network/ip_groups_data_source_test.go | 106 ++++++++++++++++ internal/services/network/registration.go | 1 + website/docs/d/ip_groups.html.markdown | 46 +++++++ 5 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 internal/services/network/ip_groups_data_source.go create mode 100644 internal/services/network/ip_groups_data_source_test.go create mode 100644 website/docs/d/ip_groups.html.markdown diff --git a/internal/services/network/ip_group_resource_test.go b/internal/services/network/ip_group_resource_test.go index 9c66a203d369..93ef90d31384 100644 --- a/internal/services/network/ip_group_resource_test.go +++ b/internal/services/network/ip_group_resource_test.go @@ -208,6 +208,32 @@ resource "azurerm_ip_group" "test" { cost_center = "MSFT" } } + +resource "azurerm_ip_group" "test2" { + name = "acceptanceTestIpGroup2" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + cidrs = ["192.168.0.1", "172.16.240.0/20", "10.48.0.0/12"] + + tags = { + environment = "Production" + cost_center = "MSFT" + } +} + +resource "azurerm_ip_group" "test3" { + name = "acceptanceTestIpGroup3" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + cidrs = ["192.168.0.1", "172.16.240.0/20", "10.48.0.0/12"] + + tags = { + environment = "Production" + cost_center = "MSFT" + } +} `, data.RandomInteger, data.Locations.Primary) } @@ -312,7 +338,6 @@ resource "azurerm_firewall_policy_rule_collection_group" "test" { } } - resource "azurerm_virtual_network" "test" { name = "testvnet" address_space = ["10.0.0.0/16"] diff --git a/internal/services/network/ip_groups_data_source.go b/internal/services/network/ip_groups_data_source.go new file mode 100644 index 000000000000..fa57da41b207 --- /dev/null +++ b/internal/services/network/ip_groups_data_source.go @@ -0,0 +1,113 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package network + +import ( + "fmt" + "slices" + "strings" + "time" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/tags" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceIpGroups() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceIpGroupsRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "location": commonschema.LocationComputed(), + + "ids": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + }, + + "names": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{Type: pluginsdk.TypeString}, + }, + + "tags": tags.SchemaDataSource(), + }, + } +} + +// Find IDs and names of multiple IP Groups, filtered by name substring +func dataSourceIpGroupsRead(d *pluginsdk.ResourceData, meta interface{}) error { + + // Establish a client to handle i/o operations against the API + client := meta.(*clients.Client).Network.IPGroupsClient + + // Create a context for the request and defer cancellation + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + // Get resource group name from data source + resourceGroupName := d.Get("resource_group_name").(string) + + // Make the request to the API to download all IP groups in the resource group + allGroups, err := client.ListByResourceGroup(ctx, resourceGroupName) + if err != nil { + return fmt.Errorf("error listing IP groups: %+v", err) + } + + // Establish lists of strings to append to, set equal to empty set to start + // If no IP groups are found, an empty set will be returned + names := []string{} + ids := []string{} + + // Filter IDs list by substring + for _, ipGroup := range allGroups.Values() { + if ipGroup.Name != nil && strings.Contains(*ipGroup.Name, d.Get("name").(string)) { + names = append(names, *ipGroup.Name) + ids = append(ids, *ipGroup.ID) + } + } + + // Sort lists of strings alphabetically + slices.Sort(names) + slices.Sort(ids) + + // Set resource ID, required for Terraform state + // Since this is a multi-resource data source, we need to create a unique ID + // Using the ID of the resource group + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + id := commonids.NewResourceGroupID(subscriptionId, resourceGroupName) + d.SetId(id.ID()) + + // Set names + err = d.Set("names", names) + if err != nil { + return fmt.Errorf("error setting names: %+v", err) + } + + // Set IDs + err = d.Set("ids", ids) + if err != nil { + return fmt.Errorf("error setting ids: %+v", err) + } + + // Return nil error + return nil + +} diff --git a/internal/services/network/ip_groups_data_source_test.go b/internal/services/network/ip_groups_data_source_test.go new file mode 100644 index 000000000000..5e74c5a909e9 --- /dev/null +++ b/internal/services/network/ip_groups_data_source_test.go @@ -0,0 +1,106 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package network_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type IPGroupsDataSource struct{} + +func TestAccDataSourceIPGroups_noResults(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_ip_groups", "test") + r := IPGroupsDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.noResults(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("ids.#").HasValue("0"), + check.That(data.ResourceName).Key("names.#").HasValue("0"), + ), + }, + }) +} + +func TestAccDataSourceIPGroups_single(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_ip_groups", "test") + r := IPGroupsDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.single(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("ids.#").HasValue("1"), + check.That(data.ResourceName).Key("names.#").HasValue("1"), + ), + }, + }) +} + +func TestAccDataSourceIPGroups_multiple(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_ip_groups", "test") + r := IPGroupsDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.multiple(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("ids.#").HasValue("3"), + check.That(data.ResourceName).Key("names.#").HasValue("3"), + ), + }, + }) +} + +// Find IP group which doesn't exist +func (IPGroupsDataSource) noResults(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_ip_groups" "test" { + name = "doesNotExist" + resource_group_name = azurerm_resource_group.test.name + depends_on = [ + azurerm_ip_group.test, + ] +} +`, IPGroupResource{}.basic(data)) +} + +// Find single IP group +func (IPGroupsDataSource) single(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_ip_groups" "test" { + name = "acceptanceTestIpGroup1" + resource_group_name = azurerm_resource_group.test.name + depends_on = [ + azurerm_ip_group.test, + ] +} +`, IPGroupResource{}.basic(data)) +} + +// Find multiple IP Groups, filtered by name substring +func (IPGroupsDataSource) multiple(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_ip_groups" "test" { + name = "acceptanceTestIpGroup" + resource_group_name = azurerm_resource_group.test.name + depends_on = [ + azurerm_ip_group.test, + azurerm_ip_group.test2, + azurerm_ip_group.test3, + ] +} +`, IPGroupResource{}.complete(data)) +} diff --git a/internal/services/network/registration.go b/internal/services/network/registration.go index f2826be05b5b..15c830e374a8 100644 --- a/internal/services/network/registration.go +++ b/internal/services/network/registration.go @@ -66,6 +66,7 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { "azurerm_bastion_host": dataSourceBastionHost(), "azurerm_express_route_circuit": dataSourceExpressRouteCircuit(), "azurerm_ip_group": dataSourceIpGroup(), + "azurerm_ip_groups": dataSourceIpGroups(), "azurerm_nat_gateway": dataSourceNatGateway(), "azurerm_network_ddos_protection_plan": dataSourceNetworkDDoSProtectionPlan(), "azurerm_network_interface": dataSourceNetworkInterface(), diff --git a/website/docs/d/ip_groups.html.markdown b/website/docs/d/ip_groups.html.markdown new file mode 100644 index 000000000000..ba9388ed3594 --- /dev/null +++ b/website/docs/d/ip_groups.html.markdown @@ -0,0 +1,46 @@ +--- +subcategory: "Network" +layout: "azurerm" +page_title: "Azure Resource Manager: Data Source: azurerm_ip_groups" +description: |- + Gets information about existing IP Groups. +--- + +# Data Source: azurerm_ip_groups + +Use this data source to access information about existing IP Groups. + +## Example Usage + +```hcl +data "azurerm_ip_groups" "example" { + name = "existing" + resource_group_name = "existing" +} + +output "id" { + value = data.azurerm_ip_groups.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) A substring to match some number of IP Groups. + +* `resource_group_name` - (Required) The name of the Resource Group where the IP Groups exist. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `ids` - A list of IP Group IDs. + +* `names` - A list of IP Group Names. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +* `read` - (Defaults to 10 minutes) Used when retrieving the IP Groups. \ No newline at end of file