diff --git a/azurerm/internal/services/compute/data_source_shared_image_versions.go b/azurerm/internal/services/compute/data_source_shared_image_versions.go new file mode 100644 index 000000000000..59f51dff0478 --- /dev/null +++ b/azurerm/internal/services/compute/data_source_shared_image_versions.go @@ -0,0 +1,183 @@ +package compute + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmSharedImageVersions() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmSharedImageVersionsRead, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "gallery_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.SharedImageGalleryName, + }, + + "image_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.SharedImageName, + }, + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "tags_filter": tags.Schema(), + + "images": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + + "location": azure.SchemaLocationForDataSource(), + + "managed_image_id": { + Type: schema.TypeString, + Computed: true, + }, + + "target_region": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + + "regional_replica_count": { + Type: schema.TypeInt, + Computed: true, + }, + + "storage_account_type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "exclude_from_latest": { + Type: schema.TypeBool, + Computed: true, + }, + + "tags": tags.SchemaDataSource(), + }, + }, + }, + }, + } +} + +func dataSourceArmSharedImageVersionsRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Compute.GalleryImageVersionsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + imageName := d.Get("image_name").(string) + galleryName := d.Get("gallery_name").(string) + resourceGroup := d.Get("resource_group_name").(string) + filterTags := tags.Expand(d.Get("tags_filter").(map[string]interface{})) + + resp, err := client.ListByGalleryImage(ctx, resourceGroup, galleryName, imageName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response().Response) { + log.Printf("[DEBUG] Shared Image Versions (Image %q / Gallery %q / Resource Group %q) was not found - removing from state", imageName, galleryName, resourceGroup) + d.SetId("") + return nil + } + return fmt.Errorf("retrieving Shared Image Versions (Image %q / Gallery %q / Resource Group %q): %+v", imageName, galleryName, resourceGroup, err) + } + + images := flattenSharedImageVersions(resp.Values(), filterTags) + if len(images) == 0 { + return fmt.Errorf("unable to find any images") + } + + d.SetId(time.Now().UTC().String()) + + d.Set("image_name", imageName) + d.Set("gallery_name", galleryName) + d.Set("resource_group_name", resourceGroup) + + if err := d.Set("images", images); err != nil { + return fmt.Errorf("setting `images`: %+v", err) + } + + return nil +} + +func flattenSharedImageVersions(input []compute.GalleryImageVersion, filterTags map[string]*string) []interface{} { + results := make([]interface{}, 0) + + for _, imageVersion := range input { + flattenedIPAddress := flattenSharedImageVersion(imageVersion) + found := true + // Loop through our filter tags and see if they match + for k, v := range filterTags { + if v != nil { + // If the tags don't match, return false + if imageVersion.Tags[k] == nil || *v != *imageVersion.Tags[k] { + found = false + } + } + } + + if found { + results = append(results, flattenedIPAddress) + } + } + + return results +} + +func flattenSharedImageVersion(input compute.GalleryImageVersion) map[string]interface{} { + output := make(map[string]interface{}) + + output["name"] = input.Name + + if location := input.Location; location != nil { + output["location"] = azure.NormalizeLocation(*location) + } + + if props := input.GalleryImageVersionProperties; props != nil { + if profile := props.PublishingProfile; profile != nil { + output["exclude_from_latest"] = profile.ExcludeFromLatest + output["target_region"] = flattenSharedImageVersionDataSourceTargetRegions(profile.TargetRegions) + } + + if profile := props.StorageProfile; profile != nil { + if source := profile.Source; source != nil { + output["managed_image_id"] = source.ID + } + } + } + + output["tags"] = tags.Flatten(input.Tags) + + return output +} diff --git a/azurerm/internal/services/compute/registration.go b/azurerm/internal/services/compute/registration.go index 01e7eb742a91..74cf68caa570 100644 --- a/azurerm/internal/services/compute/registration.go +++ b/azurerm/internal/services/compute/registration.go @@ -31,6 +31,7 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { "azurerm_proximity_placement_group": dataSourceArmProximityPlacementGroup(), "azurerm_shared_image_gallery": dataSourceArmSharedImageGallery(), "azurerm_shared_image_version": dataSourceArmSharedImageVersion(), + "azurerm_shared_image_versions": dataSourceArmSharedImageVersions(), "azurerm_shared_image": dataSourceArmSharedImage(), "azurerm_snapshot": dataSourceArmSnapshot(), "azurerm_virtual_machine": dataSourceArmVirtualMachine(), diff --git a/azurerm/internal/services/compute/tests/data_source_shared_image_versions_test.go b/azurerm/internal/services/compute/tests/data_source_shared_image_versions_test.go new file mode 100644 index 000000000000..877153860c15 --- /dev/null +++ b/azurerm/internal/services/compute/tests/data_source_shared_image_versions_test.go @@ -0,0 +1,151 @@ +package tests + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" +) + +func TestAccDataSourceAzureRMSharedImageVersions_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_shared_image_versions", "test") + username := "testadmin" + password := "Password1234!" + hostname := fmt.Sprintf("tftestcustomimagesrc%d", data.RandomInteger) + resourceGroup := fmt.Sprintf("acctestRG-%d", data.RandomInteger) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMSharedImageVersionDestroy, + Steps: []resource.TestStep{ + { + // need to create a vm and then reference it in the image creation + Config: testAccAzureRMSharedImageVersion_setup(data, username, password, hostname), + Destroy: false, + Check: resource.ComposeTestCheckFunc( + testCheckAzureVMExists("azurerm_virtual_machine.testsource", true), + testGeneralizeVMImage(resourceGroup, "testsource", username, password, hostname, "22", data.Locations.Primary), + ), + }, + { + Config: testAccDataSourceSharedImageVersions_basic(data, username, password, hostname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(data.ResourceName, "images.0.tags.%", "0"), + resource.TestCheckResourceAttrSet(data.ResourceName, "images.0.managed_image_id"), + resource.TestCheckResourceAttr(data.ResourceName, "images.0.target_region.#", "1"), + resource.TestCheckResourceAttr(data.ResourceName, "images.0.target_region.0.storage_account_type", "Standard_LRS"), + ), + }, + }, + }) +} + +func TestAccDataSourceAzureRMSharedImageVersions_tagsFilterError(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_shared_image_versions", "test") + username := "testadmin" + password := "Password1234!" + hostname := fmt.Sprintf("tftestcustomimagesrc%d", data.RandomInteger) + resourceGroup := fmt.Sprintf("acctestRG-%d", data.RandomInteger) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMSharedImageVersionDestroy, + Steps: []resource.TestStep{ + { + // need to create a vm and then reference it in the image creation + Config: testAccAzureRMSharedImageVersion_setup(data, username, password, hostname), + Destroy: false, + Check: resource.ComposeTestCheckFunc( + testCheckAzureVMExists("azurerm_virtual_machine.testsource", true), + testGeneralizeVMImage(resourceGroup, "testsource", username, password, hostname, "22", data.Locations.Primary), + ), + }, + { + Config: testAccDataSourceSharedImageVersions_tagsFilterError(data, username, password, hostname), + ExpectError: regexp.MustCompile("unable to find any images"), + }, + }, + }) +} + +func TestAccDataSourceAzureRMSharedImageVersions_tagsFilter(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_shared_image_versions", "test") + username := "testadmin" + password := "Password1234!" + hostname := fmt.Sprintf("tftestcustomimagesrc%d", data.RandomInteger) + resourceGroup := fmt.Sprintf("acctestRG-%d", data.RandomInteger) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMSharedImageVersionDestroy, + Steps: []resource.TestStep{ + { + // need to create a vm and then reference it in the image creation + Config: testAccAzureRMSharedImageVersion_setup(data, username, password, hostname), + Destroy: false, + Check: resource.ComposeTestCheckFunc( + testCheckAzureVMExists("azurerm_virtual_machine.testsource", true), + testGeneralizeVMImage(resourceGroup, "testsource", username, password, hostname, "22", data.Locations.Primary), + ), + }, + { + Config: testAccDataSourceSharedImageVersions_tagsFilter(data, username, password, hostname), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(data.ResourceName, "images.#", "1"), + ), + }, + }, + }) +} + +func testAccDataSourceSharedImageVersions_basic(data acceptance.TestData, username, password, hostname string) string { + template := testAccAzureRMSharedImageVersion_imageVersion(data, username, password, hostname) + return fmt.Sprintf(` +%s + +data "azurerm_shared_image_versions" "test" { + gallery_name = azurerm_shared_image_version.test.gallery_name + image_name = azurerm_shared_image_version.test.image_name + resource_group_name = azurerm_shared_image_version.test.resource_group_name +} +`, template) +} + +func testAccDataSourceSharedImageVersions_tagsFilterError(data acceptance.TestData, username, password, hostname string) string { + template := testAccAzureRMSharedImageVersion_imageVersion(data, username, password, hostname) + return fmt.Sprintf(` +%s + +data "azurerm_shared_image_versions" "test" { + gallery_name = azurerm_shared_image_version.test.gallery_name + image_name = azurerm_shared_image_version.test.image_name + resource_group_name = azurerm_shared_image_version.test.resource_group_name + + tags_filter = { + "foo" = "error" + } +} +`, template) +} + +func testAccDataSourceSharedImageVersions_tagsFilter(data acceptance.TestData, username, password, hostname string) string { + template := testAccAzureRMSharedImageVersion_imageVersion(data, username, password, hostname) + return fmt.Sprintf(` +%s + +data "azurerm_shared_image_versions" "test" { + gallery_name = azurerm_shared_image_version.test.gallery_name + image_name = azurerm_shared_image_version.test.image_name + resource_group_name = azurerm_shared_image_version.test.resource_group_name + + tags_filter = { + "foo" = "bar" + } +} +`, template) +} diff --git a/azurerm/internal/services/compute/tests/resource_arm_shared_image_version_test.go b/azurerm/internal/services/compute/tests/resource_arm_shared_image_version_test.go index d1bc0fc39d4e..848947682c93 100644 --- a/azurerm/internal/services/compute/tests/resource_arm_shared_image_version_test.go +++ b/azurerm/internal/services/compute/tests/resource_arm_shared_image_version_test.go @@ -278,6 +278,10 @@ resource "azurerm_shared_image_version" "test" { name = azurerm_resource_group.test.location regional_replica_count = 1 } + + tags = { + "foo" = "bar" + } } `, template) } diff --git a/website/azurerm.erb b/website/azurerm.erb index c4102eaac357..e52518a43a26 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -510,6 +510,10 @@ azurerm_shared_image_version +
  • + azurerm_shared_image_versions +
  • +
  • azurerm_signalr_service
  • diff --git a/website/docs/d/shared_image_versions.html.markdown b/website/docs/d/shared_image_versions.html.markdown new file mode 100644 index 000000000000..b32115fdcc04 --- /dev/null +++ b/website/docs/d/shared_image_versions.html.markdown @@ -0,0 +1,70 @@ +--- +subcategory: "Compute" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_shared_image_versions" +description: |- + Gets information about existing Versions of a Shared Image within a Shared Image Gallery. + +--- + +# Data Source: azurerm_shared_image_versions + +Use this data source to access information about existing Versions of a Shared Image within a Shared Image Gallery. + +## Example Usage + +```hcl +data "azurerm_shared_image_versions" "example" { + image_name = "my-image" + gallery_name = "my-image-gallery" + resource_group_name = "example-resources" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `image_name` - The name of the Shared Image in which this Version exists. + +* `gallery_name` - The name of the Shared Image in which the Shared Image exists. + +* `resource_group_name` - The name of the Resource Group in which the Shared Image Gallery exists. + +* `tags_filter` - A mapping of tags to filter the list of images against. + +## Attributes Reference + +The following attributes are exported: + +* `images` - An `images` block as defined below: + +--- + +A `images` block exports the following: + +* `exclude_from_latest` - Is this Image Version excluded from the `latest` filter? + +* `location` - The supported Azure location where the Shared Image Gallery exists. + +* `managed_image_id` - The ID of the Managed Image which was the source of this Shared Image Version. + +* `target_region` - One or more `target_region` blocks as documented below. + +* `tags` - A mapping of tags assigned to the Shared Image. + +--- + +The `target_region` block exports the following: + +* `name` - The Azure Region in which this Image Version exists. + +* `regional_replica_count` - The number of replicas of the Image Version to be created per region. + +* `storage_account_type` - The storage account type for the image version. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `read` - (Defaults to 5 minutes) Used when retrieving the Versions of a Shared Image within a Shared Image Gallery.