-
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
Changes from 1 commit
827c2c2
45a24dc
b848bfa
26114f7
2eee0b7
9d1de89
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
capacity_reservation_group
and capacity_reservation
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,163 @@ | ||||||
package compute | ||||||
|
||||||
import ( | ||||||
"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/tags" | ||||||
"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 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: validation.StringIsNotEmpty, | ||||||
}, | ||||||
|
||||||
"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 | ||||||
} | ||||||
Comment on lines
+88
to
+91
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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 |
||||||
|
||||||
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] Capacity Reservation Group %q does not exist - removing from state", d.Id()) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated |
||||||
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 | ||||||
} | ||||||
|
||||||
if _, err := client.Delete(ctx, id.ResourceGroup, id.Name); err != nil { | ||||||
return fmt.Errorf("deleting %s: %+v", id, err) | ||||||
} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so this is gone straight away? given the other API has issues, are there any API errors when deleting multiple reservations within a parent group here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This api only has the non-future version: https://github.com/Azure/azure-sdk-for-go/blob/bf144f61fde04d2f29dd52d84f25e931cea67fd8/services/compute/mgmt/2021-11-01/compute/capacityreservationgroups.go#L120. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i don't see any wait? we souldn't be waiting and instead poll to check until its finished There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @katbyte The deletion for this resource capacity_reservation_group is synchrounous per sdk. And the wait and poll is for the other resource capaicty_reservation below in this change, where the asynchronous sdk has bug There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just took another thought. The actual issue Azure/azure-rest-api-specs#18767 happens within deleting the parent resource |
||||||
return nil | ||||||
} |
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) | ||
} |
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.
do we have more specific validation requirements for this?
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.
Have added the validation for name