Skip to content

Commit 649583c

Browse files
feat: add support to create an instance from a backup (#51)
1 parent 45b17f5 commit 649583c

File tree

11 files changed

+173
-12
lines changed

11 files changed

+173
-12
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ You need the following permissions to run this module.
3737
## Examples
3838

3939
- [ Autoscale example](examples/autoscale)
40+
- [ Restore from backup example](examples/backup)
4041
- [ Complete example with byok encryption, CBR rules and storing credentials in secrets manager](examples/complete)
4142
- [ Default example](examples/default)
4243
- [ Financial Services Cloud profile example](examples/fscloud)
@@ -67,6 +68,7 @@ You need the following permissions to run this module.
6768
|------|-------------|------|---------|:--------:|
6869
| <a name="input_allowlist"></a> [allowlist](#input\_allowlist) | Set of IP address and description to allowlist in database | <pre>list(object({<br> address = optional(string)<br> description = optional(string)<br> }))</pre> | `[]` | no |
6970
| <a name="input_auto_scaling"></a> [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. | <pre>object({<br> cpu = object({<br> rate_increase_percent = optional(number)<br> rate_limit_count_per_member = optional(number)<br> rate_period_seconds = optional(number)<br> rate_units = optional(string)<br> })<br> disk = object({<br> capacity_enabled = optional(bool)<br> free_space_less_than_percent = optional(number)<br> io_above_percent = optional(number)<br> io_enabled = optional(bool)<br> io_over_period = optional(string)<br> rate_increase_percent = optional(number)<br> rate_limit_mb_per_member = optional(number)<br> rate_period_seconds = optional(number)<br> rate_units = optional(string)<br> })<br> memory = object({<br> io_above_percent = optional(number)<br> io_enabled = optional(bool)<br> io_over_period = optional(string)<br> rate_increase_percent = optional(number)<br> rate_limit_mb_per_member = optional(number)<br> rate_period_seconds = optional(number)<br> rate_units = optional(string)<br> })<br> })</pre> | <pre>{<br> "cpu": {},<br> "disk": {},<br> "memory": {}<br>}</pre> | no |
71+
| <a name="input_backup_crn"></a> [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 |
7072
| <a name="input_backup_encryption_key_crn"></a> [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 |
7173
| <a name="input_cbr_rules"></a> [cbr\_rules](#input\_cbr\_rules) | (Optional, list) List of CBR rules to create | <pre>list(object({<br> description = string<br> account_id = string<br> rule_contexts = list(object({<br> attributes = optional(list(object({<br> name = string<br> value = string<br> }))) }))<br> enforcement_mode = string<br> }))</pre> | `[]` | no |
7274
| <a name="input_configuration"></a> [configuration](#input\_configuration) | (Optional, Json String) Database Configuration in JSON format. | <pre>object({<br> max_connections = optional(number)<br> max_prepared_transactions = optional(number)<br> deadlock_timeout = optional(number)<br> effective_io_concurrency = optional(number)<br> max_replication_slots = optional(number)<br> max_wal_senders = optional(number)<br> shared_buffers = optional(number)<br> synchronous_commit = optional(string)<br> wal_level = optional(string)<br> archive_timeout = optional(number)<br> log_min_duration_statement = optional(number)<br> })</pre> | `null` | no |

examples/backup/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Restore from backup example
2+
3+
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:
4+
5+
- Create a new resource group if one is not passed in.
6+
- Create a new ICD Postgresql database instance if no existing backup crn is provided.
7+
- Create a restored ICD Postgresql database instance pointing to the backup of the first instance.

examples/backup/main.tf

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
##############################################################################
2+
# Resource Group
3+
##############################################################################
4+
5+
module "resource_group" {
6+
source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-resource-group.git?ref=v1.0.5"
7+
# if an existing resource group is not set (null) create a new one using prefix
8+
resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null
9+
existing_resource_group_name = var.resource_group
10+
}
11+
12+
module "postgresql_db" {
13+
count = var.postgresql_db_backup_crn != null ? 0 : 1
14+
source = "../.."
15+
resource_group_id = module.resource_group.resource_group_id
16+
name = "${var.prefix}-postgres"
17+
region = var.region
18+
resource_tags = var.resource_tags
19+
}
20+
21+
data "ibm_database_backups" "backup_database" {
22+
count = var.postgresql_db_backup_crn != null ? 0 : 1
23+
deployment_id = module.postgresql_db[0].id
24+
}
25+
26+
# New postgresql instance pointing to the backup instance
27+
module "restored_postgresql_db" {
28+
source = "../.."
29+
resource_group_id = module.resource_group.resource_group_id
30+
name = "${var.prefix}-postgres-restored"
31+
region = var.region
32+
resource_tags = var.resource_tags
33+
backup_crn = var.postgresql_db_backup_crn == null ? data.ibm_database_backups.backup_database[0].backups[0].backup_id : var.postgresql_db_backup_crn
34+
}

examples/backup/outputs.tf

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
##############################################################################
2+
# Outputs
3+
##############################################################################
4+
output "id" {
5+
description = "Postgresql instance id"
6+
value = var.postgresql_db_backup_crn == null ? module.postgresql_db[0].id : null
7+
}
8+
9+
output "restored_postgresql_db_id" {
10+
description = "Restored Postgresql instance id"
11+
value = module.restored_postgresql_db.id
12+
}
13+
14+
output "restored_postgresql_db_version" {
15+
description = "Restored Postgresql instance version"
16+
value = module.restored_postgresql_db.version
17+
}

examples/backup/provider.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
provider "ibm" {
2+
ibmcloud_api_key = var.ibmcloud_api_key
3+
region = var.region
4+
}

examples/backup/variables.tf

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
variable "ibmcloud_api_key" {
2+
type = string
3+
description = "The IBM Cloud API Key"
4+
sensitive = true
5+
}
6+
7+
variable "region" {
8+
type = string
9+
description = "Region to provision all resources created by this example."
10+
default = "us-south"
11+
}
12+
13+
variable "prefix" {
14+
type = string
15+
description = "Prefix to append to all resources created by this example"
16+
default = "pg-res"
17+
}
18+
19+
variable "resource_group" {
20+
type = string
21+
description = "An existing resource group name to use for this example, if unset a new resource group will be created"
22+
default = null
23+
}
24+
25+
variable "resource_tags" {
26+
type = list(string)
27+
description = "Optional list of tags to be added to created resources"
28+
default = []
29+
}
30+
31+
variable "postgresql_db_backup_crn" {
32+
type = string
33+
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."
34+
default = null
35+
}

examples/backup/version.tf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
terraform {
2+
required_version = ">= 1.3.0"
3+
required_providers {
4+
# Pin to the lowest provider version of the range defined in the main module's version.tf to ensure lowest version still works
5+
ibm = {
6+
source = "IBM-Cloud/ibm"
7+
version = "1.49.0"
8+
}
9+
}
10+
}

main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ resource "ibm_database" "postgresql_db" {
1515
service = "databases-for-postgresql"
1616
location = var.region
1717
plan = "standard" # Only standard plan is available for postgres
18+
backup_id = var.backup_crn
1819
plan_validation = var.plan_validation
1920
version = var.pg_version
2021
tags = var.resource_tags

module-metadata.json

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"default": [],
99
"pos": {
1010
"filename": "variables.tf",
11-
"line": 113
11+
"line": 126
1212
}
1313
},
1414
"auto_scaling": {
@@ -22,7 +22,19 @@
2222
},
2323
"pos": {
2424
"filename": "variables.tf",
25-
"line": 140
25+
"line": 153
26+
}
27+
},
28+
"backup_crn": {
29+
"name": "backup_crn",
30+
"type": "string",
31+
"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.",
32+
"source": [
33+
"ibm_database.postgresql_db.backup_id"
34+
],
35+
"pos": {
36+
"filename": "variables.tf",
37+
"line": 56
2638
}
2739
},
2840
"backup_encryption_key_crn": {
@@ -31,7 +43,7 @@
3143
"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.",
3244
"pos": {
3345
"filename": "variables.tf",
34-
"line": 183
46+
"line": 196
3547
}
3648
},
3749
"cbr_rules": {
@@ -48,7 +60,7 @@
4860
],
4961
"pos": {
5062
"filename": "variables.tf",
51-
"line": 194
63+
"line": 207
5264
}
5365
},
5466
"configuration": {
@@ -60,7 +72,7 @@
6072
],
6173
"pos": {
6274
"filename": "variables.tf",
63-
"line": 122
75+
"line": 135
6476
}
6577
},
6678
"key_protect_key_crn": {
@@ -72,7 +84,7 @@
7284
],
7385
"pos": {
7486
"filename": "variables.tf",
75-
"line": 177
87+
"line": 190
7688
},
7789
"immutable": true
7890
},
@@ -83,7 +95,7 @@
8395
"default": "3",
8496
"pos": {
8597
"filename": "variables.tf",
86-
"line": 69
98+
"line": 82
8799
}
88100
},
89101
"member_disk_mb": {
@@ -93,7 +105,7 @@
93105
"default": "5120",
94106
"pos": {
95107
"filename": "variables.tf",
96-
"line": 56
108+
"line": 69
97109
}
98110
},
99111
"member_memory_mb": {
@@ -113,7 +125,7 @@
113125
"default": 3,
114126
"pos": {
115127
"filename": "variables.tf",
116-
"line": 84
128+
"line": 97
117129
}
118130
},
119131
"name": {
@@ -200,7 +212,7 @@
200212
],
201213
"pos": {
202214
"filename": "variables.tf",
203-
"line": 107
215+
"line": 120
204216
},
205217
"min_length": 1,
206218
"max_length": 128,
@@ -220,7 +232,7 @@
220232
],
221233
"pos": {
222234
"filename": "variables.tf",
223-
"line": 97
235+
"line": 110
224236
},
225237
"options": "public, private, public-and-private"
226238
}
@@ -273,6 +285,7 @@
273285
"type": "ibm_database",
274286
"name": "postgresql_db",
275287
"attributes": {
288+
"backup_id": "backup_crn",
276289
"configuration": "configuration",
277290
"key_protect_key": "key_protect_key_crn",
278291
"location": "region",
@@ -351,7 +364,7 @@
351364
},
352365
"pos": {
353366
"filename": "main.tf",
354-
"line": 95
367+
"line": 96
355368
}
356369
}
357370
}

tests/other_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// 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
2+
package test
3+
4+
import (
5+
"github.com/stretchr/testify/assert"
6+
"github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper"
7+
"testing"
8+
)
9+
10+
const restoredTerraformDir = "examples/backup"
11+
12+
func TestRunRestoredDBExample(t *testing.T) {
13+
t.Parallel()
14+
15+
options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{
16+
Testing: t,
17+
TerraformDir: restoredTerraformDir,
18+
Prefix: "pg-backup",
19+
ResourceGroup: resourceGroup,
20+
})
21+
22+
output, err := options.RunTestConsistency()
23+
assert.Nil(t, err, "This should not have errored")
24+
assert.NotNil(t, output, "Expected some output")
25+
}

0 commit comments

Comments
 (0)