Skip to content

Commit

Permalink
Add Delayed Deletion Hours parameter to Vmwareengine Private Cloud
Browse files Browse the repository at this point in the history
  • Loading branch information
swamitagupta committed Jun 14, 2024
1 parent 7f7c253 commit a8b6b8c
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 45 deletions.
12 changes: 10 additions & 2 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 @@ -49,7 +49,9 @@ custom_code: !ruby/object:Provider::Terraform::CustomCode
decoder: "templates/terraform/decoders/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
constants: templates/terraform/constants/vmwareengine_private_cloud.go.erb
pre_create: templates/terraform/pre_create/vmwareengine_private_cloud.go.erb
pre_delete: templates/terraform/pre_delete/vmwareengine_private_cloud.go.erb
examples:
- !ruby/object:Provider::Terraform::Examples
name: "vmware_engine_private_cloud_basic"
Expand Down Expand Up @@ -89,6 +91,12 @@ parameters:
url_param_only: true
description: |
The ID of the PrivateCloud.
- !ruby/object:Api::Type::Integer
name: "deletionDelayHours"
url_param_only: true
ignore_read: true
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.
properties:
- !ruby/object:Api::Type::String
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
func isPrivateCloudInDeletedState(config *transport_tpg.Config, d *schema.ResourceData, billingProject string, userAgent string) (bool, error) {
baseurl, err := tpgresource.ReplaceVars(d, config, "{{<%=object.__product.name-%>BasePath}}<%=object.self_link_uri-%>")
if err != nil {
return false, err
}
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "GET",
Project: billingProject,
RawURL: baseurl,
UserAgent: userAgent,
})
// if resource does not exist
if err != nil {
log.Printf("[DEBUG] The Private cloud does not exist.")
return false, nil
}
// if resource exists but is marked for deletion
v, ok := res["state"]
if ok && v.(string) == "DELETED" {
log.Printf("[DEBUG] The Private cloud exists and is marked for deletion.")
return true, nil
}
return false, nil
}

func vmwareenginePrivateCloudStandardTypeDiffSuppressFunc(_, old, new string, _ *schema.ResourceData) bool {
if (old == "STANDARD" && new == "") || (old == "" && new == "STANDARD") {
return true
}
return false
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ resource "google_vmwareengine_private_cloud" "<%= ctx[:primary_resource_id] %>"
custom_core_count = 32
}
}
deletion_delay_hours = 4
}

resource "google_vmwareengine_network" "pc-nw" {
Expand Down
9 changes: 9 additions & 0 deletions mmv1/templates/terraform/post_delete/private_cloud.go.erb
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,18 @@ privateCloudPollRead := func(d *schema.ResourceData, meta interface{}) transport
RawURL: url,
UserAgent: userAgent,
})
// if resource does not exist
if err != nil {
log.Printf("[DEBUG] The Private cloud has been successfully deleted.")
return res, err
}
// if resource exists but is marked for deletion
v, ok := res["state"]
if ok && v.(string) == "DELETED" {
log.Printf("[DEBUG] The Private cloud has been successfully marked for delayed deletion.")
return res, errors.New("PrivateCloud is marked for deletion")
}
// if resource exists
return res, nil
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Check if the project exists in a deleted state
pcMarkedForDeletion, err := isPrivateCloudInDeletedState(config, d, billingProject, userAgent)
if err != nil {
return fmt.Errorf("Error checking if Private Cloud exists and is marked for deletion: %s", err)
}
if pcMarkedForDeletion {
log.Printf("[DEBUG] Private Cloud exists and is marked for deletion. Triggering undelete of the Private Cloud.\n")
url = url + ":undelete"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Delay deletion of the Private Cloud if delationDelayHours value is set
if deletionDelayHours := d.Get("deletionDelayHours"); deletionDelayHours != "" {
log.Printf("[DEBUG] Triggering delete of the Private Cloud with a delay of %v hours.\n", deletionDelayHours)
url = url + "?delay_hours=" + fmt.Sprintf("%v", deletionDelayHours)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package vmwareengine_test

import (
"fmt"
"log"
"strings"
"testing"

Expand All @@ -18,7 +19,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,7 +34,7 @@ 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": {}}),
testAccCheckGoogleVmwareengineNsxCredentialsMeta("data.google_vmwareengine_nsx_credentials.nsx-ds"),
Expand All @@ -47,16 +48,33 @@ func TestAccVmwareenginePrivateCloud_vmwareEnginePrivateCloudUpdate(t *testing.T
ImportStateVerifyIgnore: []string{"location", "name", "update_time", "type"},
},
{
Config: testPrivateCloudUpdateConfig(context, "description2", 4), // Expand 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": {}}),
),
},
{
ResourceName: "google_vmwareengine_private_cloud.vmw-engine-pc",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"location", "name", "update_time", "type"},
},

{
Config: testPrivateCloudUpdateConfig(context, "description2", 3), // Shrink PC
Config: testPrivateCloudDelayedDeleteConfig(context),
},
{
ResourceName: "google_vmwareengine_network.default-nw",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"location", "name"},
},

{
Config: testPrivateCloudUndeleteConfig(context),
Check: resource.ComposeTestCheckFunc(
acctest.CheckDataSourceStateMatchesResourceStateWithIgnores("data.google_vmwareengine_private_cloud.ds", "google_vmwareengine_private_cloud.vmw-engine-pc", map[string]struct{}{"type": {}}),
),
},
{
ResourceName: "google_vmwareengine_private_cloud.vmw-engine-pc",
Expand All @@ -68,46 +86,68 @@ func TestAccVmwareenginePrivateCloud_vmwareEnginePrivateCloudUpdate(t *testing.T
})
}

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_vmwareengine_network" "default-nw" {
name = "tf-test-pc-nw-%{random_suffix}"
location = "global"
type = "STANDARD"
description = "PC network description."
}
resource "google_project_service" "vmwareengine" {
project = google_project.project.project_id
service = "vmwareengine.googleapis.com"
resource "google_vmwareengine_private_cloud" "vmw-engine-pc" {
location = "%{region}-b"
name = "tf-test-sample-pc%{random_suffix}"
description = "test description"
type = "TIME_LIMITED"
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 = "1"
custom_core_count = 32
}
}
}
resource "time_sleep" "sleep" {
create_duration = "1m"
depends_on = [
google_project_service.vmwareengine,
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,
]
}
# NSX and Vcenter Credentials are child datasources of PC and are included in the PC test due to the high deployment time involved in the Creation and deletion of a PC
data "google_vmwareengine_nsx_credentials" "nsx-ds" {
parent = google_vmwareengine_private_cloud.vmw-engine-pc.id
}
data "google_vmwareengine_vcenter_credentials" "vcenter-ds" {
parent = google_vmwareengine_private_cloud.vmw-engine-pc.id
}
`, context)
}

func testPrivateCloudUpdateConfig(context map[string]interface{}) string {
return acctest.Nprintf(`
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 = "updated description"
deletion_delay_hours = 1
type = "TIME_LIMITED"
network_config {
management_cidr = "192.168.30.0/24"
Expand All @@ -117,30 +157,68 @@ 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 = "3"
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,
]
}
`, context)
}

# NSX and Vcenter Credentials are child datasources of PC and are included in the PC test due to the high deployment time involved in the Creation and deletion of a PC
data "google_vmwareengine_nsx_credentials" "nsx-ds" {
parent = google_vmwareengine_private_cloud.vmw-engine-pc.id
func testPrivateCloudDelayedDeleteConfig(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."
}
`, context)
}

data "google_vmwareengine_vcenter_credentials" "vcenter-ds" {
parent = google_vmwareengine_private_cloud.vmw-engine-pc.id
func testPrivateCloudUndeleteConfig(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 = "TIME_LIMITED"
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)
}

Expand Down Expand Up @@ -198,16 +276,25 @@ 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 {
if err != nil {
log.Printf("[DEBUG] The Private cloud has been successfully deleted.")
return nil
}
v, ok := res["state"]
if !ok {
return fmt.Errorf("Unable to fetch state for existing VmwareenginePrivateCloud %s", url)
}
if err == nil || v.(string) != "DELETED" {
return fmt.Errorf("VmwareenginePrivateCloud still exists at %s", url)
}
log.Printf("[DEBUG] The Private cloud has been successfully marked for delayed deletion.")
}
return nil
}
Expand Down

0 comments on commit a8b6b8c

Please sign in to comment.