Skip to content
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

Site Recovery - swap sdk and upgrade to 2022-10-01, support network_interface.is_primary property #19571

Merged
merged 12 commits into from
Jan 9, 2023
Merged
  •  
  •  
  •  
79 changes: 36 additions & 43 deletions internal/services/recoveryservices/client/client.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package client

import (
"github.com/Azure/azure-sdk-for-go/services/recoveryservices/mgmt/2018-07-10/siterecovery" // nolint: staticcheck
"github.com/Azure/azure-sdk-for-go/services/recoveryservices/mgmt/2021-08-01/recoveryservices" // nolint: staticcheck
"github.com/Azure/azure-sdk-for-go/services/recoveryservices/mgmt/2021-12-01/backup" // nolint: staticcheck
"github.com/hashicorp/go-azure-sdk/resource-manager/recoveryservicessiterecovery/2022-10-01/replicationfabrics"
"github.com/hashicorp/go-azure-sdk/resource-manager/recoveryservicessiterecovery/2022-10-01/replicationnetworkmappings"
"github.com/hashicorp/go-azure-sdk/resource-manager/recoveryservicessiterecovery/2022-10-01/replicationpolicies"
"github.com/hashicorp/go-azure-sdk/resource-manager/recoveryservicessiterecovery/2022-10-01/replicationprotecteditems"
"github.com/hashicorp/go-azure-sdk/resource-manager/recoveryservicessiterecovery/2022-10-01/replicationprotectioncontainermappings"
"github.com/hashicorp/go-azure-sdk/resource-manager/recoveryservicessiterecovery/2022-10-01/replicationprotectioncontainers"
"github.com/hashicorp/go-azure-sdk/resource-manager/recoveryservicessiterecovery/2022-10-01/replicationrecoveryplans"
"github.com/hashicorp/terraform-provider-azurerm/internal/common"
)

Expand All @@ -18,12 +24,13 @@ type Client struct {
VaultsClient *recoveryservices.VaultsClient
VaultsConfigsClient *backup.ResourceVaultConfigsClient // Not sure why this is in backup, but https://github.com/Azure/azure-sdk-for-go/issues/7279
StorageConfigsClient *backup.ResourceStorageConfigsNonCRRClient
FabricClient func(resourceGroupName string, vaultName string) siterecovery.ReplicationFabricsClient
ProtectionContainerClient func(resourceGroupName string, vaultName string) siterecovery.ReplicationProtectionContainersClient
ReplicationPoliciesClient func(resourceGroupName string, vaultName string) siterecovery.ReplicationPoliciesClient
ContainerMappingClient func(resourceGroupName string, vaultName string) siterecovery.ReplicationProtectionContainerMappingsClient
NetworkMappingClient func(resourceGroupName string, vaultName string) siterecovery.ReplicationNetworkMappingsClient
ReplicationMigrationItemsClient func(resourceGroupName string, vaultName string) siterecovery.ReplicationProtectedItemsClient
FabricClient *replicationfabrics.ReplicationFabricsClient
ProtectionContainerClient *replicationprotectioncontainers.ReplicationProtectionContainersClient
ReplicationPoliciesClient *replicationpolicies.ReplicationPoliciesClient
ContainerMappingClient *replicationprotectioncontainermappings.ReplicationProtectionContainerMappingsClient
NetworkMappingClient *replicationnetworkmappings.ReplicationNetworkMappingsClient
ReplicationProtectedItemsClient *replicationprotecteditems.ReplicationProtectedItemsClient
ReplicationRecoveryPlansClient *replicationrecoveryplans.ReplicationRecoveryPlansClient
}

func NewClient(o *common.ClientOptions) *Client {
Expand Down Expand Up @@ -57,41 +64,26 @@ func NewClient(o *common.ClientOptions) *Client {
backupProtectionContainerOperationResultsClient := backup.NewProtectionContainerOperationResultsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&backupProtectionContainerOperationResultsClient.Client, o.ResourceManagerAuthorizer)

fabricClient := func(resourceGroupName string, vaultName string) siterecovery.ReplicationFabricsClient {
client := siterecovery.NewReplicationFabricsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId, resourceGroupName, vaultName)
o.ConfigureClient(&client.Client, o.ResourceManagerAuthorizer)
return client
}
fabricClient := replicationfabrics.NewReplicationFabricsClientWithBaseURI(o.ResourceManagerEndpoint)
o.ConfigureClient(&fabricClient.Client, o.ResourceManagerAuthorizer)

protectionContainerClient := func(resourceGroupName string, vaultName string) siterecovery.ReplicationProtectionContainersClient {
client := siterecovery.NewReplicationProtectionContainersClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId, resourceGroupName, vaultName)
o.ConfigureClient(&client.Client, o.ResourceManagerAuthorizer)
return client
}
protectionContainerClient := replicationprotectioncontainers.NewReplicationProtectionContainersClientWithBaseURI(o.ResourceManagerEndpoint)
o.ConfigureClient(&protectionContainerClient.Client, o.ResourceManagerAuthorizer)

replicationPoliciesClient := func(resourceGroupName string, vaultName string) siterecovery.ReplicationPoliciesClient {
client := siterecovery.NewReplicationPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId, resourceGroupName, vaultName)
o.ConfigureClient(&client.Client, o.ResourceManagerAuthorizer)
return client
}
replicationPoliciesClient := replicationpolicies.NewReplicationPoliciesClientWithBaseURI(o.ResourceManagerEndpoint)
o.ConfigureClient(&replicationPoliciesClient.Client, o.ResourceManagerAuthorizer)

containerMappingClient := func(resourceGroupName string, vaultName string) siterecovery.ReplicationProtectionContainerMappingsClient {
client := siterecovery.NewReplicationProtectionContainerMappingsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId, resourceGroupName, vaultName)
o.ConfigureClient(&client.Client, o.ResourceManagerAuthorizer)
return client
}
containerMappingClient := replicationprotectioncontainermappings.NewReplicationProtectionContainerMappingsClientWithBaseURI(o.ResourceManagerEndpoint)
o.ConfigureClient(&containerMappingClient.Client, o.ResourceManagerAuthorizer)

networkMappingClient := func(resourceGroupName string, vaultName string) siterecovery.ReplicationNetworkMappingsClient {
client := siterecovery.NewReplicationNetworkMappingsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId, resourceGroupName, vaultName)
o.ConfigureClient(&client.Client, o.ResourceManagerAuthorizer)
return client
}
networkMappingClient := replicationnetworkmappings.NewReplicationNetworkMappingsClientWithBaseURI(o.ResourceManagerEndpoint)
o.ConfigureClient(&networkMappingClient.Client, o.ResourceManagerAuthorizer)

replicationMigrationItemsClient := func(resourceGroupName string, vaultName string) siterecovery.ReplicationProtectedItemsClient {
client := siterecovery.NewReplicationProtectedItemsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId, resourceGroupName, vaultName)
o.ConfigureClient(&client.Client, o.ResourceManagerAuthorizer)
return client
}
replicationMigrationItemsClient := replicationprotecteditems.NewReplicationProtectedItemsClientWithBaseURI(o.ResourceManagerEndpoint)
o.ConfigureClient(&replicationMigrationItemsClient.Client, o.ResourceManagerAuthorizer)

replicationRecoveryPlanClient := replicationrecoveryplans.NewReplicationRecoveryPlansClientWithBaseURI(o.ResourceManagerEndpoint)
o.ConfigureClient(&replicationRecoveryPlanClient.Client, o.ResourceManagerAuthorizer)

return &Client{
ProtectableItemsClient: &protectableItemsClient,
Expand All @@ -104,11 +96,12 @@ func NewClient(o *common.ClientOptions) *Client {
VaultsClient: &vaultsClient,
VaultsConfigsClient: &vaultConfigsClient,
StorageConfigsClient: &storageConfigsClient,
FabricClient: fabricClient,
ProtectionContainerClient: protectionContainerClient,
ReplicationPoliciesClient: replicationPoliciesClient,
ContainerMappingClient: containerMappingClient,
NetworkMappingClient: networkMappingClient,
ReplicationMigrationItemsClient: replicationMigrationItemsClient,
FabricClient: &fabricClient,
ProtectionContainerClient: &protectionContainerClient,
ReplicationPoliciesClient: &replicationPoliciesClient,
ContainerMappingClient: &containerMappingClient,
NetworkMappingClient: &networkMappingClient,
ReplicationProtectedItemsClient: &replicationMigrationItemsClient,
ReplicationRecoveryPlansClient: &replicationRecoveryPlanClient,
}
}
28 changes: 28 additions & 0 deletions internal/services/recoveryservices/helpers.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
package recoveryservices

import (
"net/http"
"strings"

"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/hashicorp/go-azure-helpers/lang/response"
)

// This code is a workaround for this bug https://github.com/Azure/azure-sdk-for-go/issues/2824
func handleAzureSdkForGoBug2824(id string) string {
return strings.Replace(id, "/Subscriptions/", "/subscriptions/", 1)
}

func wasBadRequestWithNotExist(resp *http.Response, err error) bool {
e, ok := err.(autorest.DetailedError)
if !ok {
return false
}

r, ok := e.Original.(*azure.RequestError)
if !ok {
return false
}

if r.ServiceError == nil || len(r.ServiceError.Details) == 0 {
return false
}

sc, ok := r.ServiceError.Details[0]["code"]
if !ok {
return false
}

return response.WasBadRequest(resp) && sc == "SubscriptionIdNotRegisteredWithSrs"
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import (
"fmt"
"time"

"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/go-azure-helpers/resourcemanager/location"
"github.com/hashicorp/go-azure-sdk/resource-manager/recoveryservicessiterecovery/2022-10-01/replicationfabrics"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/recoveryservices/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/recoveryservices/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"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

func dataSourceSiteRecoveryFabric() *pluginsdk.Resource {
Expand Down Expand Up @@ -43,30 +43,33 @@ func dataSourceSiteRecoveryFabric() *pluginsdk.Resource {

func dataSourceSiteRecoveryFabricRead(d *pluginsdk.ResourceData, meta interface{}) error {
subscriptionId := meta.(*clients.Client).Account.SubscriptionId
id := parse.NewReplicationFabricID(subscriptionId, d.Get("resource_group_name").(string), d.Get("recovery_vault_name").(string), d.Get("name").(string))
id := replicationfabrics.NewReplicationFabricID(subscriptionId, d.Get("resource_group_name").(string), d.Get("recovery_vault_name").(string), d.Get("name").(string))

client := meta.(*clients.Client).RecoveryServices.FabricClient(id.ResourceGroup, id.VaultName)
client := meta.(*clients.Client).RecoveryServices.FabricClient
ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d)
defer cancel()

resp, err := client.Get(ctx, id.Name)
resp, err := client.Get(ctx, id, replicationfabrics.DefaultGetOperationOptions())
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
if response.WasNotFound(resp.HttpResponse) {
return fmt.Errorf("%s was not found", id)
}
return fmt.Errorf("making read request on site recovery fabric %s: %+v", id.String(), err)
}

model := resp.Model
if model == nil {
return fmt.Errorf("making read request on site recovery fabric %s: model is nil", id.String())
}

d.SetId(id.ID())
d.Set("name", id.Name)
d.Set("resource_group_name", id.ResourceGroup)
d.Set("recovery_vault_name", id.VaultName)
d.Set("name", id.FabricName)
d.Set("resource_group_name", id.ResourceGroupName)
d.Set("recovery_vault_name", id.ResourceName)

normalizedLocation := ""
if props := resp.Properties; props != nil {
if azureDetails, isAzureDetails := props.CustomDetails.AsAzureFabricSpecificDetails(); isAzureDetails {
normalizedLocation = location.NormalizeNilable(azureDetails.Location)
}
if l := model.Location; l != nil {
normalizedLocation = location.NormalizeNilable(l)
}
d.Set("location", normalizedLocation)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"fmt"
"time"

"github.com/Azure/azure-sdk-for-go/services/recoveryservices/mgmt/2018-07-10/siterecovery" // nolint: staticcheck
"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/go-azure-helpers/resourcemanager/location"
"github.com/hashicorp/go-azure-sdk/resource-manager/recoveryservicessiterecovery/2022-10-01/replicationfabrics"
"github.com/hashicorp/terraform-provider-azurerm/helpers/azure"
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
Expand All @@ -14,7 +16,6 @@ import (
"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"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

func resourceSiteRecoveryFabric() *pluginsdk.Resource {
Expand Down Expand Up @@ -56,105 +57,99 @@ func resourceSiteRecoveryFabric() *pluginsdk.Resource {
}

func resourceSiteRecoveryFabricCreate(d *pluginsdk.ResourceData, meta interface{}) error {
subscriptionId := meta.(*clients.Client).Account.SubscriptionId
resGroup := d.Get("resource_group_name").(string)
vaultName := d.Get("recovery_vault_name").(string)
location := azure.NormalizeLocation(d.Get("location").(string))
name := d.Get("name").(string)

client := meta.(*clients.Client).RecoveryServices.FabricClient(resGroup, vaultName)
client := meta.(*clients.Client).RecoveryServices.FabricClient
ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d)
defer cancel()

id := replicationfabrics.NewReplicationFabricID(subscriptionId, resGroup, vaultName, name)

if d.IsNewResource() {
existing, err := client.Get(ctx, name)
existing, err := client.Get(ctx, id, replicationfabrics.DefaultGetOperationOptions())
if err != nil {
// NOTE: Bad Request due to https://github.com/Azure/azure-rest-api-specs/issues/12759
if !utils.ResponseWasNotFound(existing.Response) && !utils.ResponseWasBadRequestWithServiceCode(existing.Response, err, "SubscriptionIdNotRegisteredWithSrs") {
if !response.WasNotFound(existing.HttpResponse) && !wasBadRequestWithNotExist(existing.HttpResponse, err) {
return fmt.Errorf("checking for presence of existing site recovery fabric %s (vault %s): %+v", name, vaultName, err)
}
}

if existing.ID != nil && *existing.ID != "" {
return tf.ImportAsExistsError("azurerm_site_recovery_fabric", handleAzureSdkForGoBug2824(*existing.ID))
if model := existing.Model; model != nil && model.Id != nil && *model.Id != "" {
return tf.ImportAsExistsError("azurerm_site_recovery_fabric", handleAzureSdkForGoBug2824(*model.Id))
}
}

parameters := siterecovery.FabricCreationInput{
Properties: &siterecovery.FabricCreationInputProperties{
CustomDetails: siterecovery.AzureFabricCreationInput{
InstanceType: "Azure",
Location: &location,
parameters := replicationfabrics.FabricCreationInput{
Properties: &replicationfabrics.FabricCreationInputProperties{
CustomDetails: replicationfabrics.AzureFabricCreationInput{
Location: &location,
},
},
}

future, err := client.Create(ctx, name, parameters)
err := client.CreateThenPoll(ctx, id, parameters)
if err != nil {
return fmt.Errorf("creating site recovery fabric %s (vault %s): %+v", name, vaultName, err)
}
if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("creating site recovery fabric %s (vault %s): %+v", name, vaultName, err)
}

resp, err := client.Get(ctx, name)
if err != nil {
return fmt.Errorf("retrieving site recovery fabric %s (vault %s): %+v", name, vaultName, err)
}

d.SetId(handleAzureSdkForGoBug2824(*resp.ID))
d.SetId(id.ID())

return resourceSiteRecoveryFabricRead(d, meta)
}

func resourceSiteRecoveryFabricRead(d *pluginsdk.ResourceData, meta interface{}) error {
id, err := parse.ReplicationFabricID(d.Id())
id, err := replicationfabrics.ParseReplicationFabricID(d.Id())
if err != nil {
return err
}

fabricClient := meta.(*clients.Client).RecoveryServices.FabricClient(id.ResourceGroup, id.VaultName)
fabricClient := meta.(*clients.Client).RecoveryServices.FabricClient
client := fabricClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

resp, err := client.Get(ctx, id.Name)
resp, err := client.Get(ctx, *id, replicationfabrics.DefaultGetOperationOptions())
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
if response.WasNotFound(resp.HttpResponse) {
d.SetId("")
return nil
}
return fmt.Errorf("making read request on site recovery fabric %s: %+v", id.String(), err)
}

d.Set("name", resp.Name)
d.Set("resource_group_name", id.ResourceGroup)
if props := resp.Properties; props != nil {
if azureDetails, isAzureDetails := props.CustomDetails.AsAzureFabricSpecificDetails(); isAzureDetails {
d.Set("location", azureDetails.Location)
}
model := resp.Model
if model == nil {
return fmt.Errorf("making read request on site recovery fabric %s: model is nil", id.String())
}

d.Set("name", model.Name)
d.Set("resource_group_name", id.ResourceGroupName)
if model.Properties.CustomDetails != nil {
loc := *model.Properties.CustomDetails.(replicationfabrics.AzureFabricSpecificDetails).Location
d.Set("location", location.Normalize(loc))
}
d.Set("recovery_vault_name", id.VaultName)
d.Set("recovery_vault_name", id.ResourceName)
return nil
}

func resourceSiteRecoveryFabricDelete(d *pluginsdk.ResourceData, meta interface{}) error {
id, err := parse.ReplicationFabricID(d.Id())
id, err := replicationfabrics.ParseReplicationFabricID(d.Id())
if err != nil {
return err
}

client := meta.(*clients.Client).RecoveryServices.FabricClient(id.ResourceGroup, id.VaultName)
client := meta.(*clients.Client).RecoveryServices.FabricClient
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

future, err := client.Delete(ctx, id.Name)
err = client.DeleteThenPoll(ctx, *id)
if err != nil {
return fmt.Errorf("deleting site recovery fabric %s : %+v", id.String(), err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("waiting for deletion of site recovery fabric %s : %+v", id.String(), err)
}

return nil
}
Loading