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"