Skip to content

Commit f41d0e6

Browse files
Add continuousBackupConfig and continuousBackupInfo to AlloyDB cluster (#8406) (#5996)
* Properly handle ABP midnight (hours = 0) * Add ExpectNonEmptyPlan to test * Add continuous backup config to alloydb cluster * add more unit tests * Adding more tests * Fix cluster.yaml lint * Add default value and update cmek test * Update test to use kms key bootstrapping util * condense update tests * Change encryptionType output field to string * use two different keys * Only update encryption in CBR Signed-off-by: Modular Magician <[email protected]>
1 parent 5fbd723 commit f41d0e6

File tree

5 files changed

+723
-9
lines changed

5 files changed

+723
-9
lines changed

.changelog/8406.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
AlloyDB: added `continuous_backup_config` and `continuous_backup_info` fields to `cluster` resource
3+
```

google-beta/resource_alloydb_cluster_generated_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ resource "google_alloydb_cluster" "full" {
108108
password = "tf-test-alloydb-cluster-full%{random_suffix}"
109109
}
110110
111+
continuous_backup_config {
112+
enabled = true
113+
recovery_window_days = 14
114+
}
115+
111116
automated_backup_policy {
112117
location = "us-central1"
113118
backup_window = "1800s"

google-beta/resource_alloydb_cluster_test.go

Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,3 +739,358 @@ resource "google_kms_crypto_key_iam_binding" "crypto_key2" {
739739
}
740740
`, context)
741741
}
742+
743+
// Validates continuous backups defaults to being enabled with 14d retention, even if not explicitly configured.
744+
func TestAccAlloydbCluster_continuousBackup_enabledByDefault(t *testing.T) {
745+
t.Parallel()
746+
747+
context := map[string]interface{}{
748+
"random_suffix": acctest.RandString(t, 10),
749+
}
750+
751+
acctest.VcrTest(t, resource.TestCase{
752+
PreCheck: func() { acctest.AccTestPreCheck(t) },
753+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
754+
CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t),
755+
Steps: []resource.TestStep{
756+
{
757+
Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context),
758+
Check: resource.ComposeTestCheckFunc(
759+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"),
760+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"),
761+
),
762+
},
763+
{
764+
ResourceName: "google_alloydb_cluster.default",
765+
ImportState: true,
766+
ImportStateVerify: true,
767+
ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"},
768+
},
769+
{
770+
Config: testAccAlloydbCluster_alloydbClusterBasicExample(context),
771+
},
772+
},
773+
})
774+
}
775+
776+
// Continuous backups defaults to being enabled with 14d retention. If the same configuration is set explicitly, terraform plan
777+
// should return no changes.
778+
func TestAccAlloydbCluster_continuousBackup_update_noChangeIfDefaultsSet(t *testing.T) {
779+
t.Parallel()
780+
781+
context := map[string]interface{}{
782+
"random_suffix": acctest.RandString(t, 10),
783+
"enabled": true,
784+
"recovery_window_days": 14,
785+
}
786+
787+
acctest.VcrTest(t, resource.TestCase{
788+
PreCheck: func() { acctest.AccTestPreCheck(t) },
789+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
790+
CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t),
791+
Steps: []resource.TestStep{
792+
{
793+
Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context),
794+
Check: resource.ComposeTestCheckFunc(
795+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"),
796+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"),
797+
),
798+
},
799+
{
800+
ResourceName: "google_alloydb_cluster.default",
801+
ImportState: true,
802+
ImportStateVerify: true,
803+
ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"},
804+
},
805+
{
806+
Config: testAccAlloydbCluster_continuousBackupConfig(context),
807+
Check: resource.ComposeTestCheckFunc(
808+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"),
809+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"),
810+
),
811+
},
812+
{
813+
ResourceName: "google_alloydb_cluster.default",
814+
ImportState: true,
815+
ImportStateVerify: true,
816+
ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"},
817+
},
818+
{
819+
Config: testAccAlloydbCluster_alloydbClusterBasicExample(context),
820+
},
821+
},
822+
})
823+
}
824+
825+
// This test ensures that if you start with a terraform configuration where continuous backups are explicitly set to the default configuration
826+
// and then remove continuous backups and call terraform plan, no changes would be found.
827+
func TestAccAlloydbCluster_continuousBackup_noChangeIfRemoved(t *testing.T) {
828+
t.Parallel()
829+
830+
context := map[string]interface{}{
831+
"random_suffix": acctest.RandString(t, 10),
832+
"enabled": true,
833+
"recovery_window_days": 14,
834+
}
835+
836+
acctest.VcrTest(t, resource.TestCase{
837+
PreCheck: func() { acctest.AccTestPreCheck(t) },
838+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
839+
CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t),
840+
Steps: []resource.TestStep{
841+
{
842+
Config: testAccAlloydbCluster_continuousBackupConfig(context),
843+
Check: resource.ComposeTestCheckFunc(
844+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"),
845+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"),
846+
),
847+
},
848+
{
849+
ResourceName: "google_alloydb_cluster.default",
850+
ImportState: true,
851+
ImportStateVerify: true,
852+
ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"},
853+
},
854+
{
855+
Config: testAccAlloydbCluster_alloydbClusterBasicExample(context),
856+
Check: resource.ComposeTestCheckFunc(
857+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"),
858+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"),
859+
),
860+
},
861+
},
862+
})
863+
}
864+
865+
// Ensures changes to the continuous backup config properly applies
866+
func TestAccAlloydbCluster_continuousBackup_update(t *testing.T) {
867+
t.Parallel()
868+
869+
suffix := acctest.RandString(t, 10)
870+
context := map[string]interface{}{
871+
"random_suffix": suffix,
872+
"enabled": true,
873+
"recovery_window_days": 15,
874+
}
875+
context2 := map[string]interface{}{
876+
"random_suffix": suffix,
877+
"enabled": false,
878+
"recovery_window_days": 14,
879+
}
880+
881+
acctest.VcrTest(t, resource.TestCase{
882+
PreCheck: func() { acctest.AccTestPreCheck(t) },
883+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
884+
CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t),
885+
Steps: []resource.TestStep{
886+
{
887+
Config: testAccAlloydbCluster_withoutContinuousBackupConfig(context),
888+
Check: resource.ComposeTestCheckFunc(
889+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"),
890+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"),
891+
),
892+
},
893+
{
894+
ResourceName: "google_alloydb_cluster.default",
895+
ImportState: true,
896+
ImportStateVerify: true,
897+
ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"},
898+
},
899+
{
900+
Config: testAccAlloydbCluster_continuousBackupConfig(context),
901+
Check: resource.ComposeTestCheckFunc(
902+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "true"),
903+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "15"),
904+
),
905+
},
906+
{
907+
ResourceName: "google_alloydb_cluster.default",
908+
ImportState: true,
909+
ImportStateVerify: true,
910+
ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"},
911+
},
912+
{
913+
Config: testAccAlloydbCluster_continuousBackupConfig(context2),
914+
Check: resource.ComposeTestCheckFunc(
915+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.enabled", "false"),
916+
resource.TestCheckResourceAttr("google_alloydb_cluster.default", "continuous_backup_config.0.recovery_window_days", "14"),
917+
),
918+
},
919+
{
920+
ResourceName: "google_alloydb_cluster.default",
921+
ImportState: true,
922+
ImportStateVerify: true,
923+
ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"},
924+
},
925+
{
926+
Config: testAccAlloydbCluster_alloydbClusterBasicExample(context),
927+
},
928+
},
929+
})
930+
}
931+
932+
func testAccAlloydbCluster_withoutContinuousBackupConfig(context map[string]interface{}) string {
933+
return acctest.Nprintf(`
934+
resource "google_alloydb_cluster" "default" {
935+
cluster_id = "tf-test-alloydb-cluster%{random_suffix}"
936+
location = "us-central1"
937+
network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}"
938+
lifecycle {
939+
prevent_destroy = true
940+
}
941+
}
942+
943+
data "google_project" "project" {
944+
}
945+
946+
resource "google_compute_network" "default" {
947+
name = "tf-test-alloydb-cluster%{random_suffix}"
948+
}
949+
`, context)
950+
}
951+
952+
func testAccAlloydbCluster_continuousBackupConfig(context map[string]interface{}) string {
953+
return acctest.Nprintf(`
954+
resource "google_alloydb_cluster" "default" {
955+
cluster_id = "tf-test-alloydb-cluster%{random_suffix}"
956+
location = "us-central1"
957+
network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}"
958+
959+
continuous_backup_config {
960+
enabled = %{enabled}
961+
recovery_window_days = %{recovery_window_days}
962+
}
963+
lifecycle {
964+
prevent_destroy = true
965+
}
966+
}
967+
968+
data "google_project" "project" {
969+
}
970+
971+
resource "google_compute_network" "default" {
972+
name = "tf-test-alloydb-cluster%{random_suffix}"
973+
}
974+
`, context)
975+
}
976+
977+
func TestAccAlloydbCluster_continuousBackup_CMEKIsUpdatable(t *testing.T) {
978+
t.Parallel()
979+
980+
suffix := acctest.RandString(t, 10)
981+
kms := acctest.BootstrapKMSKeyWithPurposeInLocationAndName(t, "ENCRYPT_DECRYPT", "us-central1", "tf-bootstrap-alloydb-key1")
982+
context := map[string]interface{}{
983+
"random_suffix": suffix,
984+
"key_ring": kms.KeyRing.Name,
985+
"key_name": kms.CryptoKey.Name,
986+
}
987+
988+
kms2 := acctest.BootstrapKMSKeyWithPurposeInLocationAndName(t, "ENCRYPT_DECRYPT", "us-central1", "tf-bootstrap-alloydb-key2")
989+
context2 := map[string]interface{}{
990+
"random_suffix": suffix,
991+
"key_ring": kms2.KeyRing.Name,
992+
"key_name": kms2.CryptoKey.Name,
993+
}
994+
995+
acctest.VcrTest(t, resource.TestCase{
996+
PreCheck: func() { acctest.AccTestPreCheck(t) },
997+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
998+
CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t),
999+
Steps: []resource.TestStep{
1000+
{
1001+
Config: testAccAlloydbCluster_usingCMEKInClusterAndContinuousBackup(context),
1002+
},
1003+
{
1004+
ResourceName: "google_alloydb_cluster.default",
1005+
ImportState: true,
1006+
ImportStateVerify: true,
1007+
ImportStateVerifyIgnore: []string{"cluster_id", "location"},
1008+
},
1009+
{
1010+
Config: testAccAlloydbCluster_usingCMEKInClusterAndContinuousBackup(context2),
1011+
},
1012+
{
1013+
ResourceName: "google_alloydb_cluster.default",
1014+
ImportState: true,
1015+
ImportStateVerify: true,
1016+
ImportStateVerifyIgnore: []string{"cluster_id", "location"},
1017+
},
1018+
{
1019+
Config: testAccAlloydbCluster_continuousBackupUsingCMEKAllowDeletion(context2),
1020+
},
1021+
{
1022+
ResourceName: "google_alloydb_cluster.default",
1023+
ImportState: true,
1024+
ImportStateVerify: true,
1025+
ImportStateVerifyIgnore: []string{"cluster_id", "location"},
1026+
},
1027+
},
1028+
})
1029+
}
1030+
1031+
func testAccAlloydbCluster_usingCMEKInClusterAndContinuousBackup(context map[string]interface{}) string {
1032+
return acctest.Nprintf(`
1033+
resource "google_alloydb_cluster" "default" {
1034+
cluster_id = "tf-test-alloydb-cluster%{random_suffix}"
1035+
location = "us-central1"
1036+
network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}"
1037+
continuous_backup_config {
1038+
enabled = true
1039+
recovery_window_days = 20
1040+
encryption_config {
1041+
kms_key_name = "%{key_name}"
1042+
}
1043+
}
1044+
lifecycle {
1045+
prevent_destroy = true
1046+
}
1047+
depends_on = [google_kms_crypto_key_iam_binding.crypto_key]
1048+
}
1049+
1050+
resource "google_compute_network" "default" {
1051+
name = "tf-test-alloydb-cluster%{random_suffix}"
1052+
}
1053+
1054+
data "google_project" "project" {}
1055+
1056+
resource "google_kms_crypto_key_iam_binding" "crypto_key" {
1057+
crypto_key_id = "%{key_name}"
1058+
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
1059+
members = [
1060+
"serviceAccount:service-${data.google_project.project.number}@gcp-sa-alloydb.iam.gserviceaccount.com",
1061+
]
1062+
}
1063+
`, context)
1064+
}
1065+
1066+
func testAccAlloydbCluster_continuousBackupUsingCMEKAllowDeletion(context map[string]interface{}) string {
1067+
return acctest.Nprintf(`
1068+
resource "google_alloydb_cluster" "default" {
1069+
cluster_id = "tf-test-alloydb-cluster%{random_suffix}"
1070+
location = "us-central1"
1071+
network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}"
1072+
continuous_backup_config {
1073+
enabled = true
1074+
recovery_window_days = 20
1075+
encryption_config {
1076+
kms_key_name = "%{key_name}"
1077+
}
1078+
}
1079+
depends_on = [google_kms_crypto_key_iam_binding.crypto_key]
1080+
}
1081+
1082+
resource "google_compute_network" "default" {
1083+
name = "tf-test-alloydb-cluster%{random_suffix}"
1084+
}
1085+
1086+
data "google_project" "project" {}
1087+
1088+
resource "google_kms_crypto_key_iam_binding" "crypto_key" {
1089+
crypto_key_id = "%{key_name}"
1090+
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
1091+
members = [
1092+
"serviceAccount:service-${data.google_project.project.number}@gcp-sa-alloydb.iam.gserviceaccount.com",
1093+
]
1094+
}
1095+
`, context)
1096+
}

0 commit comments

Comments
 (0)