From 03493f86be439edb0f01f0ee31008263f7dd5105 Mon Sep 17 00:00:00 2001 From: thogarty <139183873+thogarty@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:22:17 -0700 Subject: [PATCH] feat: Route filter rules (#787) * Addition of: * data equinix_fabric_route_filter_rule * data equinix_fabric_route_filter_rules * equinix_fabric_route_filter_rule * Includes testing and documentation * Fixes typo for equinix_fabric_route_filter examples and docs --- docs/data-sources/fabric_route_filter.md | 2 +- docs/data-sources/fabric_route_filter_rule.md | 87 ++++++++ .../data-sources/fabric_route_filter_rules.md | 113 +++++++++++ docs/resources/fabric_route_filter.md | 2 +- docs/resources/fabric_route_filter_rule.md | 104 ++++++++++ equinix/provider.go | 4 + .../data-source.tf | 2 +- .../data-source.tf | 21 ++ .../data-source.tf | 21 ++ .../equinix_fabric_route_filter/resource.tf | 2 +- .../resource.tf | 23 +++ .../fabric/route_filter_rule/datasources.go | 81 ++++++++ .../route_filter_rule/datasources_schema.go | 156 +++++++++++++++ .../route_filter_rule/datasources_test.go | 79 ++++++++ .../fabric/route_filter_rule/models.go | 153 +++++++++++++++ .../fabric/route_filter_rule/resource.go | 185 ++++++++++++++++++ .../route_filter_rule/resource_schema.go | 99 ++++++++++ .../fabric/route_filter_rule/resource_test.go | 97 +++++++++ 18 files changed, 1227 insertions(+), 4 deletions(-) create mode 100644 docs/data-sources/fabric_route_filter_rule.md create mode 100644 docs/data-sources/fabric_route_filter_rules.md create mode 100644 docs/resources/fabric_route_filter_rule.md create mode 100644 examples/data-sources/equinix_fabric_route_filter_rule/data-source.tf create mode 100644 examples/data-sources/equinix_fabric_route_filter_rules/data-source.tf create mode 100644 examples/resources/equinix_fabric_route_filter_rule/resource.tf create mode 100644 internal/resources/fabric/route_filter_rule/datasources.go create mode 100644 internal/resources/fabric/route_filter_rule/datasources_schema.go create mode 100644 internal/resources/fabric/route_filter_rule/datasources_test.go create mode 100644 internal/resources/fabric/route_filter_rule/models.go create mode 100644 internal/resources/fabric/route_filter_rule/resource.go create mode 100644 internal/resources/fabric/route_filter_rule/resource_schema.go create mode 100644 internal/resources/fabric/route_filter_rule/resource_test.go diff --git a/docs/data-sources/fabric_route_filter.md b/docs/data-sources/fabric_route_filter.md index 2afd67acf..c4cb1bdd6 100644 --- a/docs/data-sources/fabric_route_filter.md +++ b/docs/data-sources/fabric_route_filter.md @@ -30,7 +30,7 @@ output "state" { } output "not_matched_rules_action" { - value = data.equinix_fabric_route_filter.rf_policy.not_matched_rules_action + value = data.equinix_fabric_route_filter.rf_policy.not_matched_rule_action } output "connections_count" { diff --git a/docs/data-sources/fabric_route_filter_rule.md b/docs/data-sources/fabric_route_filter_rule.md new file mode 100644 index 000000000..fd74f878e --- /dev/null +++ b/docs/data-sources/fabric_route_filter_rule.md @@ -0,0 +1,87 @@ +--- +subcategory: "Fabric" +--- + +# equinix_fabric_route_filter_rule (Data Source) + +Fabric V4 API compatible data resource that allow user to fetch route filter for a given UUID + +Additional Documentation: +* Getting Started: https://docs.equinix.com/en-us/Content/Interconnection/FCR/FCR-route-filters.htm +* API: https://developer.equinix.com/dev-docs/fabric/api-reference/fabric-v4-apis#route-filter-rules + +## Example Usage + +```terraform +data "equinix_fabric_route_filter_rule" "rf_rule" { + route_filter_id = "" + uuid = "" +} + +output "route_filter_rule_name" { + value = data.equinix_fabric_route_filter_rule.rf_rule.name +} + + +output "route_filter_rule_description" { + value = data.equinix_fabric_route_filter_rule.rf_rule.description +} + +output "route_filter_rule_prefix" { + value = data.equinix_fabric_route_filter_rule.rf_rule.prefix +} + +output "route_filter_rule_prefix_match" { + value = data.equinix_fabric_route_filter_rule.rf_rule.prefix_match +} +``` + + +## Schema + +### Required + +- `route_filter_id` (String) UUID of the Route Filter Policy the rule is attached to +- `uuid` (String) Equinix Assigned ID for Route Filter Rule to retrieve data for + +### Read-Only + +- `action` (String) Action that will be taken on IP Addresses matching the rule +- `change` (Set of Object) An object with the details of the previous change applied on the Route Filter (see [below for nested schema](#nestedatt--change)) +- `change_log` (Set of Object) (see [below for nested schema](#nestedatt--change_log)) +- `description` (String) Optional description to add to the Route Filter you will be creating +- `href` (String) Route filter rules URI +- `id` (String) The ID of this resource. +- `name` (String) Name of the Route Filter +- `prefix` (String) IP Address Prefix to Filter on +- `prefix_match` (String) Prefix matching operator. One of [ orlonger, exact ] Default: "orlonger" +- `state` (String) State of the Route Filter Rule in its lifecycle +- `type` (String) Route Filter Type. One of [ BGP_IPv4_PREFIX_FILTER_RULE, BGP_IPv6_PREFIX_FILTER_RULE ] + + +### Nested Schema for `change` + +Read-Only: + +- `href` (String) +- `type` (String) +- `uuid` (String) + + + +### Nested Schema for `change_log` + +Read-Only: + +- `created_by` (String) +- `created_by_email` (String) +- `created_by_full_name` (String) +- `created_date_time` (String) +- `deleted_by` (String) +- `deleted_by_email` (String) +- `deleted_by_full_name` (String) +- `deleted_date_time` (String) +- `updated_by` (String) +- `updated_by_email` (String) +- `updated_by_full_name` (String) +- `updated_date_time` (String) diff --git a/docs/data-sources/fabric_route_filter_rules.md b/docs/data-sources/fabric_route_filter_rules.md new file mode 100644 index 000000000..05ad9ec3a --- /dev/null +++ b/docs/data-sources/fabric_route_filter_rules.md @@ -0,0 +1,113 @@ +--- +subcategory: "Fabric" +--- + +# equinix_fabric_route_filter_rules (Data Source) + +Fabric V4 API compatible data resource that allow user to fetch route filter for a given search data set + +Additional Documentation: +* Getting Started: https://docs.equinix.com/en-us/Content/Interconnection/FCR/FCR-route-filters.htm +* API: https://developer.equinix.com/dev-docs/fabric/api-reference/fabric-v4-apis#route-filter-rules + +## Example Usage + +```terraform +data "equinix_fabric_route_filter_rules" "rf_rules" { + route_filter_id = " +## Schema + +### Required + +- `route_filter_id` (String) UUID of the Route Filter Policy the rule is attached to + +### Optional + +- `limit` (Number) Number of elements to be requested per page. Number must be between 1 and 100. Default is 20 +- `offset` (Number) The page offset for the pagination request. Index of the first element. Default is 0. + +### Read-Only + +- `data` (List of Object) The list of Rules attached to the given Route Filter Policy UUID (see [below for nested schema](#nestedatt--data)) +- `id` (String) The ID of this resource. +- `pagination` (Set of Object) Pagination details for the Data Source Search Request (see [below for nested schema](#nestedatt--pagination)) + + +### Nested Schema for `data` + +Read-Only: + +- `action` (String) +- `change` (Set of Object) (see [below for nested schema](#nestedobjatt--data--change)) +- `change_log` (Set of Object) (see [below for nested schema](#nestedobjatt--data--change_log)) +- `description` (String) +- `href` (String) +- `name` (String) +- `prefix` (String) +- `prefix_match` (String) +- `state` (String) +- `type` (String) +- `uuid` (String) + + +### Nested Schema for `data.change` + +Read-Only: + +- `href` (String) +- `type` (String) +- `uuid` (String) + + + +### Nested Schema for `data.change_log` + +Read-Only: + +- `created_by` (String) +- `created_by_email` (String) +- `created_by_full_name` (String) +- `created_date_time` (String) +- `deleted_by` (String) +- `deleted_by_email` (String) +- `deleted_by_full_name` (String) +- `deleted_date_time` (String) +- `updated_by` (String) +- `updated_by_email` (String) +- `updated_by_full_name` (String) +- `updated_date_time` (String) + + + + +### Nested Schema for `pagination` + +Read-Only: + +- `limit` (Number) +- `next` (String) +- `offset` (Number) +- `previous` (String) +- `total` (Number) diff --git a/docs/resources/fabric_route_filter.md b/docs/resources/fabric_route_filter.md index ad7a3462b..7109e5ef7 100644 --- a/docs/resources/fabric_route_filter.md +++ b/docs/resources/fabric_route_filter.md @@ -35,7 +35,7 @@ output "state" { } output "not_matched_rules_action" { - value = equinix_fabric_route_filter.rf_policy.not_matched_rules_action + value = equinix_fabric_route_filter.rf_policy.not_matched_rule_action } output "connections_count" { diff --git a/docs/resources/fabric_route_filter_rule.md b/docs/resources/fabric_route_filter_rule.md new file mode 100644 index 000000000..6f9594ae5 --- /dev/null +++ b/docs/resources/fabric_route_filter_rule.md @@ -0,0 +1,104 @@ +--- +subcategory: "Fabric" +--- + +# equinix_fabric_route_filter_rule (Resource) + +Fabric V4 API compatible resource allows creation and management of Equinix Fabric Route Filter Rule + +Additional Documentation: +* Getting Started: https://docs.equinix.com/en-us/Content/Interconnection/FCR/FCR-route-filters.htm +* API: https://developer.equinix.com/dev-docs/fabric/api-reference/fabric-v4-apis#route-filter-rules + +## Example Usage + +```terraform +resource "equinix_fabric_route_filter_rule" "rf_rule" { + route_filter_id = "" + name = "Route Filter Rule Name" + prefix = "192.168.0.0/24" + prefix_match = "exact" + description = "Route Filter Rule for X Purpose" +} + +output "route_filter_rule_id" { + value = equinix_fabric_route_filter_rule.rf_rule.id +} + +output "route_filter_id" { + value = equinix_fabric_route_filter_rule.rf_rule.route_filter_id +} + +output "route_filter_rule_prefix" { + value = equinix_fabric_route_filter_rule.rf_rule.prefix +} + +output "route_filter_rule_prefix_match" { + value = equinix_fabric_route_filter_rule.rf_rule.prefix_match +} +``` + + +## Schema + +### Required + +- `prefix` (String) IP Address Prefix to Filter on +- `route_filter_id` (String) UUID of the Route Filter Policy to apply this Rule to + +### Optional + +- `description` (String) Optional description to add to the Route Filter you will be creating +- `name` (String) Name of the Route Filter +- `prefix_match` (String) Prefix matching operator. One of [ orlonger, exact ] Default: "orlonger" +- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts)) + +### Read-Only + +- `action` (String) Action that will be taken on IP Addresses matching the rule +- `change` (Set of Object) An object with the details of the previous change applied on the Route Filter (see [below for nested schema](#nestedatt--change)) +- `change_log` (Set of Object) (see [below for nested schema](#nestedatt--change_log)) +- `href` (String) Route filter rules URI +- `id` (String) The ID of this resource. +- `state` (String) State of the Route Filter Rule in its lifecycle +- `type` (String) Route Filter Type. One of [ BGP_IPv4_PREFIX_FILTER_RULE, BGP_IPv6_PREFIX_FILTER_RULE ] +- `uuid` (String) Equinix Assigned ID for Route Filter Rule + + +### Nested Schema for `timeouts` + +Optional: + +- `create` (String) +- `delete` (String) +- `read` (String) +- `update` (String) + + + +### Nested Schema for `change` + +Read-Only: + +- `href` (String) +- `type` (String) +- `uuid` (String) + + + +### Nested Schema for `change_log` + +Read-Only: + +- `created_by` (String) +- `created_by_email` (String) +- `created_by_full_name` (String) +- `created_date_time` (String) +- `deleted_by` (String) +- `deleted_by_email` (String) +- `deleted_by_full_name` (String) +- `deleted_date_time` (String) +- `updated_by` (String) +- `updated_by_email` (String) +- `updated_by_full_name` (String) +- `updated_date_time` (String) diff --git a/equinix/provider.go b/equinix/provider.go index 72631a7df..b96780f49 100644 --- a/equinix/provider.go +++ b/equinix/provider.go @@ -11,6 +11,7 @@ import ( fabric_market_place_subscription "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/marketplace" fabric_network "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/network" fabric_route_filter "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/route_filter" + fabric_route_filter_rule "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/route_filter_rule" metal_device "github.com/equinix/terraform-provider-equinix/internal/resources/metal/device" metal_port "github.com/equinix/terraform-provider-equinix/internal/resources/metal/port" "github.com/equinix/terraform-provider-equinix/internal/resources/metal/virtual_circuit" @@ -94,6 +95,8 @@ func Provider() *schema.Provider { "equinix_fabric_ports": dataSourceFabricGetPortsByName(), "equinix_fabric_route_filter": fabric_route_filter.DataSource(), "equinix_fabric_route_filters": fabric_route_filter.DataSourceSearch(), + "equinix_fabric_route_filter_rule": fabric_route_filter_rule.DataSource(), + "equinix_fabric_route_filter_rules": fabric_route_filter_rule.DataSourceGetAllRules(), "equinix_fabric_service_profile": dataSourceFabricServiceProfileReadByUuid(), "equinix_fabric_service_profiles": dataSourceFabricSearchServiceProfilesByName(), "equinix_network_account": dataSourceNetworkAccount(), @@ -123,6 +126,7 @@ func Provider() *schema.Provider { "equinix_fabric_cloud_router": resourceFabricCloudRouter(), "equinix_fabric_connection": fabric_connection.Resource(), "equinix_fabric_route_filter": fabric_route_filter.Resource(), + "equinix_fabric_route_filter_rule": fabric_route_filter_rule.Resource(), "equinix_fabric_routing_protocol": resourceFabricRoutingProtocol(), "equinix_fabric_service_profile": resourceFabricServiceProfile(), "equinix_network_device": resourceNetworkDevice(), diff --git a/examples/data-sources/equinix_fabric_route_filter/data-source.tf b/examples/data-sources/equinix_fabric_route_filter/data-source.tf index ee09ce7f1..9352d7370 100644 --- a/examples/data-sources/equinix_fabric_route_filter/data-source.tf +++ b/examples/data-sources/equinix_fabric_route_filter/data-source.tf @@ -15,7 +15,7 @@ output "state" { } output "not_matched_rules_action" { - value = data.equinix_fabric_route_filter.rf_policy.not_matched_rules_action + value = data.equinix_fabric_route_filter.rf_policy.not_matched_rule_action } output "connections_count" { diff --git a/examples/data-sources/equinix_fabric_route_filter_rule/data-source.tf b/examples/data-sources/equinix_fabric_route_filter_rule/data-source.tf new file mode 100644 index 000000000..7547b59ec --- /dev/null +++ b/examples/data-sources/equinix_fabric_route_filter_rule/data-source.tf @@ -0,0 +1,21 @@ +data "equinix_fabric_route_filter_rule" "rf_rule" { + route_filter_id = "" + uuid = "" +} + +output "route_filter_rule_name" { + value = data.equinix_fabric_route_filter_rule.rf_rule.name +} + + +output "route_filter_rule_description" { + value = data.equinix_fabric_route_filter_rule.rf_rule.description +} + +output "route_filter_rule_prefix" { + value = data.equinix_fabric_route_filter_rule.rf_rule.prefix +} + +output "route_filter_rule_prefix_match" { + value = data.equinix_fabric_route_filter_rule.rf_rule.prefix_match +} diff --git a/examples/data-sources/equinix_fabric_route_filter_rules/data-source.tf b/examples/data-sources/equinix_fabric_route_filter_rules/data-source.tf new file mode 100644 index 000000000..db9ff316b --- /dev/null +++ b/examples/data-sources/equinix_fabric_route_filter_rules/data-source.tf @@ -0,0 +1,21 @@ +data "equinix_fabric_route_filter_rules" "rf_rules" { + route_filter_id = "= 400 && body.StatusCode <= 499 { + // Already deleted resource + return routeFilterRule, string(fabricv4.ROUTEFILTERRULESTATE_DEPROVISIONED), nil + } + return "", "", equinix_errors.FormatFabricError(err) + } + return routeFilterRule, string(routeFilterRule.GetState()), nil + }, + Timeout: timeout, + Delay: 30 * time.Second, + MinTimeout: 30 * time.Second, + } + + _, err := stateConf.WaitForStateContext(ctx) + + return err +} diff --git a/internal/resources/fabric/route_filter_rule/resource_schema.go b/internal/resources/fabric/route_filter_rule/resource_schema.go new file mode 100644 index 000000000..5a6b81f81 --- /dev/null +++ b/internal/resources/fabric/route_filter_rule/resource_schema.go @@ -0,0 +1,99 @@ +package route_filter_rule + +import ( + equinix_fabric_schema "github.com/equinix/terraform-provider-equinix/internal/fabric/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "route_filter_id": { + Type: schema.TypeString, + Required: true, + Description: "UUID of the Route Filter Policy to apply this Rule to", + }, + "prefix": { + Type: schema.TypeString, + Required: true, + Description: "IP Address Prefix to Filter on", + }, + "name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Name of the Route Filter", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Optional description to add to the Route Filter you will be creating", + }, + "prefix_match": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Prefix matching operator. One of [ orlonger, exact ] Default: \"orlonger\"", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Route Filter Type. One of [ BGP_IPv4_PREFIX_FILTER_RULE, BGP_IPv6_PREFIX_FILTER_RULE ] ", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "Route filter rules URI", + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + Description: "Equinix Assigned ID for Route Filter Rule", + }, + "state": { + Type: schema.TypeString, + Computed: true, + Description: "State of the Route Filter Rule in its lifecycle", + }, + "action": { + Type: schema.TypeString, + Computed: true, + Description: "Action that will be taken on IP Addresses matching the rule", + }, + "change": { + Type: schema.TypeSet, + Computed: true, + Description: "An object with the details of the previous change applied on the Route Filter", + Elem: changeSch(), + }, + "change_log": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: equinix_fabric_schema.ChangeLogSch(), + }, + }, + } +} + +func changeSch() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "href": { + Type: schema.TypeString, + Computed: true, + Description: "The URI of the previous Route Filter Rule Change", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Type of change. One of [ \"BGP_IPv4_PREFIX_FILTER_RULE_UPDATE\",\"BGP_IPv4_PREFIX_FILTER_RULE_CREATION\",\"BGP_IPv4_PREFIX_FILTER_RULE_DELETION\",\"BGP_IPv6_PREFIX_FILTER_RULE_UPDATE\",\"BGP_IPv6_PREFIX_FILTER_RULE_CREATION\",\"BGP_IPv6_PREFIX_FILTER_RULE_DELETION\" ]", + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + Description: "Unique identifier for the previous change", + }, + }, + } +} diff --git a/internal/resources/fabric/route_filter_rule/resource_test.go b/internal/resources/fabric/route_filter_rule/resource_test.go new file mode 100644 index 000000000..405d86e11 --- /dev/null +++ b/internal/resources/fabric/route_filter_rule/resource_test.go @@ -0,0 +1,97 @@ +package route_filter_rule_test + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/equinix/terraform-provider-equinix/internal/acceptance" + "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/route_filter_rule" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func TestAccFabricRouteFilterRule_PFCR(t *testing.T) { + routeFilterRuleName, routeFilterRuleUpdatedName := "RF_Rule_PFCR", "RF_RuleB_PFCR" + routeFilterRulePrefix, routeFilterRulePrefixUpdated := "192.168.0.0/24", "192.172.0.0/24" + routeFilterRuleDescription := "Route Filter Rule for X Purpose" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.TestAccPreCheck(t); acceptance.TestAccPreCheckProviderConfigured(t) }, + Providers: acceptance.TestAccProviders, + CheckDestroy: CheckRouteFilterRuleDelete, + Steps: []resource.TestStep{ + { + Config: testAccFabricRouteFilterRuleConfig(routeFilterRuleName, routeFilterRulePrefix), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("equinix_fabric_route_filter_rule.test", "id"), + resource.TestCheckResourceAttr( + "equinix_fabric_route_filter_rule.test", "name", routeFilterRuleName), + resource.TestCheckResourceAttr( + "equinix_fabric_route_filter_rule.test", "prefix", routeFilterRulePrefix), + resource.TestCheckResourceAttr( + "equinix_fabric_route_filter_rule.test", "prefix_match", "exact"), + resource.TestCheckResourceAttr( + "equinix_fabric_route_filter_rule.test", "description", routeFilterRuleDescription), + ), + ExpectNonEmptyPlan: false, + }, + { + Config: testAccFabricRouteFilterRuleConfig(routeFilterRuleUpdatedName, routeFilterRulePrefixUpdated), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("equinix_fabric_route_filter_rule.test", "id"), + resource.TestCheckResourceAttr( + "equinix_fabric_route_filter_rule.test", "name", routeFilterRuleUpdatedName), + resource.TestCheckResourceAttr( + "equinix_fabric_route_filter_rule.test", "prefix", routeFilterRulePrefixUpdated), + resource.TestCheckResourceAttr( + "equinix_fabric_route_filter_rule.test", "prefix_match", "exact"), + resource.TestCheckResourceAttr( + "equinix_fabric_route_filter_rule.test", "description", routeFilterRuleDescription), + ), + ExpectNonEmptyPlan: false, + }, + }, + }) + +} + +func testAccFabricRouteFilterRuleConfig(policyName, policyPrefix string) string { + return fmt.Sprintf(` + resource "equinix_fabric_route_filter" "test" { + name = "rf_test_PFCR" + project { + project_id = "291639000636552" + } + type = "BGP_IPv4_PREFIX_FILTER" + description = "Route Filter Policy for X Purpose" + } + + resource "equinix_fabric_route_filter_rule" "test" { + route_filter_id = equinix_fabric_route_filter.test.id + name = "%s" + prefix = "%s" + prefix_match = "exact" + description = "Route Filter Rule for X Purpose" + } + `, policyName, policyPrefix) +} + +func CheckRouteFilterRuleDelete(s *terraform.State) error { + ctx := context.Background() + for _, rs := range s.RootModule().Resources { + if rs.Type != "equinix_fabric_route_filter_rule" { + continue + } + + routeFilterId := rs.Primary.Attributes["route_filter_id"] + + err := route_filter_rule.WaitForDeletion(routeFilterId, rs.Primary.ID, acceptance.TestAccProvider.Meta(), &schema.ResourceData{}, ctx, 10*time.Minute) + if err != nil { + return fmt.Errorf("API call failed while waiting for resource deletion") + } + } + return nil +}