diff --git a/internal/services/desktopvirtualization/parse/scaling_plan_host_pool_association.go b/internal/services/desktopvirtualization/parse/scaling_plan_host_pool_association.go new file mode 100644 index 0000000000000..32bcd17269760 --- /dev/null +++ b/internal/services/desktopvirtualization/parse/scaling_plan_host_pool_association.go @@ -0,0 +1,84 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package parse + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" + "github.com/hashicorp/go-azure-sdk/resource-manager/desktopvirtualization/2022-02-10-preview/scalingplan" +) + +var _ resourceids.Id = ScalingPlanHostPoolAssociationId{} + +type ScalingPlanHostPoolAssociationId struct { + ScalingPlan scalingplan.ScalingPlanId + HostPool scalingplan.HostPoolId +} + +func (id ScalingPlanHostPoolAssociationId) String() string { + components := []string{ + fmt.Sprintf("Scaling Plan %s", id.ScalingPlan.String()), + fmt.Sprintf("Host Pool %s", id.HostPool.String()), + } + return fmt.Sprintf("Scaling Plan Host Pool Association %s", strings.Join(components, " / ")) +} + +func (id ScalingPlanHostPoolAssociationId) ID() string { + scalingplanId := id.ScalingPlan.ID() + hostPoolId := id.HostPool.ID() + return fmt.Sprintf("%s|%s", scalingplanId, hostPoolId) +} + +func NewScalingPlanHostPoolAssociationId(scalingplan scalingplan.ScalingPlanId, hostPool scalingplan.HostPoolId) ScalingPlanHostPoolAssociationId { + return ScalingPlanHostPoolAssociationId{ + ScalingPlan: scalingplan, + HostPool: hostPool, + } +} + +func ScalingPlanHostPoolAssociationID(input string) (*ScalingPlanHostPoolAssociationId, error) { + segments := strings.Split(input, "|") + if len(segments) != 2 { + return nil, fmt.Errorf("expected an ID in the format {scalingplanID}|{hostPoolID} but got %q", input) + } + + scalingplanId, err := scalingplan.ParseScalingPlanID(segments[0]) + if err != nil { + return nil, fmt.Errorf("parsing Scaling Plan ID for Scaling Plan/Host Pool Association %q: %+v", segments[0], err) + } + + hostPoolId, err := scalingplan.ParseHostPoolID(segments[1]) + if err != nil { + return nil, fmt.Errorf("parsing Host Pool ID for Scaling Plan/Host Pool Association %q: %+v", segments[1], err) + } + + return &ScalingPlanHostPoolAssociationId{ + ScalingPlan: *scalingplanId, + HostPool: *hostPoolId, + }, nil +} + +func ScalingPlanHostPoolAssociationIDInsensitively(input string) (*ScalingPlanHostPoolAssociationId, error) { + segments := strings.Split(input, "|") + if len(segments) != 2 { + return nil, fmt.Errorf("expected an ID in the format {scalingplanID}|{hostPoolID} but got %q", input) + } + + scalingplanId, err := scalingplan.ParseScalingPlanIDInsensitively(segments[0]) + if err != nil { + return nil, fmt.Errorf("parsing Scaling Plan ID for Scaling Plan/Host Pool Association %q: %+v", segments[0], err) + } + + hostPoolId, err := scalingplan.ParseHostPoolIDInsensitively(segments[1]) + if err != nil { + return nil, fmt.Errorf("parsing Host Pool ID for Scaling Plan/Host Pool Association %q: %+v", segments[1], err) + } + + return &ScalingPlanHostPoolAssociationId{ + ScalingPlan: *scalingplanId, + HostPool: *hostPoolId, + }, nil +} diff --git a/internal/services/desktopvirtualization/registration.go b/internal/services/desktopvirtualization/registration.go index 5562374d35b8f..abe5ba37fdb6c 100644 --- a/internal/services/desktopvirtualization/registration.go +++ b/internal/services/desktopvirtualization/registration.go @@ -57,6 +57,7 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_virtual_desktop_application_group": resourceVirtualDesktopApplicationGroup(), "azurerm_virtual_desktop_application": resourceVirtualDesktopApplication(), "azurerm_virtual_desktop_workspace_application_group_association": resourceVirtualDesktopWorkspaceApplicationGroupAssociation(), + "azurerm_virtual_desktop_scaling_plan_host_pool_association": resourceVirtualDesktopScalingPlanHostPoolAssociation(), "azurerm_virtual_desktop_host_pool_registration_info": resourceVirtualDesktopHostPoolRegistrationInfo(), } } diff --git a/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_host_pool_association_resource.go b/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_host_pool_association_resource.go new file mode 100644 index 0000000000000..f9e98a56f8868 --- /dev/null +++ b/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_host_pool_association_resource.go @@ -0,0 +1,305 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package desktopvirtualization + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-sdk/resource-manager/desktopvirtualization/2022-02-10-preview/scalingplan" + "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/desktopvirtualization/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +func resourceVirtualDesktopScalingPlanHostPoolAssociation() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Create: resourceVirtualDesktopScalingPlanHostPoolAssociationCreate, + Read: resourceVirtualDesktopScalingPlanHostPoolAssociationRead, + Update: resourceVirtualDesktopScalingPlanHostPoolAssociationUpdate, + Delete: resourceVirtualDesktopScalingPlanHostPoolAssociationDelete, + + Timeouts: &pluginsdk.ResourceTimeout{ + Create: pluginsdk.DefaultTimeout(60 * time.Minute), + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + Update: pluginsdk.DefaultTimeout(60 * time.Minute), + Delete: pluginsdk.DefaultTimeout(60 * time.Minute), + }, + + Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { + _, err := parse.ScalingPlanHostPoolAssociationID(id) + return err + }), + + Schema: map[string]*pluginsdk.Schema{ + "scaling_plan_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: scalingplan.ValidateScalingPlanID, + }, + + "host_pool_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: scalingplan.ValidateHostPoolID, + }, + + "enabled": { + Type: pluginsdk.TypeBool, + Required: true, + }, + }, + } +} + +func resourceVirtualDesktopScalingPlanHostPoolAssociationCreate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).DesktopVirtualization.ScalingPlansClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + log.Printf("[INFO] preparing arguments for Virtual Desktop Scaling Plan <-> Host Pool Association creation.") + scalingPlanId, err := scalingplan.ParseScalingPlanID(d.Get("scaling_plan_id").(string)) + if err != nil { + return err + } + hostPoolId, err := scalingplan.ParseHostPoolID(d.Get("host_pool_id").(string)) + if err != nil { + return err + } + associationId := parse.NewScalingPlanHostPoolAssociationId(*scalingPlanId, *hostPoolId).ID() + + locks.ByName(scalingPlanId.ScalingPlanName, scalingPlanResourceType) + defer locks.UnlockByName(scalingPlanId.ScalingPlanName, scalingPlanResourceType) + + locks.ByName(hostPoolId.HostPoolName, hostPoolResourceType) + defer locks.UnlockByName(hostPoolId.HostPoolName, hostPoolResourceType) + + existing, err := client.Get(ctx, *scalingPlanId) + if err != nil { + if response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("%s was not found", *scalingPlanId) + } + + return fmt.Errorf("retrieving %s: %+v", *scalingPlanId, err) + } + if existing.Model == nil { + return fmt.Errorf("retrieving %s: model was nil", *scalingPlanId) + } + model := *existing.Model + + hostPoolAssociations := []scalingplan.ScalingHostPoolReference{} + if props := model.Properties; props != nil && props.HostPoolReferences != nil { + hostPoolAssociations = *props.HostPoolReferences + } + + hostPoolStr := hostPoolId.ID() + if scalingPlanHostPoolAssociationExists(model.Properties, hostPoolStr) { + return tf.ImportAsExistsError("azurerm_virtual_desktop_scaling_plan_host_pool_association", associationId) + } + hostPoolAssociations = append(hostPoolAssociations, scalingplan.ScalingHostPoolReference{ + HostPoolArmPath: &hostPoolStr, + ScalingPlanEnabled: utils.Bool(d.Get("enabled").(bool)), + }) + + payload := scalingplan.ScalingPlanPatch{ + Properties: &scalingplan.ScalingPlanPatchProperties{ + HostPoolReferences: &hostPoolAssociations, + }, + Tags: model.Tags, + } + if _, err = client.Update(ctx, *scalingPlanId, payload); err != nil { + return fmt.Errorf("creating association between %s and %s: %+v", *scalingPlanId, *hostPoolId, err) + } + + d.SetId(associationId) + return resourceVirtualDesktopScalingPlanHostPoolAssociationRead(d, meta) +} + +func resourceVirtualDesktopScalingPlanHostPoolAssociationRead(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).DesktopVirtualization.ScalingPlansClient + + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ScalingPlanHostPoolAssociationID(d.Id()) + if err != nil { + return err + } + + scalingPlan, err := client.Get(ctx, id.ScalingPlan) + if err != nil { + if response.WasNotFound(scalingPlan.HttpResponse) { + log.Printf("[DEBUG] %s was not found - removing from state!", id.ScalingPlan) + d.SetId("") + return nil + } + + return fmt.Errorf("retrieving %s: %+v", id.ScalingPlan, err) + } + if model := scalingPlan.Model; model != nil { + hostPoolId := id.HostPool.ID() + exists := scalingPlanHostPoolAssociationExists(model.Properties, hostPoolId) + if !exists { + log.Printf("[DEBUG] Association between %s and %s was not found - removing from state!", id.ScalingPlan, id.HostPool) + d.SetId("") + return nil + } + if props := model.Properties; props != nil && props.HostPoolReferences != nil { + for _, referenceId := range *props.HostPoolReferences { + if referenceId.HostPoolArmPath != nil { + if strings.EqualFold(*referenceId.HostPoolArmPath, hostPoolId) { + d.Set("enabled", referenceId.ScalingPlanEnabled) + } + } + } + } + + d.Set("scaling_plan_id", id.ScalingPlan.ID()) + d.Set("host_pool_id", hostPoolId) + } + + return nil +} + +func resourceVirtualDesktopScalingPlanHostPoolAssociationUpdate(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).DesktopVirtualization.ScalingPlansClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ScalingPlanHostPoolAssociationID(d.Id()) + if err != nil { + return err + } + + locks.ByName(id.ScalingPlan.ScalingPlanName, scalingPlanResourceType) + defer locks.UnlockByName(id.ScalingPlan.ScalingPlanName, scalingPlanResourceType) + + locks.ByName(id.HostPool.HostPoolName, hostPoolResourceType) + defer locks.UnlockByName(id.HostPool.HostPoolName, hostPoolResourceType) + + existing, err := client.Get(ctx, id.ScalingPlan) + if err != nil { + if response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("%s was not found", id.ScalingPlan) + } + + return fmt.Errorf("retrieving %s: %+v", id.ScalingPlan, err) + } + if existing.Model == nil { + return fmt.Errorf("retrieving %s: model was nil", id.ScalingPlan) + } + model := *existing.Model + exists := scalingPlanHostPoolAssociationExists(model.Properties, id.HostPool.ID()) + if !exists { + log.Printf("[DEBUG] Association between %s and %s was not found - removing from state!", id.ScalingPlan, id.HostPool) + d.SetId("") + return nil + } + + hostPoolReferences := []scalingplan.ScalingHostPoolReference{} + hostPoolId := id.HostPool.ID() + if props := model.Properties; props != nil && props.HostPoolReferences != nil { + for _, referenceId := range *props.HostPoolReferences { + if referenceId.HostPoolArmPath != nil { + if strings.EqualFold(*referenceId.HostPoolArmPath, hostPoolId) { + referenceId.ScalingPlanEnabled = utils.Bool(d.Get("enabled").(bool)) + } + } + hostPoolReferences = append(hostPoolReferences, referenceId) + } + } + + payload := scalingplan.ScalingPlanPatch{ + Properties: &scalingplan.ScalingPlanPatchProperties{ + HostPoolReferences: &hostPoolReferences, + }, + Tags: model.Tags, + } + if _, err = client.Update(ctx, id.ScalingPlan, payload); err != nil { + return fmt.Errorf("updating association between %s and %s: %+v", id.ScalingPlan, id.HostPool, err) + } + + return nil +} + +func resourceVirtualDesktopScalingPlanHostPoolAssociationDelete(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).DesktopVirtualization.ScalingPlansClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ScalingPlanHostPoolAssociationID(d.Id()) + if err != nil { + return err + } + + locks.ByName(id.ScalingPlan.ScalingPlanName, scalingPlanResourceType) + defer locks.UnlockByName(id.ScalingPlan.ScalingPlanName, scalingPlanResourceType) + + locks.ByName(id.HostPool.HostPoolName, hostPoolResourceType) + defer locks.UnlockByName(id.HostPool.HostPoolName, hostPoolResourceType) + + existing, err := client.Get(ctx, id.ScalingPlan) + if err != nil { + if response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("%s was not found", id.ScalingPlan) + } + + return fmt.Errorf("retrieving %s: %+v", id.ScalingPlan, err) + } + if existing.Model == nil { + return fmt.Errorf("retrieving %s: model was nil", id.ScalingPlan) + } + model := *existing.Model + + hostPoolReferences := []scalingplan.ScalingHostPoolReference{} + hostPoolId := id.HostPool.ID() + if props := model.Properties; props != nil && props.HostPoolReferences != nil { + for _, referenceId := range *props.HostPoolReferences { + if referenceId.HostPoolArmPath != nil { + if strings.EqualFold(*referenceId.HostPoolArmPath, hostPoolId) { + continue + } + } + + hostPoolReferences = append(hostPoolReferences, referenceId) + } + } + + payload := scalingplan.ScalingPlanPatch{ + Properties: &scalingplan.ScalingPlanPatchProperties{ + HostPoolReferences: &hostPoolReferences, + }, + Tags: model.Tags, + } + if _, err = client.Update(ctx, id.ScalingPlan, payload); err != nil { + return fmt.Errorf("removing association between %s and %s: %+v", id.ScalingPlan, id.HostPool, err) + } + + return nil +} + +func scalingPlanHostPoolAssociationExists(props *scalingplan.ScalingPlanProperties, applicationGroupId string) bool { + if props == nil || props.HostPoolReferences == nil { + return false + } + + for _, id := range *props.HostPoolReferences { + if id.HostPoolArmPath != nil { + if strings.EqualFold(*id.HostPoolArmPath, applicationGroupId) { + return true + } + } + } + + return false +} diff --git a/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_host_pool_association_resource_test.go b/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_host_pool_association_resource_test.go new file mode 100644 index 0000000000000..edeb2931586c4 --- /dev/null +++ b/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_host_pool_association_resource_test.go @@ -0,0 +1,111 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package desktopvirtualization_test + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/google/uuid" + "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/desktopvirtualization/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type VirtualDesktopScalingPlanAssociationResource struct{} + +func TestAccVirtualDesktopScalingPlanAssociation_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_desktop_scaling_plan_host_pool_association", "test") + r := VirtualDesktopScalingPlanAssociationResource{} + roleAssignmentId := uuid.New().String() + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data, roleAssignmentId), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("tags.%").HasValue("0"), + ), + }, + }) +} + +func TestAccVirtualDesktopScalingPlanAssociation_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_desktop_scaling_plan_host_pool_association", "test") + r := VirtualDesktopScalingPlanAssociationResource{} + roleAssignmentId := uuid.New().String() + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data, roleAssignmentId), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + { + Config: r.requiresImport(data, roleAssignmentId), + ExpectError: acceptance.RequiresImportError("azurerm_virtual_desktop_scaling_plan_host_pool_association"), + }, + }) +} + +func (VirtualDesktopScalingPlanAssociationResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.ScalingPlanHostPoolAssociationID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.DesktopVirtualization.ScalingPlansClient.Get(ctx, id.ScalingPlan) + if err != nil { + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + + found := false + if model := resp.Model; model != nil { + if props := model.Properties; props != nil && props.HostPoolReferences != nil { + for _, hostpool := range *props.HostPoolReferences { + if strings.EqualFold(*hostpool.HostPoolArmPath, id.HostPool.ID()) { + found = true + } + } + } + } + + return utils.Bool(found), nil +} + +func (VirtualDesktopScalingPlanAssociationResource) basic(data acceptance.TestData, roleAssignmentId string) string { + return fmt.Sprintf(` +%s + +resource "azurerm_virtual_desktop_scaling_plan_host_pool_association" "test" { + host_pool_id = azurerm_virtual_desktop_host_pool.test.id + scaling_plan_id = azurerm_virtual_desktop_scaling_plan.test.id + enabled = true + depends_on = [azurerm_role_assignment.test] +} + + +`, VirtualDesktopScalingPlanResource{}.basic(data, roleAssignmentId)) +} + +func (r VirtualDesktopScalingPlanAssociationResource) requiresImport(data acceptance.TestData, roleAssignmentId string) string { + return fmt.Sprintf(` +%s + +resource "azurerm_virtual_desktop_scaling_plan_host_pool_association" "import" { + host_pool_id = azurerm_virtual_desktop_host_pool.test.id + scaling_plan_id = azurerm_virtual_desktop_scaling_plan.test.id + enabled = true + depends_on = [azurerm_role_assignment.test] +} + + +`, r.basic(data, roleAssignmentId)) +} diff --git a/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_resource.go b/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_resource.go index 18223c04f2f40..5a1ba3e1b2731 100644 --- a/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_resource.go +++ b/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_resource.go @@ -25,6 +25,8 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/utils" ) +var scalingPlanResourceType = "azurerm_virtual_desktop_scaling_plan" + func resourceVirtualDesktopScalingPlan() *pluginsdk.Resource { return &pluginsdk.Resource{ Create: resourceVirtualDesktopScalingPlanCreate, @@ -221,6 +223,7 @@ func resourceVirtualDesktopScalingPlan() *pluginsdk.Resource { "host_pool": { Type: pluginsdk.TypeList, Optional: true, + Computed: true, Elem: &pluginsdk.Resource{ Schema: map[string]*pluginsdk.Schema{ "hostpool_id": { diff --git a/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_resource_test.go b/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_resource_test.go index d04c3f83b8812..e548f4a68e6ac 100644 --- a/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_resource_test.go +++ b/internal/services/desktopvirtualization/virtual_desktop_scaling_plan_resource_test.go @@ -128,37 +128,6 @@ resource "azurerm_resource_group" "test" { location = "westeurope" } -resource "azurerm_role_definition" "test" { - name = "AVD-AutoScale%s" - scope = azurerm_resource_group.test.id - description = "AVD AutoScale Role" - - permissions { - actions = [ - "Microsoft.Insights/eventtypes/values/read", - "Microsoft.Compute/virtualMachines/deallocate/action", - "Microsoft.Compute/virtualMachines/restart/action", - "Microsoft.Compute/virtualMachines/powerOff/action", - "Microsoft.Compute/virtualMachines/start/action", - "Microsoft.Compute/virtualMachines/read", - "Microsoft.DesktopVirtualization/hostpools/read", - "Microsoft.DesktopVirtualization/hostpools/write", - "Microsoft.DesktopVirtualization/hostpools/sessionhosts/read", - "Microsoft.DesktopVirtualization/hostpools/sessionhosts/write", - "Microsoft.DesktopVirtualization/hostpools/sessionhosts/usersessions/delete", - "Microsoft.DesktopVirtualization/hostpools/sessionhosts/usersessions/read", - "Microsoft.DesktopVirtualization/hostpools/sessionhosts/usersessions/sendMessage/action", - "Microsoft.DesktopVirtualization/hostpools/sessionhosts/usersessions/read" - ] - not_actions = [] - } - - assignable_scopes = [ - azurerm_resource_group.test.id, # /subscriptions/00000000-0000-0000-0000-000000000000 - ] - - depends_on = [azurerm_resource_group.test] -} data "azuread_service_principal" "test" { display_name = "Windows Virtual Desktop" @@ -167,11 +136,9 @@ data "azuread_service_principal" "test" { resource "azurerm_role_assignment" "test" { name = "%s" scope = azurerm_resource_group.test.id - role_definition_id = azurerm_role_definition.test.role_definition_resource_id - principal_id = data.azuread_service_principal.test.application_id + role_definition_name = "Desktop Virtualization Power On Off Contributor" + principal_id = data.azuread_service_principal.test.object_id skip_service_principal_aad_check = true - - depends_on = [azurerm_role_definition.test] } resource "azurerm_virtual_desktop_host_pool" "test" { @@ -181,11 +148,16 @@ resource "azurerm_virtual_desktop_host_pool" "test" { type = "Pooled" validate_environment = true load_balancer_type = "BreadthFirst" + lifecycle { + ignore_changes = [ + load_balancer_type, + ] + } } resource "azurerm_virtual_desktop_scaling_plan" "test" { name = "scalingPlan%x" - location = "westeurope" + location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name friendly_name = "Scaling Plan Test" description = "Test Scaling Plan" @@ -215,7 +187,7 @@ resource "azurerm_virtual_desktop_scaling_plan" "test" { } -`, data.RandomInteger, data.RandomString, roleAssignmentId, data.RandomString, data.RandomString) +`, data.RandomInteger, roleAssignmentId, data.RandomString, data.RandomString) } func (VirtualDesktopScalingPlanResource) complete(data acceptance.TestData, roleAssignmentId string) string { @@ -231,38 +203,6 @@ resource "azurerm_resource_group" "test" { location = "westeurope" } -resource "azurerm_role_definition" "test" { - name = "AVD-AutoScale%s" - scope = azurerm_resource_group.test.id - description = "AVD AutoScale Role" - - permissions { - actions = [ - "Microsoft.Insights/eventtypes/values/read", - "Microsoft.Compute/virtualMachines/deallocate/action", - "Microsoft.Compute/virtualMachines/restart/action", - "Microsoft.Compute/virtualMachines/powerOff/action", - "Microsoft.Compute/virtualMachines/start/action", - "Microsoft.Compute/virtualMachines/read", - "Microsoft.DesktopVirtualization/hostpools/read", - "Microsoft.DesktopVirtualization/hostpools/write", - "Microsoft.DesktopVirtualization/hostpools/sessionhosts/read", - "Microsoft.DesktopVirtualization/hostpools/sessionhosts/write", - "Microsoft.DesktopVirtualization/hostpools/sessionhosts/usersessions/delete", - "Microsoft.DesktopVirtualization/hostpools/sessionhosts/usersessions/read", - "Microsoft.DesktopVirtualization/hostpools/sessionhosts/usersessions/sendMessage/action", - "Microsoft.DesktopVirtualization/hostpools/sessionhosts/usersessions/read" - ] - not_actions = [] - } - - assignable_scopes = [ - azurerm_resource_group.test.id, # /subscriptions/00000000-0000-0000-0000-000000000000 - ] - - depends_on = [azurerm_resource_group.test] -} - data "azuread_service_principal" "test" { display_name = "Windows Virtual Desktop" } @@ -270,11 +210,9 @@ data "azuread_service_principal" "test" { resource "azurerm_role_assignment" "test" { name = "%s" scope = azurerm_resource_group.test.id - role_definition_id = azurerm_role_definition.test.role_definition_resource_id - principal_id = data.azuread_service_principal.test.application_id + role_definition_name = "Desktop Virtualization Power On Off Contributor" + principal_id = data.azuread_service_principal.test.object_id skip_service_principal_aad_check = true - - depends_on = [azurerm_role_definition.test] } resource "azurerm_virtual_desktop_host_pool" "test" { @@ -284,11 +222,16 @@ resource "azurerm_virtual_desktop_host_pool" "test" { type = "Pooled" validate_environment = true load_balancer_type = "BreadthFirst" + lifecycle { + ignore_changes = [ + load_balancer_type, + ] + } } resource "azurerm_virtual_desktop_scaling_plan" "test" { name = "scalingPlan%x" - location = "westeurope" + location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name friendly_name = "Scaling Plan Test" description = "Test Scaling Plan" @@ -344,7 +287,7 @@ resource "azurerm_virtual_desktop_scaling_plan" "test" { depends_on = [azurerm_role_assignment.test] } -`, data.RandomInteger, data.RandomString, roleAssignmentId, data.RandomString, data.RandomString) +`, data.RandomInteger, roleAssignmentId, data.RandomString, data.RandomString) } func (r VirtualDesktopScalingPlanResource) requiresImport(data acceptance.TestData, roleAssignmentId string) string {