Skip to content

Commit

Permalink
Support Delayed Deletion for Vmwareengine Private Cloud (GoogleCloudP…
Browse files Browse the repository at this point in the history
  • Loading branch information
swamitagupta authored and pcostell committed Jul 16, 2024
1 parent c8f8065 commit 32eebe8
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 61 deletions.
17 changes: 14 additions & 3 deletions mmv1/products/vmwareengine/PrivateCloud.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
name: 'PrivateCloud'
base_url: 'projects/{{project}}/locations/{{location}}/privateClouds'
self_link: 'projects/{{project}}/locations/{{location}}/privateClouds/{{name}}'
delete_url: 'projects/{{project}}/locations/{{location}}/privateClouds/{{name}}?delay_hours=0'
delete_url: 'projects/{{project}}/locations/{{location}}/privateClouds/{{name}}'
create_url: 'projects/{{project}}/locations/{{location}}/privateClouds?privateCloudId={{name}}'
update_verb: :PATCH
references: !ruby/object:Api::Resource::ReferenceLinks
Expand Down Expand Up @@ -45,11 +45,12 @@ async: !ruby/object:Api::OpAsync
import_format: ["projects/{{project}}/locations/{{location}}/privateClouds/{{name}}"]
autogen_async: true
custom_code: !ruby/object:Provider::Terraform::CustomCode
post_delete: "templates/terraform/post_delete/private_cloud.go.erb"
constants: templates/terraform/constants/vmwareengine_private_cloud.go.erb
decoder: "templates/terraform/decoders/private_cloud.go.erb"
pre_delete: templates/terraform/pre_delete/vmwareengine_private_cloud.go.erb
post_delete: "templates/terraform/post_delete/private_cloud.go.erb"
post_update: "templates/terraform/post_update/private_cloud.go.erb"
update_encoder: "templates/terraform/update_encoder/private_cloud.go.erb"
constants: templates/terraform/constants/vmwareengine_private_cloud_type.go.erb
examples:
- !ruby/object:Provider::Terraform::Examples
name: "vmware_engine_private_cloud_basic"
Expand Down Expand Up @@ -90,6 +91,16 @@ parameters:
description: |
The ID of the PrivateCloud.
virtual_fields:
- !ruby/object:Api::Type::Integer
name: "deletion_delay_hours"
description: |
The number of hours to delay this request. You can set this value to an hour between 0 to 8, where setting it to 0 starts the deletion request immediately. If no value is set, a default value is set at the API Level.
- !ruby/object:Api::Type::Boolean
name: "send_deletion_delay_hours_if_zero"
description: |
While set true, deletion_delay_hours value will be sent in the request even for zero value of the field. This field is only useful for setting 0 value to the deletion_delay_hours field. It can be used both alone and together with deletion_delay_hours.
properties:
- !ruby/object:Api::Type::String
name: 'description'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
func vmwareenginePrivateCloudStandardTypeDiffSuppressFunc(_, old, new string, d *schema.ResourceData) bool {
if (old == "STANDARD" && new == "") || (old == "" && new == "STANDARD") {
return true
}
if (isMultiNodePrivateCloud(d) && old == "TIME_LIMITED" && new == "STANDARD") {
log.Printf("[DEBUG] Multinode Private Cloud found, facilitating TYPE change to STANDARD")
return true
}
return false
}

func isMultiNodePrivateCloud(d *schema.ResourceData) bool {
nodeConfigMap := d.Get("management_cluster.0.node_type_configs").(*schema.Set).List()
totalNodeCount := 0
for _, nodeConfig := range nodeConfigMap {
configMap, ok := nodeConfig.(map[string]interface{})
if !ok {
log.Printf("[DEBUG] Invalid node configuration format for private cloud.")
continue
}
nodeCount, ok := configMap["node_count"].(int)
if !ok {
log.Printf("[DEBUG] Invalid node_count format for private cloud.")
continue
}
totalNodeCount += nodeCount
}
log.Printf("[DEBUG] The node count of the private cloud is found to be %v nodes.", totalNodeCount)
if totalNodeCount > 2 {
return true
}
return false
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ resource "google_vmwareengine_private_cloud" "<%= ctx[:primary_resource_id] %>"
management_cidr = "192.168.30.0/24"
vmware_engine_network = google_vmwareengine_network.pc-nw.id
}

management_cluster {
cluster_id = "<%= ctx[:vars]['management_cluster_id'] %>"
node_type_configs {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ resource "google_vmwareengine_private_cloud" "<%= ctx[:primary_resource_id] %>"
management_cidr = "192.168.30.0/24"
vmware_engine_network = google_vmwareengine_network.pc-nw.id
}

management_cluster {
cluster_id = "<%= ctx[:vars]['management_cluster_id'] %>"
node_type_configs {
Expand All @@ -16,6 +15,8 @@ resource "google_vmwareengine_private_cloud" "<%= ctx[:primary_resource_id] %>"
custom_core_count = 32
}
}
deletion_delay_hours = 0
send_deletion_delay_hours_if_zero = true
}

resource "google_vmwareengine_network" "pc-nw" {
Expand Down
7 changes: 7 additions & 0 deletions mmv1/templates/terraform/post_delete/private_cloud.go.erb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ privateCloudPollRead := func(d *schema.ResourceData, meta interface{}) transport
if err != nil {
return res, err
}
// if resource exists but is marked for deletion
log.Printf("[DEBUG] Fetching state of the private cloud.")
v, ok := res["state"]
if ok && v.(string) == "DELETED" {
log.Printf("[DEBUG] The Private cloud has been successfully marked for delayed deletion.")
return nil, nil
}
return res, nil
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Delay deletion of the Private Cloud if delationDelayHours value is set
delationDelayHours := d.Get("deletion_delay_hours").(int)
if delationDelayHours > 0 || (delationDelayHours == 0 && d.Get("send_deletion_delay_hours_if_zero").(bool) == true) {
log.Printf("[DEBUG] Triggering delete of the Private Cloud with a delay of %v hours.\n", delationDelayHours)
url = url + "?delay_hours=" + fmt.Sprintf("%v", delationDelayHours)
} else {
log.Printf("[DEBUG] No deletion delay provided, triggering DELETE API without setting delay hours.\n")
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
)

func TestAccVmwareengineExternalAccessRule_vmwareEngineExternalAccessRuleUpdate(t *testing.T) {
// Temporarily skipping so that this test does not run and consume resources during PR pushes. It is bound to fail and is being fixed by PR #10992
acctest.SkipIfVcr(t)
t.Parallel()

context := map[string]interface{}{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
)

func TestAccVmwareengineExternalAddress_vmwareEngineExternalAddressUpdate(t *testing.T) {
// Temporarily skipping so that this test does not run and consume resources during PR pushes. It is bound to fail and is being fixed by PR #10992
acctest.SkipIfVcr(t)
t.Parallel()

context := map[string]interface{}{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestAccVmwareenginePrivateCloud_vmwareEnginePrivateCloudUpdate(t *testing.T
t.Parallel()

context := map[string]interface{}{
"region": "southamerica-west1",
"region": "me-west1",
"random_suffix": acctest.RandString(t, 10),
"org_id": envvar.GetTestOrgFromEnv(t),
"billing_account": envvar.GetTestBillingAccountFromEnv(t),
Expand All @@ -33,82 +33,66 @@ func TestAccVmwareenginePrivateCloud_vmwareEnginePrivateCloudUpdate(t *testing.T
CheckDestroy: testAccCheckVmwareenginePrivateCloudDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testPrivateCloudUpdateConfig(context, "description1", 1),
Config: testPrivateCloudCreateConfig(context),
Check: resource.ComposeTestCheckFunc(
acctest.CheckDataSourceStateMatchesResourceStateWithIgnores("data.google_vmwareengine_private_cloud.ds", "google_vmwareengine_private_cloud.vmw-engine-pc", map[string]struct{}{"type": {}}),
acctest.CheckDataSourceStateMatchesResourceStateWithIgnores(
"data.google_vmwareengine_private_cloud.ds",
"google_vmwareengine_private_cloud.vmw-engine-pc",
map[string]struct{}{
"type": {},
"deletion_delay_hours": {},
"send_deletion_delay_hours_if_zero": {},
}),
testAccCheckGoogleVmwareengineNsxCredentialsMeta("data.google_vmwareengine_nsx_credentials.nsx-ds"),
testAccCheckGoogleVmwareengineVcenterCredentialsMeta("data.google_vmwareengine_vcenter_credentials.vcenter-ds"),
),
},

{
ResourceName: "google_vmwareengine_private_cloud.vmw-engine-pc",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"location", "name", "update_time", "type"},
},
{
Config: testPrivateCloudUpdateConfig(context, "description2", 4), // Expand PC
},
{
ResourceName: "google_vmwareengine_private_cloud.vmw-engine-pc",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"location", "name", "update_time", "type"},
ImportStateVerifyIgnore: []string{"location", "name", "update_time", "type", "deletion_parameters"},
},
{
Config: testPrivateCloudUpdateConfig(context, "description2", 3), // Shrink PC
Config: testPrivateCloudUpdateConfig(context),
Check: resource.ComposeTestCheckFunc(
acctest.CheckDataSourceStateMatchesResourceStateWithIgnores(
"data.google_vmwareengine_private_cloud.ds",
"google_vmwareengine_private_cloud.vmw-engine-pc",
map[string]struct{}{
"type": {},
"deletion_delay_hours": {},
"send_deletion_delay_hours_if_zero": {},
}),
),
},

{
ResourceName: "google_vmwareengine_private_cloud.vmw-engine-pc",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"location", "name", "update_time", "type"},
ImportStateVerifyIgnore: []string{"location", "name", "update_time", "type", "deletion_parameters"},
},
},
})
}

func testPrivateCloudUpdateConfig(context map[string]interface{}, description string, nodeCount int) string {
context["node_count"] = nodeCount
context["description"] = description

func testPrivateCloudCreateConfig(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_project" "project" {
project_id = "tf-test%{random_suffix}"
name = "tf-test%{random_suffix}"
org_id = "%{org_id}"
billing_account = "%{billing_account}"
}
resource "google_project_service" "vmwareengine" {
project = google_project.project.project_id
service = "vmwareengine.googleapis.com"
}
resource "time_sleep" "sleep" {
create_duration = "1m"
depends_on = [
google_project_service.vmwareengine,
]
}
resource "google_vmwareengine_network" "default-nw" {
project = google_project.project.project_id
name = "tf-test-pc-nw-%{random_suffix}"
location = "global"
type = "STANDARD"
description = "PC network description."
depends_on = [
time_sleep.sleep # Sleep allows permissions in the new project to propagate
]
}
resource "google_vmwareengine_private_cloud" "vmw-engine-pc" {
project = google_project.project.project_id
location = "%{region}-a"
location = "%{region}-b"
name = "tf-test-sample-pc%{random_suffix}"
description = "%{description}"
description = "test description"
type = "TIME_LIMITED"
deletion_delay_hours = 1
network_config {
management_cidr = "192.168.30.0/24"
vmware_engine_network = google_vmwareengine_network.default-nw.id
Expand All @@ -117,15 +101,14 @@ resource "google_vmwareengine_private_cloud" "vmw-engine-pc" {
cluster_id = "tf-test-sample-mgmt-cluster-custom-core-count%{random_suffix}"
node_type_configs {
node_type_id = "standard-72"
node_count = "%{node_count}"
node_count = 1
custom_core_count = 32
}
}
}
data "google_vmwareengine_private_cloud" "ds" {
project = google_project.project.project_id
location = "%{region}-a"
location = "%{region}-b"
name = "tf-test-sample-pc%{random_suffix}"
depends_on = [
google_vmwareengine_private_cloud.vmw-engine-pc,
Expand All @@ -144,6 +127,46 @@ data "google_vmwareengine_vcenter_credentials" "vcenter-ds" {
`, context)
}

func testPrivateCloudUpdateConfig(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_vmwareengine_network" "default-nw" {
name = "tf-test-pc-nw-%{random_suffix}"
location = "global"
type = "STANDARD"
description = "PC network description."
}
resource "google_vmwareengine_private_cloud" "vmw-engine-pc" {
location = "%{region}-b"
name = "tf-test-sample-pc%{random_suffix}"
description = "updated description"
type = "STANDARD"
deletion_delay_hours = 0
send_deletion_delay_hours_if_zero = true
network_config {
management_cidr = "192.168.30.0/24"
vmware_engine_network = google_vmwareengine_network.default-nw.id
}
management_cluster {
cluster_id = "tf-test-sample-mgmt-cluster-custom-core-count%{random_suffix}"
node_type_configs {
node_type_id = "standard-72"
node_count = 3
custom_core_count = 32
}
}
}
data "google_vmwareengine_private_cloud" "ds" {
location = "%{region}-b"
name = "tf-test-sample-pc%{random_suffix}"
depends_on = [
google_vmwareengine_private_cloud.vmw-engine-pc,
]
}
`, context)
}

func testAccCheckGoogleVmwareengineNsxCredentialsMeta(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
Expand Down Expand Up @@ -198,15 +221,21 @@ func testAccCheckVmwareenginePrivateCloudDestroyProducer(t *testing.T) func(s *t
if config.BillingProject != "" {
billingProject = config.BillingProject
}
_, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "GET",
Project: billingProject,
RawURL: url,
UserAgent: config.UserAgent,
})
if err == nil {
return fmt.Errorf("VmwareenginePrivateCloud still exists at %s", url)
pcState, ok := res["state"]
if !ok {
return fmt.Errorf("Unable to fetch state for existing VmwareenginePrivateCloud %s", url)
}
if pcState.(string) != "DELETED" {
return fmt.Errorf("VmwareenginePrivateCloud still exists at %s", url)
}
}
}
return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
)

func TestAccVmwareengineSubnet_vmwareEngineUserDefinedSubnetUpdate(t *testing.T) {
// Temporarily skipping so that this test does not run and consume resources during PR pushes. It is bound to fail and is being fixed by PR #10992
acctest.SkipIfVcr(t)
t.Parallel()

context := map[string]interface{}{
Expand Down

0 comments on commit 32eebe8

Please sign in to comment.