diff --git a/README.md b/README.md index 2264e7d1..cc3ba7a2 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ You need the following permissions to run this module. ## Examples - [ Autoscale example](examples/autoscale) +- [ Restore from backup example](examples/backup) - [ Complete example with byok encryption, CBR rules and storing credentials in secrets manager](examples/complete) - [ Default example](examples/default) - [ Financial Services Cloud profile example](examples/fscloud) @@ -67,6 +68,7 @@ You need the following permissions to run this module. |------|-------------|------|---------|:--------:| | [allowlist](#input\_allowlist) | Set of IP address and description to allowlist in database |
list(object({
address = optional(string)
description = optional(string)
})) | `[]` | no |
| [auto\_scaling](#input\_auto\_scaling) | (Optional) Configure rules to allow your database to automatically increase its resources. Single block of autoscaling is allowed at once. | object({
cpu = object({
rate_increase_percent = optional(number)
rate_limit_count_per_member = optional(number)
rate_period_seconds = optional(number)
rate_units = optional(string)
})
disk = object({
capacity_enabled = optional(bool)
free_space_less_than_percent = optional(number)
io_above_percent = optional(number)
io_enabled = optional(bool)
io_over_period = optional(string)
rate_increase_percent = optional(number)
rate_limit_mb_per_member = optional(number)
rate_period_seconds = optional(number)
rate_units = optional(string)
})
memory = object({
io_above_percent = optional(number)
io_enabled = optional(bool)
io_over_period = optional(string)
rate_increase_percent = optional(number)
rate_limit_mb_per_member = optional(number)
rate_period_seconds = optional(number)
rate_units = optional(string)
})
}) | {
"cpu": {},
"disk": {},
"memory": {}
} | no |
+| [backup\_crn](#input\_backup\_crn) | The CRN of a backup resource to restore from. The backup is created by a database deployment with the same service ID. The backup is loaded after provisioning and the new deployment starts up that uses that data. A backup CRN is in the format crn:v1:<…>:backup:. If omitted, the database is provisioned empty. | `string` | `null` | no |
| [backup\_encryption\_key\_crn](#input\_backup\_encryption\_key\_crn) | (Optional) The CRN of a key protect key, that you want to use for encrypting disk that holds deployment backups. If null, will use 'key\_protect\_key\_crn' as encryption key. If 'key\_protect\_key\_crn' is also null database is encrypted by using randomly generated keys. | `string` | `null` | no |
| [cbr\_rules](#input\_cbr\_rules) | (Optional, list) List of CBR rules to create | list(object({
description = string
account_id = string
rule_contexts = list(object({
attributes = optional(list(object({
name = string
value = string
}))) }))
enforcement_mode = string
})) | `[]` | no |
| [configuration](#input\_configuration) | (Optional, Json String) Database Configuration in JSON format. | object({
max_connections = optional(number)
max_prepared_transactions = optional(number)
deadlock_timeout = optional(number)
effective_io_concurrency = optional(number)
max_replication_slots = optional(number)
max_wal_senders = optional(number)
shared_buffers = optional(number)
synchronous_commit = optional(string)
wal_level = optional(string)
archive_timeout = optional(number)
log_min_duration_statement = optional(number)
}) | `null` | no |
diff --git a/examples/backup/README.md b/examples/backup/README.md
new file mode 100644
index 00000000..18164eb4
--- /dev/null
+++ b/examples/backup/README.md
@@ -0,0 +1,7 @@
+# Restore from backup example
+
+This example provides an end-to-end executable flow of how a PostgreSQL DB can be created from a backup instance. This example uses the IBM Cloud terraform provider to:
+
+- Create a new resource group if one is not passed in.
+- Create a new ICD Postgresql database instance if no existing backup crn is provided.
+- Create a restored ICD Postgresql database instance pointing to the backup of the first instance.
diff --git a/examples/backup/main.tf b/examples/backup/main.tf
new file mode 100644
index 00000000..e7a92ce2
--- /dev/null
+++ b/examples/backup/main.tf
@@ -0,0 +1,34 @@
+##############################################################################
+# Resource Group
+##############################################################################
+
+module "resource_group" {
+ source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-resource-group.git?ref=v1.0.5"
+ # if an existing resource group is not set (null) create a new one using prefix
+ resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null
+ existing_resource_group_name = var.resource_group
+}
+
+module "postgresql_db" {
+ count = var.postgresql_db_backup_crn != null ? 0 : 1
+ source = "../.."
+ resource_group_id = module.resource_group.resource_group_id
+ name = "${var.prefix}-postgres"
+ region = var.region
+ resource_tags = var.resource_tags
+}
+
+data "ibm_database_backups" "backup_database" {
+ count = var.postgresql_db_backup_crn != null ? 0 : 1
+ deployment_id = module.postgresql_db[0].id
+}
+
+# New postgresql instance pointing to the backup instance
+module "restored_postgresql_db" {
+ source = "../.."
+ resource_group_id = module.resource_group.resource_group_id
+ name = "${var.prefix}-postgres-restored"
+ region = var.region
+ resource_tags = var.resource_tags
+ backup_crn = var.postgresql_db_backup_crn == null ? data.ibm_database_backups.backup_database[0].backups[0].backup_id : var.postgresql_db_backup_crn
+}
diff --git a/examples/backup/outputs.tf b/examples/backup/outputs.tf
new file mode 100644
index 00000000..86a00aef
--- /dev/null
+++ b/examples/backup/outputs.tf
@@ -0,0 +1,17 @@
+##############################################################################
+# Outputs
+##############################################################################
+output "id" {
+ description = "Postgresql instance id"
+ value = var.postgresql_db_backup_crn == null ? module.postgresql_db[0].id : null
+}
+
+output "restored_postgresql_db_id" {
+ description = "Restored Postgresql instance id"
+ value = module.restored_postgresql_db.id
+}
+
+output "restored_postgresql_db_version" {
+ description = "Restored Postgresql instance version"
+ value = module.restored_postgresql_db.version
+}
diff --git a/examples/backup/provider.tf b/examples/backup/provider.tf
new file mode 100644
index 00000000..df45ef50
--- /dev/null
+++ b/examples/backup/provider.tf
@@ -0,0 +1,4 @@
+provider "ibm" {
+ ibmcloud_api_key = var.ibmcloud_api_key
+ region = var.region
+}
diff --git a/examples/backup/variables.tf b/examples/backup/variables.tf
new file mode 100644
index 00000000..e34c58e7
--- /dev/null
+++ b/examples/backup/variables.tf
@@ -0,0 +1,35 @@
+variable "ibmcloud_api_key" {
+ type = string
+ description = "The IBM Cloud API Key"
+ sensitive = true
+}
+
+variable "region" {
+ type = string
+ description = "Region to provision all resources created by this example."
+ default = "us-south"
+}
+
+variable "prefix" {
+ type = string
+ description = "Prefix to append to all resources created by this example"
+ default = "pg-res"
+}
+
+variable "resource_group" {
+ type = string
+ description = "An existing resource group name to use for this example, if unset a new resource group will be created"
+ default = null
+}
+
+variable "resource_tags" {
+ type = list(string)
+ description = "Optional list of tags to be added to created resources"
+ default = []
+}
+
+variable "postgresql_db_backup_crn" {
+ type = string
+ description = "The existing CRN of a backup resource to restore from. If null then it will create a new instance first and then create another instance pointing to the backup of the first instance."
+ default = null
+}
diff --git a/examples/backup/version.tf b/examples/backup/version.tf
new file mode 100644
index 00000000..b672faa6
--- /dev/null
+++ b/examples/backup/version.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = ">= 1.3.0"
+ required_providers {
+ # Pin to the lowest provider version of the range defined in the main module's version.tf to ensure lowest version still works
+ ibm = {
+ source = "IBM-Cloud/ibm"
+ version = "1.49.0"
+ }
+ }
+}
diff --git a/main.tf b/main.tf
index 50a00eef..0066cfc2 100644
--- a/main.tf
+++ b/main.tf
@@ -15,6 +15,7 @@ resource "ibm_database" "postgresql_db" {
service = "databases-for-postgresql"
location = var.region
plan = "standard" # Only standard plan is available for postgres
+ backup_id = var.backup_crn
plan_validation = var.plan_validation
version = var.pg_version
tags = var.resource_tags
diff --git a/module-metadata.json b/module-metadata.json
index b4cc40a3..7aa886b5 100644
--- a/module-metadata.json
+++ b/module-metadata.json
@@ -8,7 +8,7 @@
"default": [],
"pos": {
"filename": "variables.tf",
- "line": 113
+ "line": 126
}
},
"auto_scaling": {
@@ -22,7 +22,19 @@
},
"pos": {
"filename": "variables.tf",
- "line": 140
+ "line": 153
+ }
+ },
+ "backup_crn": {
+ "name": "backup_crn",
+ "type": "string",
+ "description": "The CRN of a backup resource to restore from. The backup is created by a database deployment with the same service ID. The backup is loaded after provisioning and the new deployment starts up that uses that data. A backup CRN is in the format crn:v1:\u003c…\u003e:backup:. If omitted, the database is provisioned empty.",
+ "source": [
+ "ibm_database.postgresql_db.backup_id"
+ ],
+ "pos": {
+ "filename": "variables.tf",
+ "line": 56
}
},
"backup_encryption_key_crn": {
@@ -31,7 +43,7 @@
"description": "(Optional) The CRN of a key protect key, that you want to use for encrypting disk that holds deployment backups. If null, will use 'key_protect_key_crn' as encryption key. If 'key_protect_key_crn' is also null database is encrypted by using randomly generated keys.",
"pos": {
"filename": "variables.tf",
- "line": 183
+ "line": 196
}
},
"cbr_rules": {
@@ -48,7 +60,7 @@
],
"pos": {
"filename": "variables.tf",
- "line": 194
+ "line": 207
}
},
"configuration": {
@@ -60,7 +72,7 @@
],
"pos": {
"filename": "variables.tf",
- "line": 122
+ "line": 135
}
},
"key_protect_key_crn": {
@@ -72,7 +84,7 @@
],
"pos": {
"filename": "variables.tf",
- "line": 177
+ "line": 190
},
"immutable": true
},
@@ -83,7 +95,7 @@
"default": "3",
"pos": {
"filename": "variables.tf",
- "line": 69
+ "line": 82
}
},
"member_disk_mb": {
@@ -93,7 +105,7 @@
"default": "5120",
"pos": {
"filename": "variables.tf",
- "line": 56
+ "line": 69
}
},
"member_memory_mb": {
@@ -113,7 +125,7 @@
"default": 3,
"pos": {
"filename": "variables.tf",
- "line": 84
+ "line": 97
}
},
"name": {
@@ -200,7 +212,7 @@
],
"pos": {
"filename": "variables.tf",
- "line": 107
+ "line": 120
},
"min_length": 1,
"max_length": 128,
@@ -220,7 +232,7 @@
],
"pos": {
"filename": "variables.tf",
- "line": 97
+ "line": 110
},
"options": "public, private, public-and-private"
}
@@ -273,6 +285,7 @@
"type": "ibm_database",
"name": "postgresql_db",
"attributes": {
+ "backup_id": "backup_crn",
"configuration": "configuration",
"key_protect_key": "key_protect_key_crn",
"location": "region",
@@ -351,7 +364,7 @@
},
"pos": {
"filename": "main.tf",
- "line": 95
+ "line": 96
}
}
}
diff --git a/tests/other_test.go b/tests/other_test.go
new file mode 100644
index 00000000..87a437c1
--- /dev/null
+++ b/tests/other_test.go
@@ -0,0 +1,25 @@
+// Tests in this file are NOT run in the PR pipeline. They are run in the continuous testing pipeline along with the ones in pr_test.go
+package test
+
+import (
+ "github.com/stretchr/testify/assert"
+ "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper"
+ "testing"
+)
+
+const restoredTerraformDir = "examples/backup"
+
+func TestRunRestoredDBExample(t *testing.T) {
+ t.Parallel()
+
+ options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{
+ Testing: t,
+ TerraformDir: restoredTerraformDir,
+ Prefix: "pg-backup",
+ ResourceGroup: resourceGroup,
+ })
+
+ output, err := options.RunTestConsistency()
+ assert.Nil(t, err, "This should not have errored")
+ assert.NotNil(t, output, "Expected some output")
+}
diff --git a/variables.tf b/variables.tf
index 1413df6b..84f6823f 100644
--- a/variables.tf
+++ b/variables.tf
@@ -53,6 +53,19 @@ variable "member_memory_mb" {
}
}
+variable "backup_crn" {
+ type = string
+ description = "The CRN of a backup resource to restore from. The backup is created by a database deployment with the same service ID. The backup is loaded after provisioning and the new deployment starts up that uses that data. A backup CRN is in the format crn:v1:<…>:backup:. If omitted, the database is provisioned empty."
+ default = null
+ validation {
+ condition = anytrue([
+ var.backup_crn == null,
+ can(regex("^crn:.*:backup:", var.backup_crn))
+ ])
+ error_message = "backup_crn must be null OR starts with 'crn:' and contains ':backup:'"
+ }
+}
+
variable "member_disk_mb" {
type = string
description = "Disk allocation required for postgresql database"