From 8f06bc37164f967593447a9dd64933113007b897 Mon Sep 17 00:00:00 2001 From: Jie Wang Date: Sun, 28 May 2017 02:20:25 -0700 Subject: [PATCH 1/7] Data Source support for Resource Group --- .../azurerm/data_source_arm_resource_group.go | 51 +++++++++++++++++++ builtin/providers/azurerm/location.go | 10 ++++ builtin/providers/azurerm/provider.go | 3 +- builtin/providers/azurerm/tags.go | 7 +++ 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 builtin/providers/azurerm/data_source_arm_resource_group.go 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 000000000000..eb01d31c0d72 --- /dev/null +++ b/builtin/providers/azurerm/data_source_arm_resource_group.go @@ -0,0 +1,51 @@ +package azurerm + +import ( + "fmt" + + "github.com/hashicorp/errwrap" + "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) + resourceGroupClient := armClient.resourceGroupClient + + resourceGroupName := d.Get("name").(string) + result, err := resourceGroupClient.Get(resourceGroupName) + if err != nil { + return errwrap.Wrapf("Error reading Resource Group {{err}}", err) + } + + if v, ok := d.GetOk("location"); ok { + location := azureRMNormalizeLocation(v.(string)) + actualLocation := azureRMNormalizeLocation(*result.Location) + + if location != actualLocation { + return fmt.Errorf(`Resource Group's location "%s" doesn't match the location specified in Data Source: "%s"`, + actualLocation, location) + } + } + + d.Set("location", *result.Location) + flattenAndSetTags(d, result.Tags) + d.SetId(*result.ID) + + return nil +} diff --git a/builtin/providers/azurerm/location.go b/builtin/providers/azurerm/location.go index 3eb51e787c96..742a8748c04d 100644 --- a/builtin/providers/azurerm/location.go +++ b/builtin/providers/azurerm/location.go @@ -16,6 +16,16 @@ func locationSchema() *schema.Schema { } } +func locationForDataSourceSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + StateFunc: azureRMNormalizeLocation, + DiffSuppressFunc: azureRMSuppressLocationDiff, + } +} + // azureRMNormalizeLocation is a function which normalises human-readable region/location // names (e.g. "West US") to the values used and returned by the Azure API (e.g. "westus"). // In state we track the API internal version as it is easier to go from the human form diff --git a/builtin/providers/azurerm/provider.go b/builtin/providers/azurerm/provider.go index 220b34d997b1..ebee07b80ad4 100644 --- a/builtin/providers/azurerm/provider.go +++ b/builtin/providers/azurerm/provider.go @@ -62,7 +62,8 @@ func Provider() terraform.ResourceProvider { }, DataSourcesMap: map[string]*schema.Resource{ - "azurerm_client_config": dataSourceArmClientConfig(), + "azurerm_client_config": dataSourceArmClientConfig(), + "azurerm_resource_group": dataSourceArmResourceGroup(), }, ResourcesMap: map[string]*schema.Resource{ diff --git a/builtin/providers/azurerm/tags.go b/builtin/providers/azurerm/tags.go index ca79d6cee0c8..41a6701fbb65 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: From 3c6e1098bb0e9541b4c8059a70f84fc0eb839419 Mon Sep 17 00:00:00 2001 From: Jie Wang Date: Tue, 30 May 2017 11:42:50 -0700 Subject: [PATCH 2/7] Better message for mismatching locations. --- builtin/providers/azurerm/data_source_arm_resource_group.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin/providers/azurerm/data_source_arm_resource_group.go b/builtin/providers/azurerm/data_source_arm_resource_group.go index eb01d31c0d72..17daa48e0b96 100644 --- a/builtin/providers/azurerm/data_source_arm_resource_group.go +++ b/builtin/providers/azurerm/data_source_arm_resource_group.go @@ -38,8 +38,8 @@ func dataSourceArmResourceGroupRead(d *schema.ResourceData, meta interface{}) er actualLocation := azureRMNormalizeLocation(*result.Location) if location != actualLocation { - return fmt.Errorf(`Resource Group's location "%s" doesn't match the location specified in Data Source: "%s"`, - actualLocation, location) + return fmt.Errorf(`The location specified in Data Source (%s) doesn't match the actual location of the Resource Group "%s (%s)"`, + location, resourceGroupName, actualLocation) } } From cf7255033db905ccc22283c6431bf40df1d30bee Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Tue, 30 May 2017 14:04:37 -0700 Subject: [PATCH 3/7] Reuse existing read code --- .../azurerm/data_source_arm_resource_group.go | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/builtin/providers/azurerm/data_source_arm_resource_group.go b/builtin/providers/azurerm/data_source_arm_resource_group.go index 17daa48e0b96..2c83b692c8bc 100644 --- a/builtin/providers/azurerm/data_source_arm_resource_group.go +++ b/builtin/providers/azurerm/data_source_arm_resource_group.go @@ -3,7 +3,6 @@ package azurerm import ( "fmt" - "github.com/hashicorp/errwrap" "github.com/hashicorp/terraform/helper/schema" ) @@ -25,17 +24,20 @@ func dataSourceArmResourceGroup() *schema.Resource { func dataSourceArmResourceGroupRead(d *schema.ResourceData, meta interface{}) error { armClient := meta.(*ArmClient) - resourceGroupClient := armClient.resourceGroupClient resourceGroupName := d.Get("name").(string) - result, err := resourceGroupClient.Get(resourceGroupName) - if err != nil { - return errwrap.Wrapf("Error reading Resource Group {{err}}", err) + location, getLocationOk := d.GetOk("location") + resourceId := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s", armClient.subscriptionId, resourceGroupName) + + d.SetId(resourceId) + + if err := resourceArmResourceGroupRead(d, meta); err != nil { + return err } - if v, ok := d.GetOk("location"); ok { - location := azureRMNormalizeLocation(v.(string)) - actualLocation := azureRMNormalizeLocation(*result.Location) + if getLocationOk { + actualLocation := azureRMNormalizeLocation(d.Get("location").(string)) + location := azureRMNormalizeLocation(location) if location != actualLocation { return fmt.Errorf(`The location specified in Data Source (%s) doesn't match the actual location of the Resource Group "%s (%s)"`, @@ -43,9 +45,5 @@ func dataSourceArmResourceGroupRead(d *schema.ResourceData, meta interface{}) er } } - d.Set("location", *result.Location) - flattenAndSetTags(d, result.Tags) - d.SetId(*result.ID) - return nil } From cdf98a0346aa6e225a0fac03aa293bfa48811b05 Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Thu, 1 Jun 2017 23:25:05 -0700 Subject: [PATCH 4/7] Adds documentation --- .../azurerm/d/resource_group.html.markdown | 39 +++++++++++++++++++ website/source/layouts/azurerm.erb | 6 +++ 2 files changed, 45 insertions(+) create mode 100644 website/source/docs/providers/azurerm/d/resource_group.html.markdown 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 000000000000..feb7b89a2703 --- /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. +* `location` - (Optional) Specifies the location 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 + +* `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 3c8a1b6db9b5..50c80560cd5e 100644 --- a/website/source/layouts/azurerm.erb +++ b/website/source/layouts/azurerm.erb @@ -14,9 +14,15 @@ > Data Sources From e1577d1503a185c0571232e38cb15ce18f6c3c77 Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Fri, 2 Jun 2017 00:19:47 -0700 Subject: [PATCH 5/7] Adds test --- .../data_source_arm_resource_group_test.go | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 builtin/providers/azurerm/data_source_arm_resource_group_test.go 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 000000000000..c7c22149e6bf --- /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) +} From b0b9adbd857284babd1c3b639f664aae4d1bfa14 Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Mon, 5 Jun 2017 00:00:00 -0700 Subject: [PATCH 6/7] Adds a function for composing ID strings --- .../azurerm/data_source_arm_resource_group.go | 11 ++- builtin/providers/azurerm/resourceid.go | 25 ++++++ builtin/providers/azurerm/resourceid_test.go | 85 +++++++++++++++++++ 3 files changed, 119 insertions(+), 2 deletions(-) diff --git a/builtin/providers/azurerm/data_source_arm_resource_group.go b/builtin/providers/azurerm/data_source_arm_resource_group.go index 2c83b692c8bc..79583dd9a168 100644 --- a/builtin/providers/azurerm/data_source_arm_resource_group.go +++ b/builtin/providers/azurerm/data_source_arm_resource_group.go @@ -27,9 +27,16 @@ func dataSourceArmResourceGroupRead(d *schema.ResourceData, meta interface{}) er resourceGroupName := d.Get("name").(string) location, getLocationOk := d.GetOk("location") - resourceId := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s", armClient.subscriptionId, resourceGroupName) + resourceId := &ResourceID{ + SubscriptionID: armClient.subscriptionId, + ResourceGroup: resourceGroupName, + } - d.SetId(resourceId) + if resourceIdString, err := composeAzureResourceID(resourceId); err == nil { + d.SetId(resourceIdString) + } else { + return err + } if err := resourceArmResourceGroupRead(d, meta); err != nil { return err diff --git a/builtin/providers/azurerm/resourceid.go b/builtin/providers/azurerm/resourceid.go index 4f89945e79cd..bcf5eb45bcdd 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 4359b70d19af..69d64be932a8 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) + } + } +} From dbe93e4d6b81404b10abc9713638d5cb0b19f88f Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Wed, 7 Jun 2017 14:54:40 -0700 Subject: [PATCH 7/7] Change location to computed. --- .../azurerm/data_source_arm_resource_group.go | 20 ++++--------------- builtin/providers/azurerm/location.go | 7 ++----- .../azurerm/d/resource_group.html.markdown | 2 +- 3 files changed, 7 insertions(+), 22 deletions(-) diff --git a/builtin/providers/azurerm/data_source_arm_resource_group.go b/builtin/providers/azurerm/data_source_arm_resource_group.go index 79583dd9a168..21248a3895ff 100644 --- a/builtin/providers/azurerm/data_source_arm_resource_group.go +++ b/builtin/providers/azurerm/data_source_arm_resource_group.go @@ -1,8 +1,6 @@ package azurerm import ( - "fmt" - "github.com/hashicorp/terraform/helper/schema" ) @@ -26,31 +24,21 @@ func dataSourceArmResourceGroupRead(d *schema.ResourceData, meta interface{}) er armClient := meta.(*ArmClient) resourceGroupName := d.Get("name").(string) - location, getLocationOk := d.GetOk("location") resourceId := &ResourceID{ SubscriptionID: armClient.subscriptionId, ResourceGroup: resourceGroupName, } + resourceIdString, err := composeAzureResourceID(resourceId) - if resourceIdString, err := composeAzureResourceID(resourceId); err == nil { - d.SetId(resourceIdString) - } else { + if err != nil { return err } + d.SetId(resourceIdString) + if err := resourceArmResourceGroupRead(d, meta); err != nil { return err } - if getLocationOk { - actualLocation := azureRMNormalizeLocation(d.Get("location").(string)) - location := azureRMNormalizeLocation(location) - - if location != actualLocation { - return fmt.Errorf(`The location specified in Data Source (%s) doesn't match the actual location of the Resource Group "%s (%s)"`, - location, resourceGroupName, actualLocation) - } - } - return nil } diff --git a/builtin/providers/azurerm/location.go b/builtin/providers/azurerm/location.go index 146640fa2a2c..e866ff20f0bd 100644 --- a/builtin/providers/azurerm/location.go +++ b/builtin/providers/azurerm/location.go @@ -18,11 +18,8 @@ func locationSchema() *schema.Schema { func locationForDataSourceSchema() *schema.Schema { return &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - StateFunc: azureRMNormalizeLocation, - DiffSuppressFunc: azureRMSuppressLocationDiff, + Type: schema.TypeString, + Computed: true, } } diff --git a/website/source/docs/providers/azurerm/d/resource_group.html.markdown b/website/source/docs/providers/azurerm/d/resource_group.html.markdown index feb7b89a2703..6f64ea88e1f8 100644 --- a/website/source/docs/providers/azurerm/d/resource_group.html.markdown +++ b/website/source/docs/providers/azurerm/d/resource_group.html.markdown @@ -30,10 +30,10 @@ resource "azurerm_managed_disk" "test" { ## Argument Reference * `name` - (Required) Specifies the name of the resource group. -* `location` - (Optional) Specifies the location 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