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

fix: Timeout for metal ipblock #388

Merged
merged 5 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions equinix/resource_metal_reserved_ip_block.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package equinix

import (
"context"
"encoding/json"
"fmt"
"log"
Expand Down Expand Up @@ -215,12 +216,12 @@ func resourceMetalReservedIPBlock() *schema.Resource {
}
// TODO: add comments field, used for reservations that are not automatically approved
return &schema.Resource{
Create: resourceMetalReservedIPBlockCreate,
Read: resourceMetalReservedIPBlockRead,
Update: resourceMetalReservedIPBlockUpdate,
Delete: resourceMetalReservedIPBlockDelete,
CreateContext: diagnosticsWrapper(resourceMetalReservedIPBlockCreate),
ReadWithoutTimeout: diagnosticsWrapper(resourceMetalReservedIPBlockRead),
UpdateWithoutTimeout: diagnosticsWrapper(resourceMetalReservedIPBlockUpdate),
ctreatma marked this conversation as resolved.
Show resolved Hide resolved
DeleteWithoutTimeout: diagnosticsWrapper(resourceMetalReservedIPBlockDelete),
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
StateContext: schema.ImportStatePassthroughContext,
},

Schema: reservedBlockSchema,
Expand All @@ -230,14 +231,14 @@ func resourceMetalReservedIPBlock() *schema.Resource {
}
}

func resourceMetalReservedIPBlockCreate(d *schema.ResourceData, meta interface{}) error {
func resourceMetalReservedIPBlockCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) error {
meta.(*Config).addModuleToMetalUserAgent(d)
client := meta.(*Config).metal

quantity := d.Get("quantity").(int)
typ := d.Get("type").(string)

req := packngo.IPReservationRequest{
req := packngo.IPReservationCreateRequest{
Type: packngo.IPReservationType(typ),
Quantity: quantity,
}
Expand Down Expand Up @@ -285,6 +286,7 @@ func resourceMetalReservedIPBlockCreate(d *schema.ResourceData, meta interface{}
req.Network = d.Get("network").(string)
req.CIDR = d.Get("cidr").(int)

start := time.Now()
blockAddr, _, err := client.ProjectIPs.Create(projectID, &req)
if err != nil {
return fmt.Errorf("error reserving IP address block: %s", err)
Expand All @@ -302,17 +304,17 @@ func resourceMetalReservedIPBlockCreate(d *schema.ResourceData, meta interface{}
Pending: []string{string(packngo.IPReservationStatePending)},
Target: target,
Refresh: reservedIPStateRefreshFunc(client, d.Id()),
Timeout: d.Timeout(schema.TimeoutCreate),
Timeout: d.Timeout(schema.TimeoutCreate) - 30*time.Second - time.Since(start),
MinTimeout: 15 * time.Second,
}
if _, err := stateConf.WaitForState(); err != nil {
if _, err := stateConf.WaitForStateContext(ctx); err != nil {
return fmt.Errorf("error waiting for IP Reservation (%s) to become %s: %s", d.Id(), wfs, err)
}

return resourceMetalReservedIPBlockRead(d, meta)
return resourceMetalReservedIPBlockRead(ctx, d, meta)
}

func resourceMetalReservedIPBlockUpdate(d *schema.ResourceData, meta interface{}) error {
func resourceMetalReservedIPBlockUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) error {
meta.(*Config).addModuleToMetalUserAgent(d)
client := meta.(*Config).metal
id := d.Id()
Expand Down Expand Up @@ -344,7 +346,7 @@ func resourceMetalReservedIPBlockUpdate(d *schema.ResourceData, meta interface{}
return fmt.Errorf("error updating IP reservation: %w", err)
}

return resourceMetalReservedIPBlockRead(d, meta)
return resourceMetalReservedIPBlockRead(ctx, d, meta)
}

func reservedIPStateRefreshFunc(client *packngo.Client, reservedIPId string) retry.StateRefreshFunc {
Expand Down Expand Up @@ -454,7 +456,7 @@ func loadBlock(d *schema.ResourceData, reservedBlock *packngo.IPAddressReservati
return setMap(d, attributeMap)
}

func resourceMetalReservedIPBlockRead(d *schema.ResourceData, meta interface{}) error {
func resourceMetalReservedIPBlockRead(ctx context.Context, d *schema.ResourceData, meta interface{}) error {
meta.(*Config).addModuleToMetalUserAgent(d)
client := meta.(*Config).metal

Expand Down Expand Up @@ -485,7 +487,7 @@ func resourceMetalReservedIPBlockRead(d *schema.ResourceData, meta interface{})
return nil
}

func resourceMetalReservedIPBlockDelete(d *schema.ResourceData, meta interface{}) error {
func resourceMetalReservedIPBlockDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) error {
meta.(*Config).addModuleToMetalUserAgent(d)
client := meta.(*Config).metal

Expand Down
50 changes: 40 additions & 10 deletions equinix/resource_metal_reserved_ip_block_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package equinix
import (
"bytes"
"fmt"
"regexp"
"testing"
"text/template"

Expand All @@ -11,6 +12,10 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

var (
matchIpBlockErrTimeout = regexp.MustCompile(".* timeout while waiting for state to become 'created'.*")
)

func testAccMetalReservedIPBlockConfig_global(name string) string {
return fmt.Sprintf(`
resource "equinix_metal_project" "foobar" {
Expand All @@ -28,7 +33,11 @@ resource "equinix_metal_reserved_ip_block" "test" {
}`, name, name)
}

func testAccMetalReservedIPBlockConfig_public(name string) string {
func testAccMetalReservedIPBlockConfig_public(name, createTimeout string) string {
if createTimeout == "" {
createTimeout = "20m"
}

return fmt.Sprintf(`
resource "equinix_metal_project" "foobar" {
name = "tfacc-reserved_ip_block-%s"
Expand All @@ -41,7 +50,11 @@ resource "equinix_metal_reserved_ip_block" "test" {
description = "tfacc-reserved_ip_block-%s"
quantity = 2
tags = ["Tag1", "Tag2"]
}`, name, name)

timeouts {
create = "%s"
}
}`, name, name, createTimeout)
}

// testAccMetalReservedIPBlockConfig_metro generates a config for a metro IP
Expand Down Expand Up @@ -74,7 +87,7 @@ func TestAccMetalReservedIPBlock_global(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ExternalProviders: testExternalProviders,
Providers: testAccProviders,
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccMetalReservedIPBlockCheckDestroyed,
Steps: []resource.TestStep{
{
Expand Down Expand Up @@ -106,11 +119,11 @@ func TestAccMetalReservedIPBlock_public(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ExternalProviders: testExternalProviders,
Providers: testAccProviders,
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccMetalReservedIPBlockCheckDestroyed,
Steps: []resource.TestStep{
{
Config: testAccMetalReservedIPBlockConfig_public(rs),
Config: testAccMetalReservedIPBlockConfig_public(rs, ""),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"equinix_metal_reserved_ip_block.test", "facility", "ny5"),
Expand Down Expand Up @@ -141,7 +154,7 @@ func TestAccMetalReservedIPBlock_metro(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ExternalProviders: testExternalProviders,
Providers: testAccProviders,
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccMetalReservedIPBlockCheckDestroyed,
Steps: []resource.TestStep{
{
Expand Down Expand Up @@ -180,11 +193,11 @@ func TestAccMetalReservedIPBlock_importBasic(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ExternalProviders: testExternalProviders,
Providers: testAccProviders,
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccMetalReservedIPBlockCheckDestroyed,
Steps: []resource.TestStep{
{
Config: testAccMetalReservedIPBlockConfig_public(rs),
Config: testAccMetalReservedIPBlockConfig_public(rs, ""),
},
{
ResourceName: "equinix_metal_reserved_ip_block.test",
Expand Down Expand Up @@ -230,7 +243,7 @@ func TestAccMetalReservedIPBlock_facilityToMetro(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ExternalProviders: testExternalProviders,
Providers: testAccProviders,
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccMetalReservedIPBlockCheckDestroyed,
Steps: []resource.TestStep{
{
Expand Down Expand Up @@ -295,7 +308,7 @@ func TestAccMetalReservedIPBlock_device(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ExternalProviders: testExternalProviders,
Providers: testAccProviders,
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccMetalReservedIPBlockCheckDestroyed,
Steps: []resource.TestStep{
{
Expand All @@ -310,3 +323,20 @@ func TestAccMetalReservedIPBlock_device(t *testing.T) {
},
})
}

func TestAccMetalReservedIPBlockCreate_public_timeout(t *testing.T) {
rs := acctest.RandString(10)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ExternalProviders: testExternalProviders,
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccMetalReservedIPBlockCheckDestroyed,
Steps: []resource.TestStep{
{
Config: testAccMetalReservedIPBlockConfig_public(rs, "2s"),
ExpectError: matchIpBlockErrTimeout,
},
},
})
}