From 34cca8f521f221ca4d64b487e470c6aee8f6393e Mon Sep 17 00:00:00 2001 From: shemau Date: Thu, 24 Jul 2025 16:43:58 +0100 Subject: [PATCH 1/7] feat: major inplace upgrade, deletion protection --- .secrets.baseline | 23 +++++- README.md | 13 +-- cra-config.yaml | 9 +- cra-tf-validate-ignore-rules.json | 18 ++-- examples/backup-restore/main.tf | 17 ++-- examples/backup-restore/variables.tf | 11 ++- examples/backup-restore/version.tf | 2 +- examples/basic/README.md | 7 +- examples/basic/main.tf | 16 ++-- examples/basic/variables.tf | 19 +++-- examples/basic/version.tf | 2 +- examples/complete/README.md | 14 ++-- examples/complete/main.tf | 82 +++++++++++-------- examples/complete/outputs.tf | 11 ++- examples/complete/variables.tf | 52 ++++++------ examples/complete/version.tf | 2 +- examples/fscloud/README.md | 1 - examples/fscloud/main.tf | 9 +- examples/fscloud/outputs.tf | 10 +++ examples/fscloud/variables.tf | 30 +++---- ibm_catalog.json | 15 ++++ main.tf | 51 ++++++------ modules/fscloud/README.md | 5 +- modules/fscloud/main.tf | 15 ++-- modules/fscloud/variables.tf | 20 ++++- outputs.tf | 20 ++--- solutions/fully-configurable/DA-types.md | 10 +-- .../catalogValidationValues.json.template | 1 + solutions/fully-configurable/main.tf | 7 +- solutions/fully-configurable/variables.tf | 30 ++++++- .../catalogValidationValues.json.template | 3 +- solutions/security-enforced/main.tf | 11 ++- solutions/security-enforced/moved.tf | 4 - solutions/security-enforced/provider.tf | 1 + solutions/security-enforced/variables.tf | 28 +++++-- tests/go.mod | 2 +- tests/other_test.go | 82 ++++++++----------- tests/pr_test.go | 25 +++--- variables.tf | 25 +++++- version.tf | 6 +- 40 files changed, 426 insertions(+), 283 deletions(-) delete mode 100644 solutions/security-enforced/moved.tf create mode 100644 solutions/security-enforced/provider.tf diff --git a/.secrets.baseline b/.secrets.baseline index e5f32db9..a8049784 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.sum|^.secrets.baseline$", "lines": null }, - "generated_at": "2023-12-14T14:08:48Z", + "generated_at": "2025-07-24T12:57:34Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -76,7 +76,26 @@ "name": "TwilioKeyDetector" } ], - "results": {}, + "results": { + "solutions/fully-configurable/DA-types.md": [ + { + "hashed_secret": "44cdfc3615970ada14420caaaa5c5745fca06002", + "is_secret": false, + "is_verified": false, + "line_number": 124, + "type": "Secret Keyword", + "verified_result": null + }, + { + "hashed_secret": "bd0d0d73a240c29656fb8ae0dfa5f863077788dc", + "is_secret": false, + "is_verified": false, + "line_number": 129, + "type": "Secret Keyword", + "verified_result": null + } + ] + }, "version": "0.13.1+ibm.62.dss", "word_list": { "file": null, diff --git a/README.md b/README.md index f35e26aa..52925be8 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Graduated (Supported)](https://img.shields.io/badge/Status-Graduated%20(Supported)-brightgreen)](https://terraform-ibm-modules.github.io/documentation/#/badge-status) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) -[![latest release](https://img.shields.io/github/v/release/terraform-ibm-modules/terraform-ibm-module-template?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-module-template/releases/latest) +[![latest release](https://img.shields.io/github/v/release/terraform-ibm-modules/terraform-ibm-icd-rabbitmq?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-module-template/releases/latest) [![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com/) This module implements an instance of the IBM Cloud Messages for RabbitMQ service. @@ -58,14 +58,14 @@ You need the following permissions to run this module. |------|---------| | [terraform](#requirement\_terraform) | >= 1.9.0 | | [ibm](#requirement\_ibm) | >= 1.79.2, <2.0.0 | -| [time](#requirement\_time) | >= 0.9.1 | +| [time](#requirement\_time) | >= 0.9.1, < 1.0.0 | ### Modules | Name | Source | Version | |------|--------|---------| | [backup\_key\_crn\_parser](#module\_backup\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.2.0 | -| [cbr\_rule](#module\_cbr\_rule) | git::https://github.com/terraform-ibm-modules/terraform-ibm-cbr//modules/cbr-rule-module | v1.32.4 | +| [cbr\_rule](#module\_cbr\_rule) | terraform-ibm-modules/cbr/ibm//modules/cbr-rule-module | 1.32.4 | | [kms\_key\_crn\_parser](#module\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.2.0 | ### Resources @@ -92,10 +92,11 @@ You need the following permissions to run this module. | [backup\_encryption\_key\_crn](#input\_backup\_encryption\_key\_crn) | The CRN of a Key Protect or Hyper Protect Crypto Services encryption key that you want to use for encrypting the disk that holds deployment backups. Applies only if `use_ibm_owned_encryption_key` is false and `use_same_kms_key_for_backups` is false. If no value is passed, and `use_same_kms_key_for_backups` is true, the value of `kms_key_crn` is used. Alternatively set `use_default_backup_encryption_key` to true to use the IBM Cloud Databases default encryption. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `string` | `null` | no | | [cbr\_rules](#input\_cbr\_rules) | (Optional, list) List of context-based restrictions 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
tags = optional(list(object({
name = string
value = string
})))
operations = optional(list(object({
api_types = list(object({
api_type_id = string
}))
})))
}))
| `[]` | no | | [cpu\_count](#input\_cpu\_count) | Allocated dedicated CPU per member. For shared CPU, set to 0. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `0` | no | +| [deletion\_protection](#input\_deletion\_protection) | Enable deletion protection within terraform. This is not a property of the resource and does not prevent deletion outside of terraform. The database can not be deleted by terraform when this value is set to 'true'. In order to delete with terraform the value must be set to 'false' and a terraform apply performed before the destroy is performed. The default is 'true'. | `bool` | `true` | no | | [disk\_mb](#input\_disk\_mb) | Allocated disk per member. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `1024` | no | | [kms\_key\_crn](#input\_kms\_key\_crn) | The CRN of a Key Protect or Hyper Protect Crypto Services encryption key to encrypt your data. Applies only if `use_ibm_owned_encryption_key` is false. By default this key is used for both deployment data and backups, but this behaviour can be altered using the `use_same_kms_key_for_backups` and `backup_encryption_key_crn` inputs. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `string` | `null` | no | | [member\_host\_flavor](#input\_member\_host\_flavor) | Allocated host flavor per member. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor). | `string` | `null` | no | -| [members](#input\_members) | Allocated number of members. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `3` | no | +| [members](#input\_members) | The number of members that are allocated. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `3` | no | | [memory\_mb](#input\_memory\_mb) | Allocated memory per-member. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `8192` | no | | [name](#input\_name) | The name to give the RabbitMQ instance | `string` | n/a | yes | | [plan](#input\_plan) | The name of the service plan that you choose for your RabbitMQ instance | `string` | `"standard"` | no | @@ -105,11 +106,13 @@ You need the following permissions to run this module. | [service\_credential\_names](#input\_service\_credential\_names) | Map of name, role for service credentials that you want to create for the database | `map(string)` | `{}` | no | | [service\_endpoints](#input\_service\_endpoints) | Specify whether you want to enable the public, private, or both service endpoints. Supported values are 'public', 'private', or 'public-and-private'. | `string` | `"private"` | no | | [skip\_iam\_authorization\_policy](#input\_skip\_iam\_authorization\_policy) | Set to true to skip the creation of IAM authorization policies that permits all Databases for RabbitMQ instances in the given resource group 'Reader' access to the Key Protect or Hyper Protect Crypto Services key that was provided in the `kms_key_crn` and `backup_encryption_key_crn` inputs. This policy is required in order to enable KMS encryption, so only skip creation if there is one already present in your account. No policy is created if `use_ibm_owned_encryption_key` is true. | `bool` | `false` | no | -| [tags](#input\_tags) | Optional list of tags to be added to the RabbitMQ instance. | `list(any)` | `[]` | no | +| [tags](#input\_tags) | Optional list of tags to be added to the RabbitMQ instance. | `list(string)` | `[]` | no | +| [timeouts\_update](#input\_timeouts\_update) | A database update may require a longer timeout for the update to complete. The default is 120 minutes. Set this variable to change the `update` value in the `timeouts` block. [Learn more](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts). | `string` | `"120m"` | no | | [use\_default\_backup\_encryption\_key](#input\_use\_default\_backup\_encryption\_key) | When `use_ibm_owned_encryption_key` is set to false, backups will be encrypted with either the key specified in `kms_key_crn`, or in `backup_encryption_key_crn` if a value is passed. If you do not want to use your own key for backups encryption, you can set this to `true` to use the IBM Cloud Databases default encryption for backups. Alternatively set `use_ibm_owned_encryption_key` to true to use the default encryption for both backups and deployment data. | `bool` | `false` | no | | [use\_ibm\_owned\_encryption\_key](#input\_use\_ibm\_owned\_encryption\_key) | IBM Cloud Databases will secure your deployment's data at rest automatically with an encryption key that IBM hold. Alternatively, you may select your own Key Management System instance and encryption key (Key Protect or Hyper Protect Crypto Services) by setting this to false. If setting to false, a value must be passed for the `kms_key_crn` input. | `bool` | `true` | no | | [use\_same\_kms\_key\_for\_backups](#input\_use\_same\_kms\_key\_for\_backups) | Set this to false if you wan't to use a different key that you own to encrypt backups. When set to false, a value is required for the `backup_encryption_key_crn` input. Alternatiely set `use_default_backup_encryption_key` to true to use the IBM Cloud Databases default encryption. Applies only if `use_ibm_owned_encryption_key` is false. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `bool` | `true` | no | | [users](#input\_users) | A list of users that you want to create on the database. Multiple blocks are allowed. The user password must be in the range of 10-32 characters. Be warned that in most case using IAM service credentials (via the var.service\_credential\_names) is sufficient to control access to the RabbitMQ instance. This blocks creates native RabbitMQ database users, more info on that can be found here https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-user-management |
list(object({
name = string
password = string # pragma: allowlist secret
type = optional(string)
role = optional(string)
}))
| `[]` | no | +| [version\_upgrade\_skip\_backup](#input\_version\_upgrade\_skip\_backup) | Whether to skip taking a backup before upgrading the database version. Attention: Skipping a backup is not recommended. Skipping a backup before a version upgrade is dangerous and may result in data loss if the upgrade fails at any stage — there will be no immediate backup to restore from. | `bool` | `false` | no | ### Outputs diff --git a/cra-config.yaml b/cra-config.yaml index 65c84b39..4fdda851 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -1,12 +1,11 @@ # More info about this file at https://github.com/terraform-ibm-modules/common-pipeline-assets/blob/main/.github/workflows/terraform-test-pipeline.md#cra-config-yaml version: "v1" CRA_TARGETS: - - CRA_TARGET: "solutions/fully-configurable" - CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" - PROFILE_ID: "fe96bd4d-9b37-40f2-b39f-a62760e326a3" # SCC profile ID (currently set to 'IBM Cloud Framework for Financial Services' '1.7.0' profile). - CRA_ENVIRONMENT_VARIABLES: + - CRA_TARGET: "solutions/fully-configurable" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. + CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" # CRA Ignore file to use. If not provided, it checks the repo root directory for `cra-tf-validate-ignore-rules.json` + PROFILE_ID: "fe96bd4d-9b37-40f2-b39f-a62760e326a3" # SCC profile ID (currently set to 'IBM Cloud Framework for Financial Services' '1.7.0' profile). + CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. TF_VAR_existing_kms_instance_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9::" - TF_VAR_existing_kms_key_crn: "crn:v1:bluemix:public:hs-crypto:us-south:a/abac0df06b644a9cabc6e44f55b3880e:e6dce284-e80f-46e1-a3c1-830f7adff7a9:key:1368d2eb-3ed0-4a8b-b09c-2155895f01ea" TF_VAR_existing_resource_group_name: "geretain-test-rabbitmq" TF_VAR_kms_encryption_enabled: true TF_VAR_provider_visibility: "public" diff --git a/cra-tf-validate-ignore-rules.json b/cra-tf-validate-ignore-rules.json index 4749cc55..2809f91f 100644 --- a/cra-tf-validate-ignore-rules.json +++ b/cra-tf-validate-ignore-rules.json @@ -1,10 +1,10 @@ { - "scc_rules": [ - { - "scc_rule_id": "rule-216e2449-27d7-4afc-929a-b66e196a9cf9", - "description": "Check whether Flow Logs for VPC are enabled", - "ignore_reason": "This rule is not relevant to the module itself, just the VPC resource is used in the example that is scanned", - "is_valid": false - } - ] - } + "scc_rules": [ + { + "scc_rule_id": "rule-216e2449-27d7-4afc-929a-b66e196a9cf9", + "description": "Check whether Flow Logs for VPC are enabled", + "ignore_reason": "This rule is not relevant to the module itself, just the VPC resource is used in the example that is scanned", + "is_valid": false + } + ] +} diff --git a/examples/backup-restore/main.tf b/examples/backup-restore/main.tf index 6cc3d1d4..44620d45 100644 --- a/examples/backup-restore/main.tf +++ b/examples/backup-restore/main.tf @@ -20,12 +20,13 @@ module "restored_rabbitmq_db" { # remove the above line and uncomment the below 2 lines to consume the module from the registry # source = "terraform-ibm-modules/icd-rabbitmq/ibm" # version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release - resource_group_id = module.resource_group.resource_group_id - name = "${var.prefix}-rabbitmq-restored" - region = var.region - rabbitmq_version = var.rabbitmq_version - access_tags = var.access_tags - tags = var.resource_tags - member_host_flavor = "multitenant" - backup_crn = data.ibm_database_backups.backup_database.backups[0].backup_id + resource_group_id = module.resource_group.resource_group_id + name = "${var.prefix}-rabbitmq-restored" + region = var.region + rabbitmq_version = var.rabbitmq_version + access_tags = var.access_tags + tags = var.resource_tags + member_host_flavor = "multitenant" + deletion_protection = false + backup_crn = data.ibm_database_backups.backup_database.backups[0].backup_id } diff --git a/examples/backup-restore/variables.tf b/examples/backup-restore/variables.tf index e5ec2d88..e2261a9c 100644 --- a/examples/backup-restore/variables.tf +++ b/examples/backup-restore/variables.tf @@ -22,6 +22,11 @@ variable "resource_group" { default = null } +variable "access_tags" { + type = list(string) + description = "A list of access tags to apply to the rabbitmq instance created by the module, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial for more details" + default = [] +} variable "rabbitmq_version" { type = string description = "Version of rabbitmq to deploy" @@ -34,12 +39,6 @@ variable "resource_tags" { default = [] } -variable "access_tags" { - type = list(string) - description = "A list of access tags to apply to the rabbitmq instance created by the module, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial for more details" - default = [] -} - variable "rabbitmq_db_crn" { type = string description = "The existing CRN of a rabbitMQ instance to fetch the latest backup crn." diff --git a/examples/backup-restore/version.tf b/examples/backup-restore/version.tf index 30204088..dec5bbea 100644 --- a/examples/backup-restore/version.tf +++ b/examples/backup-restore/version.tf @@ -1,7 +1,7 @@ terraform { required_version = ">= 1.9.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 + # Use latest version of provider in non-basic examples to verify latest version works with module ibm = { source = "IBM-Cloud/ibm" version = ">=1.79.2, <2.0.0" diff --git a/examples/basic/README.md b/examples/basic/README.md index 2725755e..815039ce 100644 --- a/examples/basic/README.md +++ b/examples/basic/README.md @@ -1,5 +1,6 @@ # Basic example -This example uses the IBM Cloud terraform provider to: - - Create a new resource group if one is not passed in. - - Create a new RabbitMQ instance in the resource group and region provided. +An end-to-end example that creates the following infrastructure: + +- A resource group, if one is not passed in. +- An ICD RabbitMQ messaging instance. diff --git a/examples/basic/main.tf b/examples/basic/main.tf index f1925bf3..13d5aa99 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -19,11 +19,13 @@ module "database" { # remove the above line and uncomment the below 2 lines to consume the module from the registry # source = "terraform-ibm-modules/icd-rabbitmq/ibm" # version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release - resource_group_id = module.resource_group.resource_group_id - name = "${var.prefix}-rabbitmq" - region = var.region - tags = var.resource_tags - access_tags = var.access_tags - rabbitmq_version = var.rabbitmq_version - service_endpoints = var.service_endpoints + resource_group_id = module.resource_group.resource_group_id + name = "${var.prefix}-rabbitmq" + region = var.region + rabbitmq_version = var.rabbitmq_version + access_tags = var.access_tags + tags = var.resource_tags + service_endpoints = var.service_endpoints + member_host_flavor = var.member_host_flavor + deletion_protection = false } diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index e8d3aa6b..f11c98cf 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -22,6 +22,12 @@ variable "resource_group" { default = null } +variable "access_tags" { + type = list(string) + description = "A list of access tags to apply to the rabbitmq instance created by the module, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial for more details" + default = [] +} + variable "rabbitmq_version" { type = string description = "Version of rabbitmq to deploy" @@ -34,12 +40,6 @@ variable "resource_tags" { default = [] } -variable "access_tags" { - type = list(string) - description = "A list of access tags to apply to the rabbitmq instance created by the module, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial for more details" - default = [] -} - variable "service_endpoints" { type = string description = "Specify whether you want to enable the public, private, or both service endpoints. Supported values are 'public', 'private', or 'public-and-private'." @@ -50,3 +50,10 @@ variable "service_endpoints" { error_message = "Valid values for service_endpoints are 'public', 'public-and-private', and 'private'" } } + +variable "member_host_flavor" { + type = string + description = "The host flavor per member. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor)." + default = "multitenant" + # Validation is done in the Terraform plan phase by the IBM provider, so no need to add extra validation here. +} diff --git a/examples/basic/version.tf b/examples/basic/version.tf index b8d386aa..56139f05 100644 --- a/examples/basic/version.tf +++ b/examples/basic/version.tf @@ -1,7 +1,7 @@ terraform { required_version = ">= 1.9.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 + # Use latest version of provider in non-basic examples to verify latest version works with module ibm = { source = "IBM-Cloud/ibm" version = "1.79.2" diff --git a/examples/complete/README.md b/examples/complete/README.md index efec6e74..42c31afb 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -1,10 +1,10 @@ # Complete example with BYOK encryption, CBR rules, autoscaling, and service credentials creation -An end-to-end example that does the following: +An end-to-end example that uses the IBM Cloud Terraform provider to create the following infrastructure: -- Create a new resource group if one is not passed in. -- Create Key Protect instance with root key. -- Create a new Messages for RabbitMQ instance with BYOK encryption and autoscaling enabled. -- Create service credentials for the instance. -- Create a Virtual Private Cloud (VPC). -- Create Context Based Restriction (CBR) to only allow RabbitMQ to be accessible from the VPC. +- A resource group, if one is not passed in. +- A Key Protect instance with a root key. +- An instance of Messages for RabbitMQ with BYOK encryption and autoscaling enabled. +- Service credentials for the messaginginstance. +- A sample virtual private cloud (VPC). +- CA context-based restriction (CBR) rule to only allow RabbitMQ to be accessible from within the VPC. diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 7281544a..cbf5692b 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -1,3 +1,16 @@ +############################################################################## +# Locals +############################################################################## + +locals { + service_credential_names = { + "es_admin" : "Administrator", + "es_operator" : "Operator", + "es_viewer" : "Viewer", + "es_editor" : "Editor", + } +} + ############################################################################## # Resource Group ############################################################################## @@ -10,6 +23,24 @@ module "resource_group" { existing_resource_group_name = var.resource_group } +############################################################################## +# VPC +############################################################################## + +resource "ibm_is_vpc" "example_vpc" { + name = "${var.prefix}-vpc" + resource_group = module.resource_group.resource_group_id + tags = var.resource_tags +} + +resource "ibm_is_subnet" "testacc_subnet" { + name = "${var.prefix}-subnet" + vpc = ibm_is_vpc.example_vpc.id + zone = "${var.region}-1" + total_ipv4_address_count = 256 + resource_group = module.resource_group.resource_group_id +} + ############################################################################## # Key Protect All Inclusive ############################################################################## @@ -52,32 +83,15 @@ module "key_protect_all_inclusive" { data "ibm_iam_account_settings" "iam_account_settings" { } -############################################################################## -# VPC -############################################################################## - -resource "ibm_is_vpc" "example_vpc" { - name = "${var.prefix}-vpc" - resource_group = module.resource_group.resource_group_id - tags = var.resource_tags -} - -resource "ibm_is_subnet" "testacc_subnet" { - name = "${var.prefix}-subnet" - vpc = ibm_is_vpc.example_vpc.id - zone = "${var.region}-1" - total_ipv4_address_count = 256 - resource_group = module.resource_group.resource_group_id -} - ############################################################################## # Create CBR Zone ############################################################################## module "cbr_zone" { - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-cbr//modules/cbr-zone-module?ref=v1.32.4" + source = "terraform-ibm-modules/cbr/ibm//modules/cbr-zone-module" + version = "1.32.4" name = "${var.prefix}-VPC-network-zone" - zone_description = "CBR Network zone representing VPC" + zone_description = "CBR Network zone containing VPC" account_id = data.ibm_iam_account_settings.iam_account_settings.account_id addresses = [{ type = "vpc", # to bind a specific vpc to the zone @@ -94,27 +108,23 @@ module "icd_rabbitmq" { # remove the above line and uncomment the below 2 lines to consume the module from the registry # source = "terraform-ibm-modules/icd-rabbitmq/ibm" # version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release - resource_group_id = module.resource_group.resource_group_id - name = "${var.prefix}-rabbitmq" - region = var.region - admin_pass = var.admin_pass - users = var.users - rabbitmq_version = var.rabbitmq_version - tags = var.resource_tags - access_tags = var.access_tags - auto_scaling = var.auto_scaling + resource_group_id = module.resource_group.resource_group_id + name = "${var.prefix}-rabbitmq" + rabbitmq_version = var.rabbitmq_version + admin_pass = var.admin_pass + users = var.users + region = var.region + access_tags = var.access_tags + tags = var.resource_tags + deletion_protection = false + auto_scaling = var.auto_scaling # Example of how to use different KMS keys for data and backups use_ibm_owned_encryption_key = false use_same_kms_key_for_backups = false kms_key_crn = module.key_protect_all_inclusive.keys["icd.${local.data_key_name}"].crn backup_encryption_key_crn = module.key_protect_all_inclusive.keys["icd.${local.backups_key_name}"].crn - service_credential_names = { - "rabbitmq_admin" : "Administrator", - "rabbitmq_operator" : "Operator", - "rabbitmq_viewer" : "Viewer", - "rabbitmq_editor" : "Editor", - } - member_host_flavor = "multitenant" + service_credential_names = local.service_credential_names + member_host_flavor = "multitenant" cbr_rules = [ { description = "${var.prefix}-rabbitmq access only from vpc" diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf index 9d28c3d5..6ca48884 100644 --- a/examples/complete/outputs.tf +++ b/examples/complete/outputs.tf @@ -7,14 +7,19 @@ output "id" { value = module.icd_rabbitmq.id } +output "version" { + description = "RabbitMQ instance version" + value = module.icd_rabbitmq.version +} + output "guid" { description = "RabbitMQ instance guid" value = module.icd_rabbitmq.guid } -output "version" { - description = "RabbitMQ instance version" - value = module.icd_rabbitmq.version +output "crn" { + description = "RabbitMQ instance crn" + value = module.icd_rabbitmq.crn } output "service_credentials_json" { diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf index 2ec2b078..fadf3bbb 100644 --- a/examples/complete/variables.tf +++ b/examples/complete/variables.tf @@ -10,35 +10,10 @@ variable "region" { default = "us-south" } -variable "admin_pass" { - type = string - default = null - sensitive = true - description = "The password for the database administrator. If the admin password is null then the admin user ID cannot be accessed. More users can be specified in a user block." -} - -variable "users" { - type = list(object({ - name = string - password = string - type = optional(string) - role = optional(string) - })) - default = [] - sensitive = true - description = "A list of users that you want to create on the database. Multiple blocks are allowed. The user password must be in the range of 10-32 characters." -} - variable "prefix" { type = string description = "Prefix to append to all resources created by this example" - default = "complete-rabbitmq" -} - -variable "rabbitmq_version" { - type = string - description = "Version of rabbitmq to deploy" - default = null + default = "rabbitmq" } variable "resource_group" { @@ -59,6 +34,31 @@ variable "access_tags" { default = [] } +variable "rabbitmq_version" { + type = string + description = "Version of rabbitmq to deploy" + default = null +} + +variable "admin_pass" { + type = string + default = null + sensitive = true + description = "The password for the database administrator. If the admin password is null then the admin user ID cannot be accessed. More users can be specified in a user block." +} + +variable "users" { + type = list(object({ + name = string + password = string + type = optional(string) + role = optional(string) + })) + default = [] + sensitive = true + description = "A list of users that you want to create on the database. Multiple blocks are allowed. The user password must be in the range of 10-32 characters." +} + variable "auto_scaling" { type = object({ disk = object({ diff --git a/examples/complete/version.tf b/examples/complete/version.tf index 30204088..dec5bbea 100644 --- a/examples/complete/version.tf +++ b/examples/complete/version.tf @@ -1,7 +1,7 @@ terraform { required_version = ">= 1.9.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 + # Use latest version of provider in non-basic examples to verify latest version works with module ibm = { source = "IBM-Cloud/ibm" version = ">=1.79.2, <2.0.0" diff --git a/examples/fscloud/README.md b/examples/fscloud/README.md index 83116bc9..3fbd2852 100644 --- a/examples/fscloud/README.md +++ b/examples/fscloud/README.md @@ -13,7 +13,6 @@ The example uses the IBM Cloud Terraform provider to create the following infras - A context-based restriction (CBR) rule to only allow RabbitMQ to be accessible from within the VPC. :exclamation: **Important:** In this example, only the IBM Cloud Databases for RabbitMQ instance complies with the IBM Cloud Framework for Financial Services. Other parts of the infrastructure do not necessarily comply. - ## Before you begin - You need a Hyper Protect Crypto Services instance and root key available in the region that you want to deploy your RabbitMQ database instance to. diff --git a/examples/fscloud/main.tf b/examples/fscloud/main.tf index 34bc8dfb..6d255ef2 100644 --- a/examples/fscloud/main.tf +++ b/examples/fscloud/main.tf @@ -41,7 +41,7 @@ module "cbr_zone" { source = "terraform-ibm-modules/cbr/ibm//modules/cbr-zone-module" version = "1.32.4" name = "${var.prefix}-VPC-network-zone" - zone_description = "CBR Network zone representing VPC" + zone_description = "CBR Network zone containing VPC" account_id = data.ibm_iam_account_settings.iam_account_settings.account_id addresses = [{ type = "vpc", # to bind a specific vpc to the zone @@ -61,10 +61,13 @@ module "rabbitmq_database" { resource_group_id = module.resource_group.resource_group_id name = "${var.prefix}-rabbitmq" region = var.region - rabbitmq_version = var.rabbitmq_version + tags = var.resource_tags + access_tags = var.access_tags + deletion_protection = false kms_key_crn = var.kms_key_crn backup_encryption_key_crn = var.backup_encryption_key_crn backup_crn = var.backup_crn + rabbitmq_version = var.rabbitmq_version service_credential_names = { "rabbitmq_admin" : "Administrator", "rabbitmq_operator" : "Operator", @@ -81,8 +84,6 @@ module "rabbitmq_database" { } } member_host_flavor = "b3c.4x16.encrypted" - tags = var.tags - access_tags = var.access_tags cbr_rules = [ { description = "${var.prefix}-rabbitmq access only from vpc" diff --git a/examples/fscloud/outputs.tf b/examples/fscloud/outputs.tf index 6ad1a551..ca9388c2 100644 --- a/examples/fscloud/outputs.tf +++ b/examples/fscloud/outputs.tf @@ -15,3 +15,13 @@ output "version" { description = "RabbitMQ instance version" value = module.rabbitmq_database.version } + +output "hostname" { + description = "Database hostname. Only contains value when var.service_credential_names or var.users are set." + value = module.rabbitmq_database.hostname +} + +output "port" { + description = "Database port. Only contains value when var.service_credential_names or var.users are set." + value = module.rabbitmq_database.port +} diff --git a/examples/fscloud/variables.tf b/examples/fscloud/variables.tf index 0e8a753a..e5c00008 100644 --- a/examples/fscloud/variables.tf +++ b/examples/fscloud/variables.tf @@ -10,12 +10,6 @@ variable "region" { default = "us-south" } -variable "resource_tags" { - type = list(string) - description = "Optional list of tags to be added to created resources" - default = [] -} - variable "prefix" { type = string description = "Prefix to append to all resources created by this example" @@ -28,6 +22,18 @@ variable "resource_group" { default = null } +variable "resource_tags" { + type = list(string) + description = "Optional list of tags to be added to created resources" + default = [] +} + +variable "access_tags" { + type = list(string) + description = "A list of access tags to apply to the RabbitMQ instance created by the module, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial for more details" + default = [] +} + variable "kms_key_crn" { type = string description = "The root key CRN of a Hyper Protect Crypto Services (HPCS) that you want to use for disk encryption. See https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs&interface=ui for more information on integrating HPCS with RabbitMQ instance." @@ -51,15 +57,3 @@ variable "backup_encryption_key_crn" { default = null # Validation happens in the root module } - -variable "tags" { - type = list(any) - description = "Optional list of tags to be added to the RabbitMQ instance." - default = [] -} - -variable "access_tags" { - type = list(string) - description = "A list of access tags to apply to the rabbitmq instance created by the module, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial for more details" - default = [] -} diff --git a/ibm_catalog.json b/ibm_catalog.json index 379eb9bd..c790b0e4 100644 --- a/ibm_catalog.json +++ b/ibm_catalog.json @@ -273,6 +273,15 @@ } ] }, + { + "key": "deletion_protection" + }, + { + "key": "timeouts_update" + }, + { + "key": "version_upgrade_skip_backup" + }, { "key": "service_credential_names" }, @@ -570,6 +579,12 @@ { "key": "auto_scaling" }, + { + "key": "deletion_protection" + }, + { + "key": "timeouts_update" + }, { "key": "service_credential_names" }, diff --git a/main.tf b/main.tf index 7d9318cb..31d12690 100644 --- a/main.tf +++ b/main.tf @@ -1,10 +1,3 @@ -######################################################################################################################## -# Input variable validation -# (approach based on https://github.com/hashicorp/terraform/issues/25609#issuecomment-1057614400) -# -# TODO: Replace with terraform cross variable validation: https://github.ibm.com/GoldenEye/issues/issues/10836 -######################################################################################################################## - ######################################################################################################################## # Locals ######################################################################################################################## @@ -19,7 +12,6 @@ locals { # Determine if host_flavor is used host_flavor_set = var.member_host_flavor != null ? true : false - } ######################################################################################################################## @@ -109,9 +101,8 @@ resource "ibm_iam_authorization_policy" "kms_policy" { # workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 resource "time_sleep" "wait_for_authorization_policy" { - count = local.create_kms_auth_policy - depends_on = [ibm_iam_authorization_policy.kms_policy] - + count = local.create_kms_auth_policy + depends_on = [ibm_iam_authorization_policy.kms_policy] create_duration = "30s" } @@ -165,19 +156,21 @@ resource "time_sleep" "wait_for_backup_kms_authorization_policy" { ######################################################################################################################## resource "ibm_database" "rabbitmq_database" { - depends_on = [time_sleep.wait_for_authorization_policy, time_sleep.wait_for_backup_kms_authorization_policy] - name = var.name - plan = var.plan - location = var.region - service = "messages-for-rabbitmq" - version = var.rabbitmq_version - resource_group_id = var.resource_group_id - service_endpoints = var.service_endpoints - tags = var.tags - key_protect_key = var.kms_key_crn - backup_encryption_key_crn = local.backup_encryption_key_crn - adminpassword = var.admin_pass - backup_id = var.backup_crn + depends_on = [time_sleep.wait_for_authorization_policy, time_sleep.wait_for_backup_kms_authorization_policy] + name = var.name + plan = var.plan + location = var.region + service = "messages-for-rabbitmq" + version = var.rabbitmq_version + resource_group_id = var.resource_group_id + service_endpoints = var.service_endpoints + deletion_protection = var.deletion_protection + version_upgrade_skip_backup = var.version_upgrade_skip_backup + tags = var.tags + adminpassword = var.admin_pass + key_protect_key = var.kms_key_crn + backup_encryption_key_crn = local.backup_encryption_key_crn + backup_id = var.backup_crn dynamic "users" { for_each = nonsensitive(var.users != null ? var.users : []) @@ -284,8 +277,7 @@ resource "ibm_database" "rabbitmq_database" { lifecycle { ignore_changes = [ - # Ignore changes to version because a change here will destroy and recreate the instance - version, + # Ignore changes to these because a change will destroy and recreate the instance key_protect_key, backup_encryption_key_crn, ] @@ -293,6 +285,8 @@ resource "ibm_database" "rabbitmq_database" { timeouts { create = "120m" # Extending provisioning time to 120 minutes + update = var.timeouts_update + delete = "15m" } } @@ -306,9 +300,11 @@ resource "ibm_resource_tag" "rabbitmq_tag" { ############################################################################## # Context Based Restrictions ############################################################################## + module "cbr_rule" { count = length(var.cbr_rules) > 0 ? length(var.cbr_rules) : 0 - source = "git::https://github.com/terraform-ibm-modules/terraform-ibm-cbr//modules/cbr-rule-module?ref=v1.32.4" + source = "terraform-ibm-modules/cbr/ibm//modules/cbr-rule-module" + version = "1.32.4" rule_description = var.cbr_rules[count.index].description enforcement_mode = var.cbr_rules[count.index].enforcement_mode rule_contexts = var.cbr_rules[count.index].rule_contexts @@ -331,6 +327,7 @@ module "cbr_rule" { } ] }] + # There is only 1 operation type for RabbitMQ so it is not exposed as a configuration operations = [{ api_types = [ { diff --git a/modules/fscloud/README.md b/modules/fscloud/README.md index 81180841..ab407f32 100644 --- a/modules/fscloud/README.md +++ b/modules/fscloud/README.md @@ -37,6 +37,7 @@ No resources. | [backup\_encryption\_key\_crn](#input\_backup\_encryption\_key\_crn) | The CRN of a Key Protect or Hyper Protect Crypto Services encryption key that you want to use for encrypting the disk that holds deployment backups. Applies only if `use_ibm_owned_encryption_key` is false and `use_same_kms_key_for_backups` is false. If no value is passed, and `use_same_kms_key_for_backups` is true, the value of `kms_key_crn` is used. Alternatively set `use_default_backup_encryption_key` to true to use the IBM Cloud Databases default encryption. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `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 | | [cpu\_count](#input\_cpu\_count) | Allocated dedicated CPU per member. For shared CPU, set to 0. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `0` | no | +| [deletion\_protection](#input\_deletion\_protection) | Enable deletion protection within terraform. This is not a property of the resource and does not prevent deletion outside of terraform. The database can not be deleted by terraform when this value is set to 'true'. In order to delete with terraform the value must be set to 'false' and a terraform apply performed before the destroy is performed. The default is 'true'. | `bool` | `true` | no | | [disk\_mb](#input\_disk\_mb) | Allocated disk per member. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling) | `number` | `1024` | no | | [kms\_key\_crn](#input\_kms\_key\_crn) | The CRN of a Key Protect or Hyper Protect Crypto Services encryption key to encrypt your data. Applies only if `use_ibm_owned_encryption_key` is false. By default this key is used for both deployment data and backups, but this behaviour can be altered using the `use_same_kms_key_for_backups` and `backup_encryption_key_crn` inputs. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `string` | `null` | no | | [member\_host\_flavor](#input\_member\_host\_flavor) | Allocated host flavor per member. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor). | `string` | `null` | no | @@ -48,11 +49,13 @@ No resources. | [resource\_group\_id](#input\_resource\_group\_id) | The resource group ID where the RabbitMQ instance will be created. | `string` | n/a | yes | | [service\_credential\_names](#input\_service\_credential\_names) | Map of name, role for service credentials that you want to create for the database | `map(string)` | `{}` | no | | [skip\_iam\_authorization\_policy](#input\_skip\_iam\_authorization\_policy) | Set to true to skip the creation of IAM authorization policies that permits all Databases for RabbitMQ instances in the given resource group 'Reader' access to the Key Protect or Hyper Protect Crypto Services key that was provided in the `kms_key_crn` and `backup_encryption_key_crn` inputs. This policy is required in order to enable KMS encryption, so only skip creation if there is one already present in your account. No policy is created if `use_ibm_owned_encryption_key` is true. | `bool` | `false` | no | -| [tags](#input\_tags) | Optional list of tags to be added to the RabbitMQ instance. | `list(any)` | `[]` | no | +| [tags](#input\_tags) | Optional list of tags to be added to the RabbitMQ instance. | `list(string)` | `[]` | no | +| [timeouts\_update](#input\_timeouts\_update) | A database update may require a longer timeout for the update to complete. The default is 120 minutes. Set this variable to change the `update` value in the `timeouts` block. [Learn more](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts). | `string` | `"120m"` | no | | [use\_default\_backup\_encryption\_key](#input\_use\_default\_backup\_encryption\_key) | When `use_ibm_owned_encryption_key` is set to false, backups will be encrypted with either the key specified in `kms_key_crn`, or in `backup_encryption_key_crn` if a value is passed. If you do not want to use your own key for backups encryption, you can set this to `true` to use the IBM Cloud Databases default encryption for backups. Alternatively set `use_ibm_owned_encryption_key` to true to use the default encryption for both backups and deployment data. | `bool` | `false` | no | | [use\_ibm\_owned\_encryption\_key](#input\_use\_ibm\_owned\_encryption\_key) | Set to true to use the default IBM Cloud® Databases randomly generated keys for disk and backups encryption. To control the encryption keys, use the `kms_key_crn` and `backup_encryption_key_crn` inputs. | `string` | `false` | no | | [use\_same\_kms\_key\_for\_backups](#input\_use\_same\_kms\_key\_for\_backups) | Set this to false if you wan't to use a different key that you own to encrypt backups. When set to false, a value is required for the `backup_encryption_key_crn` input. Alternatiely set `use_default_backup_encryption_key` to true to use the IBM Cloud Databases default encryption. Applies only if `use_ibm_owned_encryption_key` is false. Bare in mind that backups encryption is only available in certain regions. See [Bring your own key for backups](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-key-protect&interface=ui#key-byok) and [Using the HPCS Key for Backup encryption](https://cloud.ibm.com/docs/cloud-databases?topic=cloud-databases-hpcs#use-hpcs-backups). | `bool` | `true` | no | | [users](#input\_users) | A list of users that you want to create on the database. Multiple blocks are allowed. The user password must be in the range of 10-32 characters. Be warned that in most case using IAM service credentials (via the var.service\_credential\_names) is sufficient to control access to the RabbitMQ instance. This blocks creates native RabbitMQ database users, more info on that can be found here https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-user-management |
list(object({
name = string
password = string # pragma: allowlist secret
type = optional(string)
role = optional(string)
}))
| `[]` | no | +| [version\_upgrade\_skip\_backup](#input\_version\_upgrade\_skip\_backup) | Whether to skip taking a backup before upgrading the database version. Attention: Skipping a backup is not recommended. Skipping a backup before a version upgrade is dangerous and may result in data loss if the upgrade fails at any stage — there will be no immediate backup to restore from. | `bool` | `false` | no | ### Outputs diff --git a/modules/fscloud/main.tf b/modules/fscloud/main.tf index 3cae4fcf..81866de9 100644 --- a/modules/fscloud/main.tf +++ b/modules/fscloud/main.tf @@ -5,23 +5,26 @@ module "rabbitmq_database" { region = var.region skip_iam_authorization_policy = var.skip_iam_authorization_policy service_endpoints = "private" + deletion_protection = var.deletion_protection + version_upgrade_skip_backup = var.version_upgrade_skip_backup + timeouts_update = var.timeouts_update rabbitmq_version = var.rabbitmq_version - tags = var.tags - access_tags = var.access_tags use_ibm_owned_encryption_key = var.use_ibm_owned_encryption_key use_same_kms_key_for_backups = var.use_same_kms_key_for_backups use_default_backup_encryption_key = var.use_default_backup_encryption_key kms_key_crn = var.kms_key_crn backup_crn = var.backup_crn backup_encryption_key_crn = var.backup_encryption_key_crn - service_credential_names = var.service_credential_names - admin_pass = var.admin_pass + cbr_rules = var.cbr_rules + access_tags = var.access_tags + tags = var.tags members = var.members - users = var.users memory_mb = var.memory_mb + admin_pass = var.admin_pass + users = var.users disk_mb = var.disk_mb cpu_count = var.cpu_count member_host_flavor = var.member_host_flavor auto_scaling = var.auto_scaling - cbr_rules = var.cbr_rules + service_credential_names = var.service_credential_names } diff --git a/modules/fscloud/variables.tf b/modules/fscloud/variables.tf index 94045766..9c58f803 100644 --- a/modules/fscloud/variables.tf +++ b/modules/fscloud/variables.tf @@ -84,7 +84,7 @@ variable "service_credential_names" { } variable "tags" { - type = list(any) + type = list(string) description = "Optional list of tags to be added to the RabbitMQ instance." default = [] } @@ -95,6 +95,24 @@ variable "access_tags" { default = [] } +variable "version_upgrade_skip_backup" { + type = bool + description = "Whether to skip taking a backup before upgrading the database version. Attention: Skipping a backup is not recommended. Skipping a backup before a version upgrade is dangerous and may result in data loss if the upgrade fails at any stage — there will be no immediate backup to restore from." + default = false +} + +variable "deletion_protection" { + type = bool + description = "Enable deletion protection within terraform. This is not a property of the resource and does not prevent deletion outside of terraform. The database can not be deleted by terraform when this value is set to 'true'. In order to delete with terraform the value must be set to 'false' and a terraform apply performed before the destroy is performed. The default is 'true'." + default = true +} + +variable "timeouts_update" { + type = string + description = "A database update may require a longer timeout for the update to complete. The default is 120 minutes. Set this variable to change the `update` value in the `timeouts` block. [Learn more](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts)." + default = "120m" +} + ############################################################## # Auto Scaling ############################################################## diff --git a/outputs.tf b/outputs.tf index 9b9f4630..e9fbb5dd 100644 --- a/outputs.tf +++ b/outputs.tf @@ -7,26 +7,21 @@ output "id" { value = ibm_database.rabbitmq_database.id } -output "guid" { - description = "RabbitMQ instance guid" - value = ibm_database.rabbitmq_database.guid -} - output "version" { description = "RabbitMQ instance version" value = ibm_database.rabbitmq_database.version } +output "guid" { + description = "RabbitMQ instance guid" + value = ibm_database.rabbitmq_database.guid +} + output "crn" { description = "RabbitMQ instance crn" value = ibm_database.rabbitmq_database.resource_crn } -output "cbr_rule_ids" { - description = "CBR rule ids created to restrict RabbitMQ" - value = module.cbr_rule[*].rule_id -} - output "service_credentials_json" { description = "Service credentials json map" value = local.service_credentials_json @@ -39,6 +34,11 @@ output "service_credentials_object" { sensitive = true } +output "cbr_rule_ids" { + description = "CBR rule ids created to restrict RabbitMQ" + value = module.cbr_rule[*].rule_id +} + output "adminuser" { description = "Database admin user name" value = ibm_database.rabbitmq_database.adminuser diff --git a/solutions/fully-configurable/DA-types.md b/solutions/fully-configurable/DA-types.md index b11e27da..f4232205 100644 --- a/solutions/fully-configurable/DA-types.md +++ b/solutions/fully-configurable/DA-types.md @@ -69,7 +69,7 @@ The following example includes all the configuration options for four service cr { "secret_group_name": "sg-1" "existing_secret_group": true - "service_credentials": [ # pragma: allowlist secret + "service_credentials": [ # pragma: allowlist secret { "secret_name": "cred-1" "service_credentials_source_service_role_crn": "crn:v1:bluemix:public:iam::::role:Editor" @@ -117,17 +117,16 @@ If you can't use the IAM-enabled `service_credential_names` input variable for a ### Example users - ```hcl [ { "name": "es_admin", - "password": "securepassword123", # pragma: allowlist secret + "password": "securepassword123", "type": "database", }, { "name": "es_reader", - "password": "readpassword123", # pragma: allowlist secret + "password": "readpassword123", "type": "ops_manager" } ] @@ -138,7 +137,7 @@ If you can't use the IAM-enabled `service_credential_names` input variable for a The Autoscaling variable sets the rules for how database increase resources in response to usage. Make sure you understand the effects of autoscaling, especially for production environments. For more information, see [Autoscaling](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-autoscaling&interface=ui#autoscaling-consider). - Variable name: `auto_scaling` -- Type: An object with `disk` and `memory` configurations. +- Type: An object with `disk` and `memory` configurations ### Disk options for auto_scaling @@ -156,7 +155,6 @@ The disk object in the `auto_scaling` input contains the following options. All - `rate_period_seconds`: How long (in seconds) the rate limit is applied for disk (default: `900` (15 minutes)). - `rate_units`: The units to use for the rate increase (default: `"mb"` (megabytes)). - ### Memory options for auto_scaling The memory object within auto_scaling contains the following options. All options are optional. diff --git a/solutions/fully-configurable/catalogValidationValues.json.template b/solutions/fully-configurable/catalogValidationValues.json.template index a8cd4380..0dde19bb 100644 --- a/solutions/fully-configurable/catalogValidationValues.json.template +++ b/solutions/fully-configurable/catalogValidationValues.json.template @@ -5,5 +5,6 @@ "name": $PREFIX, "existing_resource_group_name":"geretain-test-rabbitmq", "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN, + "deletion_protection": false, "kms_encryption_enabled": true } diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf index 89f43273..a3b9fa45 100644 --- a/solutions/fully-configurable/main.tf +++ b/solutions/fully-configurable/main.tf @@ -95,7 +95,7 @@ locals { create_cross_account_kms_auth_policy = var.kms_encryption_enabled && !var.skip_rabbitmq_kms_auth_policy && var.ibmcloud_kms_api_key != null create_cross_account_backup_kms_auth_policy = var.kms_encryption_enabled && !var.skip_rabbitmq_kms_auth_policy && var.ibmcloud_kms_api_key != null && var.existing_backup_kms_key_crn != null - # If KMS encryption enabled (and existing ES instance is not being passed), parse details from the existing key if being passed, otherwise get it from the key that the DA creates + # If KMS encryption enabled (and existing RabbitMQ instance is not being passed), parse details from the existing key if being passed, otherwise get it from the key that the DA creates kms_account_id = !var.kms_encryption_enabled || var.existing_rabbitmq_instance_crn != null ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].account_id : module.kms_instance_crn_parser[0].account_id kms_service = !var.kms_encryption_enabled || var.existing_rabbitmq_instance_crn != null ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].service_name : module.kms_instance_crn_parser[0].service_name kms_instance_guid = !var.kms_encryption_enabled || var.existing_rabbitmq_instance_crn != null ? null : var.existing_kms_key_crn != null ? module.kms_key_crn_parser[0].service_instance : module.kms_instance_crn_parser[0].service_instance @@ -282,7 +282,6 @@ module "rabbitmq" { name = "${local.prefix}${var.name}" region = var.region rabbitmq_version = var.rabbitmq_version - service_endpoints = var.service_endpoints skip_iam_authorization_policy = var.skip_rabbitmq_kms_auth_policy use_ibm_owned_encryption_key = local.use_ibm_owned_encryption_key kms_key_crn = local.kms_key_crn @@ -301,6 +300,10 @@ module "rabbitmq" { auto_scaling = var.auto_scaling service_credential_names = var.service_credential_names backup_crn = var.backup_crn + service_endpoints = var.service_endpoints + deletion_protection = var.deletion_protection + version_upgrade_skip_backup = var.version_upgrade_skip_backup + timeouts_update = var.timeouts_update cbr_rules = var.cbr_rules } diff --git a/solutions/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf index b4e1dce5..e5aebb1f 100644 --- a/solutions/fully-configurable/variables.tf +++ b/solutions/fully-configurable/variables.tf @@ -10,8 +10,9 @@ variable "ibmcloud_api_key" { variable "existing_resource_group_name" { type = string - description = "The name of an existing resource group to provision the Databases for RabbitMQ in." + description = "The name of an existing resource group to provision the Messages for RabbitMQ in." default = "Default" + nullable = false } variable "prefix" { @@ -113,6 +114,11 @@ variable "member_host_flavor" { type = string description = "The host flavor per member. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor)." default = "multitenant" + # Prevent null or "", require multitenant or a machine type + validation { + condition = (length(var.member_host_flavor) > 0) + error_message = "Member host flavor must be specified. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor)." + } } variable "service_credential_names" { @@ -141,7 +147,7 @@ variable "users" { } variable "resource_tags" { - type = list(any) + type = list(string) description = "The list of tags to be added to the Messages for RabbitMQ instance." default = [] } @@ -152,6 +158,24 @@ variable "access_tags" { default = [] } +variable "version_upgrade_skip_backup" { + type = bool + description = "Whether to skip taking a backup before upgrading the database version. Attention: Skipping a backup is not recommended. Skipping a backup before a version upgrade is dangerous and may result in data loss if the upgrade fails at any stage — there will be no immediate backup to restore from." + default = false +} + +variable "deletion_protection" { + type = bool + description = "Enable deletion protection within terraform. This is not a property of the resource and does not prevent deletion outside of terraform. The database can not be deleted by terraform when this value is set to 'true'. In order to delete with terraform the value must be set to 'false' and a terraform apply performed before the destroy is performed. The default is 'true'." + default = true +} + +variable "timeouts_update" { + type = string + description = "A database update may require a longer timeout for the update to complete. The default is 120 minutes. Set this variable to change the `update` value in the `timeouts` block. [Learn more](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts)." + default = "120m" +} + ############################################################## # Encryption ############################################################## @@ -193,6 +217,7 @@ variable "kms_endpoint_type" { type = string description = "The type of endpoint to use for communicating with the Key Protect or Hyper Protect Crypto Services instance. Possible values: `public`, `private`. Applies only if `existing_kms_key_crn` is not specified." default = "private" + validation { condition = can(regex("public|private", var.kms_endpoint_type)) error_message = "The kms_endpoint_type value must be 'public' or 'private'." @@ -306,6 +331,7 @@ variable "existing_secrets_manager_endpoint_type" { type = string description = "The endpoint type to use if `existing_secrets_manager_instance_crn` is specified. Possible values: public, private." default = "private" + validation { condition = contains(["public", "private"], var.existing_secrets_manager_endpoint_type) error_message = "Only \"public\" and \"private\" are allowed values for 'existing_secrets_endpoint_type'." diff --git a/solutions/security-enforced/catalogValidationValues.json.template b/solutions/security-enforced/catalogValidationValues.json.template index a0370e26..3684442f 100644 --- a/solutions/security-enforced/catalogValidationValues.json.template +++ b/solutions/security-enforced/catalogValidationValues.json.template @@ -4,5 +4,6 @@ "resource_tags": $TAGS, "name": $PREFIX, "existing_resource_group_name": "geretain-test-rabbitmq", - "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN + "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN, + "deletion_protection": false } diff --git a/solutions/security-enforced/main.tf b/solutions/security-enforced/main.tf index 04d50458..5d8c5e69 100644 --- a/solutions/security-enforced/main.tf +++ b/solutions/security-enforced/main.tf @@ -1,14 +1,13 @@ module "icd_rabbitmq" { source = "../fully-configurable" - prefix = var.prefix ibmcloud_api_key = var.ibmcloud_api_key existing_resource_group_name = var.existing_resource_group_name + prefix = var.prefix name = var.name provider_visibility = "private" region = var.region - rabbitmq_version = var.rabbitmq_version existing_rabbitmq_instance_crn = var.existing_rabbitmq_instance_crn - service_endpoints = "private" + rabbitmq_version = var.rabbitmq_version members = var.members member_memory_mb = var.member_memory_mb member_cpu_count = var.member_cpu_count @@ -28,7 +27,7 @@ module "icd_rabbitmq" { key_ring_name = var.key_ring_name key_name = var.key_name existing_backup_kms_key_crn = var.existing_backup_kms_key_crn - use_default_backup_encryption_key = "false" + use_default_backup_encryption_key = false backup_crn = var.backup_crn auto_scaling = var.auto_scaling existing_secrets_manager_instance_crn = var.existing_secrets_manager_instance_crn @@ -38,5 +37,9 @@ module "icd_rabbitmq" { admin_pass_secrets_manager_secret_group = var.admin_pass_secrets_manager_secret_group use_existing_admin_pass_secrets_manager_secret_group = var.use_existing_admin_pass_secrets_manager_secret_group admin_pass_secrets_manager_secret_name = var.admin_pass_secrets_manager_secret_name + service_endpoints = "private" + deletion_protection = var.deletion_protection + version_upgrade_skip_backup = false + timeouts_update = var.timeouts_update cbr_rules = var.cbr_rules } diff --git a/solutions/security-enforced/moved.tf b/solutions/security-enforced/moved.tf deleted file mode 100644 index 2c783c3c..00000000 --- a/solutions/security-enforced/moved.tf +++ /dev/null @@ -1,4 +0,0 @@ -moved { - from = module.rabbitmq - to = module.rabbitmq[0] -} diff --git a/solutions/security-enforced/provider.tf b/solutions/security-enforced/provider.tf new file mode 100644 index 00000000..4c6add22 --- /dev/null +++ b/solutions/security-enforced/provider.tf @@ -0,0 +1 @@ +# Explicit provider config not required here as provider config in fully-configurable is used diff --git a/solutions/security-enforced/variables.tf b/solutions/security-enforced/variables.tf index fb34c88d..1f6f62ac 100644 --- a/solutions/security-enforced/variables.tf +++ b/solutions/security-enforced/variables.tf @@ -10,8 +10,9 @@ variable "ibmcloud_api_key" { variable "existing_resource_group_name" { type = string - description = "The name of an existing resource group to provision the Databases for RabbitMQ in." + description = "The name of an existing resource group to provision resource in." default = "Default" + nullable = false } variable "prefix" { @@ -97,6 +98,11 @@ variable "member_host_flavor" { type = string description = "The host flavor per member. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor)." default = "multitenant" + # Prevent null or "", require multitenant or a machine type + validation { + condition = (length(var.member_host_flavor) > 0) + error_message = "Member host flavor must be specified. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/database#host_flavor)." + } } variable "service_credential_names" { @@ -125,7 +131,7 @@ variable "users" { } variable "resource_tags" { - type = list(any) + type = list(string) description = "The list of resource tags to be added to the Messages for RabbitMQ instance." default = [] } @@ -136,6 +142,18 @@ variable "access_tags" { default = [] } +variable "deletion_protection" { + type = bool + description = "Enable deletion protection within terraform. This is not a property of the resource and does not prevent deletion outside of terraform. The database can not be deleted by terraform when this value is set to 'true'. In order to delete with terraform the value must be set to 'false' and a terraform apply performed before the destroy is performed. The default is 'true'." + default = true +} + +variable "timeouts_update" { + type = string + description = "A database update may require a longer timeout for the update to complete. The default is 120 minutes. Set this variable to change the `update` value in the `timeouts` block. [Learn more](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts)." + default = "120m" +} + ############################################################## # Encryption ############################################################## @@ -233,9 +251,9 @@ variable "auto_scaling" { default = null } -############################################################################## -## Secrets Manager Service Credentials -############################################################################## +############################################################################# +# Secrets Manager Service Credentials +############################################################################# variable "existing_secrets_manager_instance_crn" { type = string diff --git a/tests/go.mod b/tests/go.mod index d877c963..5748ec66 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -5,6 +5,7 @@ go 1.24.0 toolchain go1.24.5 require ( + github.com/google/uuid v1.6.0 github.com/gruntwork-io/terratest v0.50.0 github.com/stretchr/testify v1.10.0 github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper v1.57.0 @@ -52,7 +53,6 @@ require ( github.com/go-playground/validator/v10 v10.26.0 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-getter/v2 v2.2.3 // indirect diff --git a/tests/other_test.go b/tests/other_test.go index b063765c..48b8181b 100644 --- a/tests/other_test.go +++ b/tests/other_test.go @@ -1,59 +1,14 @@ -// Tests in this file are run in the PR pipeline +// 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 ( - "crypto/rand" - "encoding/base64" "fmt" - "log" "testing" "github.com/stretchr/testify/assert" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" ) -func TestRunCompleteExample(t *testing.T) { - t.Parallel() - - // Generate a 15 char long random string for the admin_pass - randomBytes := make([]byte, 13) - _, err := rand.Read(randomBytes) - if err != nil { - log.Fatal(err) - } - // add character prefix to avoid generated password beginning with special char and must have a number - randomPass := "A1" + base64.URLEncoding.EncodeToString(randomBytes)[:13] - - options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ - Testing: t, - TerraformDir: completeExampleTerraformDir, - Prefix: "rmq-upg", - BestRegionYAMLPath: regionSelectionPath, - ResourceGroup: resourceGroup, - TerraformVars: map[string]interface{}{ - "rabbitmq_version": earliestVersion, // Always lock to the lowest supported RabbitMQ version - "users": []map[string]interface{}{ - { - "name": "testuser", - "password": randomPass, // pragma: allowlist secret - "type": "database", - }, - }, - "admin_pass": randomPass, - }, - CloudInfoService: sharedInfoSvc, - }) - - output, err := options.RunTestConsistency() - assert.Nil(t, err, "This should not have errored") - assert.NotNil(t, output, "Expected some output") - - outputs := options.LastTestTerraformOutputs - expectedOutputs := []string{"port", "hostname"} - _, outputErr := testhelper.ValidateTerraformOutputs(outputs, expectedOutputs...) - assert.NoErrorf(t, outputErr, "Some outputs not found or nil") -} - func testPlanICDVersions(t *testing.T, version string) { t.Parallel() @@ -87,8 +42,8 @@ func TestRunRestoredDBExample(t *testing.T) { Testing: t, TerraformDir: "examples/backup-restore", Prefix: "rmq-restored", - ResourceGroup: resourceGroup, Region: fmt.Sprint(permanentResources["rabbitmqRegion"]), + ResourceGroup: resourceGroup, TerraformVars: map[string]interface{}{ "rabbitmq_db_crn": permanentResources["rabbitmqCrn"], "rabbitmq_version": permanentResources["rabbitmqVersion"], @@ -100,3 +55,36 @@ func TestRunRestoredDBExample(t *testing.T) { assert.Nil(t, err, "This should not have errored") assert.NotNil(t, output, "Expected some output") } + +func TestRunCompleteExample(t *testing.T) { + t.Parallel() + + options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ + Testing: t, + TerraformDir: completeExampleTerraformDir, + Prefix: "rmq-upg", + BestRegionYAMLPath: regionSelectionPath, + ResourceGroup: resourceGroup, + TerraformVars: map[string]interface{}{ + "rabbitmq_version": earliestVersion, // Always lock to the lowest supported RabbitMQ version + "users": []map[string]interface{}{ + { + "name": "testuser", + "password": GetRandomAdminPassword(t), + "type": "database", + }, + }, + "admin_pass": GetRandomAdminPassword(t), + }, + CloudInfoService: sharedInfoSvc, + }) + + output, err := options.RunTestConsistency() + assert.Nil(t, err, "This should not have errored") + assert.NotNil(t, output, "Expected some output") + + outputs := options.LastTestTerraformOutputs + expectedOutputs := []string{"port", "hostname"} + _, outputErr := testhelper.ValidateTerraformOutputs(outputs, expectedOutputs...) + assert.NoErrorf(t, outputErr, "Some outputs not found or nil") +} diff --git a/tests/pr_test.go b/tests/pr_test.go index 6cd9108f..78810d7f 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -40,7 +40,7 @@ const regionSelectionPath = "../common-dev-assets/common-go-assets/icd-region-pr // Define a struct with fields that match the structure of the YAML data const yamlLocation = "../common-dev-assets/common-go-assets/common-permanent-resources.yaml" -var permanentResources map[string]any +var permanentResources map[string]interface{} var sharedInfoSvc *cloudinfo.CloudInfoService var validICDRegions = []string{ @@ -79,7 +79,7 @@ func TestRunFullyConfigurableSolutionSchematics(t *testing.T) { WaitJobCompleteMinutes: 60, }) - serviceCredentialSecrets := []map[string]any{ + serviceCredentialSecrets := []map[string]interface{}{ { "secret_group_name": fmt.Sprintf("%s-secret-group", options.Prefix), "service_credentials": []map[string]string{ @@ -108,17 +108,18 @@ func TestRunFullyConfigurableSolutionSchematics(t *testing.T) { options.TerraformVars = []testschematic.TestSchematicTerraformVar{ {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, - {Name: "prefix", Value: options.Prefix, DataType: "string"}, {Name: "access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, - {Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"}, {Name: "kms_encryption_enabled", Value: true, DataType: "bool"}, + {Name: "deletion_protection", Value: false, DataType: "bool"}, + {Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"}, {Name: "kms_endpoint_type", Value: "private", DataType: "string"}, - {Name: "existing_resource_group_name", Value: resourceGroup, DataType: "string"}, {Name: "rabbitmq_version", Value: latestVersion, DataType: "string"}, // Always lock this test into the latest supported RabbitMQ version + {Name: "existing_resource_group_name", Value: resourceGroup, DataType: "string"}, {Name: "service_credential_names", Value: string(serviceCredentialNamesJSON), DataType: "map(string)"}, {Name: "existing_secrets_manager_instance_crn", Value: permanentResources["secretsManagerCRN"], DataType: "string"}, {Name: "service_credential_secrets", Value: serviceCredentialSecrets, DataType: "list(object)"}, {Name: "admin_pass", Value: GetRandomAdminPassword(t), DataType: "string"}, + {Name: "prefix", Value: options.Prefix, DataType: "string"}, } err = options.RunSchematicTest() assert.Nil(t, err, "This should not have errored") @@ -165,13 +166,13 @@ func TestRunSecurityEnforcedSchematics(t *testing.T) { }, TemplateFolder: securityEnforcedTerraformDir, BestRegionYAMLPath: regionSelectionPath, - Prefix: "rmq-sec", + Prefix: "rmq-se-da", ResourceGroup: resourceGroup, DeleteWorkspaceOnFail: false, WaitJobCompleteMinutes: 60, }) - serviceCredentialSecrets := []map[string]any{ + serviceCredentialSecrets := []map[string]interface{}{ { "secret_group_name": fmt.Sprintf("%s-secret-group", options.Prefix), "service_credentials": []map[string]string{ @@ -202,16 +203,17 @@ func TestRunSecurityEnforcedSchematics(t *testing.T) { options.TerraformVars = []testschematic.TestSchematicTerraformVar{ {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, - {Name: "prefix", Value: options.Prefix, DataType: "string"}, {Name: "access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, + {Name: "deletion_protection", Value: false, DataType: "bool"}, {Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"}, {Name: "existing_backup_kms_key_crn", Value: permanentResources["hpcs_south_root_key_crn"], DataType: "string"}, - {Name: "existing_resource_group_name", Value: uniqueResourceGroup, DataType: "string"}, {Name: "rabbitmq_version", Value: latestVersion, DataType: "string"}, // Always lock this test into the latest supported RabbitMQ version + {Name: "existing_resource_group_name", Value: uniqueResourceGroup, DataType: "string"}, {Name: "service_credential_names", Value: string(serviceCredentialNamesJSON), DataType: "map(string)"}, {Name: "existing_secrets_manager_instance_crn", Value: permanentResources["secretsManagerCRN"], DataType: "string"}, {Name: "service_credential_secrets", Value: serviceCredentialSecrets, DataType: "list(object)"}, {Name: "admin_pass", Value: GetRandomAdminPassword(t), DataType: "string"}, + {Name: "prefix", Value: options.Prefix, DataType: "string"}, } err = sharedInfoSvc.WithNewResourceGroup(uniqueResourceGroup, func() error { return options.RunSchematicTest() @@ -298,7 +300,7 @@ func TestRunExistingInstance(t *testing.T) { logger.Log(t, "Tempdir: ", tempTerraformDir) existingTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ TerraformDir: tempTerraformDir + "/examples/basic", - Vars: map[string]any{ + Vars: map[string]interface{}{ "prefix": prefix, "region": region, "resource_group": resourceGroup, @@ -332,10 +334,11 @@ func TestRunExistingInstance(t *testing.T) { }) options.TerraformVars = []testschematic.TestSchematicTerraformVar{ - {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, {Name: "prefix", Value: options.Prefix, DataType: "string"}, + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, {Name: "existing_rabbitmq_instance_crn", Value: terraform.Output(t, existingTerraformOptions, "rabbitmq_crn"), DataType: "string"}, {Name: "existing_resource_group_name", Value: resourceGroup, DataType: "string"}, + {Name: "deletion_protection", Value: false, DataType: "bool"}, {Name: "region", Value: region, DataType: "string"}, {Name: "provider_visibility", Value: "public", DataType: "string"}, } diff --git a/variables.tf b/variables.tf index 86e1d62d..84f62173 100644 --- a/variables.tf +++ b/variables.tf @@ -52,9 +52,9 @@ variable "plan" { variable "members" { type = number - description = "Allocated number of members. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling)" + description = "The number of members that are allocated. [Learn more](https://cloud.ibm.com/docs/messages-for-rabbitmq?topic=messages-for-rabbitmq-resources-scaling)" default = 3 - # Validation is done in the Terraform plan phase by the IBM provider, so no need to add extra validation here. + # Validation is done in terraform plan phase by IBM provider, so no need to add any extra validation here } variable "cpu_count" { @@ -127,7 +127,7 @@ variable "service_endpoints" { } variable "tags" { - type = list(any) + type = list(string) description = "Optional list of tags to be added to the RabbitMQ instance." default = [] } @@ -145,6 +145,24 @@ variable "access_tags" { } } +variable "version_upgrade_skip_backup" { + type = bool + description = "Whether to skip taking a backup before upgrading the database version. Attention: Skipping a backup is not recommended. Skipping a backup before a version upgrade is dangerous and may result in data loss if the upgrade fails at any stage — there will be no immediate backup to restore from." + default = false +} + +variable "deletion_protection" { + type = bool + description = "Enable deletion protection within terraform. This is not a property of the resource and does not prevent deletion outside of terraform. The database can not be deleted by terraform when this value is set to 'true'. In order to delete with terraform the value must be set to 'false' and a terraform apply performed before the destroy is performed. The default is 'true'." + default = true +} + +variable "timeouts_update" { + type = string + description = "A database update may require a longer timeout for the update to complete. The default is 120 minutes. Set this variable to change the `update` value in the `timeouts` block. [Learn more](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts)." + default = "120m" +} + ############################################################## # Auto Scaling ############################################################## @@ -288,6 +306,7 @@ variable "cbr_rules" { })) description = "(Optional, list) List of context-based restrictions rules to create." default = [] + # Validation happens in the rule module } ############################################################## diff --git a/version.tf b/version.tf index cba2bf66..857e2b1c 100644 --- a/version.tf +++ b/version.tf @@ -1,14 +1,14 @@ terraform { required_version = ">= 1.9.0" - # Add any required providers below and uncomment required_providers { ibm = { - source = "IBM-Cloud/ibm" + source = "IBM-Cloud/ibm" + # Use "greater than or equal to" range in modules version = ">= 1.79.2, <2.0.0" } time = { source = "hashicorp/time" - version = ">= 0.9.1" + version = ">= 0.9.1, < 1.0.0" } } } From 0c989ca968f1783c81119a3da168a56b05b9ce03 Mon Sep 17 00:00:00 2001 From: shemau Date: Fri, 25 Jul 2025 09:18:07 +0100 Subject: [PATCH 2/7] fix: move upgrade test to schematics --- tests/pr_test.go | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/tests/pr_test.go b/tests/pr_test.go index 78810d7f..72b7b98b 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -125,32 +125,36 @@ func TestRunFullyConfigurableSolutionSchematics(t *testing.T) { assert.Nil(t, err, "This should not have errored") } -func TestRunFullyConfigurableUpgradeSolution(t *testing.T) { +func TestRunSecurityEnforcedUpgradeSolutionSchematics(t *testing.T) { t.Parallel() - options := testhelper.TestOptionsDefault(&testhelper.TestOptions{ - Testing: t, - TerraformDir: fullyConfigurableSolutionTerraformDir, - BestRegionYAMLPath: regionSelectionPath, - Prefix: "rmq-upg", - ResourceGroup: resourceGroup, + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Region: "us-south", + Prefix: "rmq-upgv", + ResourceGroup: resourceGroup, + TarIncludePatterns: []string{ + "*.tf", + fullyConfigurableSolutionTerraformDir + "/*.tf", + securityEnforcedTerraformDir + "/*.tf", + }, + TemplateFolder: securityEnforcedTerraformDir, + Tags: []string{"rmq-upgv"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 120, + CheckApplyResultForUpgrade: true, }) - options.TerraformVars = map[string]any{ - "prefix": options.Prefix, - "access_tags": permanentResources["accessTags"], - "existing_kms_instance_crn": permanentResources["hpcs_south_crn"], - "kms_encryption_enabled": true, - "kms_endpoint_type": "public", - "provider_visibility": "public", - "existing_resource_group_name": resourceGroup, + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "prefix", Value: options.Prefix, DataType: "string"}, + {Name: "deletion_protection", Value: false, DataType: "bool"}, + {Name: "existing_resource_group_name", Value: resourceGroup, DataType: "string"}, + {Name: "existing_kms_instance_crn", Value: permanentResources["hpcs_south_crn"], DataType: "string"}, } - output, err := options.RunTestUpgrade() - if !options.UpgradeTestSkipped { - assert.Nil(t, err, "This should not have errored") - assert.NotNil(t, output, "Expected some output") - } + err := options.RunSchematicUpgradeTest() + assert.Nil(t, err, "This should not have errored") } func TestRunSecurityEnforcedSchematics(t *testing.T) { From 0ca7d8ac7ea3ffb19462f4d5bdb2df870fe15b23 Mon Sep 17 00:00:00 2001 From: shemau Date: Fri, 25 Jul 2025 10:21:58 +0100 Subject: [PATCH 3/7] SKIP UPGRADE From 6fc589fea47f6248184f2473056afd79ca5f2be5 Mon Sep 17 00:00:00 2001 From: shemau Date: Fri, 25 Jul 2025 12:34:12 +0100 Subject: [PATCH 4/7] SKIP UPGRADE TEST From b8ca1f9af0f810e159549d987c738315340fb7be Mon Sep 17 00:00:00 2001 From: shemau Date: Mon, 28 Jul 2025 11:29:32 +0100 Subject: [PATCH 5/7] fix: bump following merge with main --- README.md | 2 +- examples/complete/main.tf | 2 +- main.tf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 52925be8..9134e15d 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ You need the following permissions to run this module. | Name | Source | Version | |------|--------|---------| | [backup\_key\_crn\_parser](#module\_backup\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.2.0 | -| [cbr\_rule](#module\_cbr\_rule) | terraform-ibm-modules/cbr/ibm//modules/cbr-rule-module | 1.32.4 | +| [cbr\_rule](#module\_cbr\_rule) | terraform-ibm-modules/cbr/ibm//modules/cbr-rule-module | 1.32.5 | | [kms\_key\_crn\_parser](#module\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.2.0 | ### Resources diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 1dc8ea86..f45951de 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -89,7 +89,7 @@ data "ibm_iam_account_settings" "iam_account_settings" { module "cbr_zone" { source = "terraform-ibm-modules/cbr/ibm//modules/cbr-zone-module" - version = "1.32.4" + version = "1.32.5" name = "${var.prefix}-VPC-network-zone" zone_description = "CBR Network zone containing VPC" account_id = data.ibm_iam_account_settings.iam_account_settings.account_id diff --git a/main.tf b/main.tf index 31d12690..630b1896 100644 --- a/main.tf +++ b/main.tf @@ -304,7 +304,7 @@ resource "ibm_resource_tag" "rabbitmq_tag" { module "cbr_rule" { count = length(var.cbr_rules) > 0 ? length(var.cbr_rules) : 0 source = "terraform-ibm-modules/cbr/ibm//modules/cbr-rule-module" - version = "1.32.4" + version = "1.32.5" rule_description = var.cbr_rules[count.index].description enforcement_mode = var.cbr_rules[count.index].enforcement_mode rule_contexts = var.cbr_rules[count.index].rule_contexts From eb7dd9738cc61a57b3540ae381290bf875a67a25 Mon Sep 17 00:00:00 2001 From: shemau Date: Wed, 30 Jul 2025 16:45:27 +0100 Subject: [PATCH 6/7] Update examples/complete/README.md Co-authored-by: Md Anam Raihan --- examples/complete/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/complete/README.md b/examples/complete/README.md index 42c31afb..5561a8ba 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -5,6 +5,6 @@ An end-to-end example that uses the IBM Cloud Terraform provider to create the f - A resource group, if one is not passed in. - A Key Protect instance with a root key. - An instance of Messages for RabbitMQ with BYOK encryption and autoscaling enabled. -- Service credentials for the messaginginstance. +- Service credentials for the messaging instance. - A sample virtual private cloud (VPC). - CA context-based restriction (CBR) rule to only allow RabbitMQ to be accessible from within the VPC. From f8edf857cf4ae510add1cff0d60d88364ce08384 Mon Sep 17 00:00:00 2001 From: shemau Date: Wed, 30 Jul 2025 16:45:53 +0100 Subject: [PATCH 7/7] Update examples/complete/README.md Co-authored-by: Md Anam Raihan --- examples/complete/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/complete/README.md b/examples/complete/README.md index 5561a8ba..7061d7bc 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -7,4 +7,4 @@ An end-to-end example that uses the IBM Cloud Terraform provider to create the f - An instance of Messages for RabbitMQ with BYOK encryption and autoscaling enabled. - Service credentials for the messaging instance. - A sample virtual private cloud (VPC). -- CA context-based restriction (CBR) rule to only allow RabbitMQ to be accessible from within the VPC. +- Create context-based restriction (CBR) rule to only allow RabbitMQ to be accessible from within the VPC.