From b465b0135534c68e20d4c7f032742e8692ee905e Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Fri, 9 Jun 2017 03:10:42 -0700 Subject: [PATCH] [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. --- .../azurerm/data_source_arm_resource_group.go | 44 ++++++++++ .../data_source_arm_resource_group_test.go | 46 ++++++++++ builtin/providers/azurerm/location.go | 7 ++ builtin/providers/azurerm/provider.go | 5 +- builtin/providers/azurerm/resourceid.go | 25 ++++++ builtin/providers/azurerm/resourceid_test.go | 85 +++++++++++++++++++ builtin/providers/azurerm/tags.go | 7 ++ .../azurerm/d/resource_group.html.markdown | 39 +++++++++ website/source/layouts/azurerm.erb | 5 ++ 9 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 builtin/providers/azurerm/data_source_arm_resource_group.go create mode 100644 builtin/providers/azurerm/data_source_arm_resource_group_test.go create mode 100644 website/source/docs/providers/azurerm/d/resource_group.html.markdown diff --git a/builtin/providers/azurerm/data_source_arm_resource_group.go b/builtin/providers/azurerm/data_source_arm_resource_group.go new file mode 100644 index 000000000..21248a389 --- /dev/null +++ b/builtin/providers/azurerm/data_source_arm_resource_group.go @@ -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 +} diff --git a/builtin/providers/azurerm/data_source_arm_resource_group_test.go b/builtin/providers/azurerm/data_source_arm_resource_group_test.go new file mode 100644 index 000000000..c7c22149e --- /dev/null +++ b/builtin/providers/azurerm/data_source_arm_resource_group_test.go @@ -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) +} diff --git a/builtin/providers/azurerm/location.go b/builtin/providers/azurerm/location.go index 21f40515b..e866ff20f 100644 --- a/builtin/providers/azurerm/location.go +++ b/builtin/providers/azurerm/location.go @@ -16,6 +16,13 @@ func locationSchema() *schema.Schema { } } +func locationForDataSourceSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeString, + Computed: true, + } +} + func deprecatedLocationSchema() *schema.Schema { return &schema.Schema{ Type: schema.TypeString, diff --git a/builtin/providers/azurerm/provider.go b/builtin/providers/azurerm/provider.go index f690ea369..05c10505c 100644 --- a/builtin/providers/azurerm/provider.go +++ b/builtin/providers/azurerm/provider.go @@ -62,8 +62,9 @@ func Provider() terraform.ResourceProvider { }, DataSourcesMap: map[string]*schema.Resource{ - "azurerm_client_config": dataSourceArmClientConfig(), - "azurerm_public_ip": dataSourceArmPublicIP(), + "azurerm_client_config": dataSourceArmClientConfig(), + "azurerm_resource_group": dataSourceArmResourceGroup(), + "azurerm_public_ip": dataSourceArmPublicIP(), }, ResourcesMap: map[string]*schema.Resource{ diff --git a/builtin/providers/azurerm/resourceid.go b/builtin/providers/azurerm/resourceid.go index 4f89945e7..bcf5eb45b 100644 --- a/builtin/providers/azurerm/resourceid.go +++ b/builtin/providers/azurerm/resourceid.go @@ -101,6 +101,31 @@ func parseAzureResourceID(id string) (*ResourceID, error) { 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) { id, err := parseAzureResourceID(networkSecurityGroupId) if err != nil { diff --git a/builtin/providers/azurerm/resourceid_test.go b/builtin/providers/azurerm/resourceid_test.go index 4359b70d1..69d64be93 100644 --- a/builtin/providers/azurerm/resourceid_test.go +++ b/builtin/providers/azurerm/resourceid_test.go @@ -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) + } + } +} diff --git a/builtin/providers/azurerm/tags.go b/builtin/providers/azurerm/tags.go index ca79d6cee..41a6701fb 100644 --- a/builtin/providers/azurerm/tags.go +++ b/builtin/providers/azurerm/tags.go @@ -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) { switch value := v.(type) { case string: diff --git a/website/source/docs/providers/azurerm/d/resource_group.html.markdown b/website/source/docs/providers/azurerm/d/resource_group.html.markdown new file mode 100644 index 000000000..6f64ea88e --- /dev/null +++ b/website/source/docs/providers/azurerm/d/resource_group.html.markdown @@ -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. \ No newline at end of file diff --git a/website/source/layouts/azurerm.erb b/website/source/layouts/azurerm.erb index db032a31d..95c5b3979 100644 --- a/website/source/layouts/azurerm.erb +++ b/website/source/layouts/azurerm.erb @@ -17,6 +17,11 @@ > azurerm_client_config + + > + azurerm_resource_group + + > azurerm_public_ip