diff --git a/azurerm/data_source_public_ips.go b/azurerm/data_source_public_ips.go new file mode 100644 index 000000000000..3b236d276500 --- /dev/null +++ b/azurerm/data_source_public_ips.go @@ -0,0 +1,174 @@ +package azurerm + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2017-09-01/network" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmPublicIPs() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmPublicIPsRead, + + Schema: map[string]*schema.Schema{ + "resource_group_name": resourceGroupNameForDataSourceSchema(), + + "name_prefix": { + Type: schema.TypeString, + Optional: true, + }, + + "attached": { + Type: schema.TypeBool, + Optional: true, + }, + + "allocation_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(network.Dynamic), + string(network.Static), + }, false), + }, + + "public_ips": { + 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, + }, + "fqdn": { + Type: schema.TypeString, + Computed: true, + }, + "domain_name_label": { + Type: schema.TypeString, + Computed: true, + }, + "ip_address": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceArmPublicIPsRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).publicIPClient + ctx := meta.(*ArmClient).StopContext + + resourceGroup := d.Get("resource_group_name").(string) + + log.Printf("[DEBUG] Reading Public IP's in Resource Group %q", resourceGroup) + resp, err := client.List(ctx, resourceGroup) + if err != nil { + if utils.ResponseWasNotFound(resp.Response().Response) { + d.SetId("") + return nil + } + + return fmt.Errorf("Error listing Public IP Addresses in the Resource Group %q: %v", resourceGroup, err) + } + + filteredIPAddresses := make([]network.PublicIPAddress, 0) + for _, element := range resp.Values() { + nicIsAttached := element.IPConfiguration != nil + shouldInclude := true + + if v, ok := d.GetOkExists("name_prefix"); ok { + if prefix := v.(string); prefix != "" { + if !strings.HasPrefix(*element.Name, prefix) { + shouldInclude = false + } + } + } + + if v, ok := d.GetOkExists("attached"); ok { + attachedOnly := v.(bool) + + if attachedOnly != nicIsAttached { + shouldInclude = false + } + } + + if v, ok := d.GetOkExists("allocation_type"); ok { + if allocationType := v.(string); allocationType != "" { + allocation := network.IPAllocationMethod(allocationType) + if element.PublicIPAllocationMethod != allocation { + shouldInclude = false + } + } + } + + if shouldInclude { + filteredIPAddresses = append(filteredIPAddresses, element) + } + } + + d.SetId(time.Now().UTC().String()) + + results := flattenDataSourcePublicIPs(filteredIPAddresses) + if err := d.Set("public_ips", results); err != nil { + return fmt.Errorf("Error setting `public_ips`: %+v", err) + } + + return nil +} + +func flattenDataSourcePublicIPs(input []network.PublicIPAddress) []interface{} { + results := make([]interface{}, 0) + + for _, element := range input { + flattenedIPAddress := flattenDataSourcePublicIP(element) + results = append(results, flattenedIPAddress) + } + + return results +} + +func flattenDataSourcePublicIP(input network.PublicIPAddress) map[string]string { + output := make(map[string]string, 0) + + if input.ID != nil { + output["id"] = *input.ID + } + + if input.Name != nil { + output["name"] = *input.Name + } + + if props := input.PublicIPAddressPropertiesFormat; props != nil { + if dns := props.DNSSettings; dns != nil { + if fqdn := dns.Fqdn; fqdn != nil { + output["fqdn"] = *fqdn + } + + if label := dns.DomainNameLabel; label != nil { + output["domain_name_label"] = *label + } + } + + if ip := props.IPAddress; ip != nil { + output["ip_address"] = *ip + } + } + + return output +} diff --git a/azurerm/data_source_public_ips_test.go b/azurerm/data_source_public_ips_test.go new file mode 100644 index 000000000000..bd4111353b95 --- /dev/null +++ b/azurerm/data_source_public_ips_test.go @@ -0,0 +1,252 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccDataSourceAzureRMPublicIPs_namePrefix(t *testing.T) { + dataSourceName := "data.azurerm_public_ips.test" + ri := acctest.RandInt() + rs := acctest.RandString(5) + location := testLocation() + + resourceConfig := testAccDataSourceAzureRMPublicIPs_prefix(ri, rs, location) + dataSourceConfig := testAccDataSourceAzureRMPublicIPs_prefixDataSource(ri, rs, location) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPublicIpDestroy, + Steps: []resource.TestStep{ + { + Config: resourceConfig, + Check: resource.ComposeTestCheckFunc(), + }, + { + Config: dataSourceConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "public_ips.#", "2"), + resource.TestCheckResourceAttr(dataSourceName, "public_ips.0.name", fmt.Sprintf("acctestpipa%s-0", rs)), + ), + }, + }, + }) +} + +func TestAccDataSourceAzureRMPublicIPs_assigned(t *testing.T) { + attachedDataSourceName := "data.azurerm_public_ips.attached" + unattachedDataSourceName := "data.azurerm_public_ips.unattached" + ri := acctest.RandInt() + rs := acctest.RandString(5) + location := testLocation() + + resourceConfig := testAccDataSourceAzureRMPublicIPs_attached(ri, rs, location) + dataSourceConfig := testAccDataSourceAzureRMPublicIPs_attachedDataSource(ri, rs, location) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPublicIpDestroy, + Steps: []resource.TestStep{ + { + Config: resourceConfig, + Check: resource.ComposeTestCheckFunc(), + }, + { + Config: dataSourceConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(attachedDataSourceName, "public_ips.#", "3"), + resource.TestCheckResourceAttr(attachedDataSourceName, "public_ips.0.name", fmt.Sprintf("acctestpip%s-0", rs)), + resource.TestCheckResourceAttr(unattachedDataSourceName, "public_ips.#", "4"), + resource.TestCheckResourceAttr(unattachedDataSourceName, "public_ips.0.name", fmt.Sprintf("acctestpip%s-3", rs)), + ), + }, + }, + }) +} + +func TestAccDataSourceAzureRMPublicIPs_allocationType(t *testing.T) { + staticDataSourceName := "data.azurerm_public_ips.static" + dynamicDataSourceName := "data.azurerm_public_ips.dynamic" + ri := acctest.RandInt() + rs := acctest.RandString(5) + location := testLocation() + + resourceConfig := testAccDataSourceAzureRMPublicIPs_allocationType(ri, rs, location) + dataSourceConfig := testAccDataSourceAzureRMPublicIPs_allocationTypeDataSources(ri, rs, location) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPublicIpDestroy, + Steps: []resource.TestStep{ + { + Config: resourceConfig, + Check: resource.ComposeTestCheckFunc(), + }, + { + Config: dataSourceConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(staticDataSourceName, "public_ips.#", "3"), + resource.TestCheckResourceAttr(staticDataSourceName, "public_ips.0.name", fmt.Sprintf("acctestpips%s-0", rs)), + resource.TestCheckResourceAttr(dynamicDataSourceName, "public_ips.#", "4"), + resource.TestCheckResourceAttr(dynamicDataSourceName, "public_ips.0.name", fmt.Sprintf("acctestpipd%s-0", rs)), + ), + }, + }, + }) +} + +func testAccDataSourceAzureRMPublicIPs_attached(rInt int, rString string, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestrg-%d" + location = "%s" +} + +resource "azurerm_public_ip" "test" { + count = 7 + name = "acctestpip%s-${count.index}" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + public_ip_address_allocation = "static" + idle_timeout_in_minutes = 30 + + tags { + environment = "test" + } +} + +resource "azurerm_lb" "test" { + count = 3 + name = "acctestlb-${count.index}" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + frontend_ip_configuration { + name = "frontend" + public_ip_address_id = "${element(azurerm_public_ip.test.*.id, count.index)}" + } +} +`, rInt, location, rString) +} + +func testAccDataSourceAzureRMPublicIPs_attachedDataSource(rInt int, rString string, location string) string { + resources := testAccDataSourceAzureRMPublicIPs_attached(rInt, rString, location) + return fmt.Sprintf(` +%s + +data "azurerm_public_ips" "unattached" { + resource_group_name = "${azurerm_resource_group.test.name}" + attached = false +} + +data "azurerm_public_ips" "attached" { + resource_group_name = "${azurerm_resource_group.test.name}" + attached = true +} +`, resources) +} + +func testAccDataSourceAzureRMPublicIPs_prefix(rInt int, rString string, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestrg-%d" + location = "%s" +} + +resource "azurerm_public_ip" "test" { + count = 2 + name = "acctestpipb%s-${count.index}" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + public_ip_address_allocation = "static" + idle_timeout_in_minutes = 30 + + tags { + environment = "test" + } +} + +resource "azurerm_public_ip" "test2" { + count = 2 + name = "acctestpipa%s-${count.index}" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + public_ip_address_allocation = "static" + idle_timeout_in_minutes = 30 + + tags { + environment = "test" + } +} +`, rInt, location, rString, rString) +} + +func testAccDataSourceAzureRMPublicIPs_prefixDataSource(rInt int, rString string, location string) string { + prefixed := testAccDataSourceAzureRMPublicIPs_prefix(rInt, rString, location) + return fmt.Sprintf(` +%s + +data "azurerm_public_ips" "test" { + resource_group_name = "${azurerm_resource_group.test.name}" + name_prefix = "acctestpipa" +} +`, prefixed) +} + +func testAccDataSourceAzureRMPublicIPs_allocationType(rInt int, rString string, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestrg-%d" + location = "%s" +} + +resource "azurerm_public_ip" "dynamic" { + count = 4 + name = "acctestpipd%s-${count.index}" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + public_ip_address_allocation = "dynamic" + idle_timeout_in_minutes = 30 + + tags { + environment = "test" + } +} + +resource "azurerm_public_ip" "static" { + count = 3 + name = "acctestpips%s-${count.index}" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + public_ip_address_allocation = "static" + idle_timeout_in_minutes = 30 + + tags { + environment = "test" + } +} +`, rInt, location, rString, rString) +} + +func testAccDataSourceAzureRMPublicIPs_allocationTypeDataSources(rInt int, rString string, location string) string { + allocationType := testAccDataSourceAzureRMPublicIPs_allocationType(rInt, rString, location) + return fmt.Sprintf(` +%s + +data "azurerm_public_ips" "dynamic" { + resource_group_name = "${azurerm_resource_group.test.name}" + allocation_type = "Dynamic" +} + +data "azurerm_public_ips" "static" { + resource_group_name = "${azurerm_resource_group.test.name}" + allocation_type = "Static" +} +`, allocationType) +} diff --git a/azurerm/provider.go b/azurerm/provider.go index 623de61ed6eb..c54d964a13a9 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -90,6 +90,7 @@ func Provider() terraform.ResourceProvider { "azurerm_network_security_group": dataSourceArmNetworkSecurityGroup(), "azurerm_platform_image": dataSourceArmPlatformImage(), "azurerm_public_ip": dataSourceArmPublicIP(), + "azurerm_public_ips": dataSourceArmPublicIPs(), "azurerm_resource_group": dataSourceArmResourceGroup(), "azurerm_role_definition": dataSourceArmRoleDefinition(), "azurerm_storage_account": dataSourceArmStorageAccount(), diff --git a/website/azurerm.erb b/website/azurerm.erb index d79d4923e665..0c478d300db1 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -75,10 +75,14 @@ azurerm_platform_image - > + > azurerm_public_ip + > + azurerm_public_ips + + > azurerm_resource_group diff --git a/website/docs/d/public_ip.html.markdown b/website/docs/d/public_ip.html.markdown index 89d228d72c54..14df94a888d2 100644 --- a/website/docs/d/public_ip.html.markdown +++ b/website/docs/d/public_ip.html.markdown @@ -1,7 +1,7 @@ --- layout: "azurerm" page_title: "Azure Resource Manager: azurerm_public_ip" -sidebar_current: "docs-azurerm-datasource-public-ip" +sidebar_current: "docs-azurerm-datasource-public-ip-x" description: |- Retrieves information about the specified public IP address. diff --git a/website/docs/d/public_ips.html.markdown b/website/docs/d/public_ips.html.markdown new file mode 100644 index 000000000000..09051f11cc99 --- /dev/null +++ b/website/docs/d/public_ips.html.markdown @@ -0,0 +1,38 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_public_ips" +sidebar_current: "docs-azurerm-datasource-public-ips" +description: |- + Provides a list of public IP addresses. +--- + +# azurerm_public_ips + +Use this data source to access a filtered list of Public IP Addresses + +## Example Usage + +```hcl +data "azurerm_public_ips" "test" { + resource_group_name = "pip-test" + attached = false +} +``` + +## Argument Reference + +* `resource_group_name` - (Required) Specifies the name of the resource group. +* `attached` - (Optional) Filter to include IP Addresses which are attached to a device, such as a VM/LB (`true`) or unattached (`false`). +* `name_prefix` - (Optional) A prefix match used for the IP Addresses `name` field, case sensitive. +* `allocation_type` - (Optional) The Allocation Type for the Public IP Address. Possible values include `Static` or `Dynamic`. + +## Attributes Reference + +* `public_ips` - A List of `public_ips` blocks as defined below filtered by the criteria above. + +A `public_ips` block contains: + +* `id` - The ID of the Public IP Address +* `domain_name_label` - The Domain Name Label of the Public IP Address +* `fqdn` - The FQDN of the Public IP Address +* `name` - The Name of the Public IP Address