Skip to content

Commit

Permalink
New Resource - azurerm_virtual_machine_scale_set_standby_pool (#28441)
Browse files Browse the repository at this point in the history
* add new resource `azurerm_virtual_machine_scale_set_standby_pool`

* go fmt

* fix gencheck

* go mod vendor

* resolve comments

* resolved comments
  • Loading branch information
ms-zhenhua authored Feb 11, 2025
1 parent 982b7c4 commit 7db4561
Show file tree
Hide file tree
Showing 24 changed files with 1,624 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/labeler-issue-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ service/cognitive-services:
- '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_(ai_services|cognitive_)((.|\n)*)###'

service/communication:
- '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_(communication_service|email_communication_service|gallery_application|orchestrated_virtual_machine_scale_set\W+|restore_point_collection|virtual_machine_gallery_application_assignment\W+|virtual_machine_implicit_data_disk_from_source\W+|virtual_machine_restore_point\W+|virtual_machine_restore_point_collection\W+|virtual_machine_run_command\W+)((.|\n)*)###'
- '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_(communication_service|email_communication_service|gallery_application|orchestrated_virtual_machine_scale_set\W+|restore_point_collection|virtual_machine_gallery_application_assignment\W+|virtual_machine_implicit_data_disk_from_source\W+|virtual_machine_restore_point\W+|virtual_machine_restore_point_collection\W+|virtual_machine_run_command\W+|virtual_machine_scale_set_standby_pool\W+)((.|\n)*)###'

service/connections:
- '### (|New or )Affected Resource\(s\)\/Data Source\(s\)((.|\n)*)azurerm_(api_connection|managed_api)((.|\n)*)###'
Expand Down
9 changes: 9 additions & 0 deletions internal/services/compute/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
"github.com/hashicorp/go-azure-sdk/resource-manager/compute/2024-03-01/virtualmachinescalesetvms"
"github.com/hashicorp/go-azure-sdk/resource-manager/compute/2024-07-01/virtualmachinescalesets"
"github.com/hashicorp/go-azure-sdk/resource-manager/marketplaceordering/2015-06-01/agreements"
"github.com/hashicorp/go-azure-sdk/resource-manager/standbypool/2024-03-01/standbyvirtualmachinepools"
"github.com/hashicorp/terraform-provider-azurerm/internal/common"
)

Expand Down Expand Up @@ -68,6 +69,7 @@ type Client struct {
SkusClient *skus.SkusClient
SSHPublicKeysClient *sshpublickeys.SshPublicKeysClient
SnapshotsClient *snapshots.SnapshotsClient
StandbyVirtualMachinePoolsClient *standbyvirtualmachinepools.StandbyVirtualMachinePoolsClient
VirtualMachinesClient *virtualmachines.VirtualMachinesClient
VirtualMachineExtensionsClient *virtualmachineextensions.VirtualMachineExtensionsClient
VirtualMachineRunCommandsClient *virtualmachineruncommands.VirtualMachineRunCommandsClient
Expand Down Expand Up @@ -211,6 +213,12 @@ func NewClient(o *common.ClientOptions) (*Client, error) {
}
o.Configure(sshPublicKeysClient.Client, o.Authorizers.ResourceManager)

standbyVirtualMachinePoolsClient, err := standbyvirtualmachinepools.NewStandbyVirtualMachinePoolsClientWithBaseURI(o.Environment.ResourceManager)
if err != nil {
return nil, fmt.Errorf("building Standby Virtual Machine Pools client: %+v", err)
}
o.Configure(standbyVirtualMachinePoolsClient.Client, o.Authorizers.ResourceManager)

virtualMachinesClient, err := virtualmachines.NewVirtualMachinesClientWithBaseURI(o.Environment.ResourceManager)
if err != nil {
return nil, fmt.Errorf("building VirtualMachines client: %+v", err)
Expand Down Expand Up @@ -282,6 +290,7 @@ func NewClient(o *common.ClientOptions) (*Client, error) {
SkusClient: skusClient,
SSHPublicKeysClient: sshPublicKeysClient,
SnapshotsClient: snapshotsClient,
StandbyVirtualMachinePoolsClient: standbyVirtualMachinePoolsClient,
VirtualMachinesClient: virtualMachinesClient,
VirtualMachineExtensionsClient: virtualMachineExtensionsClient,
VirtualMachineRunCommandsClient: virtualMachineRunCommandsClient,
Expand Down
1 change: 1 addition & 0 deletions internal/services/compute/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,6 @@ func (r Registration) Resources() []sdk.Resource {
VirtualMachineRestorePointCollectionResource{},
VirtualMachineRestorePointResource{},
VirtualMachineGalleryApplicationAssignmentResource{},
VirtualMachineScaleSetStandbyPoolResource{},
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
package compute

import (
"context"
"fmt"
"regexp"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"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/compute/2024-07-01/virtualmachinescalesets"
"github.com/hashicorp/go-azure-sdk/resource-manager/standbypool/2024-03-01/standbyvirtualmachinepools"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
)

type VirtualMachineScaleSetStandbyPoolModel struct {
Name string `tfschema:"name"`
ResourceGroupName string `tfschema:"resource_group_name"`
Location string `tfschema:"location"`
AttachedVirtualMachineScaleSetId string `tfschema:"attached_virtual_machine_scale_set_id"`
ElasticityProfile []VirtualMachineScaleSetStandbyPoolElasticityProfileModel `tfschema:"elasticity_profile"`
VirtualMachineState standbyvirtualmachinepools.VirtualMachineState `tfschema:"virtual_machine_state"`
Tags map[string]string `tfschema:"tags"`
}

type VirtualMachineScaleSetStandbyPoolElasticityProfileModel struct {
MaxReadyCapacity int64 `tfschema:"max_ready_capacity"`
MinReadyCapacity int64 `tfschema:"min_ready_capacity"`
}

type VirtualMachineScaleSetStandbyPoolResource struct{}

var (
_ sdk.ResourceWithUpdate = VirtualMachineScaleSetStandbyPoolResource{}
_ sdk.ResourceWithCustomizeDiff = VirtualMachineScaleSetStandbyPoolResource{}
)

func (r VirtualMachineScaleSetStandbyPoolResource) ResourceType() string {
return "azurerm_virtual_machine_scale_set_standby_pool"
}

func (r VirtualMachineScaleSetStandbyPoolResource) ModelObject() interface{} {
return &VirtualMachineScaleSetStandbyPoolModel{}
}

func (r VirtualMachineScaleSetStandbyPoolResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
return standbyvirtualmachinepools.ValidateStandbyVirtualMachinePoolID
}

func (r VirtualMachineScaleSetStandbyPoolResource) Arguments() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"name": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringMatch(
regexp.MustCompile("^[a-zA-Z0-9-]{3,24}$"),
"name must be between 3 and 24 characters in length and may contain only letters, numbers and hyphens (-).",
),
},

"resource_group_name": commonschema.ResourceGroupName(),

"location": commonschema.Location(),

"attached_virtual_machine_scale_set_id": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: virtualmachinescalesets.ValidateVirtualMachineScaleSetID,
},

"elasticity_profile": {
Type: pluginsdk.TypeList,
Required: true,
MaxItems: 1,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"max_ready_capacity": {
Type: pluginsdk.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(0, 2000),
},

"min_ready_capacity": {
Type: pluginsdk.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(0, 2000),
},
},
},
},

"virtual_machine_state": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(standbyvirtualmachinepools.PossibleValuesForVirtualMachineState(), false),
},

"tags": commonschema.Tags(),
}
}

func (r VirtualMachineScaleSetStandbyPoolResource) Attributes() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{}
}

func (r VirtualMachineScaleSetStandbyPoolResource) CustomizeDiff() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
var config VirtualMachineScaleSetStandbyPoolModel
if err := metadata.DecodeDiff(&config); err != nil {
return fmt.Errorf("decoding: %+v", err)
}

if len(config.ElasticityProfile) > 0 && config.ElasticityProfile[0].MaxReadyCapacity < config.ElasticityProfile[0].MinReadyCapacity {
return fmt.Errorf("`min_ready_capacity` cannot exceed `max_ready_capacity`")
}

return nil
},
}
}

func (r VirtualMachineScaleSetStandbyPoolResource) Create() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 30 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.Compute.StandbyVirtualMachinePoolsClient
subscriptionId := metadata.Client.Account.SubscriptionId

var model VirtualMachineScaleSetStandbyPoolModel
if err := metadata.Decode(&model); err != nil {
return fmt.Errorf("decoding: %+v", err)
}

id := standbyvirtualmachinepools.NewStandbyVirtualMachinePoolID(subscriptionId, model.ResourceGroupName, model.Name)
existing, err := client.Get(ctx, id)
if err != nil && !response.WasNotFound(existing.HttpResponse) {
return fmt.Errorf("checking for existing %s: %+v", id, err)
}

if !response.WasNotFound(existing.HttpResponse) {
return metadata.ResourceRequiresImport(r.ResourceType(), id)
}

properties := &standbyvirtualmachinepools.StandbyVirtualMachinePoolResource{
Location: location.Normalize(model.Location),
Properties: &standbyvirtualmachinepools.StandbyVirtualMachinePoolResourceProperties{
AttachedVirtualMachineScaleSetId: pointer.To(model.AttachedVirtualMachineScaleSetId),
ElasticityProfile: expandStandbyVirtualMachinePoolElasticityProfileModel(model.ElasticityProfile),
VirtualMachineState: model.VirtualMachineState,
},
Tags: &model.Tags,
}

if err := client.CreateOrUpdateThenPoll(ctx, id, *properties); err != nil {
return fmt.Errorf("creating %s: %+v", id, err)
}

metadata.SetID(id)
return nil
},
}
}

func (r VirtualMachineScaleSetStandbyPoolResource) Update() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 30 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.Compute.StandbyVirtualMachinePoolsClient

id, err := standbyvirtualmachinepools.ParseStandbyVirtualMachinePoolID(metadata.ResourceData.Id())
if err != nil {
return err
}

var model VirtualMachineScaleSetStandbyPoolModel
if err := metadata.Decode(&model); err != nil {
return fmt.Errorf("decoding: %+v", err)
}

resp, err := client.Get(ctx, *id)
if err != nil {
return fmt.Errorf("retrieving %s: %+v", *id, err)
}

properties := resp.Model
if properties == nil {
return fmt.Errorf("retrieving %s: properties was nil", id)
}

if metadata.ResourceData.HasChange("attached_virtual_machine_scale_set_id") {
properties.Properties.AttachedVirtualMachineScaleSetId = pointer.To(model.AttachedVirtualMachineScaleSetId)
}

if metadata.ResourceData.HasChange("elasticity_profile") {
properties.Properties.ElasticityProfile = expandStandbyVirtualMachinePoolElasticityProfileModel(model.ElasticityProfile)
}

if metadata.ResourceData.HasChange("virtual_machine_state") {
properties.Properties.VirtualMachineState = model.VirtualMachineState
}

if metadata.ResourceData.HasChange("tags") {
properties.Tags = &model.Tags
}

if err := client.CreateOrUpdateThenPoll(ctx, *id, *properties); err != nil {
return fmt.Errorf("updating %s: %+v", *id, err)
}

return nil
},
}
}

func (r VirtualMachineScaleSetStandbyPoolResource) Read() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.Compute.StandbyVirtualMachinePoolsClient

id, err := standbyvirtualmachinepools.ParseStandbyVirtualMachinePoolID(metadata.ResourceData.Id())
if err != nil {
return err
}

resp, err := client.Get(ctx, *id)
if err != nil {
if response.WasNotFound(resp.HttpResponse) {
return metadata.MarkAsGone(id)
}

return fmt.Errorf("retrieving %s: %+v", *id, err)
}

state := VirtualMachineScaleSetStandbyPoolModel{
Name: id.StandbyVirtualMachinePoolName,
ResourceGroupName: id.ResourceGroupName,
}

if model := resp.Model; model != nil {
state.Location = location.Normalize(model.Location)
if properties := model.Properties; properties != nil {
parsedAttachedVirtualMachineScaleSetId, err := virtualmachinescalesets.ParseVirtualMachineScaleSetIDInsensitively(pointer.From(properties.AttachedVirtualMachineScaleSetId))
if err != nil {
return fmt.Errorf("parsing `attached_virtual_machine_scale_set_id` for %s: %+v", *id, err)
}

state.AttachedVirtualMachineScaleSetId = parsedAttachedVirtualMachineScaleSetId.ID()
state.ElasticityProfile = flattenStandbyVirtualMachinePoolElasticityProfileModel(properties.ElasticityProfile)
state.VirtualMachineState = properties.VirtualMachineState
}

state.Tags = pointer.From(model.Tags)
}

return metadata.Encode(&state)
},
}
}

func (r VirtualMachineScaleSetStandbyPoolResource) Delete() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 30 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.Compute.StandbyVirtualMachinePoolsClient

id, err := standbyvirtualmachinepools.ParseStandbyVirtualMachinePoolID(metadata.ResourceData.Id())
if err != nil {
return err
}

if err := client.DeleteThenPoll(ctx, *id); err != nil {
return fmt.Errorf("deleting %s: %+v", id, err)
}

return nil
},
}
}

func expandStandbyVirtualMachinePoolElasticityProfileModel(inputList []VirtualMachineScaleSetStandbyPoolElasticityProfileModel) *standbyvirtualmachinepools.StandbyVirtualMachinePoolElasticityProfile {
if len(inputList) == 0 {
return nil
}

input := &inputList[0]
output := standbyvirtualmachinepools.StandbyVirtualMachinePoolElasticityProfile{
MaxReadyCapacity: input.MaxReadyCapacity,
MinReadyCapacity: pointer.To(input.MinReadyCapacity),
}

return &output
}

func flattenStandbyVirtualMachinePoolElasticityProfileModel(input *standbyvirtualmachinepools.StandbyVirtualMachinePoolElasticityProfile) []VirtualMachineScaleSetStandbyPoolElasticityProfileModel {
outputList := make([]VirtualMachineScaleSetStandbyPoolElasticityProfileModel, 0)
if input == nil {
return outputList
}

output := VirtualMachineScaleSetStandbyPoolElasticityProfileModel{
MaxReadyCapacity: input.MaxReadyCapacity,
MinReadyCapacity: pointer.From(input.MinReadyCapacity),
}

return append(outputList, output)
}
Loading

0 comments on commit 7db4561

Please sign in to comment.