From 9c8dd74e8633d0d8be1b57b28eb56efbef829cd1 Mon Sep 17 00:00:00 2001 From: Matt Mencel Date: Mon, 8 Jul 2019 10:04:11 -0500 Subject: [PATCH] cleanup PR --- azurerm/config.go | 2 +- azurerm/data_source_compute_resource_skus.go | 385 ++++++++++++++++++ .../data_source_compute_resource_skus_test.go | 37 ++ azurerm/provider.go | 1 + .../d/compute_resource_skus.html.markdown | 59 +++ 5 files changed, 483 insertions(+), 1 deletion(-) create mode 100644 azurerm/data_source_compute_resource_skus.go create mode 100644 azurerm/data_source_compute_resource_skus_test.go create mode 100644 website/docs/d/compute_resource_skus.html.markdown diff --git a/azurerm/config.go b/azurerm/config.go index 9b385b0e732ac..b6a8fada24ba3 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -175,7 +175,7 @@ type ArmClient struct { galleriesClient compute.GalleriesClient galleryImagesClient compute.GalleryImagesClient galleryImageVersionsClient compute.GalleryImageVersionsClient - resourceSkusClient compute.ResourceSkusClient + resourceSkusClient compute.ResourceSkusClient snapshotsClient compute.SnapshotsClient usageOpsClient compute.UsageClient vmExtensionImageClient compute.VirtualMachineExtensionImagesClient diff --git a/azurerm/data_source_compute_resource_skus.go b/azurerm/data_source_compute_resource_skus.go new file mode 100644 index 0000000000000..92624e9ee96eb --- /dev/null +++ b/azurerm/data_source_compute_resource_skus.go @@ -0,0 +1,385 @@ +package azurerm + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-06-01/compute" + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" +) + +func dataSourceArmComputeResourceSkus() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmComputeResourceSkusRead, + + Schema: map[string]*schema.Schema{ + + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "location": { + Type: schema.TypeString, + Required: true, + }, + + "resource_type": { + Type: schema.TypeString, + Computed: true, + }, + + "tier": { + Type: schema.TypeString, + Computed: true, + }, + + "size": { + Type: schema.TypeString, + Computed: true, + }, + + "family": { + Type: schema.TypeString, + Computed: true, + }, + + "kind": { + Type: schema.TypeString, + Computed: true, + }, + + "capacity": { + Type: schema.TypeString, + Computed: true, + }, + + "locations": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "location_info": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Computed: true, + }, + + "zones": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + + "api_versions": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "costs": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "meter_id": { + Type: schema.TypeString, + Computed: true, + }, + + "quantity": { + Type: schema.TypeInt, + Computed: true, + }, + + "extended_unit": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "capabilities": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + + "value": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "restrictions": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "restriction_type": { + Type: schema.TypeString, + Computed: true, + }, + + "values": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + + // TODO + // "restriction_info": { + // Type: schema.TypeList, + // Computed: true, + // Elem: &schema.Resource{ + // Schema: map[string]*schema.Schema{ + // "locations": { + // Type: schema.TypeList, + // Computed: true, + // Elem: &schema.Schema{ + // Type: schema.TypeString, + // }, + // }, + + // "zones": { + // Type: schema.TypeList, + // Computed: true, + // Elem: &schema.Schema{ + // Type: schema.TypeString, + // }, + // }, + // }, + // }, + // }, + + // "reason_code": { + // Type: schema.TypeString, + // Computed: true, + // }, + }, + }, + }, + }, + }, + } +} + +func dataSourceArmComputeResourceSkusRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).resourceSkusClient + ctx := meta.(*ArmClient).StopContext + + name := d.Get("name").(string) + + resourceSkus, err := client.ListComplete(ctx) + + if err != nil { + return fmt.Errorf("Error loading Compute Resource SKUs: %+v", err) + } + + filteredResourceSkus := make([]compute.ResourceSku, 0) + for resourceSkus.NotDone() { + shouldInclude := false + sku := resourceSkus.Value() + + if v, ok := d.GetOkExists("location"); ok { + if location := v.(string); location != "" { + if Contains(*sku.Locations, location) && *sku.Name == name { + shouldInclude = true + } + } + } else { + if *sku.Name == name { + shouldInclude = true + } + } + + if shouldInclude { + filteredResourceSkus = append(filteredResourceSkus, sku) + } + err = resourceSkus.NextWithContext(ctx) + if err != nil { + return fmt.Errorf("Error loading Compute Resource SKUs: %+v", err) + } + } + + d.SetId(time.Now().UTC().String()) + d.Set("name", name) + + log.Printf("[DEBUG] filteredResourceSkus: %+v\n", filteredResourceSkus) + + if len(filteredResourceSkus) == 0 { + return fmt.Errorf("Error loading Resource SKU: could not find SKU '%s'. Invalid SKU Name or not valid in this subscription or location.", name) + } else if len(filteredResourceSkus) == 1 { + frs := filteredResourceSkus[0] + + if resource_type := frs.ResourceType; resource_type != nil { + d.Set("resource_type", *frs.ResourceType) + } + + if tier := frs.Tier; tier != nil { + d.Set("tier", *frs.Tier) + } + + if size := frs.Size; size != nil { + d.Set("size", *frs.Size) + } + + if family := frs.Family; family != nil { + d.Set("family", *frs.Family) + } + + if kind := frs.Kind; kind != nil { + d.Set("kind", *frs.Kind) + } + + if capacity := frs.Capacity; capacity != nil { + d.Set("capacity", *frs.Capacity) + } + + if frs.LocationInfo != nil { + locationInfo := flattenLocationInfo(frs.LocationInfo) + if err := d.Set("location_info", locationInfo); err != nil { + return fmt.Errorf("Error setting `location_info`: %+v", err) + } + } + + if api_versions := frs.APIVersions; api_versions != nil { + d.Set("api_versions", *frs.APIVersions) + } + + // TODO + // if frs.Costs != nil { + // } + + if frs.Capabilities != nil { + capabilities := flattenCapabilities(frs.Capabilities) + if err := d.Set("capabilities", capabilities); err != nil { + return fmt.Errorf("Error setting `capabilities`: %+v", err) + } + } + + if frs.Restrictions != nil { + restrictions := flattenRestrictions(frs.Restrictions) + if err := d.Set("restrictions", restrictions); err != nil { + return fmt.Errorf("Error setting `restrictions`: %+v", err) + } + } + } + + return nil +} + +func Contains(a []string, x string) bool { + for _, n := range a { + if x == n { + return true + } + } + return false +} + +func flattenLocationInfo(locationInfo *[]compute.ResourceSkuLocationInfo) []interface{} { + result := make([]interface{}, 0) + if locationInfo == nil { + return result + } + + for _, locInfo := range *locationInfo { + info := make(map[string]interface{}) + + if locInfo.Location != nil { + info["location"] = azure.NormalizeLocation(*locInfo.Location) + } + + zones := make([]string, 0) + if zs := locInfo.Zones; zs != nil { + zones = *zs + } + info["zones"] = zones + + result = append(result, info) + } + return result +} + +func flattenCapabilities(capabilities *[]compute.ResourceSkuCapabilities) []interface{} { + result := make([]interface{}, 0) + if capabilities == nil { + return result + } + + for _, capability := range *capabilities { + cap := make(map[string]interface{}) + + if capability.Name != nil { + cap["name"] = capability.Name + } + + if capability.Value != nil { + cap["value"] = capability.Value + } + + result = append(result, cap) + } + return result +} + +func flattenRestrictions(restrictions *[]compute.ResourceSkuRestrictions) []interface{} { + result := make([]interface{}, 0) + if restrictions == nil { + return result + } + + for _, restriction := range *restrictions { + res := make(map[string]interface{}) + + // TODO + // if restriction.Type != nil { + // res["type"] = restriction.Type + // } + + values := make([]string, 0) + if val := restriction.Values; val != nil { + values = *val + } + res["values"] = values + + if restriction.RestrictionInfo != nil { + res["restriction_info"] = restriction.RestrictionInfo + } + + // TODO + // if restriction.ReasonCode != nil { + // res["reason_code"] = restriction.ReasonCode + // } + + result = append(result, res) + } + return result +} diff --git a/azurerm/data_source_compute_resource_skus_test.go b/azurerm/data_source_compute_resource_skus_test.go new file mode 100644 index 0000000000000..06f5679627f37 --- /dev/null +++ b/azurerm/data_source_compute_resource_skus_test.go @@ -0,0 +1,37 @@ +package azurerm + +import ( + "fmt" + "testing" + + //"github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccDataSourceAzureRMComputeResourceSkus_basic(t *testing.T) { + dataSourceName := "data.azurerm_compute_resource_skus.test" + location := testLocation() + name := "Standard_DS2_v2" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAzureRMComputeResourceSkus_basic(name, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "name"), + ), + }, + }, + }) +} + +func testAccDataSourceAzureRMComputeResourceSkus_basic(name string, location string) string { + return fmt.Sprintf(` +data "azurerm_compute_resource_skus" "test" { + name = "%s" + location = "%s" +} +`, name, location) +} diff --git a/azurerm/provider.go b/azurerm/provider.go index 83a3ce642211c..9a2ab98ba1b59 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -121,6 +121,7 @@ func Provider() terraform.ResourceProvider { "azurerm_cdn_profile": dataSourceArmCdnProfile(), "azurerm_client_config": dataSourceArmClientConfig(), "azurerm_kubernetes_service_versions": dataSourceArmKubernetesServiceVersions(), + "azurerm_compute_resource_skus": dataSourceArmComputeResourceSkus(), "azurerm_container_registry": dataSourceArmContainerRegistry(), "azurerm_cosmosdb_account": dataSourceArmCosmosDbAccount(), "azurerm_data_lake_store": dataSourceArmDataLakeStoreAccount(), diff --git a/website/docs/d/compute_resource_skus.html.markdown b/website/docs/d/compute_resource_skus.html.markdown new file mode 100644 index 0000000000000..bc51adb24a7bf --- /dev/null +++ b/website/docs/d/compute_resource_skus.html.markdown @@ -0,0 +1,59 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_compute_resource_skus" +sidebar_current: "docs-azurerm-datasource-compute-resource-skus" +description: |- + Retrieve information about a Compute SKU + +--- + +# Data Source: azurerm_compute_resource_skus + +Use this data source to access information about Compute Resource SKUs. + +## Example Usage + +```hcl +data "azurerm_compute_resource_skus" "test" { + name = "Standard_D2s_v2" + location = "eastus" +} + +output "location_info" { + value = "${data.azurerm_compute_resource_skus.test.location_info}" +} +``` + +## Argument Reference + +* `name` - (Required) The name of the SKU to retrieve information for (e.g. Standard_DS2_v2). +* `location` - (Required) The location to retrieve SKU information from. + +## Attributes Reference + +The following attributes are exported (Not all attributes may be available for every SKU): + +* `resource_type` - The type of resource the SKU applies to. + +* `name` - The name of the SKU. + +* `tier` - Specifies the tier of the virtual machines in a scale set. Possible values: **Standard** or **Basic**. + +* `size` - The size of the SKU. + +* `family` - The Family of this particular SKU. + +* `kind` - The Kind of resources that are supported in this SKU. + +* `capacity` - Specifies the number of virtual machines in the scale set. + +* `location_info` - A list of locations and availability zones in those locations where the SKU is available. + +* `api_versions` - (TODO) The api versions that support this SKU. + +* `costs` - (TODO) Metadata for retrieving price info. + +* `capabilities` - A set of name value pairs describing capabilities. + +* `restrictions` - (TODO) The restrictions because of which SKU cannot be used. This is empty if there are no restrictions. + \ No newline at end of file