From 268cff59d912e82a5b380e07a3a8eedaad623310 Mon Sep 17 00:00:00 2001 From: Harshavardhan Musanalli Date: Tue, 22 Feb 2022 21:06:41 +0100 Subject: [PATCH 1/8] New datasource azurerm_managed_disk_export for managed disks export --- .../compute/disk_export_data_source.go | 102 ++++++++++++++++++ .../compute/disk_export_data_source_test.go | 52 +++++++++ internal/services/compute/registration.go | 1 + .../docs/d/managed_disk_export.html.markdown | 67 ++++++++++++ 4 files changed, 222 insertions(+) create mode 100644 internal/services/compute/disk_export_data_source.go create mode 100644 internal/services/compute/disk_export_data_source_test.go create mode 100644 website/docs/d/managed_disk_export.html.markdown diff --git a/internal/services/compute/disk_export_data_source.go b/internal/services/compute/disk_export_data_source.go new file mode 100644 index 000000000000..b95dbab435b9 --- /dev/null +++ b/internal/services/compute/disk_export_data_source.go @@ -0,0 +1,102 @@ +package compute + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-07-01/compute" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceManagedDiskExport() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceManagedDiskExportRead, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "managed_disk_id": { + Type: pluginsdk.TypeString, + Required: true, + DiffSuppressFunc: suppress.CaseDifference, + ValidateFunc: azure.ValidateResourceID, + }, + + "duration_in_seconds": { + Type: pluginsdk.TypeInt, + Required: true, + }, + + "access": { + Type: pluginsdk.TypeString, + Optional: true, + Default: "Read", + }, + + "sas": { + Type: pluginsdk.TypeString, + Computed: true, + Sensitive: true, + }, + }, + } +} + +func dataSourceManagedDiskExportRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Compute.DisksClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + managedDiskId := d.Get("managed_disk_id").(string) + durationInSeconds := int32(d.Get("duration_in_seconds").(int)) + access := d.Get("access").(string) + + parsedManagedDiskId, err := parse.ManagedDiskID(managedDiskId) + if err != nil { + return fmt.Errorf("parsing Managed Disk ID %q: %+v", parsedManagedDiskId.ID(), err) + } + + diskName := parsedManagedDiskId.DiskName + resourceGroupName := parsedManagedDiskId.ResourceGroup + + grantAccessData := compute.GrantAccessData{ + Access: compute.AccessLevel(access), + DurationInSeconds: &durationInSeconds, + } + + // Request to Grant Access for Disk + diskGrantFuture, err := client.GrantAccess(ctx, resourceGroupName, diskName, grantAccessData) + if err != nil { + return fmt.Errorf("Error while granting access for disk export %q: %+v", parsedManagedDiskId.ID(), err) + } + + // Wait until the Grant Request is complete + err = diskGrantFuture.WaitForCompletionRef(ctx, client.Client) + if err != nil { + return fmt.Errorf("Grant access operation failed %q (Resource Group %q): %+v", diskName, resourceGroupName, err) + } + + // Fetch the SAS token from the response + diskGrantResponse, err := diskGrantFuture.Result(*client) + if err != nil { + return fmt.Errorf("Error while fetching the response %q: %+v", parsedManagedDiskId.ID(), err) + } + + sasToken := diskGrantResponse.AccessSAS + + d.Set("sas", *sasToken) + tokenHash := sha256.Sum256([]byte(*sasToken)) + d.SetId(hex.EncodeToString(tokenHash[:])) + + return nil + +} diff --git a/internal/services/compute/disk_export_data_source_test.go b/internal/services/compute/disk_export_data_source_test.go new file mode 100644 index 000000000000..6de98141b00e --- /dev/null +++ b/internal/services/compute/disk_export_data_source_test.go @@ -0,0 +1,52 @@ +package compute_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DataSourceManagedDiskExportDataSource struct{} + +func TestAccDataSourceDiskExportSas_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_managed_disk_export", "test") + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: DataSourceManagedDiskExportDataSource{}.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("managed_disk_id").HasValue("/subscriptions/42cbb0b8a331-abaf-4e69-8d8f-14b86a40/resourceGroups/disksrg/providers/Microsoft.Compute/disks/disk1"), + check.That(data.ResourceName).Key("access").HasValue("Write"), + check.That(data.ResourceName).Key("duration_in_seconds").HasValue("30"), + check.That(data.ResourceName).Key("sas").Exists(), + ), + }, + }) +} + +func (d DataSourceManagedDiskExportDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +resource "azurerm_resource_group" "rg" { + name = "acctestRG-disk-%d" + location = "%s" +} +resource "azurerm_managed_disk" "disk" { + name = "acctestsads%s" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" +} +data "azurerm_managed_disk_export" "test" { + managed_disk_id = azurerm_managed_disk.disk.id + duration_in_seconds = 300 + access = "Read" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} diff --git a/internal/services/compute/registration.go b/internal/services/compute/registration.go index da17055db751..a65e13d4b7a9 100644 --- a/internal/services/compute/registration.go +++ b/internal/services/compute/registration.go @@ -39,6 +39,7 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { "azurerm_virtual_machine": dataSourceVirtualMachine(), "azurerm_virtual_machine_scale_set": dataSourceVirtualMachineScaleSet(), "azurerm_ssh_public_key": dataSourceSshPublicKey(), + "azurerm_managed_disk_export": dataSourceManagedDiskExport(), } } diff --git a/website/docs/d/managed_disk_export.html.markdown b/website/docs/d/managed_disk_export.html.markdown new file mode 100644 index 000000000000..8d9e4e1efb25 --- /dev/null +++ b/website/docs/d/managed_disk_export.html.markdown @@ -0,0 +1,67 @@ +--- +subcategory: "Compute" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_managed_disk_export" +description: |- + Gets a Shared Access Signature (SAS Token) for an existing Managed Disk. + +--- + +# Data Source: azurerm_managed_disk_export + +Use this data source to obtain a Shared Access Signature (SAS Token) for an existing Managed Disk. + +Shared access signatures allow fine-grained, ephemeral access control to various aspects of Managed Disk similar to blob/storage account container. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "rg" { + name = "resourceGroupName" + location = "West Europe" +} + +resource "azurerm_managed_disk" "disk" { + name = "azureManagedDisk" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" + + tags = { + environment = "staging" + } +} + +data "azurerm_managed_disk_export" "disk" { + managed_disk_id = azurerm_managed_disk.disk.id + duration_in_seconds = 300 + access = "Read" +} + +output "sas_url_query_string" { + value = data.azurerm_managed_disk_export.disk.sas +} +``` + +## Argument Reference + +* `managed_disk_id` - The ID of an existing Managed Disk which should be exported. Changing this forces a new resource to be created. + +* `duration_in_seconds` - The duration for which the export should be allowed. Should be greater than 30 seconds. + +* `access` - (Optional) The level of access required on the disk. Supported are Read, Write. Defaults to Read. + +Refer to the [SAS creation reference from Azure](https://docs.microsoft.com/en-us/rest/api/compute/disks/grant-access) +for additional details on the fields above. + +## Attributes Reference + +* `sas` - The computed Shared Access Signature (SAS) of the Managed Disk. + +## 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 Blob Container. \ No newline at end of file From 2c87c9ef5bf3c092fd0999ac0579f789bd6a5ecc Mon Sep 17 00:00:00 2001 From: Harshavardhan Musanalli Date: Tue, 22 Feb 2022 21:25:27 +0100 Subject: [PATCH 2/8] Formatting tf and website files to meet lint needs --- .../compute/disk_export_data_source_test.go | 18 ++++++------ .../docs/d/managed_disk_export.html.markdown | 28 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/internal/services/compute/disk_export_data_source_test.go b/internal/services/compute/disk_export_data_source_test.go index 6de98141b00e..577705efb50a 100644 --- a/internal/services/compute/disk_export_data_source_test.go +++ b/internal/services/compute/disk_export_data_source_test.go @@ -36,17 +36,17 @@ resource "azurerm_resource_group" "rg" { location = "%s" } resource "azurerm_managed_disk" "disk" { - name = "acctestsads%s" - location = azurerm_resource_group.rg.location - resource_group_name = azurerm_resource_group.rg.name - storage_account_type = "Standard_LRS" - create_option = "Empty" - disk_size_gb = "1" + name = "acctestsads%s" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" } data "azurerm_managed_disk_export" "test" { - managed_disk_id = azurerm_managed_disk.disk.id - duration_in_seconds = 300 - access = "Read" + managed_disk_id = azurerm_managed_disk.disk.id + duration_in_seconds = 300 + access = "Read" } `, data.RandomInteger, data.Locations.Primary, data.RandomString) } diff --git a/website/docs/d/managed_disk_export.html.markdown b/website/docs/d/managed_disk_export.html.markdown index 8d9e4e1efb25..b72f7996dbc4 100644 --- a/website/docs/d/managed_disk_export.html.markdown +++ b/website/docs/d/managed_disk_export.html.markdown @@ -22,22 +22,22 @@ resource "azurerm_resource_group" "rg" { } resource "azurerm_managed_disk" "disk" { - name = "azureManagedDisk" - location = azurerm_resource_group.rg.location - resource_group_name = azurerm_resource_group.rg.name - storage_account_type = "Standard_LRS" - create_option = "Empty" - disk_size_gb = "1" - - tags = { - environment = "staging" - } + name = "azureManagedDisk" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" + + tags = { + environment = "staging" + } } data "azurerm_managed_disk_export" "disk" { - managed_disk_id = azurerm_managed_disk.disk.id - duration_in_seconds = 300 - access = "Read" + managed_disk_id = azurerm_managed_disk.disk.id + duration_in_seconds = 300 + access = "Read" } output "sas_url_query_string" { @@ -64,4 +64,4 @@ for additional details on the fields above. 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 Blob Container. \ No newline at end of file +* `read` - (Defaults to 5 minutes) Used when retrieving the Blob Container. From 77d008408c884dbaaa98b91cdde6e30b3226450c Mon Sep 17 00:00:00 2001 From: Harshavardhan Musanalli Date: Wed, 23 Feb 2022 11:51:18 +0100 Subject: [PATCH 3/8] Adding azurerm_managed_disk_export_revoke data source to revoke export sas token post disk operations --- .../compute/disk_export_data_source.go | 6 +- .../compute/disk_export_data_source_test.go | 15 +-- .../compute/disk_export_revoke_data_source.go | 65 +++++++++++++ .../disk_export_revoke_data_source_test.go | 53 +++++++++++ internal/services/compute/registration.go | 39 ++++---- .../docs/d/managed_disk_export.html.markdown | 28 +++++- .../managed_disk_export_revoke.html.markdown | 93 +++++++++++++++++++ 7 files changed, 269 insertions(+), 30 deletions(-) create mode 100644 internal/services/compute/disk_export_revoke_data_source.go create mode 100644 internal/services/compute/disk_export_revoke_data_source_test.go create mode 100644 website/docs/d/managed_disk_export_revoke.html.markdown diff --git a/internal/services/compute/disk_export_data_source.go b/internal/services/compute/disk_export_data_source.go index b95dbab435b9..ce6c6e653d22 100644 --- a/internal/services/compute/disk_export_data_source.go +++ b/internal/services/compute/disk_export_data_source.go @@ -91,10 +91,10 @@ func dataSourceManagedDiskExportRead(d *pluginsdk.ResourceData, meta interface{} return fmt.Errorf("Error while fetching the response %q: %+v", parsedManagedDiskId.ID(), err) } - sasToken := diskGrantResponse.AccessSAS + sasToken := *diskGrantResponse.AccessSAS - d.Set("sas", *sasToken) - tokenHash := sha256.Sum256([]byte(*sasToken)) + d.Set("sas", sasToken) + tokenHash := sha256.Sum256([]byte(sasToken)) d.SetId(hex.EncodeToString(tokenHash[:])) return nil diff --git a/internal/services/compute/disk_export_data_source_test.go b/internal/services/compute/disk_export_data_source_test.go index 577705efb50a..ddad109c4e5f 100644 --- a/internal/services/compute/disk_export_data_source_test.go +++ b/internal/services/compute/disk_export_data_source_test.go @@ -11,15 +11,14 @@ import ( type DataSourceManagedDiskExportDataSource struct{} func TestAccDataSourceDiskExportSas_basic(t *testing.T) { - data := acceptance.BuildTestData(t, "data.azurerm_managed_disk_export", "test") + data := acceptance.BuildTestData(t, "data.azurerm_managed_disk_export", "export") data.DataSourceTest(t, []acceptance.TestStep{ { Config: DataSourceManagedDiskExportDataSource{}.basic(data), Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).Key("managed_disk_id").HasValue("/subscriptions/42cbb0b8a331-abaf-4e69-8d8f-14b86a40/resourceGroups/disksrg/providers/Microsoft.Compute/disks/disk1"), - check.That(data.ResourceName).Key("access").HasValue("Write"), - check.That(data.ResourceName).Key("duration_in_seconds").HasValue("30"), + check.That(data.ResourceName).Key("access").HasValue("Read"), + check.That(data.ResourceName).Key("duration_in_seconds").HasValue("300"), check.That(data.ResourceName).Key("sas").Exists(), ), }, @@ -32,7 +31,7 @@ provider "azurerm" { features {} } resource "azurerm_resource_group" "rg" { - name = "acctestRG-disk-%d" + name = "acctestRG-exportdisk-%d" location = "%s" } resource "azurerm_managed_disk" "disk" { @@ -43,10 +42,14 @@ resource "azurerm_managed_disk" "disk" { create_option = "Empty" disk_size_gb = "1" } -data "azurerm_managed_disk_export" "test" { +data "azurerm_managed_disk_export" "export" { managed_disk_id = azurerm_managed_disk.disk.id duration_in_seconds = 300 access = "Read" } +data "azurerm_managed_disk_export_revoke" "revoke" { + depends_on = [data.azurerm_managed_disk_export.export] + managed_disk_id = azurerm_managed_disk.disk.id +} `, data.RandomInteger, data.Locations.Primary, data.RandomString) } diff --git a/internal/services/compute/disk_export_revoke_data_source.go b/internal/services/compute/disk_export_revoke_data_source.go new file mode 100644 index 000000000000..9991842ddd89 --- /dev/null +++ b/internal/services/compute/disk_export_revoke_data_source.go @@ -0,0 +1,65 @@ +package compute + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func dataSourceManagedDiskExportRevoke() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: dataSourceManagedDiskExportCancel, + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "managed_disk_id": { + Type: pluginsdk.TypeString, + Required: true, + DiffSuppressFunc: suppress.CaseDifference, + ValidateFunc: azure.ValidateResourceID, + }, + }, + } +} + +func dataSourceManagedDiskExportCancel(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Compute.DisksClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + managedDiskId := d.Get("managed_disk_id").(string) + + parsedManagedDiskId, err := parse.ManagedDiskID(managedDiskId) + if err != nil { + return fmt.Errorf("parsing Managed Disk ID %q: %+v", parsedManagedDiskId.ID(), err) + } + + diskName := parsedManagedDiskId.DiskName + resourceGroupName := parsedManagedDiskId.ResourceGroup + + // Request to Revoke Access for Disk + diskRevokeFuture, err := client.RevokeAccess(ctx, resourceGroupName, diskName) + if err != nil { + return fmt.Errorf("Error while revoking access for disk export %q: %+v", parsedManagedDiskId.ID(), err) + } + + // Wait until the Revoke Request is complete + diskRevokeFuture.WaitForCompletionRef(ctx, client.Client) + if err != nil { + return fmt.Errorf("Revoke access operation failed %q (Resource Group %q): %+v", diskName, resourceGroupName, err) + } + + d.SetId(time.Now().UTC().String()) + + return nil + +} diff --git a/internal/services/compute/disk_export_revoke_data_source_test.go b/internal/services/compute/disk_export_revoke_data_source_test.go new file mode 100644 index 000000000000..1d0c80c9ab40 --- /dev/null +++ b/internal/services/compute/disk_export_revoke_data_source_test.go @@ -0,0 +1,53 @@ +package compute_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DataSourceManagedDiskExportRevokeDataSource struct{} + +func TestAccDataSourceDiskExportRevokeSas_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_managed_disk_export", "revoke") + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: DataSourceManagedDiskExportRevokeDataSource{}.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("id").Exists(), + ), + }, + }) +} + +func (d DataSourceManagedDiskExportRevokeDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +resource "azurerm_resource_group" "rg" { + name = "acctestRG-revokedisk-%d" + location = "%s" +} +resource "azurerm_managed_disk" "disk" { + name = "acctestsads%s" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" +} +data "azurerm_managed_disk_export" "export" { + managed_disk_id = azurerm_managed_disk.disk.id + duration_in_seconds = 300 + access = "Read" +} +data "azurerm_managed_disk_export_revoke" "revoke" { + depends_on = [data.azurerm_managed_disk_export.export] + managed_disk_id = azurerm_managed_disk.disk.id +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} diff --git a/internal/services/compute/registration.go b/internal/services/compute/registration.go index a65e13d4b7a9..14d420f8d8d0 100644 --- a/internal/services/compute/registration.go +++ b/internal/services/compute/registration.go @@ -21,25 +21,26 @@ func (r Registration) WebsiteCategories() []string { // SupportedDataSources returns the supported Data Sources supported by this Service func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { return map[string]*pluginsdk.Resource{ - "azurerm_availability_set": dataSourceAvailabilitySet(), - "azurerm_dedicated_host": dataSourceDedicatedHost(), - "azurerm_dedicated_host_group": dataSourceDedicatedHostGroup(), - "azurerm_disk_encryption_set": dataSourceDiskEncryptionSet(), - "azurerm_managed_disk": dataSourceManagedDisk(), - "azurerm_image": dataSourceImage(), - "azurerm_images": dataSourceImages(), - "azurerm_disk_access": dataSourceDiskAccess(), - "azurerm_platform_image": dataSourcePlatformImage(), - "azurerm_proximity_placement_group": dataSourceProximityPlacementGroup(), - "azurerm_shared_image_gallery": dataSourceSharedImageGallery(), - "azurerm_shared_image_version": dataSourceSharedImageVersion(), - "azurerm_shared_image_versions": dataSourceSharedImageVersions(), - "azurerm_shared_image": dataSourceSharedImage(), - "azurerm_snapshot": dataSourceSnapshot(), - "azurerm_virtual_machine": dataSourceVirtualMachine(), - "azurerm_virtual_machine_scale_set": dataSourceVirtualMachineScaleSet(), - "azurerm_ssh_public_key": dataSourceSshPublicKey(), - "azurerm_managed_disk_export": dataSourceManagedDiskExport(), + "azurerm_availability_set": dataSourceAvailabilitySet(), + "azurerm_dedicated_host": dataSourceDedicatedHost(), + "azurerm_dedicated_host_group": dataSourceDedicatedHostGroup(), + "azurerm_disk_encryption_set": dataSourceDiskEncryptionSet(), + "azurerm_managed_disk": dataSourceManagedDisk(), + "azurerm_image": dataSourceImage(), + "azurerm_images": dataSourceImages(), + "azurerm_disk_access": dataSourceDiskAccess(), + "azurerm_platform_image": dataSourcePlatformImage(), + "azurerm_proximity_placement_group": dataSourceProximityPlacementGroup(), + "azurerm_shared_image_gallery": dataSourceSharedImageGallery(), + "azurerm_shared_image_version": dataSourceSharedImageVersion(), + "azurerm_shared_image_versions": dataSourceSharedImageVersions(), + "azurerm_shared_image": dataSourceSharedImage(), + "azurerm_snapshot": dataSourceSnapshot(), + "azurerm_virtual_machine": dataSourceVirtualMachine(), + "azurerm_virtual_machine_scale_set": dataSourceVirtualMachineScaleSet(), + "azurerm_ssh_public_key": dataSourceSshPublicKey(), + "azurerm_managed_disk_export": dataSourceManagedDiskExport(), + "azurerm_managed_disk_export_revoke": dataSourceManagedDiskExportRevoke(), } } diff --git a/website/docs/d/managed_disk_export.html.markdown b/website/docs/d/managed_disk_export.html.markdown index b72f7996dbc4..2780b2e08125 100644 --- a/website/docs/d/managed_disk_export.html.markdown +++ b/website/docs/d/managed_disk_export.html.markdown @@ -13,6 +13,8 @@ Use this data source to obtain a Shared Access Signature (SAS Token) for an exis Shared access signatures allow fine-grained, ephemeral access control to various aspects of Managed Disk similar to blob/storage account container. +With the help of this resource, data from the disk can be copied from managed disk to a storage blob or to some other system without the need of azcopy. + ## Example Usage ```hcl @@ -34,14 +36,36 @@ resource "azurerm_managed_disk" "disk" { } } -data "azurerm_managed_disk_export" "disk" { +data "azurerm_managed_disk_export" "export" { managed_disk_id = azurerm_managed_disk.disk.id duration_in_seconds = 300 access = "Read" } +resource "azurerm_storage_account" "example" { + name = "examplestoracc" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_storage_container" "example" { + name = "content" + storage_account_name = azurerm_storage_account.example.name + container_access_type = "private" +} + +resource "azurerm_storage_blob" "example" { + name = "${azurerm_managed_disk.disk.name}.vhd" + storage_account_name = azurerm_storage_account.example.name + storage_container_name = azurerm_storage_container.example.name + type = "Page" + source_uri = data.azurerm_managed_disk_export.export.sas +} + output "sas_url_query_string" { - value = data.azurerm_managed_disk_export.disk.sas + value = data.azurerm_managed_disk_export.export.sas } ``` diff --git a/website/docs/d/managed_disk_export_revoke.html.markdown b/website/docs/d/managed_disk_export_revoke.html.markdown new file mode 100644 index 000000000000..402fa59d0ef9 --- /dev/null +++ b/website/docs/d/managed_disk_export_revoke.html.markdown @@ -0,0 +1,93 @@ +--- +subcategory: "Compute" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_managed_disk_export_revoke" +description: |- + Revokes a Shared Access Signature (SAS Token) for an existing Managed Disk. + +--- + +# Data Source: azurerm_managed_disk_export_revoke + +Use this data source to revoke Shared Access Signature (SAS Token) for an existing Managed Disk obtained after grant. + +Shared access signatures allow fine-grained, ephemeral access control to various aspects of Managed Disk similar to blob/storage account container. + +With the help of this resource, data from the disk can be copied from managed disk to a storage blob or to some other system without the need of azcopy. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "rg" { + name = "resourceGroupName" + location = "West Europe" +} + +resource "azurerm_managed_disk" "disk" { + name = "azureManagedDisk" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" + + tags = { + environment = "staging" + } +} + +resource "azurerm_storage_account" "example" { + name = "examplestoracc" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_storage_container" "example" { + name = "content" + storage_account_name = azurerm_storage_account.example.name + container_access_type = "private" +} + +resource "azurerm_storage_blob" "example" { + name = "${azurerm_managed_disk.disk.name}.vhd" + storage_account_name = azurerm_storage_account.example.name + storage_container_name = azurerm_storage_container.example.name + type = "Page" + source_uri = data.azurerm_managed_disk_export.export.sas +} + +data "azurerm_managed_disk_export" "export" { + managed_disk_id = azurerm_managed_disk.disk.id + duration_in_seconds = 300 + access = "Read" +} + +## revoke the sas token post export is complete +data "azurerm_managed_disk_export_revoke" "revoke" { + depends_on = [azurerm_storage_blob.example] + managed_disk_id = "/subscriptions/14b86a40-8d8f-4e69-abaf-42cbb0b8a331/resourceGroups/FACTORY/providers/Microsoft.Compute/disks/ash-rhel7-image" +} +``` + +## Argument Reference + +* `managed_disk_id` - The ID of an existing Managed Disk which should be exported. Changing this forces a new resource to be created. + +* `duration_in_seconds` - The duration for which the export should be allowed. Should be greater than 30 seconds. + +* `access` - (Optional) The level of access required on the disk. Supported are Read, Write. Defaults to Read. + +Refer to the [SAS creation reference from Azure](https://docs.microsoft.com/en-us/rest/api/compute/disks/grant-access) +for additional details on the fields above. + +## Attributes Reference + +* `sas` - The computed Shared Access Signature (SAS) of the Managed Disk. + +## 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 Blob Container. From c7c011d59ab03b1ebcbe642e76092b25f0a91929 Mon Sep 17 00:00:00 2001 From: Harshavardhan Musanalli Date: Wed, 23 Feb 2022 12:21:23 +0100 Subject: [PATCH 4/8] Adding err return value for diskRevokeFuture.WaitForCompletionRef func --- internal/services/compute/disk_export_revoke_data_source.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/services/compute/disk_export_revoke_data_source.go b/internal/services/compute/disk_export_revoke_data_source.go index 9991842ddd89..f1d05ba97aca 100644 --- a/internal/services/compute/disk_export_revoke_data_source.go +++ b/internal/services/compute/disk_export_revoke_data_source.go @@ -53,7 +53,7 @@ func dataSourceManagedDiskExportCancel(d *pluginsdk.ResourceData, meta interface } // Wait until the Revoke Request is complete - diskRevokeFuture.WaitForCompletionRef(ctx, client.Client) + err = diskRevokeFuture.WaitForCompletionRef(ctx, client.Client) if err != nil { return fmt.Errorf("Revoke access operation failed %q (Resource Group %q): %+v", diskName, resourceGroupName, err) } From da3b6f35a10112977db533d3e10699c03126d94e Mon Sep 17 00:00:00 2001 From: Harshavardhan Musanalli Date: Fri, 25 Feb 2022 19:01:45 +0100 Subject: [PATCH 5/8] New resource azurerm_disk_export to manage disk exports instead of data sources --- .../compute/disk_export_data_source_test.go | 55 ----------- ...data_source.go => disk_export_resource.go} | 57 +++++++++--- .../compute/disk_export_resource_test.go | 49 ++++++++++ .../compute/disk_export_revoke_data_source.go | 65 ------------- .../disk_export_revoke_data_source_test.go | 53 ----------- internal/services/compute/registration.go | 39 ++++---- .../docs/d/managed_disk_export.html.markdown | 91 ------------------ .../managed_disk_export_revoke.html.markdown | 93 ------------------- website/docs/r/disk_export.html.markdown | 69 ++++++++++++++ 9 files changed, 183 insertions(+), 388 deletions(-) delete mode 100644 internal/services/compute/disk_export_data_source_test.go rename internal/services/compute/{disk_export_data_source.go => disk_export_resource.go} (62%) create mode 100644 internal/services/compute/disk_export_resource_test.go delete mode 100644 internal/services/compute/disk_export_revoke_data_source.go delete mode 100644 internal/services/compute/disk_export_revoke_data_source_test.go delete mode 100644 website/docs/d/managed_disk_export.html.markdown delete mode 100644 website/docs/d/managed_disk_export_revoke.html.markdown create mode 100644 website/docs/r/disk_export.html.markdown diff --git a/internal/services/compute/disk_export_data_source_test.go b/internal/services/compute/disk_export_data_source_test.go deleted file mode 100644 index ddad109c4e5f..000000000000 --- a/internal/services/compute/disk_export_data_source_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package compute_test - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" - "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" -) - -type DataSourceManagedDiskExportDataSource struct{} - -func TestAccDataSourceDiskExportSas_basic(t *testing.T) { - data := acceptance.BuildTestData(t, "data.azurerm_managed_disk_export", "export") - - data.DataSourceTest(t, []acceptance.TestStep{ - { - Config: DataSourceManagedDiskExportDataSource{}.basic(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).Key("access").HasValue("Read"), - check.That(data.ResourceName).Key("duration_in_seconds").HasValue("300"), - check.That(data.ResourceName).Key("sas").Exists(), - ), - }, - }) -} - -func (d DataSourceManagedDiskExportDataSource) basic(data acceptance.TestData) string { - return fmt.Sprintf(` -provider "azurerm" { - features {} -} -resource "azurerm_resource_group" "rg" { - name = "acctestRG-exportdisk-%d" - location = "%s" -} -resource "azurerm_managed_disk" "disk" { - name = "acctestsads%s" - location = azurerm_resource_group.rg.location - resource_group_name = azurerm_resource_group.rg.name - storage_account_type = "Standard_LRS" - create_option = "Empty" - disk_size_gb = "1" -} -data "azurerm_managed_disk_export" "export" { - managed_disk_id = azurerm_managed_disk.disk.id - duration_in_seconds = 300 - access = "Read" -} -data "azurerm_managed_disk_export_revoke" "revoke" { - depends_on = [data.azurerm_managed_disk_export.export] - managed_disk_id = azurerm_managed_disk.disk.id -} -`, data.RandomInteger, data.Locations.Primary, data.RandomString) -} diff --git a/internal/services/compute/disk_export_data_source.go b/internal/services/compute/disk_export_resource.go similarity index 62% rename from internal/services/compute/disk_export_data_source.go rename to internal/services/compute/disk_export_resource.go index ce6c6e653d22..97daefc42f93 100644 --- a/internal/services/compute/disk_export_data_source.go +++ b/internal/services/compute/disk_export_resource.go @@ -4,6 +4,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "log" "time" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-07-01/compute" @@ -12,15 +13,23 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" ) -func dataSourceManagedDiskExport() *pluginsdk.Resource { +func resourceDiskExport() *pluginsdk.Resource { + return &pluginsdk.Resource{ - Read: dataSourceManagedDiskExportRead, + Create: resourceDiskExportCreateUpdate, + Read: resourceDiskExportRead, + Update: resourceDiskExportCreateUpdate, + Delete: resourceDiskExportDelete, Timeouts: &pluginsdk.ResourceTimeout{ - Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(30 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), }, Schema: map[string]*pluginsdk.Schema{ @@ -42,20 +51,25 @@ func dataSourceManagedDiskExport() *pluginsdk.Resource { Default: "Read", }, - "sas": { - Type: pluginsdk.TypeString, - Computed: true, - Sensitive: true, + "sas_url": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Sensitive: true, + ValidateFunc: validation.IsURLWithScheme([]string{"http", "https"}), }, }, } + } -func dataSourceManagedDiskExportRead(d *pluginsdk.ResourceData, meta interface{}) error { +func resourceDiskExportCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Compute.DisksClient - ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() + log.Printf("[INFO] preparing arguments for AzureRM Disk Export.") managedDiskId := d.Get("managed_disk_id").(string) durationInSeconds := int32(d.Get("duration_in_seconds").(int)) access := d.Get("access").(string) @@ -92,11 +106,32 @@ func dataSourceManagedDiskExportRead(d *pluginsdk.ResourceData, meta interface{} } sasToken := *diskGrantResponse.AccessSAS - - d.Set("sas", sasToken) + d.Set("sas_url", sasToken) tokenHash := sha256.Sum256([]byte(sasToken)) d.SetId(hex.EncodeToString(tokenHash[:])) + return resourceDiskExportRead(d, meta) + +} + +func resourceDiskExportRead(d *pluginsdk.ResourceData, meta interface{}) error { return nil +} + +func resourceDiskExportDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Compute.DisksClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ManagedDiskID(d.Get("managed_disk_id").(string)) + if err != nil { + return err + } + + future, err := client.RevokeAccess(ctx, id.ResourceGroup, id.DiskName) + if err != nil { + return err + } + return future.WaitForCompletionRef(ctx, client.Client) } diff --git a/internal/services/compute/disk_export_resource_test.go b/internal/services/compute/disk_export_resource_test.go new file mode 100644 index 000000000000..3cba7e04cf83 --- /dev/null +++ b/internal/services/compute/disk_export_resource_test.go @@ -0,0 +1,49 @@ +package compute_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type DiskExportResource struct{} + +func TestAccDiskExport_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_disk_export", "test") + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: DiskExportResource{}.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("id").Exists(), + ), + }, + }) +} + +func (t DiskExportResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +resource "azurerm_resource_group" "test" { + name = "acctestRG-revokedisk-%d" + location = "%s" +} +resource "azurerm_managed_disk" "test" { + name = "acctestsads%s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" +} +resource "azurerm_disk_export" "test" { + managed_disk_id = azurerm_managed_disk.test.id + duration_in_seconds = 300 + access = "Read" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} diff --git a/internal/services/compute/disk_export_revoke_data_source.go b/internal/services/compute/disk_export_revoke_data_source.go deleted file mode 100644 index f1d05ba97aca..000000000000 --- a/internal/services/compute/disk_export_revoke_data_source.go +++ /dev/null @@ -1,65 +0,0 @@ -package compute - -import ( - "fmt" - "time" - - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" - "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" - "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" - "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" -) - -func dataSourceManagedDiskExportRevoke() *pluginsdk.Resource { - return &pluginsdk.Resource{ - Read: dataSourceManagedDiskExportCancel, - - Timeouts: &pluginsdk.ResourceTimeout{ - Read: pluginsdk.DefaultTimeout(5 * time.Minute), - }, - - Schema: map[string]*pluginsdk.Schema{ - "managed_disk_id": { - Type: pluginsdk.TypeString, - Required: true, - DiffSuppressFunc: suppress.CaseDifference, - ValidateFunc: azure.ValidateResourceID, - }, - }, - } -} - -func dataSourceManagedDiskExportCancel(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Compute.DisksClient - ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) - defer cancel() - - managedDiskId := d.Get("managed_disk_id").(string) - - parsedManagedDiskId, err := parse.ManagedDiskID(managedDiskId) - if err != nil { - return fmt.Errorf("parsing Managed Disk ID %q: %+v", parsedManagedDiskId.ID(), err) - } - - diskName := parsedManagedDiskId.DiskName - resourceGroupName := parsedManagedDiskId.ResourceGroup - - // Request to Revoke Access for Disk - diskRevokeFuture, err := client.RevokeAccess(ctx, resourceGroupName, diskName) - if err != nil { - return fmt.Errorf("Error while revoking access for disk export %q: %+v", parsedManagedDiskId.ID(), err) - } - - // Wait until the Revoke Request is complete - err = diskRevokeFuture.WaitForCompletionRef(ctx, client.Client) - if err != nil { - return fmt.Errorf("Revoke access operation failed %q (Resource Group %q): %+v", diskName, resourceGroupName, err) - } - - d.SetId(time.Now().UTC().String()) - - return nil - -} diff --git a/internal/services/compute/disk_export_revoke_data_source_test.go b/internal/services/compute/disk_export_revoke_data_source_test.go deleted file mode 100644 index 1d0c80c9ab40..000000000000 --- a/internal/services/compute/disk_export_revoke_data_source_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package compute_test - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" - "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" -) - -type DataSourceManagedDiskExportRevokeDataSource struct{} - -func TestAccDataSourceDiskExportRevokeSas_basic(t *testing.T) { - data := acceptance.BuildTestData(t, "data.azurerm_managed_disk_export", "revoke") - - data.DataSourceTest(t, []acceptance.TestStep{ - { - Config: DataSourceManagedDiskExportRevokeDataSource{}.basic(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).Key("id").Exists(), - ), - }, - }) -} - -func (d DataSourceManagedDiskExportRevokeDataSource) basic(data acceptance.TestData) string { - return fmt.Sprintf(` -provider "azurerm" { - features {} -} -resource "azurerm_resource_group" "rg" { - name = "acctestRG-revokedisk-%d" - location = "%s" -} -resource "azurerm_managed_disk" "disk" { - name = "acctestsads%s" - location = azurerm_resource_group.rg.location - resource_group_name = azurerm_resource_group.rg.name - storage_account_type = "Standard_LRS" - create_option = "Empty" - disk_size_gb = "1" -} -data "azurerm_managed_disk_export" "export" { - managed_disk_id = azurerm_managed_disk.disk.id - duration_in_seconds = 300 - access = "Read" -} -data "azurerm_managed_disk_export_revoke" "revoke" { - depends_on = [data.azurerm_managed_disk_export.export] - managed_disk_id = azurerm_managed_disk.disk.id -} -`, data.RandomInteger, data.Locations.Primary, data.RandomString) -} diff --git a/internal/services/compute/registration.go b/internal/services/compute/registration.go index 14d420f8d8d0..3e3cadff5548 100644 --- a/internal/services/compute/registration.go +++ b/internal/services/compute/registration.go @@ -21,26 +21,24 @@ func (r Registration) WebsiteCategories() []string { // SupportedDataSources returns the supported Data Sources supported by this Service func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { return map[string]*pluginsdk.Resource{ - "azurerm_availability_set": dataSourceAvailabilitySet(), - "azurerm_dedicated_host": dataSourceDedicatedHost(), - "azurerm_dedicated_host_group": dataSourceDedicatedHostGroup(), - "azurerm_disk_encryption_set": dataSourceDiskEncryptionSet(), - "azurerm_managed_disk": dataSourceManagedDisk(), - "azurerm_image": dataSourceImage(), - "azurerm_images": dataSourceImages(), - "azurerm_disk_access": dataSourceDiskAccess(), - "azurerm_platform_image": dataSourcePlatformImage(), - "azurerm_proximity_placement_group": dataSourceProximityPlacementGroup(), - "azurerm_shared_image_gallery": dataSourceSharedImageGallery(), - "azurerm_shared_image_version": dataSourceSharedImageVersion(), - "azurerm_shared_image_versions": dataSourceSharedImageVersions(), - "azurerm_shared_image": dataSourceSharedImage(), - "azurerm_snapshot": dataSourceSnapshot(), - "azurerm_virtual_machine": dataSourceVirtualMachine(), - "azurerm_virtual_machine_scale_set": dataSourceVirtualMachineScaleSet(), - "azurerm_ssh_public_key": dataSourceSshPublicKey(), - "azurerm_managed_disk_export": dataSourceManagedDiskExport(), - "azurerm_managed_disk_export_revoke": dataSourceManagedDiskExportRevoke(), + "azurerm_availability_set": dataSourceAvailabilitySet(), + "azurerm_dedicated_host": dataSourceDedicatedHost(), + "azurerm_dedicated_host_group": dataSourceDedicatedHostGroup(), + "azurerm_disk_encryption_set": dataSourceDiskEncryptionSet(), + "azurerm_managed_disk": dataSourceManagedDisk(), + "azurerm_image": dataSourceImage(), + "azurerm_images": dataSourceImages(), + "azurerm_disk_access": dataSourceDiskAccess(), + "azurerm_platform_image": dataSourcePlatformImage(), + "azurerm_proximity_placement_group": dataSourceProximityPlacementGroup(), + "azurerm_shared_image_gallery": dataSourceSharedImageGallery(), + "azurerm_shared_image_version": dataSourceSharedImageVersion(), + "azurerm_shared_image_versions": dataSourceSharedImageVersions(), + "azurerm_shared_image": dataSourceSharedImage(), + "azurerm_snapshot": dataSourceSnapshot(), + "azurerm_virtual_machine": dataSourceVirtualMachine(), + "azurerm_virtual_machine_scale_set": dataSourceVirtualMachineScaleSet(), + "azurerm_ssh_public_key": dataSourceSshPublicKey(), } } @@ -69,6 +67,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_windows_virtual_machine": resourceWindowsVirtualMachine(), "azurerm_windows_virtual_machine_scale_set": resourceWindowsVirtualMachineScaleSet(), "azurerm_ssh_public_key": resourceSshPublicKey(), + "azurerm_disk_export": resourceDiskExport(), } return resources diff --git a/website/docs/d/managed_disk_export.html.markdown b/website/docs/d/managed_disk_export.html.markdown deleted file mode 100644 index 2780b2e08125..000000000000 --- a/website/docs/d/managed_disk_export.html.markdown +++ /dev/null @@ -1,91 +0,0 @@ ---- -subcategory: "Compute" -layout: "azurerm" -page_title: "Azure Resource Manager: azurerm_managed_disk_export" -description: |- - Gets a Shared Access Signature (SAS Token) for an existing Managed Disk. - ---- - -# Data Source: azurerm_managed_disk_export - -Use this data source to obtain a Shared Access Signature (SAS Token) for an existing Managed Disk. - -Shared access signatures allow fine-grained, ephemeral access control to various aspects of Managed Disk similar to blob/storage account container. - -With the help of this resource, data from the disk can be copied from managed disk to a storage blob or to some other system without the need of azcopy. - -## Example Usage - -```hcl -resource "azurerm_resource_group" "rg" { - name = "resourceGroupName" - location = "West Europe" -} - -resource "azurerm_managed_disk" "disk" { - name = "azureManagedDisk" - location = azurerm_resource_group.rg.location - resource_group_name = azurerm_resource_group.rg.name - storage_account_type = "Standard_LRS" - create_option = "Empty" - disk_size_gb = "1" - - tags = { - environment = "staging" - } -} - -data "azurerm_managed_disk_export" "export" { - managed_disk_id = azurerm_managed_disk.disk.id - duration_in_seconds = 300 - access = "Read" -} - -resource "azurerm_storage_account" "example" { - name = "examplestoracc" - resource_group_name = azurerm_resource_group.example.name - location = azurerm_resource_group.example.location - account_tier = "Standard" - account_replication_type = "LRS" -} - -resource "azurerm_storage_container" "example" { - name = "content" - storage_account_name = azurerm_storage_account.example.name - container_access_type = "private" -} - -resource "azurerm_storage_blob" "example" { - name = "${azurerm_managed_disk.disk.name}.vhd" - storage_account_name = azurerm_storage_account.example.name - storage_container_name = azurerm_storage_container.example.name - type = "Page" - source_uri = data.azurerm_managed_disk_export.export.sas -} - -output "sas_url_query_string" { - value = data.azurerm_managed_disk_export.export.sas -} -``` - -## Argument Reference - -* `managed_disk_id` - The ID of an existing Managed Disk which should be exported. Changing this forces a new resource to be created. - -* `duration_in_seconds` - The duration for which the export should be allowed. Should be greater than 30 seconds. - -* `access` - (Optional) The level of access required on the disk. Supported are Read, Write. Defaults to Read. - -Refer to the [SAS creation reference from Azure](https://docs.microsoft.com/en-us/rest/api/compute/disks/grant-access) -for additional details on the fields above. - -## Attributes Reference - -* `sas` - The computed Shared Access Signature (SAS) of the Managed Disk. - -## 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 Blob Container. diff --git a/website/docs/d/managed_disk_export_revoke.html.markdown b/website/docs/d/managed_disk_export_revoke.html.markdown deleted file mode 100644 index 402fa59d0ef9..000000000000 --- a/website/docs/d/managed_disk_export_revoke.html.markdown +++ /dev/null @@ -1,93 +0,0 @@ ---- -subcategory: "Compute" -layout: "azurerm" -page_title: "Azure Resource Manager: azurerm_managed_disk_export_revoke" -description: |- - Revokes a Shared Access Signature (SAS Token) for an existing Managed Disk. - ---- - -# Data Source: azurerm_managed_disk_export_revoke - -Use this data source to revoke Shared Access Signature (SAS Token) for an existing Managed Disk obtained after grant. - -Shared access signatures allow fine-grained, ephemeral access control to various aspects of Managed Disk similar to blob/storage account container. - -With the help of this resource, data from the disk can be copied from managed disk to a storage blob or to some other system without the need of azcopy. - -## Example Usage - -```hcl -resource "azurerm_resource_group" "rg" { - name = "resourceGroupName" - location = "West Europe" -} - -resource "azurerm_managed_disk" "disk" { - name = "azureManagedDisk" - location = azurerm_resource_group.rg.location - resource_group_name = azurerm_resource_group.rg.name - storage_account_type = "Standard_LRS" - create_option = "Empty" - disk_size_gb = "1" - - tags = { - environment = "staging" - } -} - -resource "azurerm_storage_account" "example" { - name = "examplestoracc" - resource_group_name = azurerm_resource_group.example.name - location = azurerm_resource_group.example.location - account_tier = "Standard" - account_replication_type = "LRS" -} - -resource "azurerm_storage_container" "example" { - name = "content" - storage_account_name = azurerm_storage_account.example.name - container_access_type = "private" -} - -resource "azurerm_storage_blob" "example" { - name = "${azurerm_managed_disk.disk.name}.vhd" - storage_account_name = azurerm_storage_account.example.name - storage_container_name = azurerm_storage_container.example.name - type = "Page" - source_uri = data.azurerm_managed_disk_export.export.sas -} - -data "azurerm_managed_disk_export" "export" { - managed_disk_id = azurerm_managed_disk.disk.id - duration_in_seconds = 300 - access = "Read" -} - -## revoke the sas token post export is complete -data "azurerm_managed_disk_export_revoke" "revoke" { - depends_on = [azurerm_storage_blob.example] - managed_disk_id = "/subscriptions/14b86a40-8d8f-4e69-abaf-42cbb0b8a331/resourceGroups/FACTORY/providers/Microsoft.Compute/disks/ash-rhel7-image" -} -``` - -## Argument Reference - -* `managed_disk_id` - The ID of an existing Managed Disk which should be exported. Changing this forces a new resource to be created. - -* `duration_in_seconds` - The duration for which the export should be allowed. Should be greater than 30 seconds. - -* `access` - (Optional) The level of access required on the disk. Supported are Read, Write. Defaults to Read. - -Refer to the [SAS creation reference from Azure](https://docs.microsoft.com/en-us/rest/api/compute/disks/grant-access) -for additional details on the fields above. - -## Attributes Reference - -* `sas` - The computed Shared Access Signature (SAS) of the Managed Disk. - -## 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 Blob Container. diff --git a/website/docs/r/disk_export.html.markdown b/website/docs/r/disk_export.html.markdown new file mode 100644 index 000000000000..fc4b97a9332f --- /dev/null +++ b/website/docs/r/disk_export.html.markdown @@ -0,0 +1,69 @@ +--- +subcategory: "Compute" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_disk_export" +description: |- + Manages a Disk Export. +--- + +# azurerm_disk_export + +Manages a Disk Export. + +Use this resource to obtain a Shared Access Signature (SAS Token) for an existing Managed Disk. + +Shared access signatures allow fine-grained, ephemeral access control to various aspects of Managed Disk similar to blob/storage account container. + +With the help of this resource, data from the disk can be copied from managed disk to a storage blob or to some other system without the need of azcopy. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "test" { + name = "testrg" + location = "West Europe" +} +resource "azurerm_managed_disk" "test" { + name = "tst-disk-export" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" +} +resource "azurerm_disk_export" "test" { + managed_disk_id = azurerm_managed_disk.test.id + duration_in_seconds = 300 + access = "Read" +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `managed_disk_id` - (Required) The ID of an existing Managed Disk which should be exported. Changing this forces a new resource to be created. + +* `duration_in_seconds` - (Required) The duration for which the export should be allowed. Should be greater than 30 seconds. + +* `access` - (Optional) The level of access required on the disk. Supported are Read, Write. Defaults to Read. + +Refer to the [SAS creation reference from Azure](https://docs.microsoft.com/en-us/rest/api/compute/disks/grant-access) +for additional details on the fields above. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Disk Export resource. + +* `sas_url` - The computed Shared Access Signature (SAS) of the Managed Disk. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Disk. +* `read` - (Defaults to 5 minutes) Used when retrieving the Disk. +* `update` - (Defaults to 30 minutes) Used when updating the Disk. +* `delete` - (Defaults to 30 minutes) Used when deleting the Disk. From 3cfc731d9336de1db63d81caa16b3ba786ebd222 Mon Sep 17 00:00:00 2001 From: Harshavardhan Musanalli Date: Sun, 24 Apr 2022 17:25:09 +0200 Subject: [PATCH 6/8] Renaming azurerm_disk_export to azurerm_managed_disk_sas_token as per PR review & other changes --- .../services/compute/disk_export_resource.go | 137 --------------- .../compute/disk_export_resource_test.go | 49 ------ .../compute/disk_sas_token_resource.go | 163 ++++++++++++++++++ .../compute/disk_sas_token_resource_test.go | 73 ++++++++ internal/services/compute/registration.go | 2 +- website/docs/r/disk_export.html.markdown | 13 +- 6 files changed, 243 insertions(+), 194 deletions(-) delete mode 100644 internal/services/compute/disk_export_resource.go delete mode 100644 internal/services/compute/disk_export_resource_test.go create mode 100644 internal/services/compute/disk_sas_token_resource.go create mode 100644 internal/services/compute/disk_sas_token_resource_test.go diff --git a/internal/services/compute/disk_export_resource.go b/internal/services/compute/disk_export_resource.go deleted file mode 100644 index 97daefc42f93..000000000000 --- a/internal/services/compute/disk_export_resource.go +++ /dev/null @@ -1,137 +0,0 @@ -package compute - -import ( - "crypto/sha256" - "encoding/hex" - "fmt" - "log" - "time" - - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-07-01/compute" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" - "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" - "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" - "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" - "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" -) - -func resourceDiskExport() *pluginsdk.Resource { - - return &pluginsdk.Resource{ - Create: resourceDiskExportCreateUpdate, - Read: resourceDiskExportRead, - Update: resourceDiskExportCreateUpdate, - Delete: resourceDiskExportDelete, - - Timeouts: &pluginsdk.ResourceTimeout{ - Create: pluginsdk.DefaultTimeout(30 * time.Minute), - Read: pluginsdk.DefaultTimeout(5 * time.Minute), - Update: pluginsdk.DefaultTimeout(30 * time.Minute), - Delete: pluginsdk.DefaultTimeout(30 * time.Minute), - }, - - Schema: map[string]*pluginsdk.Schema{ - "managed_disk_id": { - Type: pluginsdk.TypeString, - Required: true, - DiffSuppressFunc: suppress.CaseDifference, - ValidateFunc: azure.ValidateResourceID, - }, - - "duration_in_seconds": { - Type: pluginsdk.TypeInt, - Required: true, - }, - - "access": { - Type: pluginsdk.TypeString, - Optional: true, - Default: "Read", - }, - - "sas_url": { - Type: pluginsdk.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - Sensitive: true, - ValidateFunc: validation.IsURLWithScheme([]string{"http", "https"}), - }, - }, - } - -} - -func resourceDiskExportCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Compute.DisksClient - ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) - defer cancel() - - log.Printf("[INFO] preparing arguments for AzureRM Disk Export.") - managedDiskId := d.Get("managed_disk_id").(string) - durationInSeconds := int32(d.Get("duration_in_seconds").(int)) - access := d.Get("access").(string) - - parsedManagedDiskId, err := parse.ManagedDiskID(managedDiskId) - if err != nil { - return fmt.Errorf("parsing Managed Disk ID %q: %+v", parsedManagedDiskId.ID(), err) - } - - diskName := parsedManagedDiskId.DiskName - resourceGroupName := parsedManagedDiskId.ResourceGroup - - grantAccessData := compute.GrantAccessData{ - Access: compute.AccessLevel(access), - DurationInSeconds: &durationInSeconds, - } - - // Request to Grant Access for Disk - diskGrantFuture, err := client.GrantAccess(ctx, resourceGroupName, diskName, grantAccessData) - if err != nil { - return fmt.Errorf("Error while granting access for disk export %q: %+v", parsedManagedDiskId.ID(), err) - } - - // Wait until the Grant Request is complete - err = diskGrantFuture.WaitForCompletionRef(ctx, client.Client) - if err != nil { - return fmt.Errorf("Grant access operation failed %q (Resource Group %q): %+v", diskName, resourceGroupName, err) - } - - // Fetch the SAS token from the response - diskGrantResponse, err := diskGrantFuture.Result(*client) - if err != nil { - return fmt.Errorf("Error while fetching the response %q: %+v", parsedManagedDiskId.ID(), err) - } - - sasToken := *diskGrantResponse.AccessSAS - d.Set("sas_url", sasToken) - tokenHash := sha256.Sum256([]byte(sasToken)) - d.SetId(hex.EncodeToString(tokenHash[:])) - - return resourceDiskExportRead(d, meta) - -} - -func resourceDiskExportRead(d *pluginsdk.ResourceData, meta interface{}) error { - return nil -} - -func resourceDiskExportDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Compute.DisksClient - ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) - defer cancel() - - id, err := parse.ManagedDiskID(d.Get("managed_disk_id").(string)) - if err != nil { - return err - } - - future, err := client.RevokeAccess(ctx, id.ResourceGroup, id.DiskName) - if err != nil { - return err - } - - return future.WaitForCompletionRef(ctx, client.Client) -} diff --git a/internal/services/compute/disk_export_resource_test.go b/internal/services/compute/disk_export_resource_test.go deleted file mode 100644 index 3cba7e04cf83..000000000000 --- a/internal/services/compute/disk_export_resource_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package compute_test - -import ( - "fmt" - "testing" - - "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" - "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" -) - -type DiskExportResource struct{} - -func TestAccDiskExport_basic(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_disk_export", "test") - - data.DataSourceTest(t, []acceptance.TestStep{ - { - Config: DiskExportResource{}.basic(data), - Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).Key("id").Exists(), - ), - }, - }) -} - -func (t DiskExportResource) basic(data acceptance.TestData) string { - return fmt.Sprintf(` -provider "azurerm" { - features {} -} -resource "azurerm_resource_group" "test" { - name = "acctestRG-revokedisk-%d" - location = "%s" -} -resource "azurerm_managed_disk" "test" { - name = "acctestsads%s" - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name - storage_account_type = "Standard_LRS" - create_option = "Empty" - disk_size_gb = "1" -} -resource "azurerm_disk_export" "test" { - managed_disk_id = azurerm_managed_disk.test.id - duration_in_seconds = 300 - access = "Read" -} -`, data.RandomInteger, data.Locations.Primary, data.RandomString) -} diff --git a/internal/services/compute/disk_sas_token_resource.go b/internal/services/compute/disk_sas_token_resource.go new file mode 100644 index 000000000000..a8a11837fbbc --- /dev/null +++ b/internal/services/compute/disk_sas_token_resource.go @@ -0,0 +1,163 @@ +package compute + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" +) + +func resourceDiskExport() *pluginsdk.Resource { + + return &pluginsdk.Resource{ + Create: resourceDiskExportCreate, + Read: resourceDiskExportRead, + Delete: resourceDiskExportDelete, + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(30 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Delete: pluginsdk.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*pluginsdk.Schema{ + "managed_disk_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ManagedDiskID, + }, + + "duration_in_seconds": { + Type: pluginsdk.TypeInt, + Required: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(30, 4294967295), + }, + + "access_level": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(compute.AccessLevelRead), + string(compute.AccessLevelWrite), + }, false), + }, + + "sas_url": { + Type: pluginsdk.TypeString, + Computed: true, + Sensitive: true, + }, + }, + } + +} + +func resourceDiskExportCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Compute.DisksClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + log.Printf("[INFO] preparing arguments for AzureRM Disk Export.") + durationInSeconds := int32(d.Get("duration_in_seconds").(int)) + access := compute.AccessLevel(d.Get("access_level").(string)) + + diskId, err := parse.ManagedDiskID(d.Get("managed_disk_id").(string)) + if err != nil { + return err + } + + grantAccessData := compute.GrantAccessData{ + Access: access, + DurationInSeconds: &durationInSeconds, + } + + resp, err := client.Get(ctx, diskId.ResourceGroup, diskId.DiskName) + if err != nil { + return fmt.Errorf("Error retrieving Disk %s: %+v", *diskId, err) + } + + // checking whether disk export SAS URL is active already before creating. If yes, we raise an error + if resp.DiskState == "ActiveSAS" { + return fmt.Errorf("Active SAS Token for Disk Export already exists, it should be imported %s: %+v", *diskId, err) + } + + future, err := client.GrantAccess(ctx, diskId.ResourceGroup, diskId.DiskName, grantAccessData) + if err != nil { + return fmt.Errorf("granting access to %s: %+v", *diskId, err) + } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for access to be granted to %s: %+v", *diskId, err) + } + read, err := future.Result(*client) + if err != nil { + return fmt.Errorf("retrieving SAS Token for Disk Access %s: %+v", *diskId, err) + } + if read.AccessSAS == nil { + return fmt.Errorf("retrieving SAS Token for Disk Access %s: SAS was nil", *diskId) + } + + d.SetId(diskId.ID()) + sasToken := *read.AccessSAS + d.Set("sas_url", sasToken) + + return resourceDiskExportRead(d, meta) + +} + +func resourceDiskExportRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Compute.DisksClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + diskId, err := parse.ManagedDiskID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, diskId.ResourceGroup, diskId.DiskName) + if err != nil { + // checking whether disk export SAS URL is active post creation. If no, we raise an error + if resp.DiskState != "ActiveSAS" { + log.Printf("[INFO] Disk SAS token %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("making Read request on Azure Disk Export for SAS Token %s (resource group %s): %s", diskId.DiskName, diskId.ResourceGroup, err) + } + + d.SetId(diskId.ID()) + + return nil +} + +func resourceDiskExportDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Compute.DisksClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ManagedDiskID(d.Id()) + if err != nil { + return err + } + + future, err := client.RevokeAccess(ctx, id.ResourceGroup, id.DiskName) + if err != nil { + return fmt.Errorf("revoking access to %s: %+v", *id, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for revocation of access to %s: %+v", *id, err) + } + + return nil +} diff --git a/internal/services/compute/disk_sas_token_resource_test.go b/internal/services/compute/disk_sas_token_resource_test.go new file mode 100644 index 000000000000..5fa5cf7f5d90 --- /dev/null +++ b/internal/services/compute/disk_sas_token_resource_test.go @@ -0,0 +1,73 @@ +package compute_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/compute/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type ManagedDiskSASTokenResource struct{} + +func TestAccManagedDiskSASToken_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_managed_disk_sas_token", "test") + r := ManagedDiskSASTokenResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + }) +} + +func (t ManagedDiskSASTokenResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.ManagedDiskID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.Compute.DisksClient.Get(ctx, id.ResourceGroup, id.DiskName) + if err != nil { + return nil, fmt.Errorf("retrieving Compute Disk Export status %q", id.String()) + } + + if resp.DiskState != "ActiveSAS" { + return nil, fmt.Errorf("Disk SAS token %s (resource group %s): %s", id.DiskName, id.ResourceGroup, err) + } + + return utils.Bool(resp.ID != nil), nil +} + +func (r ManagedDiskSASTokenResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +resource "azurerm_resource_group" "test" { + name = "acctestRG-revokedisk-%d" + location = "%s" +} +resource "azurerm_managed_disk" "test" { + name = "acctestsads%s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + storage_account_type = "Standard_LRS" + create_option = "Empty" + disk_size_gb = "1" +} +resource "azurerm_managed_disk_sas_token" "test" { + managed_disk_id = azurerm_managed_disk.test.id + duration_in_seconds = 300 + access_level = "Read" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} diff --git a/internal/services/compute/registration.go b/internal/services/compute/registration.go index 3e3cadff5548..b67d2ee114d5 100644 --- a/internal/services/compute/registration.go +++ b/internal/services/compute/registration.go @@ -67,7 +67,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_windows_virtual_machine": resourceWindowsVirtualMachine(), "azurerm_windows_virtual_machine_scale_set": resourceWindowsVirtualMachineScaleSet(), "azurerm_ssh_public_key": resourceSshPublicKey(), - "azurerm_disk_export": resourceDiskExport(), + "azurerm_managed_disk_sas_token": resourceDiskExport(), } return resources diff --git a/website/docs/r/disk_export.html.markdown b/website/docs/r/disk_export.html.markdown index fc4b97a9332f..beee11eb86a6 100644 --- a/website/docs/r/disk_export.html.markdown +++ b/website/docs/r/disk_export.html.markdown @@ -1,12 +1,12 @@ --- subcategory: "Compute" layout: "azurerm" -page_title: "Azure Resource Manager: azurerm_disk_export" +page_title: "Azure Resource Manager: azurerm_managed_disk_sas_token" description: |- Manages a Disk Export. --- -# azurerm_disk_export +# azurerm_managed_disk_sas_token Manages a Disk Export. @@ -31,10 +31,10 @@ resource "azurerm_managed_disk" "test" { create_option = "Empty" disk_size_gb = "1" } -resource "azurerm_disk_export" "test" { +resource "azurerm_managed_disk_sas_token" "test" { managed_disk_id = azurerm_managed_disk.test.id duration_in_seconds = 300 - access = "Read" + access_level = "Read" } ``` @@ -44,9 +44,9 @@ The following arguments are supported: * `managed_disk_id` - (Required) The ID of an existing Managed Disk which should be exported. Changing this forces a new resource to be created. -* `duration_in_seconds` - (Required) The duration for which the export should be allowed. Should be greater than 30 seconds. +* `duration_in_seconds` - (Required) The duration for which the export should be allowed. Should be between 30 & 4294967295 seconds. -* `access` - (Optional) The level of access required on the disk. Supported are Read, Write. Defaults to Read. +* `access_level` - (Required) The level of access required on the disk. Supported are Read, Write. Refer to the [SAS creation reference from Azure](https://docs.microsoft.com/en-us/rest/api/compute/disks/grant-access) for additional details on the fields above. @@ -65,5 +65,4 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/d * `create` - (Defaults to 30 minutes) Used when creating the Disk. * `read` - (Defaults to 5 minutes) Used when retrieving the Disk. -* `update` - (Defaults to 30 minutes) Used when updating the Disk. * `delete` - (Defaults to 30 minutes) Used when deleting the Disk. From 9eb76d62ccc3e50130898111f7fbf488f23b7b82 Mon Sep 17 00:00:00 2001 From: Harshavardhan Musanalli Date: Tue, 3 May 2022 11:54:32 +0200 Subject: [PATCH 7/8] Only min condition while validating duration_in_seconds & using import function as tests are failing --- internal/services/compute/disk_sas_token_resource.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/services/compute/disk_sas_token_resource.go b/internal/services/compute/disk_sas_token_resource.go index a8a11837fbbc..fe7538233b72 100644 --- a/internal/services/compute/disk_sas_token_resource.go +++ b/internal/services/compute/disk_sas_token_resource.go @@ -27,6 +27,11 @@ func resourceDiskExport() *pluginsdk.Resource { Delete: pluginsdk.DefaultTimeout(30 * time.Minute), }, + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.ManagedDiskID(id) + return err + }), + Schema: map[string]*pluginsdk.Schema{ "managed_disk_id": { Type: pluginsdk.TypeString, @@ -35,11 +40,12 @@ func resourceDiskExport() *pluginsdk.Resource { ValidateFunc: validate.ManagedDiskID, }, + // unable to provide upper value of 4294967295 as it's not comptabile with 32-bit (overflow errors) "duration_in_seconds": { Type: pluginsdk.TypeInt, Required: true, ForceNew: true, - ValidateFunc: validation.IntBetween(30, 4294967295), + ValidateFunc: validation.IntAtLeast(30), }, "access_level": { @@ -83,12 +89,12 @@ func resourceDiskExportCreate(d *pluginsdk.ResourceData, meta interface{}) error resp, err := client.Get(ctx, diskId.ResourceGroup, diskId.DiskName) if err != nil { - return fmt.Errorf("Error retrieving Disk %s: %+v", *diskId, err) + return fmt.Errorf("error retrieving Disk %s: %+v", *diskId, err) } // checking whether disk export SAS URL is active already before creating. If yes, we raise an error if resp.DiskState == "ActiveSAS" { - return fmt.Errorf("Active SAS Token for Disk Export already exists, it should be imported %s: %+v", *diskId, err) + return fmt.Errorf("active SAS Token for Disk Export already exists, cannot create another one %s: %+v", *diskId, err) } future, err := client.GrantAccess(ctx, diskId.ResourceGroup, diskId.DiskName, grantAccessData) From 192f97022a3737b58671926b38719ea8acfdf36b Mon Sep 17 00:00:00 2001 From: Harshavardhan Musanalli Date: Fri, 6 May 2022 10:49:30 +0200 Subject: [PATCH 8/8] Changes as request in PR review --- .../services/compute/disk_sas_token_resource.go | 16 ++++++++-------- .../compute/disk_sas_token_resource_test.go | 3 +++ internal/services/compute/registration.go | 2 +- ...tml.markdown => disk_sas_token.html.markdown} | 14 ++++++++++++-- 4 files changed, 24 insertions(+), 11 deletions(-) rename website/docs/r/{disk_export.html.markdown => disk_sas_token.html.markdown} (88%) diff --git a/internal/services/compute/disk_sas_token_resource.go b/internal/services/compute/disk_sas_token_resource.go index fe7538233b72..967da4ed1ed5 100644 --- a/internal/services/compute/disk_sas_token_resource.go +++ b/internal/services/compute/disk_sas_token_resource.go @@ -14,12 +14,12 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" ) -func resourceDiskExport() *pluginsdk.Resource { +func resourceManagedDiskSasToken() *pluginsdk.Resource { return &pluginsdk.Resource{ - Create: resourceDiskExportCreate, - Read: resourceDiskExportRead, - Delete: resourceDiskExportDelete, + Create: resourceManagedDiskSasTokenCreate, + Read: resourceManagedDiskSasTokenRead, + Delete: resourceManagedDiskSasTokenDelete, Timeouts: &pluginsdk.ResourceTimeout{ Create: pluginsdk.DefaultTimeout(30 * time.Minute), @@ -68,7 +68,7 @@ func resourceDiskExport() *pluginsdk.Resource { } -func resourceDiskExportCreate(d *pluginsdk.ResourceData, meta interface{}) error { +func resourceManagedDiskSasTokenCreate(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Compute.DisksClient ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -116,11 +116,11 @@ func resourceDiskExportCreate(d *pluginsdk.ResourceData, meta interface{}) error sasToken := *read.AccessSAS d.Set("sas_url", sasToken) - return resourceDiskExportRead(d, meta) + return resourceManagedDiskSasTokenRead(d, meta) } -func resourceDiskExportRead(d *pluginsdk.ResourceData, meta interface{}) error { +func resourceManagedDiskSasTokenRead(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Compute.DisksClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -146,7 +146,7 @@ func resourceDiskExportRead(d *pluginsdk.ResourceData, meta interface{}) error { return nil } -func resourceDiskExportDelete(d *pluginsdk.ResourceData, meta interface{}) error { +func resourceManagedDiskSasTokenDelete(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Compute.DisksClient ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() diff --git a/internal/services/compute/disk_sas_token_resource_test.go b/internal/services/compute/disk_sas_token_resource_test.go index 5fa5cf7f5d90..1fb5a2cbcfe9 100644 --- a/internal/services/compute/disk_sas_token_resource_test.go +++ b/internal/services/compute/disk_sas_token_resource_test.go @@ -52,10 +52,12 @@ func (r ManagedDiskSASTokenResource) basic(data acceptance.TestData) string { provider "azurerm" { features {} } + resource "azurerm_resource_group" "test" { name = "acctestRG-revokedisk-%d" location = "%s" } + resource "azurerm_managed_disk" "test" { name = "acctestsads%s" location = azurerm_resource_group.test.location @@ -64,6 +66,7 @@ resource "azurerm_managed_disk" "test" { create_option = "Empty" disk_size_gb = "1" } + resource "azurerm_managed_disk_sas_token" "test" { managed_disk_id = azurerm_managed_disk.test.id duration_in_seconds = 300 diff --git a/internal/services/compute/registration.go b/internal/services/compute/registration.go index b67d2ee114d5..32741bcef1ed 100644 --- a/internal/services/compute/registration.go +++ b/internal/services/compute/registration.go @@ -67,7 +67,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_windows_virtual_machine": resourceWindowsVirtualMachine(), "azurerm_windows_virtual_machine_scale_set": resourceWindowsVirtualMachineScaleSet(), "azurerm_ssh_public_key": resourceSshPublicKey(), - "azurerm_managed_disk_sas_token": resourceDiskExport(), + "azurerm_managed_disk_sas_token": resourceManagedDiskSasToken(), } return resources diff --git a/website/docs/r/disk_export.html.markdown b/website/docs/r/disk_sas_token.html.markdown similarity index 88% rename from website/docs/r/disk_export.html.markdown rename to website/docs/r/disk_sas_token.html.markdown index beee11eb86a6..6c005399f09f 100644 --- a/website/docs/r/disk_export.html.markdown +++ b/website/docs/r/disk_sas_token.html.markdown @@ -3,12 +3,12 @@ subcategory: "Compute" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_managed_disk_sas_token" description: |- - Manages a Disk Export. + Manages a Disk SAS Token. --- # azurerm_managed_disk_sas_token -Manages a Disk Export. +Manages a Disk SAS Token. Use this resource to obtain a Shared Access Signature (SAS Token) for an existing Managed Disk. @@ -23,6 +23,7 @@ resource "azurerm_resource_group" "test" { name = "testrg" location = "West Europe" } + resource "azurerm_managed_disk" "test" { name = "tst-disk-export" location = azurerm_resource_group.test.location @@ -31,6 +32,7 @@ resource "azurerm_managed_disk" "test" { create_option = "Empty" disk_size_gb = "1" } + resource "azurerm_managed_disk_sas_token" "test" { managed_disk_id = azurerm_managed_disk.test.id duration_in_seconds = 300 @@ -66,3 +68,11 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/d * `create` - (Defaults to 30 minutes) Used when creating the Disk. * `read` - (Defaults to 5 minutes) Used when retrieving the Disk. * `delete` - (Defaults to 30 minutes) Used when deleting the Disk. + +## Import + +Disk SAS Token can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_managed_disk_sas_token.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/microsoft.compute/disks/manageddisk1 +``` \ No newline at end of file