-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
New resources azurerm_capacity_reservation_group
and azurerm_capacity_reservation
#16464
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
827c2c2
New resources `capacity_reservation_group` and `capacity_reservation`
myc2h6o 45a24dc
Resolve comments
myc2h6o b848bfa
Upadte doc
myc2h6o 26114f7
Update delete workaround
myc2h6o 2eee0b7
Update sku with more quota in test
myc2h6o 9d1de89
use stateConf instead of sleep
myc2h6o 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
187 changes: 187 additions & 0 deletions
187
internal/services/compute/capacity_reservation_group_resource.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,187 @@ | ||
package compute | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2021-11-01/compute" | ||
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" | ||
"github.com/hashicorp/go-azure-helpers/resourcemanager/location" | ||
"github.com/hashicorp/go-azure-helpers/resourcemanager/zones" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"github.com/hashicorp/terraform-provider-azurerm/helpers/azure" | ||
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf" | ||
"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/tags" | ||
"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 resourceCapacityReservationGroup() *pluginsdk.Resource { | ||
return &pluginsdk.Resource{ | ||
Create: resourceCapacityReservationGroupCreate, | ||
Read: resourceCapacityReservationGroupRead, | ||
Update: resourceCapacityReservationGroupUpdate, | ||
Delete: resourceCapacityReservationGroupDelete, | ||
|
||
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), | ||
}, | ||
|
||
Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { | ||
_, err := parse.CapacityReservationGroupID(id) | ||
return err | ||
}), | ||
|
||
Schema: map[string]*pluginsdk.Schema{ | ||
"name": { | ||
Type: pluginsdk.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: validate.CapacityReservationGroupName(), | ||
}, | ||
|
||
"resource_group_name": azure.SchemaResourceGroupName(), | ||
|
||
"location": azure.SchemaLocation(), | ||
|
||
"zones": commonschema.ZonesMultipleOptionalForceNew(), | ||
|
||
"tags": tags.Schema(), | ||
}, | ||
} | ||
} | ||
|
||
func resourceCapacityReservationGroupCreate(d *pluginsdk.ResourceData, meta interface{}) error { | ||
client := meta.(*clients.Client).Compute.CapacityReservationGroupsClient | ||
subscriptionId := meta.(*clients.Client).Account.SubscriptionId | ||
ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) | ||
defer cancel() | ||
|
||
name := d.Get("name").(string) | ||
resourceGroup := d.Get("resource_group_name").(string) | ||
id := parse.NewCapacityReservationGroupID(subscriptionId, resourceGroup, name) | ||
existing, err := client.Get(ctx, id.ResourceGroup, id.Name, "") | ||
if err != nil { | ||
if !utils.ResponseWasNotFound(existing.Response) { | ||
return fmt.Errorf("checking for existing %s: %+v", id, err) | ||
} | ||
} | ||
if !utils.ResponseWasNotFound(existing.Response) { | ||
return tf.ImportAsExistsError("azurerm_capacity_reservation_group", id.ID()) | ||
} | ||
|
||
parameters := compute.CapacityReservationGroup{ | ||
Name: utils.String(name), | ||
Location: utils.String(location.Normalize(d.Get("location").(string))), | ||
Tags: tags.Expand(d.Get("tags").(map[string]interface{})), | ||
} | ||
|
||
zones := zones.Expand(d.Get("zones").(*schema.Set).List()) | ||
if len(zones) > 0 { | ||
parameters.Zones = &zones | ||
} | ||
|
||
if _, err := client.CreateOrUpdate(ctx, resourceGroup, name, parameters); err != nil { | ||
return fmt.Errorf("creating %s: %+v", id, err) | ||
} | ||
|
||
d.SetId(id.ID()) | ||
return resourceCapacityReservationGroupRead(d, meta) | ||
} | ||
|
||
func resourceCapacityReservationGroupRead(d *pluginsdk.ResourceData, meta interface{}) error { | ||
client := meta.(*clients.Client).Compute.CapacityReservationGroupsClient | ||
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) | ||
defer cancel() | ||
|
||
id, err := parse.CapacityReservationGroupID(d.Id()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
resp, err := client.Get(ctx, id.ResourceGroup, id.Name, "") | ||
if err != nil { | ||
if utils.ResponseWasNotFound(resp.Response) { | ||
log.Printf("[INFO] %s was not found - removing from state", *id) | ||
d.SetId("") | ||
return nil | ||
} | ||
return fmt.Errorf("retrieving %s: %+v", id, err) | ||
} | ||
|
||
d.Set("name", resp.Name) | ||
d.Set("resource_group_name", id.ResourceGroup) | ||
d.Set("location", location.NormalizeNilable(resp.Location)) | ||
d.Set("zones", utils.FlattenStringSlice(resp.Zones)) | ||
return tags.FlattenAndSet(d, resp.Tags) | ||
} | ||
|
||
func resourceCapacityReservationGroupUpdate(d *pluginsdk.ResourceData, meta interface{}) error { | ||
client := meta.(*clients.Client).Compute.CapacityReservationGroupsClient | ||
ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) | ||
defer cancel() | ||
|
||
id, err := parse.CapacityReservationGroupID(d.Id()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
parameters := compute.CapacityReservationGroupUpdate{} | ||
|
||
if d.HasChange("tags") { | ||
parameters.Tags = tags.Expand(d.Get("tags").(map[string]interface{})) | ||
} | ||
|
||
if _, err := client.Update(ctx, id.ResourceGroup, id.Name, parameters); err != nil { | ||
return fmt.Errorf("updating %s: %+v", id, err) | ||
} | ||
return resourceCapacityReservationGroupRead(d, meta) | ||
} | ||
|
||
func resourceCapacityReservationGroupDelete(d *pluginsdk.ResourceData, meta interface{}) error { | ||
client := meta.(*clients.Client).Compute.CapacityReservationGroupsClient | ||
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) | ||
defer cancel() | ||
|
||
id, err := parse.CapacityReservationGroupID(d.Id()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// It takes several seconds to sync the cache of reservations list in Capacity Reservation Group. Delete operation requires the list to be empty, and fails before the cache sync is completed. | ||
// Retry the delete operation after a minute as a workaround. Issue is tracked by: https://github.com/Azure/azure-rest-api-specs/issues/18767 | ||
if _, err := client.Delete(ctx, id.ResourceGroup, id.Name); err != nil { | ||
stateConf := &pluginsdk.StateChangeConf{ | ||
Pending: []string{"Deleting"}, | ||
Target: []string{"Deleted"}, | ||
Refresh: capacityReservationGroupDeleteRefreshFunc(ctx, client, id.ResourceGroup, id.Name), | ||
MinTimeout: 15 * time.Second, | ||
Timeout: 1 * time.Minute, | ||
} | ||
|
||
if _, err := stateConf.WaitForStateContext(ctx); err != nil { | ||
return fmt.Errorf("waiting for %s to be deleted: %+v", id, err) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func capacityReservationGroupDeleteRefreshFunc(ctx context.Context, client *compute.CapacityReservationGroupsClient, resourceGroup string, name string) pluginsdk.StateRefreshFunc { | ||
return func() (interface{}, string, error) { | ||
res, err := client.Delete(ctx, resourceGroup, name) | ||
if err != nil { | ||
return res, "Deleting", nil | ||
} | ||
return res, "Deleted", nil | ||
} | ||
} |
182 changes: 182 additions & 0 deletions
182
internal/services/compute/capacity_reservation_group_resource_test.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,182 @@ | ||
package compute_test | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform" | ||
"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/utils" | ||
) | ||
|
||
type CapacityReservationGroupResource struct{} | ||
|
||
func TestAccCapacityReservationGroup_basic(t *testing.T) { | ||
data := acceptance.BuildTestData(t, "azurerm_capacity_reservation_group", "test") | ||
r := CapacityReservationGroupResource{} | ||
data.ResourceTest(t, r, []resource.TestStep{ | ||
{ | ||
Config: r.basic(data), | ||
Check: resource.ComposeTestCheckFunc( | ||
check.That(data.ResourceName).ExistsInAzure(r), | ||
), | ||
}, | ||
data.ImportStep(), | ||
}) | ||
} | ||
|
||
func TestAccCapacityReservationGroup_requiresImport(t *testing.T) { | ||
data := acceptance.BuildTestData(t, "azurerm_capacity_reservation_group", "test") | ||
r := CapacityReservationGroupResource{} | ||
data.ResourceTest(t, r, []resource.TestStep{ | ||
{ | ||
Config: r.basic(data), | ||
Check: resource.ComposeTestCheckFunc( | ||
check.That(data.ResourceName).ExistsInAzure(r), | ||
), | ||
}, | ||
data.RequiresImportErrorStep(r.requiresImport), | ||
}) | ||
} | ||
|
||
func TestAccCapacityReservationGroup_zones(t *testing.T) { | ||
data := acceptance.BuildTestData(t, "azurerm_capacity_reservation_group", "test") | ||
r := CapacityReservationGroupResource{} | ||
data.ResourceTest(t, r, []resource.TestStep{ | ||
{ | ||
Config: r.zones(data), | ||
Check: resource.ComposeTestCheckFunc( | ||
check.That(data.ResourceName).ExistsInAzure(r), | ||
), | ||
}, | ||
data.ImportStep(), | ||
}) | ||
} | ||
|
||
func TestAccCapacityReservationGroup_tags(t *testing.T) { | ||
data := acceptance.BuildTestData(t, "azurerm_capacity_reservation_group", "test") | ||
r := CapacityReservationGroupResource{} | ||
data.ResourceTest(t, r, []resource.TestStep{ | ||
{ | ||
Config: r.tags(data), | ||
Check: resource.ComposeTestCheckFunc( | ||
check.That(data.ResourceName).ExistsInAzure(r), | ||
), | ||
}, | ||
data.ImportStep(), | ||
{ | ||
Config: r.tagsUpdated(data), | ||
Check: resource.ComposeTestCheckFunc( | ||
check.That(data.ResourceName).ExistsInAzure(r), | ||
), | ||
}, | ||
data.ImportStep(), | ||
}) | ||
} | ||
|
||
func (r CapacityReservationGroupResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { | ||
id, err := parse.CapacityReservationGroupID(state.ID) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
resp, err := client.Compute.CapacityReservationGroupsClient.Get(ctx, id.ResourceGroup, id.Name, "") | ||
if err != nil { | ||
if utils.ResponseWasNotFound(resp.Response) { | ||
return utils.Bool(false), nil | ||
} | ||
return nil, fmt.Errorf("retrieving %s: %+v", id, err) | ||
} | ||
|
||
return utils.Bool(resp.ID != nil), nil | ||
} | ||
|
||
func (r CapacityReservationGroupResource) template(data acceptance.TestData) string { | ||
return fmt.Sprintf(` | ||
provider "azurerm" { | ||
features {} | ||
} | ||
|
||
resource "azurerm_resource_group" "test" { | ||
name = "acctest-compute-%d" | ||
location = "%s" | ||
} | ||
`, data.RandomInteger, data.Locations.Primary) | ||
} | ||
|
||
func (r CapacityReservationGroupResource) basic(data acceptance.TestData) string { | ||
template := r.template(data) | ||
return fmt.Sprintf(` | ||
%s | ||
|
||
resource "azurerm_capacity_reservation_group" "test" { | ||
name = "acctest-crg-%d" | ||
resource_group_name = azurerm_resource_group.test.name | ||
location = azurerm_resource_group.test.location | ||
} | ||
`, template, data.RandomInteger) | ||
} | ||
|
||
func (r CapacityReservationGroupResource) requiresImport(data acceptance.TestData) string { | ||
config := r.basic(data) | ||
return fmt.Sprintf(` | ||
%s | ||
|
||
resource "azurerm_capacity_reservation_group" "import" { | ||
name = azurerm_capacity_reservation_group.test.name | ||
resource_group_name = azurerm_capacity_reservation_group.test.resource_group_name | ||
location = azurerm_capacity_reservation_group.test.location | ||
} | ||
`, config) | ||
} | ||
|
||
func (r CapacityReservationGroupResource) zones(data acceptance.TestData) string { | ||
template := r.template(data) | ||
return fmt.Sprintf(` | ||
%s | ||
|
||
resource "azurerm_capacity_reservation_group" "test" { | ||
name = "acctest-ccrg-%d" | ||
resource_group_name = azurerm_resource_group.test.name | ||
location = azurerm_resource_group.test.location | ||
zones = ["1", "2"] | ||
} | ||
`, template, data.RandomInteger) | ||
} | ||
|
||
func (r CapacityReservationGroupResource) tags(data acceptance.TestData) string { | ||
template := r.template(data) | ||
return fmt.Sprintf(` | ||
%s | ||
|
||
resource "azurerm_capacity_reservation_group" "test" { | ||
name = "acctest-ccrg-%d" | ||
resource_group_name = azurerm_resource_group.test.name | ||
location = azurerm_resource_group.test.location | ||
tags = { | ||
ENV = "Test" | ||
} | ||
} | ||
`, template, data.RandomInteger) | ||
} | ||
|
||
func (r CapacityReservationGroupResource) tagsUpdated(data acceptance.TestData) string { | ||
template := r.template(data) | ||
return fmt.Sprintf(` | ||
%s | ||
|
||
resource "azurerm_capacity_reservation_group" "test" { | ||
name = "acctest-ccrg-%d" | ||
resource_group_name = azurerm_resource_group.test.name | ||
location = azurerm_resource_group.test.location | ||
tags = { | ||
ENV2 = "Test2" | ||
} | ||
} | ||
`, template, data.RandomInteger) | ||
} |
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.
this should be using the standard Expand functions for Zones
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.
different from the other resource in this change, in line 87 (before the new commit), already used the standard
zones.Expand