-
Notifications
You must be signed in to change notification settings - Fork 4.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for Azure File Share backup #5213
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
f4fb349
New resources for file share backup policies and protected items
60dc069
New resource azurerm_backup_protection_container_storage_account
2c15d5d
Add acc tests for r/backup_protected_file_share
2fd5b7f
r/backup_protected_file_share async operation handling
de16aa6
r/backup_protected_file_share remove tags property
374b4e7
r/backup_protected_file_share fix acc tests
ea7a4e1
r/backup_protection_policy_file_share remove tags
4c3b648
Update website for Azure File backup resources
f01c543
Simplify naming of file share backup policy resource
98d803d
Simplify naming backup container resource
e09381a
Run go fmt
55ac076
Apply suggestions from code review
sean-nixon 8f28d57
File backup misc cleanup from review
f11714f
Update resource_arm_backup_protected_file_share_test.go
katbyte 536d088
Update resource_arm_backup_policy_file_share_test.go
katbyte 70643aa
Update resource_arm_backup_policy_file_share_test.go
katbyte 1bc9405
Update resource_arm_backup_policy_file_share_test.go
katbyte 4a075e1
Merge branch 'master' into azure-file-backup
katbyte File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
250 changes: 250 additions & 0 deletions
250
azurerm/resource_arm_backup_container_storage_account.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
package azurerm | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"github.com/Azure/azure-sdk-for-go/services/recoveryservices/mgmt/2017-07-01/backup" | ||
"github.com/hashicorp/terraform-plugin-sdk/helper/resource" | ||
"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/tf" | ||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" | ||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" | ||
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" | ||
) | ||
|
||
func resourceArmBackupProtectionContainerStorageAccount() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceArmBackupProtectionContainerStorageAccountCreate, | ||
Read: resourceArmBackupProtectionContainerStorageAccountRead, | ||
Update: nil, | ||
Delete: resourceArmBackupProtectionContainerStorageAccountDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
|
||
Timeouts: &schema.ResourceTimeout{ | ||
Create: schema.DefaultTimeout(30 * time.Minute), | ||
Read: schema.DefaultTimeout(5 * time.Minute), | ||
Update: schema.DefaultTimeout(30 * time.Minute), | ||
Delete: schema.DefaultTimeout(30 * time.Minute), | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"resource_group_name": azure.SchemaResourceGroupName(), | ||
|
||
"recovery_vault_name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: azure.ValidateRecoveryServicesVaultName, | ||
}, | ||
"storage_account_id": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: azure.ValidateResourceID, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceArmBackupProtectionContainerStorageAccountCreate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*ArmClient).RecoveryServices.BackupProtectionContainersClient | ||
opStatusClient := meta.(*ArmClient).RecoveryServices.BackupOperationStatusesClient | ||
ctx, cancel := timeouts.ForRead(meta.(*ArmClient).StopContext, d) | ||
defer cancel() | ||
|
||
resGroup := d.Get("resource_group_name").(string) | ||
vaultName := d.Get("recovery_vault_name").(string) | ||
storageAccountID := d.Get("storage_account_id").(string) | ||
|
||
parsedStorageAccountID, err := azure.ParseAzureResourceID(storageAccountID) | ||
if err != nil { | ||
return fmt.Errorf("[ERROR] Unable to parse storage_account_id '%s': %+v", storageAccountID, err) | ||
} | ||
accountName, hasName := parsedStorageAccountID.Path["storageAccounts"] | ||
if !hasName { | ||
return fmt.Errorf("[ERROR] parsed storage_account_id '%s' doesn't contain 'storageAccounts'", storageAccountID) | ||
} | ||
|
||
containerName := fmt.Sprintf("StorageContainer;storage;%s;%s", parsedStorageAccountID.ResourceGroup, accountName) | ||
|
||
if features.ShouldResourcesBeImported() && d.IsNewResource() { | ||
existing, err := client.Get(ctx, vaultName, resGroup, "Azure", containerName) | ||
if err != nil { | ||
if !utils.ResponseWasNotFound(existing.Response) { | ||
return fmt.Errorf("Error checking for presence of existing recovery services protection container %s (Vault %s): %+v", containerName, vaultName, err) | ||
} | ||
} | ||
|
||
if existing.ID != nil && *existing.ID != "" { | ||
return tf.ImportAsExistsError("azurerm_backup_protection_container_storage", azure.HandleAzureSdkForGoBug2824(*existing.ID)) | ||
} | ||
} | ||
|
||
parameters := backup.ProtectionContainerResource{ | ||
Properties: &backup.AzureStorageContainer{ | ||
SourceResourceID: &storageAccountID, | ||
FriendlyName: &accountName, | ||
BackupManagementType: backup.ManagementTypeAzureStorage, | ||
ContainerType: backup.ContainerTypeStorageContainer1, | ||
}, | ||
} | ||
|
||
resp, err := client.Register(ctx, vaultName, resGroup, "Azure", containerName, parameters) | ||
if err != nil { | ||
return fmt.Errorf("Error registering backup protection container %s (Vault %s): %+v", containerName, vaultName, err) | ||
} | ||
|
||
locationURL, err := resp.Response.Location() // Operation ID found in the Location header | ||
if locationURL == nil || err != nil { | ||
return fmt.Errorf("Unable to determine operation URL for protection container registration status for %s. (Vault %s): Location header missing or empty", containerName, vaultName) | ||
} | ||
|
||
opResourceID := azure.HandleAzureSdkForGoBug2824(locationURL.Path) | ||
|
||
parsedLocation, err := azure.ParseAzureResourceID(opResourceID) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
operationID := parsedLocation.Path["operationResults"] | ||
if _, err = resourceArmBackupProtectionContainerStorageAccountWaitForOperation(ctx, opStatusClient, vaultName, resGroup, operationID, d); err != nil { | ||
return err | ||
} | ||
|
||
resp, err = client.Get(ctx, vaultName, resGroup, "Azure", containerName) | ||
if err != nil { | ||
return fmt.Errorf("Error retrieving site recovery protection container %s (Vault %s): %+v", containerName, vaultName, err) | ||
} | ||
|
||
d.SetId(azure.HandleAzureSdkForGoBug2824(*resp.ID)) | ||
|
||
return resourceArmBackupProtectionContainerStorageAccountRead(d, meta) | ||
} | ||
|
||
func resourceArmBackupProtectionContainerStorageAccountRead(d *schema.ResourceData, meta interface{}) error { | ||
id, err := azure.ParseAzureResourceID(d.Id()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
resGroup := id.ResourceGroup | ||
vaultName := id.Path["vaults"] | ||
fabricName := id.Path["backupFabrics"] | ||
containerName := id.Path["protectionContainers"] | ||
|
||
client := meta.(*ArmClient).RecoveryServices.BackupProtectionContainersClient | ||
ctx, cancel := timeouts.ForRead(meta.(*ArmClient).StopContext, d) | ||
defer cancel() | ||
|
||
resp, err := client.Get(ctx, vaultName, resGroup, fabricName, containerName) | ||
if err != nil { | ||
if utils.ResponseWasNotFound(resp.Response) { | ||
d.SetId("") | ||
return nil | ||
} | ||
return fmt.Errorf("Error making Read request on backup protection container %s (Vault %s): %+v", containerName, vaultName, err) | ||
} | ||
|
||
d.Set("resource_group_name", resGroup) | ||
d.Set("recovery_vault_name", vaultName) | ||
|
||
if properties, ok := resp.Properties.AsAzureStorageContainer(); ok && properties != nil { | ||
d.Set("storage_account_id", properties.SourceResourceID) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceArmBackupProtectionContainerStorageAccountDelete(d *schema.ResourceData, meta interface{}) error { | ||
id, err := azure.ParseAzureResourceID(d.Id()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
resGroup := id.ResourceGroup | ||
vaultName := id.Path["vaults"] | ||
fabricName := id.Path["backupFabrics"] | ||
containerName := id.Path["protectionContainers"] | ||
|
||
client := meta.(*ArmClient).RecoveryServices.BackupProtectionContainersClient | ||
opClient := meta.(*ArmClient).RecoveryServices.BackupOperationStatusesClient | ||
ctx, cancel := timeouts.ForDelete(meta.(*ArmClient).StopContext, d) | ||
defer cancel() | ||
|
||
resp, err := client.Unregister(ctx, vaultName, resGroup, fabricName, containerName) | ||
if err != nil { | ||
return fmt.Errorf("Error deregistering backup protection container %s (Vault %s): %+v", containerName, vaultName, err) | ||
} | ||
|
||
locationURL, err := resp.Response.Location() | ||
if err != nil || locationURL == nil { | ||
return fmt.Errorf("Error unregistering backup protection container %s (Vault %s): Location header missing or empty", containerName, vaultName) | ||
} | ||
|
||
opResourceID := azure.HandleAzureSdkForGoBug2824(locationURL.Path) | ||
|
||
parsedLocation, err := azure.ParseAzureResourceID(opResourceID) | ||
if err != nil { | ||
return err | ||
} | ||
operationID := parsedLocation.Path["backupOperationResults"] | ||
|
||
if _, err = resourceArmBackupProtectionContainerStorageAccountWaitForOperation(ctx, opClient, vaultName, resGroup, operationID, d); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceArmBackupProtectionContainerStorageAccountWaitForOperation(ctx context.Context, client *backup.OperationStatusesClient, vaultName, resourceGroup, operationID string, d *schema.ResourceData) (backup.OperationStatus, error) { | ||
state := &resource.StateChangeConf{ | ||
MinTimeout: 10 * time.Second, | ||
Delay: 10 * time.Second, | ||
Pending: []string{"InProgress"}, | ||
Target: []string{"Succeeded"}, | ||
Refresh: resourceArmBackupProtectionContainerStorageAccountCheckOperation(ctx, client, vaultName, resourceGroup, operationID), | ||
ContinuousTargetOccurence: 5, // Without this buffer, file share backups and storage account deletions may fail if performed immediately after creating/destroying the container | ||
} | ||
|
||
if features.SupportsCustomTimeouts() { | ||
if d.IsNewResource() { | ||
state.Timeout = d.Timeout(schema.TimeoutCreate) | ||
} else { | ||
state.Timeout = d.Timeout(schema.TimeoutUpdate) | ||
} | ||
} else { | ||
state.Timeout = 30 * time.Minute | ||
} | ||
|
||
log.Printf("[DEBUG] Waiting for backup container operation %q (Vault %q) to complete", operationID, vaultName) | ||
resp, err := state.WaitForState() | ||
if err != nil { | ||
return resp.(backup.OperationStatus), err | ||
} | ||
return resp.(backup.OperationStatus), nil | ||
} | ||
|
||
func resourceArmBackupProtectionContainerStorageAccountCheckOperation(ctx context.Context, client *backup.OperationStatusesClient, vaultName, resourceGroup, operationID string) resource.StateRefreshFunc { | ||
return func() (interface{}, string, error) { | ||
resp, err := client.Get(ctx, vaultName, resourceGroup, operationID) | ||
if err != nil { | ||
return resp, "Error", fmt.Errorf("Error making Read request on Recovery Service Protection Container operation %q (Vault %q in Resource Group %q): %+v", operationID, vaultName, resourceGroup, err) | ||
} | ||
|
||
if opErr := resp.Error; opErr != nil { | ||
errMsg := "No upstream error message" | ||
if opErr.Message != nil { | ||
errMsg = *opErr.Message | ||
} | ||
err = fmt.Errorf("Recovery Service Protection Container operation status failed with status %q (Vault %q Resource Group %q Operation ID %q): %+v", resp.Status, vaultName, resourceGroup, operationID, errMsg) | ||
} | ||
|
||
return resp, string(resp.Status), err | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the
HandleAzureSdkForGoBug2824
isn't required anymore (the service team claims its been fixed Azure/azure-sdk-for-go#2824 (comment))