[MS] provider/azurerm: Data Source for Azure Resource Group (#15022)

* Data Source support for Resource Group

* Better message for mismatching locations.

* Reuse existing read code

* Adds documentation

* Adds test

* Adds a function for composing ID strings

* Change location to computed.
This commit is contained in:
Jay Wang 2017-06-09 03:10:42 -07:00 committed by Paul Stack
parent d587b68863
commit b465b01355
9 changed files with 261 additions and 2 deletions

View File

@ -0,0 +1,44 @@
package azurerm
import (
"github.com/hashicorp/terraform/helper/schema"
)
func dataSourceArmResourceGroup() *schema.Resource {
return &schema.Resource{
Read: dataSourceArmResourceGroupRead,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"location": locationForDataSourceSchema(),
"tags": tagsForDataSourceSchema(),
},
}
}
func dataSourceArmResourceGroupRead(d *schema.ResourceData, meta interface{}) error {
armClient := meta.(*ArmClient)
resourceGroupName := d.Get("name").(string)
resourceId := &ResourceID{
SubscriptionID: armClient.subscriptionId,
ResourceGroup: resourceGroupName,
}
resourceIdString, err := composeAzureResourceID(resourceId)
if err != nil {
return err
}
d.SetId(resourceIdString)
if err := resourceArmResourceGroupRead(d, meta); err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,46 @@
package azurerm
import (
"testing"
"fmt"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
)
func TestAccDataSourceAzureRMResourceGroup_basic(t *testing.T) {
ri := acctest.RandInt()
name := fmt.Sprintf("acctestRg_%d", ri)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAzureRMResourceGroupBasic(name),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.azurerm_resource_group.test", "name", name),
resource.TestCheckResourceAttr("data.azurerm_resource_group.test", "location", "westus2"),
resource.TestCheckResourceAttr("data.azurerm_resource_group.test", "tags.%", "1"),
resource.TestCheckResourceAttr("data.azurerm_resource_group.test", "tags.env", "test"),
),
},
},
})
}
func testAccDataSourceAzureRMResourceGroupBasic(name string) string {
return fmt.Sprintf(`resource "azurerm_resource_group" "test" {
name = "%s"
location = "West US 2"
tags {
env = "test"
}
}
data "azurerm_resource_group" "test" {
name = "${azurerm_resource_group.test.name}"
}
`, name)
}

View File

@ -16,6 +16,13 @@ func locationSchema() *schema.Schema {
} }
} }
func locationForDataSourceSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeString,
Computed: true,
}
}
func deprecatedLocationSchema() *schema.Schema { func deprecatedLocationSchema() *schema.Schema {
return &schema.Schema{ return &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,

View File

@ -62,8 +62,9 @@ func Provider() terraform.ResourceProvider {
}, },
DataSourcesMap: map[string]*schema.Resource{ DataSourcesMap: map[string]*schema.Resource{
"azurerm_client_config": dataSourceArmClientConfig(), "azurerm_client_config": dataSourceArmClientConfig(),
"azurerm_public_ip": dataSourceArmPublicIP(), "azurerm_resource_group": dataSourceArmResourceGroup(),
"azurerm_public_ip": dataSourceArmPublicIP(),
}, },
ResourcesMap: map[string]*schema.Resource{ ResourcesMap: map[string]*schema.Resource{

View File

@ -101,6 +101,31 @@ func parseAzureResourceID(id string) (*ResourceID, error) {
return idObj, nil return idObj, nil
} }
func composeAzureResourceID(idObj *ResourceID) (id string, err error) {
if idObj.SubscriptionID == "" || idObj.ResourceGroup == "" {
return "", fmt.Errorf("SubscriptionID and ResourceGroup cannot be empty")
}
id = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s", idObj.SubscriptionID, idObj.ResourceGroup)
if idObj.Provider != "" {
if len(idObj.Path) < 1 {
return "", fmt.Errorf("ResourceID.Path should have at least one item when ResourceID.Provider is specified")
}
id += fmt.Sprintf("/providers/%s", idObj.Provider)
for k, v := range idObj.Path {
if k == "" || v == "" {
return "", fmt.Errorf("ResourceID.Path cannot contain empty strings")
}
id += fmt.Sprintf("/%s/%s", k, v)
}
}
return
}
func parseNetworkSecurityGroupName(networkSecurityGroupId string) (string, error) { func parseNetworkSecurityGroupName(networkSecurityGroupId string) (string, error) {
id, err := parseAzureResourceID(networkSecurityGroupId) id, err := parseAzureResourceID(networkSecurityGroupId)
if err != nil { if err != nil {

View File

@ -143,3 +143,88 @@ func TestParseAzureResourceID(t *testing.T) {
} }
} }
} }
func TestComposeAzureResourceID(t *testing.T) {
testCases := []struct {
resourceID *ResourceID
expectedID string
expectError bool
}{
{
&ResourceID{
SubscriptionID: "00000000-0000-0000-0000-000000000000",
ResourceGroup: "testGroup1",
Provider: "foo.bar",
Path: map[string]string{
"k1": "v1",
"k2": "v2",
"k3": "v3",
},
},
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup1/providers/foo.bar/k1/v1/k2/v2/k3/v3",
false,
},
{
&ResourceID{
SubscriptionID: "00000000-0000-0000-0000-000000000000",
ResourceGroup: "testGroup1",
},
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup1",
false,
},
{
// If Provider is specified, there must be at least one element in Path.
&ResourceID{
SubscriptionID: "00000000-0000-0000-0000-000000000000",
ResourceGroup: "testGroup1",
Provider: "foo.bar",
},
"",
true,
},
{
// One of the keys in Path is an empty string.
&ResourceID{
SubscriptionID: "00000000-0000-0000-0000-000000000000",
ResourceGroup: "testGroup1",
Provider: "foo.bar",
Path: map[string]string{
"k2": "v2",
"": "v1",
},
},
"",
true,
},
{
// One of the values in Path is an empty string.
&ResourceID{
SubscriptionID: "00000000-0000-0000-0000-000000000000",
ResourceGroup: "testGroup1",
Provider: "foo.bar",
Path: map[string]string{
"k1": "v1",
"k2": "",
},
},
"",
true,
},
}
for _, test := range testCases {
idString, err := composeAzureResourceID(test.resourceID)
if test.expectError && err != nil {
continue
}
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}
if test.expectedID != idString {
t.Fatalf("Unexpected resource ID string:\nExpected: %s\nGot: %s\n", test.expectedID, idString)
}
}
}

View File

@ -16,6 +16,13 @@ func tagsSchema() *schema.Schema {
} }
} }
func tagsForDataSourceSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeMap,
Computed: true,
}
}
func tagValueToString(v interface{}) (string, error) { func tagValueToString(v interface{}) (string, error) {
switch value := v.(type) { switch value := v.(type) {
case string: case string:

View File

@ -0,0 +1,39 @@
---
layout: "azurerm"
page_title: "Azure Resource Manager: azurerm_resource_group"
sidebar_current: "docs-azurerm-datasource-resource-group"
description: |-
Get information about the specified resource group.
---
# azurerm\_resource\_group
Use this data source to access the properties of an Azure resource group.
## Example Usage
```hcl
data "azurerm_resource_group" "test" {
name = "dsrg_test"
}
resource "azurerm_managed_disk" "test" {
name = "managed_disk_name"
location = "${data.azurerm_resource_group.test.location}"
resource_group_name = "${data.azurerm_resource_group.test.name}"
storage_account_type = "Standard_LRS"
create_option = "Empty"
disk_size_gb = "1"
}
```
## Argument Reference
* `name` - (Required) Specifies the name of the resource group.
~> **NOTE:** If the specified location doesn't match the actual resource group location, an error message with the actual location value will be shown.
## Attributes Reference
* `location` - The location of the resource group.
* `tags` - A mapping of tags assigned to the resource group.

View File

@ -17,6 +17,11 @@
<li<%= sidebar_current("docs-azurerm-datasource-client-config") %>> <li<%= sidebar_current("docs-azurerm-datasource-client-config") %>>
<a href="/docs/providers/azurerm/d/client_config.html">azurerm_client_config</a> <a href="/docs/providers/azurerm/d/client_config.html">azurerm_client_config</a>
</li> </li>
<li<%= sidebar_current("docs-azurerm-datasource-resource-group") %>>
<a href="/docs/providers/azurerm/d/resource_group.html">azurerm_resource_group</a>
</li>
<li<%= sidebar_current("docs-azurerm-datasource-public-ip") %>> <li<%= sidebar_current("docs-azurerm-datasource-public-ip") %>>
<a href="/docs/providers/azurerm/d/public_ip.html">azurerm_public_ip</a> <a href="/docs/providers/azurerm/d/public_ip.html">azurerm_public_ip</a>
</li> </li>