diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/README.md b/manageability-and-operations/observability-and-manageability/external-database-enablement/README.md new file mode 100644 index 000000000..6b3e3bede --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/README.md @@ -0,0 +1,123 @@ +# Enable Observability & Management for Multiple External Database Systems with Terraform + +This Terraform asset enables Database Management, Operations Insights, and/or Stack Monitoring for multiple external container and pluggable databases based on input from two JSON-files in **root_module**: +- **db_systems.json** +- **db_credentials.json** + +Reviewed: 21.02.2024 + +## How does it work? + +OCI's [External Database Service](https://docs.oracle.com/en-us/iaas/external-database/index.html) handles management agent connections to on-prem database systems. Using these connections, certain services in Observability & Management can then be enabled for the external databases: [Database Management](https://docs.oracle.com/en-us/iaas/database-management/home.htm), [Operations Insights](https://docs.oracle.com/en-us/iaas/operations-insights/home.htm), and [Stack Monitoring](https://docs.oracle.com/en-us/iaas/stack-monitoring/index.html). After [installing management agents](https://docs.oracle.com/en-us/iaas/management-agents/doc/install-management-agent-chapter.html), the Terraform configuration files in this asset can perform the database connection setup for agents and enable Observability & Management services for all external databases + +## When to use this asset? + +This asset is for anyone managing multiple on-prem database systems who needs to enable services in Observability & Management. Instead of spending valuable time doing this manually for each container and pluggable database in the OCI Console, just use these Terraform configuration files to complete the setup for you + +## How to use this asset? + +### Prerequisites + +1. Prepare required policies for Management Agent Service, Database Management, Operations Insights, and/or Stack Monitoring: + - Click [here](https://docs.oracle.com/en-us/iaas/management-agents/doc/perform-prerequisites-deploying-management-agents.html) for more about Management Agent policies + - Click [here](https://docs.oracle.com/en-us/iaas/database-management/doc/permissions-required-enable-database-management-external-databases.html#DBMGM-GUID-3DDC9D5F-99B8-4DD5-A0C4-194D29FC883F) for more about Database Management policies + - Click [here](https://docs.oracle.com/en-us/iaas/operations-insights/doc/set-groups-users-and-policies.html) for more about Operations Insights policies + - Click [here](https://docs.oracle.com/en-us/iaas/stack-monitoring/doc/service-requirements.html) for more about Stack Monitoring policies +2. [Install management agent(s)](https://docs.oracle.com/en-us/iaas/management-agents/doc/install-management-agent-chapter.html) connecting to database systems + + **NOTE**: The management agent can either be installed locally on a database instance host or connect to databases remotely on a separate machine. The agent can connect to and monitor one or more databases + +4. [Install Terraform and create RSA keys for API signing](https://docs.oracle.com/en-us/iaas/developer-tutorials/tutorials/tf-provider/01-summary.htm) + + **NOTE**: Remember to save the values in the **configuration file preview** when adding the public API key to an OCI user + +### Prepare and apply Terraform configurations + +1. Download **root_module** and its configuration files to the machine with the private RSA key and Terraform installation +2. Set configuration options for the OCI provider in **root_module/provider.tf** + + **NOTE**: Most options can be set with the configuration file preview values shown when adding a public API key to an OCI user +3. Set **compartment_ocid** variable in **root_module/variables.tf** + + **NOTE**: This is the compartment where everything will be managed in the External Database Service: database connections and enablement of services in Observability & Management. This will also be the compartment where all monitoring data will be located across the enabled services +4. Define your database systems in **root_module/db_systems.json**. See **root_module/db_systems_example.json** for an example: + - Create a database system object for every database system. You can copy-paste the **system1** object as a template in **root_module/db_systems.json** + + **NOTE**: You can name the keys for the system objects however you want as long as they are unique e.g. system1, system2, systemA, systemB, Alpha, Beta, etc. + - For each database system object, copy-paste the template within the **pdbs** array to match the number of pluggable databases per system + - Now fill out the details for each container and pluggable database in the database system objects as described below: + + | ***Key*** | ***Description*** | ***Mandatory*** | + |--------------|-----------|------------| + | **host** | Host name used by management agent for connections with container and pluggable databases in system
**NOTE**: It is recommended to use the SCAN hostname for RAC systems | Yes | + | **port** | Port used by management agent for connections with container and pluggable databases in system
**NOTE**: Set to 1521 by default if no value is provided | Yes | + | **protocol** | Protocol used by management agent for connections with container and pluggable databases in system
**NOTE**: Must be **TCP** or **TCPS** | Yes | + | **managementAgentId** | OCID of the management agent connecting to container and pluggable databases in system | Yes | + | **databaseCredentials** | Key for credential object in **root_module/db_credentials.json** used by management agent for database connections
**NOTE**: If **protocol** is set to **TCPS**, the credential object must include **sslSecretId** | Yes | + | **containerName** | Desired name for container database | Yes | + | **containerServiceName** | Service name used by management agent for container database connection | Yes | + | **containerDBManagement** | Add **enable** or **disable** to manage Database Management enablement for container database | Yes | + | **dbManagementLicense** | Add **BRING_YOUR_OWN_LICENSE** or **LICENSE_INCLUDED** to select the license type used for Database Management. Click [here](https://docs.oracle.com/en-us/iaas/database-management/doc/enable-database-management-external-databases.html) for more | Yes, if **containerDBManagement** is set to **enable** | + | **containerStackMonitoring** | Add **enable** or **disable** to manage Stack Monitoring enablement for container database | Yes | + | **asmStackMonitoring** | Add **enable** or **disable** to manage Stack Monitoring enablement for ASM
**NOTE**: Enablement requires **containerStackMonitoring** to be **enable** as well | Yes | + | **asmHost** | Host name used by management agent for ASM connection | Yes, if **asmStackMonitoring** is set to **enable** | + | **asmPort** | Port used by management agent for ASM connection | Yes, if **asmStackMonitoring** is set to **enable** | + | **asmServiceName** | Service name used by management agent for ASM connection | Yes, if **asmStackMonitoring** is set to **enable** | + | **asmCredentials** | Key for credential object in **root_module/db_credentials.json** used by management agent for ASM connection
**NOTE**: Credential object must include **userPasswordSecretId** for the ASM password | Yes, if **asmStackMonitoring** is set to **enable** | + | **pdbName** | Desired name for pluggable database | Yes | + | **databaseCredentials** | Key for credential object in **root_module/db_credentials.json** used by management agent for database connections
**NOTE**: If **protocol** is set to **TCPS**, the credential object must include **sslSecretId** | Yes | + | **pdbServiceName** | Service name used by management agent for pluggable database connection | Yes | + | **pdbDBManagement** | Add **enable** or **disable** to manage Database Management enablement for pluggable database
**NOTE**: Enablement requires **containerDBManagement** to be **enable** as well | Yes | + | **pdbStackMonitoring** | Add **enable** or **disable** to manage Database Management enablement for pluggable database
**NOTE**: Enablement DOES NOT REQUIRE **containerStackMonitoring** to be **enable** as well | Yes | + | **pdbOPSI** | Add **enable** or **disable** to manage Operations Insights enablement for pluggable database | Yes | + +5. Define your database credentials in **root_module/db_credentials.json**. See **root_module/db_credentials_example.json** for an example: + - Create a credential object for every credential set used for management agent connections in **root_module/db_systems.json**. You can copy-paste the **cred1** and/or **cred2** objects as templates in **root_module/db_credentials.json** + - Now fill out the details for each credential object as described below: + | ***Key*** | ***Description*** | ***Mandatory*** | + |--------------|-----------|------------| + | **userName** | Database user name for management agent connections e.g. DBSNMP | Yes | + | **userPassword** | Database user password in plain text for management agent connections | No, if using **userPasswordSecretId** instead | + | **userPasswordSecretId** | OCID for encrypted Secret with database user password in OCI Vault. Click [here](https://docs.oracle.com/en-us/iaas/Content/KeyManagement/Tasks/managingsecrets.htm) for more
**NOTE**: Required to enable Stack Monitoring for ASM | No, if using **userPassword** instead | + | **userRole** | Database user role for management agent connections
**NOTE**: For database connections, **userRole** can be **NORMAL** or **SYSDBA**. For ASM connections, **userRole** can be **SYSASM**, **SYSDBA**, or **SYSOPER** | Yes | + | **sslSecretId** | OCID for encrypted Secret with JSON containing SSL-settings for database connections via TCPS. Click [here](https://docs.oracle.com/en-us/iaas/external-database/doc/create-connection-external-database.html#EXTUG-GUID-59ECD72C-EAC2-426D-B865-D8DDB1297F0E) for more | Yes, if **protocol** is set to **TCPS** for database system object in **root_module/db_systems.json**| + + **NOTE**: **CREDENTIAL VALUES ABOVE ARE SAVED AS PLAIN TEXT** IN BOTH **root_module/db_credentials.json** AS WELL AS IN **root_module/terraform.tfstate** AFTER APPLYING THE TERRAFORM CONFIGURATION. **ENSURE THAT THESE FILES ARE STORED SECURELY** + +6. Run the following commands from **root_module** to initialize the Terraform configuration, see its execution plan, and finally apply that plan: + + **terraform init**
+ **terraform plan**
+ **terraform apply**
+ +### Update applied Terraform configurations + +To apply new configurations, update **root_module/db_systems.json** and/or **root_module/db_credentials.json** and run **terraform apply** from **root_module** again + +### Destroy applied Terraform configurations +To remove everything previously applied by Terraform configurations, run **terraform destroy** from **root_module** + +## Useful Links + +- [Oracle](https://www.oracle.com) + - Oracle's Main Website +- [Terraform Provider](https://registry.terraform.io/providers/oracle/oci/latest/docs) + - General documentaion for Terraform's Oracle Cloud Infrastructure Provider +- [Management Agent Service](https://docs.oracle.com/en-us/iaas/management-agents/index.html) + - General documentation for Management Agent Service +- [External Database Service](https://docs.oracle.com/en-us/iaas/external-database/index.html) + - General documentation for External Database Service +- [Database Management](https://docs.oracle.com/en-us/iaas/database-management/home.htm) + - General documentation for Database Management +- [Operations Insights](https://docs.oracle.com/en-us/iaas/operations-insights/home.htm) + - General documentation for Operations Insights +- [Stack Monitoring](https://docs.oracle.com/en-us/iaas/stack-monitoring/index.html) + - General documentation for Stack Monitoring + +## License + +Copyright (c) 2024 Oracle and/or its affiliates. + +Licensed under the Universal Permissive License (UPL), Version 1.0. + +See [LICENSE](https://github.com/oracle-devrel/technology-engineering/blob/main/LICENSE) for more details. \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/db_credentials_example.json b/manageability-and-operations/observability-and-manageability/external-database-enablement/db_credentials_example.json new file mode 100644 index 000000000..c02b94ff2 --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/db_credentials_example.json @@ -0,0 +1,18 @@ +{ + "cred1": { + "userName":"DBSNMP", + "userPassword":"", + "userRole":"NORMAL" + }, + "cred2": { + "userName":"ASMSNMP", + "userPasswordSecretId":"ocid1.vaultsecret.oc1.XXXXXX", + "userRole":"SYSDBA" + }, + "cred3": { + "userName":"DBSNMP", + "userPasswordSecretId":"ocid1.vaultsecret.oc1.XXXXXX", + "userRole":"NORMAL", + "sslSecretId":"ocid1.vaultsecret.oc1.XXXXXX" + } +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/db_systems_example.json b/manageability-and-operations/observability-and-manageability/external-database-enablement/db_systems_example.json new file mode 100644 index 000000000..089267d83 --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/db_systems_example.json @@ -0,0 +1,64 @@ +{ + "system1": { + "host":"dba.com", + "port":"1521", + "protocol":"TCP", + "managementAgentId":"ocid1.managementagent.oc1.XXXXXX", + "databaseCredentials":"cred1", + "containerName":"DBA_container", + "containerServiceName":"dba_container_service", + "containerDBManagement":"disable", + "dbManagementLicense":"", + "containerStackMonitoring":"enable", + "asmStackMonitoring":"enable", + "asmHost":"dba_asm.com", + "asmPort":"1525", + "asmServiceName":"+ASM", + "asmCredentials":"cred2", + "pdbs":[ + { + "pdbName":"DBA_pdb1", + "databaseCredentials":"cred1", + "pdbServiceName":"dba_pdb1_service", + "pdbDBManagement":"disable", + "pdbStackMonitoring":"enable", + "pdbOPSI":"enable" + } + ] + }, + "system2": { + "host":"dbb-scan.com", + "port":"2484", + "protocol":"TCPS", + "managementAgentId":"ocid1.managementagent.oc1.XXXXXX", + "databaseCredentials":"cred3", + "containerName":"DBB_container", + "containerServiceName":"dbb_container_service", + "containerDBManagement":"enable", + "dbManagementLicense":"BRING_YOUR_OWN_LICENSE", + "containerStackMonitoring":"enable", + "asmStackMonitoring":"disable", + "asmHost":"", + "asmPort":"", + "asmServiceName":"", + "asmCredentials":"", + "pdbs":[ + { + "pdbName":"DBB_pdb1", + "databaseCredentials":"cred3", + "pdbServiceName":"dbb_pdb1_service", + "pdbDBManagement":"enable", + "pdbStackMonitoring":"disable", + "pdbOPSI":"enable" + }, + { + "pdbName":"DBB_pdb2", + "databaseCredentials":"cred3", + "pdbServiceName":"dbb_pdb2_service", + "pdbDBManagement":"enable", + "pdbStackMonitoring":"enable", + "pdbOPSI":"disable" + } + ] + } +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/db_credentials.json b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/db_credentials.json new file mode 100644 index 000000000..7f54650c9 --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/db_credentials.json @@ -0,0 +1,13 @@ +{ + "cred1": { + "userName":"DBSNMP", + "userPassword":"", + "userRole":"NORMAL" + }, + "cred2": { + "userName":"DBSNMP", + "userPasswordSecretId":"ocid1.vaultsecret.oc1.XXXXXX", + "userRole":"NORMAL", + "sslSecretId":"ocid1.vaultsecret.oc1.XXXXXX" + } +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/db_systems.json b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/db_systems.json new file mode 100644 index 000000000..93a07ca14 --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/db_systems.json @@ -0,0 +1,29 @@ +{ + "system1": { + "host":"IP ADDRESS OR HOSTNAME TO ACCESS DATABASE SYSTEM", + "port":"1521", + "protocol":"TCP OR TCPS", + "managementAgentId":"OCID FOR MANAGEMENT AGENT CONNECTING TO CONTAINER AND PLUGGABLE DATABASES", + "databaseCredentials":"KEY FOR THE CORRECT CREDENTIAL OBJECT IN db_credentials.json. IF protocol IS TCPS, CREDENTIAL OBJECT MUST INCLUDE sslSecretId", + "containerName":"container1", + "containerServiceName":"CONTAINER SERVICE NAME", + "containerDBManagement":"INSERT enable OR disable TO MANAGE DATABASE MANAGEMENT FOR CONTAINER DATABASE", + "dbManagementLicense":"BRING_YOUR_OWN_LICENSE OR LICENSE_INCLUDED", + "containerStackMonitoring":"INSERT enable OR disable TO MANAGE STACK MONITORING FOR CONTAINER DATABASE", + "asmStackMonitoring":"INSERT enable OR disable TO MANAGE STACK MONITORING FOR ASM. IF disable, OTHER ASM DETAILS ARE IGNORED", + "asmHost":"IP ADDRESS OR HOSTNAME TO ACCESS ASM INSTANCE", + "asmPort":"PORT TO ACCESS ASM INSTANCE", + "asmServiceName":"ASM SERVICE NAME", + "asmCredentials":"KEY FOR THE CORRECT CREDENTIAL OBJECT IN db_credentials.json. CREDENTIAL OBJECT MUST INCLUDE userPasswordSecretId", + "pdbs":[ + { + "pdbName":"pdb1", + "databaseCredentials":"KEY FOR THE CORRECT CREDENTIAL OBJECT IN db_credentials.json", + "pdbServiceName":"PDB SERVICE NAME", + "pdbDBManagement":"INSERT enable OR disable TO MANAGE DATABASE MANAGEMENT FOR PLUGGABLE DATABASE", + "pdbStackMonitoring":"INSERT enable OR disable TO MANAGE STACK MONITORING FOR PLUGGABLE DATABASE", + "pdbOPSI":"INSERT enable OR disable TO MANAGE OPERATIONS INSIGHTS FOR PLUGGABLE DATABASE" + } + ] + } +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/main.tf b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/main.tf new file mode 100644 index 000000000..5bd83f3c3 --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/main.tf @@ -0,0 +1,86 @@ +module "container_connection" { + source = "./modules/container/container_connection" + compartment_ocid = var.compartment_ocid + + for_each = local.dbsystem_def_map + external_container_database_display_name = "${each.key}_${each.value.containerName}" + external_cdb_connector_connection_credentials_credential_name = "${each.key}.${each.value.databaseCredentials}" + external_cdb_connector_connection_credentials_credential_type = upper(each.value.protocol) == "TCPS" ? "SSL_DETAILS" : "DETAILS" + external_cdb_connector_connection_credentials_password = try(local.dbcred_def_map["${each.value.databaseCredentials}"].userPasswordSecretId, null) != null ? base64decode(module.password_secret["${each.value.databaseCredentials}"].password_secret_content) : local.dbcred_def_map["${each.value.databaseCredentials}"].userPassword + external_cdb_connector_connection_credentials_role = local.dbcred_def_map["${each.value.databaseCredentials}"].userRole + external_cdb_connector_connection_credentials_username = local.dbcred_def_map["${each.value.databaseCredentials}"].userName + external_database_connector_connection_string_hostname = each.value.host + external_database_connector_connection_string_port = each.value.port + external_database_connector_connection_string_protocol = upper(each.value.protocol) + ssl_secret_id = upper(each.value.protocol) == "TCPS" ? local.dbcred_def_map["${each.value.databaseCredentials}"].sslSecretId : null + external_cdb_connector_connection_string_service = each.value.containerServiceName + external_database_connector_agent_id = each.value.managementAgentId +} + +module "container_services" { + source = "./modules/container/container_services" + compartment_ocid = var.compartment_ocid + + for_each = local.dbsystem_def_map + external_database_connector_agent_id = each.value.managementAgentId + external_container_id = module.container_connection["${each.key}"].external_container_id + external_container_display_name = module.container_connection["${each.key}"].external_container_display_name + external_container_connector_id = module.container_connection["${each.key}"].external_container_connector_id + enable_database_management_cdb = lower(each.value.containerDBManagement) + external_container_database_management_license = upper(each.value.dbManagementLicense) + enable_stack_monitoring_cdb = lower(each.value.containerStackMonitoring) + enable_stack_monitoring_asm = lower(each.value.asmStackMonitoring) + asm_hostname = each.value.asmHost + asm_port = each.value.asmPort + asm_service = each.value.asmServiceName + asm_credentials_role = lower(each.value.asmStackMonitoring == "enable") ? upper(local.dbcred_def_map["${each.value.asmCredentials}"].userRole) : "" + asm_credentials_username = lower(each.value.asmStackMonitoring == "enable") ? local.dbcred_def_map["${each.value.asmCredentials}"].userName : "" + asm_credentials_password_secret_id = lower(each.value.asmStackMonitoring == "enable") ? local.dbcred_def_map["${each.value.asmCredentials}"].userPasswordSecretId : "" +} + +module "pdb" { + source = "./modules/pdb" + compartment_ocid = var.compartment_ocid + + for_each = { for pdb in local.pdb_flat_list : "${pdb.dbsystemKey}_${pdb.pdbServiceName}" => pdb } + external_pluggable_database_display_name = "${each.value.dbsystemKey}_${each.value.pdbName}" + oci_database_external_container_database_id = module.container_connection["${each.value.dbsystemKey}"].external_container_id + external_pdb_connector_connection_credentials_credential_name = "${each.value.dbsystemKey}.${each.value.databaseCredentials}" + external_pdb_connector_connection_credentials_credential_type = upper(local.dbsystem_def_map["${each.value.dbsystemKey}"].protocol) == "TCPS" ? "SSL_DETAILS" : "DETAILS" + external_pdb_connector_connection_credentials_password = try(local.dbcred_def_map["${each.value.databaseCredentials}"].userPasswordSecretId, null) != null ? base64decode(module.password_secret["${each.value.databaseCredentials}"].password_secret_content) : local.dbcred_def_map["${each.value.databaseCredentials}"].userPassword + external_pdb_connector_connection_credentials_role = local.dbcred_def_map["${each.value.databaseCredentials}"].userRole + external_pdb_connector_connection_credentials_username = local.dbcred_def_map["${each.value.databaseCredentials}"].userName + external_database_connector_connection_string_hostname = local.dbsystem_def_map["${each.value.dbsystemKey}"].host + external_database_connector_connection_string_port = local.dbsystem_def_map["${each.value.dbsystemKey}"].port + external_database_connector_connection_string_protocol = upper(local.dbsystem_def_map["${each.value.dbsystemKey}"].protocol) + ssl_secret_id = upper(local.dbsystem_def_map["${each.value.dbsystemKey}"].protocol) == "TCPS" ? local.dbcred_def_map["${each.value.databaseCredentials}"].sslSecretId : null + external_pdb_connector_connection_string_service = each.value.pdbServiceName + external_database_connector_agent_id = local.dbsystem_def_map["${each.value.dbsystemKey}"].managementAgentId + enable_database_management_pdb = module.container_services["${each.value.dbsystemKey}"].database_management_cdb_status ? lower(each.value.pdbDBManagement) : "disable" + enable_stack_monitoring_pdb = lower(each.value.pdbStackMonitoring) + enable_operations_insights_pdb = lower(each.value.pdbOPSI) +} + +module "password_secret" { + source = "./modules/password_secret" + + for_each = { for cred_key, cred in local.dbcred_def_map : cred_key => cred.userPasswordSecretId if try(cred.userPasswordSecretId, null) != null } + password_secret_id = each.value +} + +locals { + dbsystem_def_map = jsondecode(file("./db_systems.json")) + dbcred_def_map = jsondecode(file("./db_credentials.json")) + pdb_flat_list = flatten([for dbsystem_key, dbsystem in local.dbsystem_def_map : [ + for pdb_key, pdb in dbsystem.pdbs : { + dbsystemKey = dbsystem_key + pdbName = pdb.pdbName + databaseCredentials = pdb.databaseCredentials + pdbServiceName = pdb.pdbServiceName + pdbDBManagement = pdb.pdbDBManagement + pdbOPSI = pdb.pdbOPSI + pdbStackMonitoring = pdb.pdbStackMonitoring + } + ] + ]) +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/container/container_connection/main.tf b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/container/container_connection/main.tf new file mode 100644 index 000000000..86aadaf43 --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/container/container_connection/main.tf @@ -0,0 +1,36 @@ +resource "oci_database_external_container_database" "this" { + compartment_id = var.compartment_ocid + display_name = var.external_container_database_display_name +} + +resource "oci_database_external_database_connector" "container_connector" { + connection_credentials { + credential_name = var.external_cdb_connector_connection_credentials_credential_name + credential_type = var.external_cdb_connector_connection_credentials_credential_type + password = var.external_cdb_connector_connection_credentials_password + role = var.external_cdb_connector_connection_credentials_role + ssl_secret_id = var.ssl_secret_id + username = var.external_cdb_connector_connection_credentials_username + } + connection_string { + hostname = var.external_database_connector_connection_string_hostname + port = var.external_database_connector_connection_string_port + protocol = var.external_database_connector_connection_string_protocol + service = var.external_cdb_connector_connection_string_service + } + connector_agent_id = var.external_database_connector_agent_id + display_name = "${var.external_container_database_display_name}_connector" + external_database_id = oci_database_external_container_database.this.id +} + +output "external_container_display_name" { + value = oci_database_external_container_database.this.display_name +} + +output "external_container_id" { + value = oci_database_external_container_database.this.id +} + +output "external_container_connector_id" { + value = oci_database_external_database_connector.container_connector.id +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/container/container_connection/variables.tf b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/container/container_connection/variables.tf new file mode 100644 index 000000000..415f33303 --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/container/container_connection/variables.tf @@ -0,0 +1,105 @@ +#Common database system variables + +variable "compartment_ocid" { + type = string +} + +variable "external_database_connector_connection_string_hostname" { + description = "Hostname for connection string" + type = string + validation { + condition = var.external_database_connector_connection_string_hostname != "" + error_message = "The value of 'host' in the JSON-input for database systems is an empty string" + } +} + +variable "external_database_connector_connection_string_port" { + description = "Port for connection string" + type = number + default = 1521 +} + +variable "external_database_connector_connection_string_protocol" { + description = "Protocol for connection string. Can be 'TCP' or 'TCPS'" + type = string + validation { + condition = contains(["TCP", "TCPS"], var.external_database_connector_connection_string_protocol) + error_message = "The value of 'protocol' in the JSON-input for database systems must be 'TCP' or 'TCPS'" + } +} + +variable "ssl_secret_id" { + description = "The OCID for the OCI Vault Secret used for TCPS-connections. PKCS12 and JKS are supported as trust store types" + type = string + default = null +} + +variable "external_database_connector_agent_id" { + description = "The OCID for the management agent used for database connections" + type = string + validation { + condition = var.external_database_connector_agent_id != "" + error_message = "The value of 'managementAgentId' in the JSON-input for database systems is an empty string" + } +} + +#Container database variables + +variable "external_container_database_display_name" { + description = "Name for external container database" + type = string +} + +variable "external_cdb_connector_connection_credentials_credential_name" { + description = "Name of credential set for container database connector. Must be in a 'x.y' format" + type = string + validation { + condition = can(regex("[a-zA-Z\\d_]{1,64}\\.[a-zA-Z\\d_]{1,199}", var.external_cdb_connector_connection_credentials_credential_name)) + error_message = "The value of var.external_cdb_connector_connection_credentials_credential_name must be in 'x.y' format. x has a maximum of 64 characters, and y has a maximum of 199 characters. The strings can only contain letters, numbers, and underscores" + } +} + +variable "external_cdb_connector_connection_credentials_credential_type" { + description = "Set to 'DETAILS' for TCP credentials and 'SSL_DETAILS' for TCPS credentials" + type = string + validation { + condition = contains(["DETAILS", "SSL_DETAILS"], var.external_cdb_connector_connection_credentials_credential_type) + error_message = "The value of var.external_cdb_connector_connection_credentials_credential_type must be 'DETAILS' or 'SSL_DETAILS'" + } +} + +variable "external_cdb_connector_connection_credentials_password" { + description = "Password for container database connector" + type = string + validation { + condition = var.external_cdb_connector_connection_credentials_password != "" + error_message = "Container database connector password is an empty string. Confirm values in the JSON-input for credentials" + } +} + +variable "external_cdb_connector_connection_credentials_role" { + description = "User role for container database connector. Can be NORMAL or SYSDBA" + type = string + validation { + condition = contains(["NORMAL", "SYSDBA"], var.external_cdb_connector_connection_credentials_role) + error_message = "The value of 'userRole' in the JSON-input for credentials used for external database connectors must be 'NORMAL' or 'SYSDBA'" + } +} + +variable "external_cdb_connector_connection_credentials_username" { + description = "Username for container database connector" + type = string + validation { + condition = var.external_cdb_connector_connection_credentials_username != "" + error_message = "Container database connector username is an empty string. Confirm values in the JSON-input for credentials" + } +} + +variable "external_cdb_connector_connection_string_service" { + description = "Service name for container database connector" + type = string + validation { + condition = var.external_cdb_connector_connection_string_service != "" + error_message = "The value of 'containerServiceName' in the JSON-input for database systems is an empty string" + } +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/container/container_services/main.tf b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/container/container_services/main.tf new file mode 100644 index 000000000..c980f858e --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/container/container_services/main.tf @@ -0,0 +1,99 @@ +resource "oci_database_external_container_database_management" "this" { + count = var.enable_database_management_cdb == "enable" ? 1 : 0 + + external_container_database_id = var.external_container_id + external_database_connector_id = var.external_container_connector_id + license_model = var.external_container_database_management_license + enable_management = true +} + +resource "time_static" "database_management_cdb_status_update" { + triggers = { + status_update = try(tobool(oci_database_external_container_database_management.this[0].enable_management), false) + } +} + +resource "oci_database_externalcontainerdatabases_stack_monitoring" "this" { + count = var.enable_stack_monitoring_cdb == "enable" ? 1 : 0 + + external_container_database_id = var.external_container_id + external_database_connector_id = var.external_container_connector_id + enable_stack_monitoring = true + + depends_on = [oci_database_external_container_database_management.this] +} + +resource "oci_stack_monitoring_monitored_resources_search" "external_cdb_search" { + count = var.enable_stack_monitoring_cdb == "enable" ? 1 : 0 + + compartment_id = var.compartment_ocid + external_id = var.external_container_id + state = "ACTIVE" + type = "OCI_ORACLE_CDB" + + depends_on = [oci_database_externalcontainerdatabases_stack_monitoring.this] +} + +resource "oci_stack_monitoring_discovery_job" "db_system_refresh_job" { + count = var.enable_stack_monitoring_cdb == "enable" && var.enable_stack_monitoring_asm == "disable" ? 1 : 0 + + compartment_id = var.compartment_ocid + discovery_details { + agent_id = var.external_database_connector_agent_id + + properties { + properties_map = { + "allow_delete_resources" : "true", + "resource_id" : "${element(oci_stack_monitoring_monitored_resources_search.external_cdb_search.0.items, 0).id}", + } + } + + resource_name = var.external_container_display_name + resource_type = "ORACLE_DATABASE" + } + + discovery_type = "REFRESH" +} + +resource "oci_stack_monitoring_discovery_job" "db_system_asm_refresh_job" { + count = var.enable_stack_monitoring_cdb == "enable" && var.enable_stack_monitoring_asm == "enable" ? 1 : 0 + + compartment_id = var.compartment_ocid + discovery_details { + agent_id = var.external_database_connector_agent_id + + properties { + properties_map = { + "allow_delete_resources" : "true", + "resource_id" : "${element(oci_stack_monitoring_monitored_resources_search.external_cdb_search.0.items, 0).id}", + "is_asm_discovery" : "true", + "asm_host" : "${var.asm_hostname}", + "asm_port" : "${var.asm_port}", + "asm_service_name" : "${var.asm_service}", + } + } + + credentials { + items { + credential_name = base64encode("ASMPasswordInVault") + credential_type = base64encode("SSL_SECRET_ID") + properties { + properties_map = { + "ASMRole" : base64encode("${var.asm_credentials_role}"), + "ASMUserName" : base64encode("${var.asm_credentials_username}"), + "PasswordSecretId" : base64encode("${var.asm_credentials_password_secret_id}") + } + } + } + } + + resource_name = var.external_container_display_name + resource_type = "ORACLE_DATABASE" + } + + discovery_type = "REFRESH" +} + +output "database_management_cdb_status" { + value = time_static.database_management_cdb_status_update.triggers.status_update +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/container/container_services/variables.tf b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/container/container_services/variables.tf new file mode 100644 index 000000000..260b8509d --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/container/container_services/variables.tf @@ -0,0 +1,89 @@ +variable "compartment_ocid" { + type = string +} + +variable "external_database_connector_agent_id" { + type = string +} + +variable "external_container_id" { + type = string +} + +variable "external_container_display_name" { + type = string +} + +variable "external_container_connector_id" { + type = string +} + +variable "enable_database_management_cdb" { + description = "Set enablement of Database Management for container database" + type = string + validation { + condition = contains(["enable", "disable"], var.enable_database_management_cdb) + error_message = "The value of 'containerDBManagement' in the JSON-input for database systems must be 'enable' or 'disable'" + } +} + +variable "external_container_database_management_license" { + description = "Database Management license. Can be 'BRING_YOUR_OWN_LICENSE' or 'LICENSE_INCLUDED'" + type = string + validation { + condition = contains(["BRING_YOUR_OWN_LICENSE", "LICENSE_INCLUDED"], var.external_container_database_management_license) + error_message = "The value of 'dbManagementLicense' in the JSON-input for database systems must be 'BRING_YOUR_OWN_LICENSE' or 'LICENSE_INCLUDED'" + } +} + +variable "enable_stack_monitoring_cdb" { + description = "Set enablement of Stack Monitoring for container database" + type = string + validation { + condition = contains(["enable", "disable"], var.enable_stack_monitoring_cdb) + error_message = "The value of 'containerStackMonitoring' in the JSON-input for database systems must be 'enable' or 'disable'" + } +} + +variable "enable_stack_monitoring_asm" { + description = "Set enablement of ASM discovery in Stack Monitoring" + type = string + validation { + condition = contains(["enable", "disable"], var.enable_stack_monitoring_asm) + error_message = "The value of 'asmStackMonitoring' in the JSON-input for database systems must be 'enable' or 'disable'" + } +} + +variable "asm_hostname" { + description = "Hostname for ASM discovery in Stack Monitoring" + type = string +} + +variable "asm_port" { + description = "Port for ASM discovery in Stack Monitoring" + type = string +} + +variable "asm_service" { + description = "Service name for ASM discovery in Stack Monitoring" + type = string +} + +variable "asm_credentials_role" { + description = "User role for ASM discovery in Stack Monitoring. Can be 'SYSASM', 'SYSDBA', or 'SYSOPER'" + type = string + validation { + condition = contains(["SYSASM", "SYSDBA", "SYSOPER", ""], var.asm_credentials_role) + error_message = "The value of 'userRole' in the JSON-input for credentials used for ASM discovery in Stack Monitoring must be 'SYSASM', 'SYSDBA', or 'SYSOPER'" + } +} + +variable "asm_credentials_username" { + description = "Username for ASM discovery in Stack Monitoring" + type = string +} + +variable "asm_credentials_password_secret_id" { + description = "The OCID for the OCI Vault Secret conaining the password for ASM discovery in Stack Monitoring" + type = string +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/password_secret/main.tf b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/password_secret/main.tf new file mode 100644 index 000000000..d452613ca --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/password_secret/main.tf @@ -0,0 +1,7 @@ +data "oci_secrets_secretbundle" "password_secret" { + secret_id = var.password_secret_id +} + +output "password_secret_content" { + value = data.oci_secrets_secretbundle.password_secret.secret_bundle_content.0.content +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/password_secret/variables.tf b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/password_secret/variables.tf new file mode 100644 index 000000000..88d319d22 --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/password_secret/variables.tf @@ -0,0 +1,5 @@ +variable "password_secret_id" { + description = "Optional OCI Vault Secret OCID for password instead of plain text" + type = string + default = null +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/pdb/main.tf b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/pdb/main.tf new file mode 100644 index 000000000..f4b15ff3e --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/pdb/main.tf @@ -0,0 +1,53 @@ +resource "oci_database_external_pluggable_database" "that" { + compartment_id = var.compartment_ocid + display_name = var.external_pluggable_database_display_name + external_container_database_id = var.oci_database_external_container_database_id +} + +resource "oci_database_external_database_connector" "pdb_connector" { + connection_credentials { + credential_name = var.external_pdb_connector_connection_credentials_credential_name + credential_type = var.external_pdb_connector_connection_credentials_credential_type + password = var.external_pdb_connector_connection_credentials_password + role = var.external_pdb_connector_connection_credentials_role + ssl_secret_id = var.ssl_secret_id + username = var.external_pdb_connector_connection_credentials_username + } + connection_string { + hostname = var.external_database_connector_connection_string_hostname + port = var.external_database_connector_connection_string_port + protocol = var.external_database_connector_connection_string_protocol + service = var.external_pdb_connector_connection_string_service + } + connector_agent_id = var.external_database_connector_agent_id + display_name = "${var.external_pluggable_database_display_name}_connector" + external_database_id = oci_database_external_pluggable_database.that.id +} + +resource "oci_database_external_pluggable_database_management" "that" { + count = var.enable_database_management_pdb == "enable" ? 1 : 0 + + external_database_connector_id = oci_database_external_database_connector.pdb_connector.id + external_pluggable_database_id = oci_database_external_pluggable_database.that.id + enable_management = true + + depends_on = [oci_database_external_pluggable_database_operations_insights_management.that, oci_database_externalpluggabledatabases_stack_monitoring.that] +} + +resource "oci_database_externalpluggabledatabases_stack_monitoring" "that" { + count = var.enable_stack_monitoring_pdb == "enable" ? 1 : 0 + + external_pluggable_database_id = oci_database_external_pluggable_database.that.id + external_database_connector_id = oci_database_external_database_connector.pdb_connector.id + enable_stack_monitoring = true + + depends_on = [oci_database_external_pluggable_database_operations_insights_management.that] +} + +resource "oci_database_external_pluggable_database_operations_insights_management" "that" { + count = var.enable_operations_insights_pdb == "enable" ? 1 : 0 + + external_database_connector_id = oci_database_external_database_connector.pdb_connector.id + external_pluggable_database_id = oci_database_external_pluggable_database.that.id + enable_operations_insights = true +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/pdb/variables.tf b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/pdb/variables.tf new file mode 100644 index 000000000..5330a6bd7 --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/modules/pdb/variables.tf @@ -0,0 +1,129 @@ +#Common database system variables + +variable "compartment_ocid" { + type = string +} + +variable "external_database_connector_connection_string_hostname" { + description = "Hostname for connection string" + type = string +} + +variable "external_database_connector_connection_string_port" { + description = "Port for connection string" + type = number + default = 1521 +} + +variable "external_database_connector_connection_string_protocol" { + description = "Protocol for connection string. Can be 'TCP' or 'TCPS'" + type = string + validation { + condition = contains(["TCP", "TCPS"], var.external_database_connector_connection_string_protocol) + error_message = "The value of 'protocol' in the JSON-input for database systems must be 'TCP' or 'TCPS'" + } +} + +variable "ssl_secret_id" { + description = "The OCID for the OCI Vault Secret used for TCPS-connections. PKCS12 and JKS are supported as trust store types" + type = string + default = null +} + +variable "external_database_connector_agent_id" { + description = "The OCID for the management agent used for database connections" + type = string +} + +#Pluggable database variables + +variable "external_pluggable_database_display_name" { + description = "Name for external pluggable database" + type = string +} + +variable "oci_database_external_container_database_id" { + description = "ID for related container database" + type = string +} + +variable "external_pdb_connector_connection_credentials_credential_name" { + description = "Name of credential set for pluggable database connector. Must be in a 'x.y' format" + type = string + validation { + condition = can(regex("[a-zA-Z\\d_]{1,64}\\.[a-zA-Z\\d_]{1,199}", var.external_pdb_connector_connection_credentials_credential_name)) + error_message = "The value of var.external_pdb_connector_connection_credentials_credential_name must be in 'x.y' format. x has a maximum of 64 characters, and y has a maximum of 199 characters. The strings can only contain letters, numbers, and underscores" + } +} + +variable "external_pdb_connector_connection_credentials_credential_type" { + description = "Set to 'DETAILS' for TCP credentials and 'SSL_DETAILS' for TCPS credentials" + type = string + validation { + condition = contains(["DETAILS", "SSL_DETAILS"], var.external_pdb_connector_connection_credentials_credential_type) + error_message = "The value of var.external_pdb_connector_connection_credentials_credential_type must be 'DETAILS' or 'SSL_DETAILS'" + } +} + +variable "external_pdb_connector_connection_credentials_password" { + description = "Password for pluggable database connector" + type = string + validation { + condition = var.external_pdb_connector_connection_credentials_password != "" + error_message = "Pluggable database connector password is an empty string. Confirm values in the JSON-input for credentials" + } +} + +variable "external_pdb_connector_connection_credentials_role" { + description = "User role for pluggable database connector. Can be 'NORMAL' OR 'SYSDBA'" + type = string + validation { + condition = contains(["NORMAL", "SYSDBA"], var.external_pdb_connector_connection_credentials_role) + error_message = "The value of 'userRole' in the JSON-input for credentials used for external database connectors must be 'NORMAL' or 'SYSDBA'" + } +} + +variable "external_pdb_connector_connection_credentials_username" { + description = "Username for pluggable database connector" + type = string + validation { + condition = var.external_pdb_connector_connection_credentials_username != "" + error_message = "Pluggable database connector username is an empty string. Confirm values in the JSON-input for credentials" + } +} + +variable "external_pdb_connector_connection_string_service" { + description = "Service name for pluggable database connector" + type = string + validation { + condition = var.external_pdb_connector_connection_string_service != "" + error_message = "The value of 'pdbServiceName' in the JSON-input for database systems is an empty string" + } +} + +variable "enable_database_management_pdb" { + description = "Set enablement of Database Management for pluggable database" + type = string + validation { + condition = contains(["enable", "disable"], var.enable_database_management_pdb) + error_message = "The value of 'pdbDBManagement' in the JSON-input for database systems must be 'enable' or 'disable'" + } +} + +variable "enable_stack_monitoring_pdb" { + description = "Set enablement of Stack Monitoring for pluggable database" + type = string + validation { + condition = contains(["enable", "disable"], var.enable_stack_monitoring_pdb) + error_message = "The value of 'pdbStackMonitoring' in the JSON-input for database systems must be 'enable' or 'disable'" + } +} + +variable "enable_operations_insights_pdb" { + description = "Set enablement of Operations Insights for pluggable database" + type = string + validation { + condition = contains(["enable", "disable"], var.enable_operations_insights_pdb) + error_message = "The value of 'pdbOPSI' in the JSON-input for database systems must be 'enable' or 'disable'" + } +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/provider.tf b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/provider.tf new file mode 100644 index 000000000..2a2b5cb6e --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/provider.tf @@ -0,0 +1,17 @@ +terraform { + required_providers { + oci = { + source = "oracle/oci" + version = ">= 5.11.0" + } + } +} + +provider "oci" { + # Configuration options + tenancy_ocid = "ocid1.tenancy.oc1..XXXXXX" + user_ocid = "ocid1.user.oc1..XXXXXX" + private_key_path = "/path/private_key.pem" + fingerprint = "" + region = "" +} \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/variables.tf b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/variables.tf new file mode 100644 index 000000000..a84477a1d --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/external-database-enablement/root_module/variables.tf @@ -0,0 +1,4 @@ +variable "compartment_ocid" { + description = "Compartment OCID" + type = string +} \ No newline at end of file