From 6e380952e08ab8706931c8a4e0f7676a5600c6c1 Mon Sep 17 00:00:00 2001 From: lfeldman Date: Fri, 5 Nov 2021 12:22:08 +0100 Subject: [PATCH] First commit --- LICENSE | 44 +- README.md | 127 ++- bastion.tf | 94 ++ block_volume.tf | 90 ++ compute.tf | 222 +++++ datasources.tf | 117 +++ .../main.tf | 32 + examples/remote-module-no-hotstandbys/main.tf | 104 ++ examples/remote-module-private-subnet/main.tf | 121 +++ examples/remote-module-public-subnet/main.tf | 105 ++ images/postgre-oci.png | Bin 0 -> 44623 bytes network.tf | 84 ++ orm/provider.tf | 30 + orm/variables.tf | 184 ++++ outputs.tf | 27 + provider.tf | 30 + release_files.json | 38 +- remote.tf | 909 ++++++++++++++++++ schema.yaml | 537 +++++++++++ scripts/iscsiattach.sh | 78 ++ scripts/postgresql_install_binaries.sh | 22 + scripts/postgresql_master_initdb.sh | 44 + scripts/postgresql_master_setup.sh | 76 ++ scripts/postgresql_master_setup.sql | 3 + scripts/postgresql_master_setup2.sh | 34 + scripts/postgresql_standby_setup.sh | 94 ++ scripts/sshkey.tpl | 5 + security-lists.tf | 35 + tags.tf | 34 + tls.tf | 6 + variables.tf | 184 ++++ 31 files changed, 3471 insertions(+), 39 deletions(-) create mode 100644 bastion.tf create mode 100644 block_volume.tf create mode 100644 compute.tf create mode 100644 datasources.tf create mode 100644 examples/remote-module-network-inside-module/main.tf create mode 100644 examples/remote-module-no-hotstandbys/main.tf create mode 100644 examples/remote-module-private-subnet/main.tf create mode 100644 examples/remote-module-public-subnet/main.tf create mode 100644 images/postgre-oci.png create mode 100644 network.tf create mode 100644 orm/provider.tf create mode 100644 orm/variables.tf create mode 100644 outputs.tf create mode 100644 provider.tf create mode 100644 remote.tf create mode 100644 schema.yaml create mode 100644 scripts/iscsiattach.sh create mode 100644 scripts/postgresql_install_binaries.sh create mode 100644 scripts/postgresql_master_initdb.sh create mode 100644 scripts/postgresql_master_setup.sh create mode 100644 scripts/postgresql_master_setup.sql create mode 100644 scripts/postgresql_master_setup2.sh create mode 100644 scripts/postgresql_standby_setup.sh create mode 100644 scripts/sshkey.tpl create mode 100644 security-lists.tf create mode 100644 tags.tf create mode 100644 tls.tf create mode 100644 variables.tf diff --git a/LICENSE b/LICENSE index fe41e72..5e6d632 100644 --- a/LICENSE +++ b/LICENSE @@ -1,35 +1,27 @@ -Copyright (c) 2021 Oracle and/or its affiliates. +Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. The Universal Permissive License (UPL), Version 1.0 -Subject to the condition set forth below, permission is hereby granted to any -person obtaining a copy of this software, associated documentation and/or data -(collectively the "Software"), free of charge and under any and all copyright -rights in the Software, and any and all patent rights owned or freely -licensable by each licensor hereunder covering either (i) the unmodified -Software as contributed to or provided by such licensor, or (ii) the Larger -Works (as defined below), to deal in both +Subject to the condition set forth below, permission is hereby granted to any person obtaining a copy of this +software, associated documentation and/or data (collectively the "Software"), free of charge and under any and +all copyright rights in the Software, and any and all patent rights owned or freely licensable by each licensor +hereunder covering either (i) the unmodified Software as contributed to or provided by such licensor, or +(ii) the Larger Works (as defined below), to deal in both (a) the Software, and -(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if -one is included with the Software (each a "Larger Work" to which the Software -is contributed by such licensors), +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if one is included with the Software +(each a “Larger Work” to which the Software is contributed by such licensors), -without restriction, including without limitation the rights to copy, create -derivative works of, display, perform, and distribute the Software and make, -use, sell, offer for sale, import, export, have made, and have sold the -Software and the Larger Work(s), and to sublicense the foregoing rights on -either these or other terms. +without restriction, including without limitation the rights to copy, create derivative works of, display, +perform, and distribute the Software and make, use, sell, offer for sale, import, export, have made, and have +sold the Software and the Larger Work(s), and to sublicense the foregoing rights on either these or other terms. This license is subject to the following condition: -The above copyright notice and either this complete permission notice or at -a minimum a reference to the UPL must be included in all copies or -substantial portions of the Software. +The above copyright notice and either this complete permission notice or at a minimum a reference to the UPL must +be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/README.md b/README.md index 9d08cb5..ba58bd3 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,125 @@ -# oci-postgresql +# terraform-oci-arch-postgresql -[![License: UPL](https://img.shields.io/badge/license-UPL-green)](https://img.shields.io/badge/license-UPL-green) [![Quality gate](https://sonarcloud.io/api/project_badges/quality_gate?project=oracle-devrel_terraform-oci-arch-postgresql)](https://sonarcloud.io/dashboard?id=oracle-devrel_terraform-oci-arch-postgresql) +PostgreSQL is an open source object-relational database management system. It’s highly extensible, highly scalable, and has many features. PostgreSQL supports data replication across multiple data centers. -## THIS IS A NEW, BLANK REPO THAT IS NOT READY FOR USE YET. PLEASE CHECK BACK SOON! +This reference architecture shows a typical three-node deployment of a PostgreSQL cluster on Oracle Cloud Infrastructure Compute instances. In this architecture, the servers are configured in master and standby configuration and use streaming replication. -## Introduction -MISSING +For details of the architecture, see [_Deploy a PostgreSQL database_](https://docs.oracle.com/en/solutions/deploy-postgresql-db/index.html) -## Getting Started -MISSING +## Prerequisites + +- Permission to `manage` the following types of resources in your Oracle Cloud Infrastructure tenancy: `vcns`, `internet-gateways`, `route-tables`, `security-lists`, `subnets`, and `instances`. + +- Quota to create the following resources: 1 VCN, 1 subnet, 1 Internet Gateway, 1 route rules, and 3 compute instances (1 primary master PostgreSQL instance and 2 Standby instances of PostgreSQL). + +If you don't have the required permissions and quota, contact your tenancy administrator. See [Policy Reference](https://docs.cloud.oracle.com/en-us/iaas/Content/Identity/Reference/policyreference.htm), [Service Limits](https://docs.cloud.oracle.com/en-us/iaas/Content/General/Concepts/servicelimits.htm), [Compartment Quotas](https://docs.cloud.oracle.com/iaas/Content/General/Concepts/resourcequotas.htm). + +## Deploy Using Oracle Resource Manager + +1. Click [![Deploy to Oracle Cloud](https://oci-resourcemanager-plugin.plugins.oci.oraclecloud.com/latest/deploy-to-oracle-cloud.svg)](https://cloud.oracle.com/resourcemanager/stacks/create?region=home&zipUrl=https://github.com/oracle-devrel/terraform-oci-arch-postgresql/releases/latest/download/terraform-oci-arch-postgresql-stack-latest.zip) + + If you aren't already signed in, when prompted, enter the tenancy and user credentials. + +2. Review and accept the terms and conditions. + +3. Select the region where you want to deploy the stack. + +4. Follow the on-screen prompts and instructions to create the stack. + +5. After creating the stack, click **Terraform Actions**, and select **Plan**. + +6. Wait for the job to be completed, and review the plan. + + To make any changes, return to the Stack Details page, click **Edit Stack**, and make the required changes. Then, run the **Plan** action again. + +7. If no further changes are necessary, return to the Stack Details page, click **Terraform Actions**, and select **Apply**. + +## Deploy Using the Terraform CLI + +### Clone the Repository +Now, you'll want a local copy of this repo. You can make that with the commands: + + git clone https://github.com/oracle-devrel/terraform-oci-arch-postgresql + cd terraform-oci-arch-postgresql + ls ### Prerequisites -MISSING +First off, you'll need to do some pre-deploy setup. That's all detailed [here](https://github.com/cloud-partners/oci-prerequisites). + +Secondly, create a `terraform.tfvars` file and populate with the following information: -## Notes/Issues -MISSING +``` +# Authentication +tenancy_ocid = "" +user_ocid = "" +fingerprint = "" +private_key_path = "" -## URLs -* Nothing at this time +# Region +region = "" + +# Availablity Domain +availablity_domain_name = "" # for example GrCH:US-ASHBURN-AD-1 + +# Compartment +compartment_ocid = "" + +# PostgreSQL Password +postgresql_password = "" + +# PostgreSQL Version (supported versions 9.6, 10, 11, 12, 13) +postgresql_version = "" + +# Optional first HotStandby +postgresql_deploy_hotstandby1 = true +postgresql_hotstandby1_ad = "" # for example GrCH:US-ASHBURN-AD-2 +postgresql_hotstandby1_fd = "" # for example FAULT-DOMAIN-2 + +# Optional second HotStandby +postgresql_deploy_hotstandby2 = true +postgresql_hotstandby2_ad = "" # for example GrCH:US-ASHBURN-AD-3 +postgresql_hotstandby2_fd = "" # for example FAULT-DOMAIN-3 + +```` + +### Create the Resources +Run the following commands: + + terraform init + terraform plan + terraform apply + +### Destroy the Deployment +When you no longer need the deployment, you can run this command to destroy the resources: + + terraform destroy + +## Deploy as a Module +It's possible to utilize this repository as remote module, providing the necessary inputs: + +``` +module "oci-postgresql" { + source = "github.com/oracle-devrel/terraform-oci-arch-postgresql" + tenancy_ocid = "" + user_ocid = "" + fingerprint = "" + private_key_path = "" + region = "" + availablity_domain_name = "" + compartment_ocid = "" + use_existing_vcn = true # You can inject your own VCN and subnet + create_in_private_subnet = true # Subnet should be associated with NATGW and proper Route Table. + postgresql_vcn = oci_core_virtual_network.my_vcn.id # Injected VCN + postgresql_subnet = oci_core_subnet.my_private_subnet.id # Injected Private Subnet + postgresql_password = "" + postgresql_deploy_hotstandby1 = true # if we want to setup hotstandby1 + postgresql_deploy_hotstandby2 = true # if we want to setup hotstandby2 +} +``` + +## Architecture Diagram + +![](./images/postgre-oci.png) ## Contributing This project is open source. Please submit your contributions by forking this repository and submitting a pull request! Oracle appreciates any contributions that are made by the open source community. @@ -28,3 +130,4 @@ Copyright (c) 2021 Oracle and/or its affiliates. Licensed under the Universal Permissive License (UPL), Version 1.0. See [LICENSE](LICENSE) for more details. + diff --git a/bastion.tf b/bastion.tf new file mode 100644 index 0000000..5e5f67e --- /dev/null +++ b/bastion.tf @@ -0,0 +1,94 @@ +## Copyright (c) 2021 Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + +resource "oci_bastion_bastion" "bastion-service" { + count = var.create_in_private_subnet ? 1 : 0 + bastion_type = "STANDARD" + compartment_id = var.compartment_ocid + target_subnet_id = !var.use_existing_vcn ? oci_core_subnet.postgresql_subnet[0].id : var.postgresql_subnet + client_cidr_block_allow_list = ["0.0.0.0/0"] + defined_tags = { "${oci_identity_tag_namespace.ArchitectureCenterTagNamespace.name}.${oci_identity_tag.ArchitectureCenterTag.name}" = var.release } + name = "BastionService${random_id.tag.hex}" + max_session_ttl_in_seconds = 10800 +} + +resource "oci_bastion_session" "ssh_postgresql_master_session" { + depends_on = [oci_core_instance.postgresql_master, + oci_core_nat_gateway.postgresql_nat, + # oci_core_route_table_attachment.vcn01_subnet_app01_route_table_attachment, + oci_core_route_table.postgresql_rt2 + ] + + count = var.create_in_private_subnet ? 1 : 0 + bastion_id = oci_bastion_bastion.bastion-service[0].id + + key_details { + public_key_content = tls_private_key.public_private_key_pair.public_key_openssh + } + target_resource_details { + session_type = "MANAGED_SSH" + target_resource_id = oci_core_instance.postgresql_master.id + + target_resource_operating_system_user_name = "opc" + target_resource_port = 22 + target_resource_private_ip_address = oci_core_instance.postgresql_master.private_ip + } + + display_name = "ssh_postgresql_master_session" + key_type = "PUB" + session_ttl_in_seconds = 10800 +} + +resource "oci_bastion_session" "ssh_postgresql_hotstandby1_session" { + depends_on = [oci_core_instance.postgresql_master, + oci_core_nat_gateway.postgresql_nat, + # oci_core_route_table_attachment.vcn01_subnet_app01_route_table_attachment, + oci_core_route_table.postgresql_rt2 + ] + + count = (var.create_in_private_subnet && var.postgresql_deploy_hotstandby1) ? 1 : 0 + bastion_id = oci_bastion_bastion.bastion-service[0].id + + key_details { + public_key_content = tls_private_key.public_private_key_pair.public_key_openssh + } + target_resource_details { + session_type = "MANAGED_SSH" + target_resource_id = oci_core_instance.postgresql_hotstandby1[count.index].id + + target_resource_operating_system_user_name = "opc" + target_resource_port = 22 + target_resource_private_ip_address = oci_core_instance.postgresql_hotstandby1[count.index].private_ip + } + + display_name = "ssh_postgresql_hotstandby1_session" + key_type = "PUB" + session_ttl_in_seconds = 10800 +} + +resource "oci_bastion_session" "ssh_postgresql_hotstandby2_session" { + depends_on = [oci_core_instance.postgresql_master, + oci_core_nat_gateway.postgresql_nat, + # oci_core_route_table_attachment.vcn01_subnet_app01_route_table_attachment, + oci_core_route_table.postgresql_rt2 + ] + + count = (var.create_in_private_subnet && var.postgresql_deploy_hotstandby2) ? 1 : 0 + bastion_id = oci_bastion_bastion.bastion-service[0].id + + key_details { + public_key_content = tls_private_key.public_private_key_pair.public_key_openssh + } + target_resource_details { + session_type = "MANAGED_SSH" + target_resource_id = oci_core_instance.postgresql_hotstandby2[count.index].id + + target_resource_operating_system_user_name = "opc" + target_resource_port = 22 + target_resource_private_ip_address = oci_core_instance.postgresql_hotstandby2[count.index].private_ip + } + + display_name = "ssh_postgresql_hotstandby2_session" + key_type = "PUB" + session_ttl_in_seconds = 10800 +} diff --git a/block_volume.tf b/block_volume.tf new file mode 100644 index 0000000..ffef847 --- /dev/null +++ b/block_volume.tf @@ -0,0 +1,90 @@ +## Copyright (c) 2021 Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + +resource "oci_core_volume" "postgresql_master_volume" { + count = var.add_iscsi_volume ? 1 : 0 + availability_domain = var.availablity_domain_name + compartment_id = var.compartment_ocid + display_name = "PostgreSQL_Master_Volume" + size_in_gbs = var.iscsi_volume_size_in_gbs + defined_tags = { "${oci_identity_tag_namespace.ArchitectureCenterTagNamespace.name}.${oci_identity_tag.ArchitectureCenterTag.name}" = var.release } +} + +resource "oci_core_volume_attachment" "postgresql_master_volume_attachment" { + count = var.add_iscsi_volume ? 1 : 0 + attachment_type = "iscsi" + instance_id = oci_core_instance.postgresql_master.id + volume_id = oci_core_volume.postgresql_master_volume[0].id +} + +resource "oci_core_volume_backup" "postgresql_master_volume_backup" { + count = (var.add_iscsi_volume && var.boot_volume_initial_backup) ? 1 : 0 + volume_id = oci_core_volume.postgresql_master_volume[0].id + display_name = "PostgreSQL_Master_Volume_Backup_FULL" + type = "FULL" +} + +resource "oci_core_volume_backup_policy_assignment" "postgresql_master_volume_backup_policy_assignment" { + count = (var.add_iscsi_volume && var.block_volume_backup_policy_enabled) ? 1 : 0 + asset_id = oci_core_volume.postgresql_master_volume[0].id + policy_id = data.oci_core_volume_backup_policies.block_volume_backup_policy[count.index].volume_backup_policies[0].id +} + +resource "oci_core_volume" "postgresql_hotstandby1_volume" { + count = (var.postgresql_deploy_hotstandby1 && var.add_iscsi_volume && var.boot_volume_initial_backup) ? 1 : 0 + availability_domain = var.postgresql_hotstandby1_ad == "" ? var.availablity_domain_name : var.postgresql_hotstandby1_ad + compartment_id = var.compartment_ocid + display_name = "PostgreSQL_HotStandby1_Volume" + size_in_gbs = var.iscsi_volume_size_in_gbs + defined_tags = { "${oci_identity_tag_namespace.ArchitectureCenterTagNamespace.name}.${oci_identity_tag.ArchitectureCenterTag.name}" = var.release } +} + +resource "oci_core_volume_attachment" "postgresql_hotstandby1_volume_attachment" { + count = (var.postgresql_deploy_hotstandby1 && var.add_iscsi_volume) ? 1 : 0 + attachment_type = "iscsi" + instance_id = oci_core_instance.postgresql_hotstandby1[0].id + volume_id = oci_core_volume.postgresql_hotstandby1_volume[0].id +} + +resource "oci_core_volume_backup" "postgresql_hotstandby1_volume_backup" { + count = (var.postgresql_deploy_hotstandby1 && var.add_iscsi_volume && var.boot_volume_initial_backup) ? 1 : 0 + volume_id = oci_core_volume.postgresql_hotstandby1_volume[0].id + display_name = "PostgreSQL_HotStandby1_Volume_Backup_FULL" + type = "FULL" +} + +resource "oci_core_volume_backup_policy_assignment" "postgresql_hotstandby1_volume_backup_policy_assignment" { + count = (var.postgresql_deploy_hotstandby1 && var.add_iscsi_volume && var.block_volume_backup_policy_enabled) ? 1 : 0 + asset_id = oci_core_volume.postgresql_hotstandby1_volume[0].id + policy_id = data.oci_core_volume_backup_policies.block_volume_backup_policy[count.index].volume_backup_policies[0].id +} + +resource "oci_core_volume" "postgresql_hotstandby2_volume" { + count = (var.postgresql_deploy_hotstandby2 && var.add_iscsi_volume) ? 1 : 0 + availability_domain = var.postgresql_hotstandby2_ad == "" ? var.availablity_domain_name : var.postgresql_hotstandby2_ad + compartment_id = var.compartment_ocid + display_name = "PostgreSQL_HotStandby2_Volume" + size_in_gbs = var.iscsi_volume_size_in_gbs + defined_tags = { "${oci_identity_tag_namespace.ArchitectureCenterTagNamespace.name}.${oci_identity_tag.ArchitectureCenterTag.name}" = var.release } +} + +resource "oci_core_volume_attachment" "postgresql_hotstandby2_volume_attachment" { + count = (var.postgresql_deploy_hotstandby2 && var.add_iscsi_volume) ? 1 : 0 + attachment_type = "iscsi" + instance_id = oci_core_instance.postgresql_hotstandby2[0].id + volume_id = oci_core_volume.postgresql_hotstandby2_volume[0].id +} + +resource "oci_core_volume_backup" "postgresql_hotstandby2_volume_backup" { + count = (var.postgresql_deploy_hotstandby2 && var.add_iscsi_volume && var.boot_volume_initial_backup) ? 1 : 0 + volume_id = oci_core_volume.postgresql_hotstandby2_volume[0].id + display_name = "PostgreSQL_HotStandby2_Volume_Backup_FULL" + type = "FULL" +} + +resource "oci_core_volume_backup_policy_assignment" "postgresql_hotstandby2_volume_backup_policy_assignment" { + count = (var.postgresql_deploy_hotstandby2 && var.add_iscsi_volume && var.block_volume_backup_policy_enabled) ? 1 : 0 + asset_id = oci_core_volume.postgresql_hotstandby2_volume[0].id + policy_id = data.oci_core_volume_backup_policies.block_volume_backup_policy[count.index].volume_backup_policies[0].id +} + diff --git a/compute.tf b/compute.tf new file mode 100644 index 0000000..ebd93de --- /dev/null +++ b/compute.tf @@ -0,0 +1,222 @@ +## Copyright (c) 2021 Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + +data "template_file" "key_script" { + template = file("${path.module}/scripts/sshkey.tpl") + vars = { + ssh_public_key = tls_private_key.public_private_key_pair.public_key_openssh + } +} + +data "template_cloudinit_config" "cloud_init" { + gzip = true + base64_encode = true + + part { + filename = "ainit.sh" + content_type = "text/x-shellscript" + content = data.template_file.key_script.rendered + } +} + +resource "oci_core_instance" "postgresql_master" { + availability_domain = var.availablity_domain_name + compartment_id = var.compartment_ocid + display_name = "PostgreSQL_Master" + shape = var.postgresql_instance_shape + + dynamic "shape_config" { + for_each = local.is_flexible_postgresql_instance_shape ? [1] : [] + content { + memory_in_gbs = var.postgresql_instance_flex_shape_memory + ocpus = var.postgresql_instance_flex_shape_ocpus + } + } + + dynamic "agent_config" { + for_each = var.create_in_private_subnet ? [1] : [] + content { + are_all_plugins_disabled = false + is_management_disabled = false + is_monitoring_disabled = false + plugins_config { + desired_state = "ENABLED" + name = "Bastion" + } + } + } + + fault_domain = var.postgresql_master_fd + + create_vnic_details { + subnet_id = !var.use_existing_vcn ? oci_core_subnet.postgresql_subnet[0].id : var.postgresql_subnet + display_name = "primaryvnic" + assign_public_ip = var.create_in_private_subnet ? false : true + hostname_label = "pgmaster" + } + + source_details { + source_type = "image" + source_id = data.oci_core_images.InstanceImageOCID_postgresql_instance_shape.images[0].id + } + + metadata = { + ssh_authorized_keys = var.ssh_public_key + user_data = data.template_cloudinit_config.cloud_init.rendered + } + + provisioner "local-exec" { + command = "sleep 240" + } + + defined_tags = { "${oci_identity_tag_namespace.ArchitectureCenterTagNamespace.name}.${oci_identity_tag.ArchitectureCenterTag.name}" = var.release } +} + +resource "oci_core_boot_volume_backup" "postgresql_master_boot_volume_backup" { + count = var.boot_volume_initial_backup ? 1 : 0 + boot_volume_id = oci_core_instance.postgresql_master.boot_volume_id + display_name = "PostgreSQL_Master_Boot_Volume_Backup_FULL" + type = "FULL" +} + +resource "oci_core_volume_backup_policy_assignment" "postgresql_master_boot_volume_backup_policy_assignment" { + count = var.boot_volume_backup_policy_enabled ? 1 : 0 + asset_id = oci_core_instance.postgresql_master.boot_volume_id + policy_id = data.oci_core_volume_backup_policies.boot_volume_backup_policy.volume_backup_policies[0].id +} + +resource "oci_core_instance" "postgresql_hotstandby1" { + count = var.postgresql_deploy_hotstandby1 ? 1 : 0 + availability_domain = var.postgresql_hotstandby1_ad == "" ? var.availablity_domain_name : var.postgresql_hotstandby1_ad + compartment_id = var.compartment_ocid + display_name = "PostgreSQL_HotStandby1" + shape = var.postgresql_hotstandby1_shape + + dynamic "shape_config" { + for_each = local.is_flexible_postgresql_hotstandby1_shape ? [1] : [] + content { + memory_in_gbs = var.postgresql_hotstandby1_flex_shape_memory + ocpus = var.postgresql_hotstandby1_flex_shape_ocpus + } + } + + dynamic "agent_config" { + for_each = var.create_in_private_subnet ? [1] : [] + content { + are_all_plugins_disabled = false + is_management_disabled = false + is_monitoring_disabled = false + plugins_config { + desired_state = "ENABLED" + name = "Bastion" + } + } + } + + + fault_domain = var.postgresql_hotstandby1_fd + + create_vnic_details { + subnet_id = !var.use_existing_vcn ? oci_core_subnet.postgresql_subnet[0].id : var.postgresql_subnet + display_name = "primaryvnic" + assign_public_ip = var.create_in_private_subnet ? false : true + hostname_label = "pgstandby1" + } + + source_details { + source_type = "image" + source_id = data.oci_core_images.InstanceImageOCID_postgresql_hotstandby1_shape.images[0].id + } + + metadata = { + ssh_authorized_keys = var.ssh_public_key + user_data = data.template_cloudinit_config.cloud_init.rendered + } + + provisioner "local-exec" { + command = "sleep 240" + } + + defined_tags = { "${oci_identity_tag_namespace.ArchitectureCenterTagNamespace.name}.${oci_identity_tag.ArchitectureCenterTag.name}" = var.release } +} + +resource "oci_core_boot_volume_backup" "postgresql_hotstandby1_boot_volume_backup" { + count = (var.postgresql_deploy_hotstandby1 && var.boot_volume_initial_backup) ? 1 : 0 + boot_volume_id = oci_core_instance.postgresql_hotstandby1[0].boot_volume_id + display_name = "PostgreSQL_Hotstandby1_Boot_Volume_Backup_FULL" + type = "FULL" +} + +resource "oci_core_volume_backup_policy_assignment" "postgresql_hotstandby1_boot_volume_backup_policy_assignment" { + count = (var.postgresql_deploy_hotstandby1 && var.boot_volume_backup_policy_enabled) ? 1 : 0 + asset_id = oci_core_instance.postgresql_hotstandby1[0].boot_volume_id + policy_id = data.oci_core_volume_backup_policies.boot_volume_backup_policy.volume_backup_policies[0].id +} + +resource "oci_core_instance" "postgresql_hotstandby2" { + count = var.postgresql_deploy_hotstandby2 ? 1 : 0 + availability_domain = var.postgresql_hotstandby2_ad == "" ? var.availablity_domain_name : var.postgresql_hotstandby2_ad + compartment_id = var.compartment_ocid + display_name = "PostgreSQL_HotStandby2" + shape = var.postgresql_hotstandby2_shape + + dynamic "shape_config" { + for_each = local.is_flexible_postgresql_hotstandby2_shape ? [1] : [] + content { + memory_in_gbs = var.postgresql_hotstandby2_flex_shape_memory + ocpus = var.postgresql_hotstandby2_flex_shape_ocpus + } + } + + + dynamic "agent_config" { + for_each = var.create_in_private_subnet ? [1] : [] + content { + are_all_plugins_disabled = false + is_management_disabled = false + is_monitoring_disabled = false + plugins_config { + desired_state = "ENABLED" + name = "Bastion" + } + } + } + + fault_domain = var.postgresql_hotstandby2_fd + + create_vnic_details { + subnet_id = !var.use_existing_vcn ? oci_core_subnet.postgresql_subnet[0].id : var.postgresql_subnet + display_name = "primaryvnic" + assign_public_ip = var.create_in_private_subnet ? false : true + hostname_label = "pgstandby2" + } + + source_details { + source_type = "image" + source_id = data.oci_core_images.InstanceImageOCID_postgresql_hotstandby2_shape.images[0].id + } + + metadata = { + ssh_authorized_keys = var.ssh_public_key + user_data = data.template_cloudinit_config.cloud_init.rendered + } + + provisioner "local-exec" { + command = "sleep 240" + } + + defined_tags = { "${oci_identity_tag_namespace.ArchitectureCenterTagNamespace.name}.${oci_identity_tag.ArchitectureCenterTag.name}" = var.release } +} + +resource "oci_core_boot_volume_backup" "postgresql_hotstandby2_boot_volume_backup" { + count = (var.postgresql_deploy_hotstandby2 && var.boot_volume_initial_backup) ? 1 : 0 + boot_volume_id = oci_core_instance.postgresql_hotstandby2[0].boot_volume_id + display_name = "PostgreSQL_Hotstandby2_Boot_Volume_Backup_FULL" + type = "FULL" +} + +resource "oci_core_volume_backup_policy_assignment" "postgresql_hotstandby2_boot_volume_backup_policy_assignment" { + count = (var.postgresql_deploy_hotstandby2 && var.boot_volume_backup_policy_enabled) ? 1 : 0 + asset_id = oci_core_instance.postgresql_hotstandby2[0].boot_volume_id + policy_id = data.oci_core_volume_backup_policies.boot_volume_backup_policy.volume_backup_policies[0].id +} diff --git a/datasources.tf b/datasources.tf new file mode 100644 index 0000000..b57c99f --- /dev/null +++ b/datasources.tf @@ -0,0 +1,117 @@ +## Copyright (c) 2021 Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + +data "oci_core_vnic_attachments" "postgresql_master_vnics" { + compartment_id = var.compartment_ocid + availability_domain = var.availablity_domain_name + instance_id = oci_core_instance.postgresql_master.id +} + + +data "oci_core_vnic_attachments" "postgresql_master_primaryvnic_attach" { + availability_domain = var.availablity_domain_name + compartment_id = var.compartment_ocid + instance_id = oci_core_instance.postgresql_master.id +} + +data "oci_core_vnic" "postgresql_master_primaryvnic" { + vnic_id = data.oci_core_vnic_attachments.postgresql_master_primaryvnic_attach.vnic_attachments.0.vnic_id +} + +data "oci_core_vnic_attachments" "postgresql_hotstandby1_primaryvnic_attach" { + count = var.postgresql_deploy_hotstandby1 ? 1 : 0 + availability_domain = var.postgresql_hotstandby1_ad + compartment_id = var.compartment_ocid + instance_id = oci_core_instance.postgresql_hotstandby1[count.index].id +} + +data "oci_core_vnic" "postgresql_hotstandby1_primaryvnic" { + count = var.postgresql_deploy_hotstandby1 ? 1 : 0 + vnic_id = data.oci_core_vnic_attachments.postgresql_hotstandby1_primaryvnic_attach[count.index].vnic_attachments.0.vnic_id +} + +data "oci_core_vnic_attachments" "postgresql_hotstandby2_primaryvnic_attach" { + count = var.postgresql_deploy_hotstandby2 ? 1 : 0 + availability_domain = var.postgresql_hotstandby2_ad + compartment_id = var.compartment_ocid + instance_id = oci_core_instance.postgresql_hotstandby2[count.index].id +} + +data "oci_core_vnic" "postgresql_hotstandby2_primaryvnic" { + count = var.postgresql_deploy_hotstandby2 ? 1 : 0 + vnic_id = data.oci_core_vnic_attachments.postgresql_hotstandby2_primaryvnic_attach[count.index].vnic_attachments.0.vnic_id +} + + +# Get the latest Oracle Linux image +data "oci_core_images" "InstanceImageOCID_postgresql_instance_shape" { + compartment_id = var.compartment_ocid + operating_system = var.instance_os + operating_system_version = var.linux_os_version + shape = var.postgresql_instance_shape + + filter { + name = "display_name" + values = ["^.*Oracle[^G]*$"] + regex = true + } +} + +# Get the latest Oracle Linux image +data "oci_core_images" "InstanceImageOCID_postgresql_hotstandby1_shape" { + compartment_id = var.compartment_ocid + operating_system = var.instance_os + operating_system_version = var.linux_os_version + shape = var.postgresql_hotstandby1_shape + + filter { + name = "display_name" + values = ["^.*Oracle[^G]*$"] + regex = true + } +} + +# Get the latest Oracle Linux image +data "oci_core_images" "InstanceImageOCID_postgresql_hotstandby2_shape" { + compartment_id = var.compartment_ocid + operating_system = var.instance_os + operating_system_version = var.linux_os_version + shape = var.postgresql_hotstandby2_shape + + filter { + name = "display_name" + values = ["^.*Oracle[^G]*$"] + regex = true + } +} + +data "oci_identity_region_subscriptions" "home_region_subscriptions" { + tenancy_id = var.tenancy_ocid + + filter { + name = "is_home_region" + values = [true] + } +} + + +data "oci_core_volume_backup_policies" "boot_volume_backup_policy" { + # count = var.add_iscsi_volume ? 1 : 0 + + filter { + name = "display_name" + values = [var.boot_volume_backup_policy_level] + regex = true + } +} + + +data "oci_core_volume_backup_policies" "block_volume_backup_policy" { + count = var.add_iscsi_volume ? 1 : 0 + + filter { + name = "display_name" + values = [var.block_volume_backup_policy_level] + regex = true + } +} diff --git a/examples/remote-module-network-inside-module/main.tf b/examples/remote-module-network-inside-module/main.tf new file mode 100644 index 0000000..d5e834a --- /dev/null +++ b/examples/remote-module-network-inside-module/main.tf @@ -0,0 +1,32 @@ +## Copyright (c) 2021 Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + +variable "tenancy_ocid" {} +variable "user_ocid" {} +variable "fingerprint" {} +variable "private_key_path" {} +variable "region" {} +variable "compartment_ocid" {} +variable "availablity_domain_name" {} +variable "postgresql_password" {} + +provider "oci" { + tenancy_ocid = var.tenancy_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + private_key_path = var.private_key_path + region = var.region +} + +module "postgres" { + source = "github.com/oracle-devrel/terraform-oci-arch-postgresql" + tenancy_ocid = var.tenancy_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + region = var.region + private_key_path = var.private_key_path + availablity_domain_name = var.availablity_domain_name + compartment_ocid = var.compartment_ocid + postgresql_password = var.postgresql_password +} + diff --git a/examples/remote-module-no-hotstandbys/main.tf b/examples/remote-module-no-hotstandbys/main.tf new file mode 100644 index 0000000..847e03d --- /dev/null +++ b/examples/remote-module-no-hotstandbys/main.tf @@ -0,0 +1,104 @@ +## Copyright (c) 2021 Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + +variable "tenancy_ocid" {} +variable "user_ocid" {} +variable "fingerprint" {} +variable "private_key_path" {} +variable "region" {} +variable "compartment_ocid" {} +variable "availablity_domain_name" {} +variable "postgresql_password" {} + +provider "oci" { + tenancy_ocid = var.tenancy_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + private_key_path = var.private_key_path + region = var.region +} + +resource "oci_core_virtual_network" "my_vcn" { + cidr_block = "192.168.0.0/16" + compartment_id = var.compartment_ocid + display_name = "myVCN" + dns_label = "myvcn" +} + +resource "oci_core_nat_gateway" "my_nat" { + compartment_id = var.compartment_ocid + display_name = "myNAT" + vcn_id = oci_core_virtual_network.my_vcn.id +} + +resource "oci_core_route_table" "my_rt" { + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.my_vcn.id + display_name = "myRT" + + route_rules { + destination = "0.0.0.0/0" + destination_type = "CIDR_BLOCK" + network_entity_id = oci_core_nat_gateway.my_nat.id + } +} + +resource "oci_core_security_list" "my_securitylist" { + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.my_vcn.id + display_name = "mySecurityList" + + egress_security_rules { + protocol = "6" + destination = "0.0.0.0/0" + } + + ingress_security_rules { + protocol = "6" + source = "0.0.0.0/0" + + tcp_options { + max = "22" + min = "22" + } + } + + ingress_security_rules { + protocol = "6" + source = "0.0.0.0/0" + + tcp_options { + max = "5432" + min = "5432" + } + } +} + +resource "oci_core_subnet" "my_subnet" { + cidr_block = "192.168.1.0/24" + display_name = "mySubnet" + dns_label = "mysubnet" + security_list_ids = [oci_core_security_list.my_securitylist.id] + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.my_vcn.id + route_table_id = oci_core_route_table.my_rt.id + dhcp_options_id = oci_core_virtual_network.my_vcn.default_dhcp_options_id + prohibit_public_ip_on_vnic = true +} + +module "postgres" { + source = "github.com/oracle-devrel/terraform-oci-arch-postgresql" + tenancy_ocid = var.tenancy_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + region = var.region + private_key_path = var.private_key_path + availablity_domain_name = var.availablity_domain_name + compartment_ocid = var.compartment_ocid + use_existing_vcn = true # usage of the external existing VCN + create_in_private_subnet = true # usage of the private subnet + postgresql_vcn = oci_core_virtual_network.my_vcn.id # injecting myVCN + postgresql_subnet = oci_core_subnet.my_subnet.id # injecting private mySubnet + postgresql_password = var.postgresql_password +} + diff --git a/examples/remote-module-private-subnet/main.tf b/examples/remote-module-private-subnet/main.tf new file mode 100644 index 0000000..30bb29e --- /dev/null +++ b/examples/remote-module-private-subnet/main.tf @@ -0,0 +1,121 @@ +## Copyright (c) 2021 Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + +variable "tenancy_ocid" {} +variable "user_ocid" {} +variable "fingerprint" {} +variable "private_key_path" {} +variable "region" {} +variable "compartment_ocid" {} +variable "availablity_domain_name" {} +variable "postgresql_password" {} + +provider "oci" { + tenancy_ocid = var.tenancy_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + private_key_path = var.private_key_path + region = var.region +} + +resource "oci_core_virtual_network" "my_vcn" { + cidr_block = "192.168.0.0/16" + compartment_id = var.compartment_ocid + display_name = "myVCN" + dns_label = "myvcn" +} + +resource "oci_core_nat_gateway" "my_nat" { + compartment_id = var.compartment_ocid + display_name = "myNAT" + vcn_id = oci_core_virtual_network.my_vcn.id +} + +resource "oci_core_route_table" "my_rt" { + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.my_vcn.id + display_name = "myRT" + + route_rules { + destination = "0.0.0.0/0" + destination_type = "CIDR_BLOCK" + network_entity_id = oci_core_nat_gateway.my_nat.id + } +} + +resource "oci_core_security_list" "my_securitylist" { + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.my_vcn.id + display_name = "mySecurityList" + + egress_security_rules { + protocol = "6" + destination = "0.0.0.0/0" + } + + ingress_security_rules { + protocol = "6" + source = "0.0.0.0/0" + + tcp_options { + max = "22" + min = "22" + } + } + + ingress_security_rules { + protocol = "6" + source = "0.0.0.0/0" + + tcp_options { + max = "5432" + min = "5432" + } + } +} + +resource "oci_core_subnet" "my_subnet" { + cidr_block = "192.168.1.0/24" + display_name = "mySubnet" + dns_label = "mysubnet" + security_list_ids = [oci_core_security_list.my_securitylist.id] + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.my_vcn.id + route_table_id = oci_core_route_table.my_rt.id + dhcp_options_id = oci_core_virtual_network.my_vcn.default_dhcp_options_id + prohibit_public_ip_on_vnic = true +} + +module "postgres" { + source = "github.com/oracle-devrel/terraform-oci-arch-postgresql" + tenancy_ocid = var.tenancy_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + region = var.region + private_key_path = var.private_key_path + availablity_domain_name = var.availablity_domain_name + compartment_ocid = var.compartment_ocid + use_existing_vcn = true # usage of the external existing VCN + create_in_private_subnet = true # usage of the private subnet + postgresql_vcn = oci_core_virtual_network.my_vcn.id # injecting myVCN + postgresql_subnet = oci_core_subnet.my_subnet.id # injecting private mySubnet + postgresql_password = var.postgresql_password + add_iscsi_volume = true # adding iSCSI volume... + iscsi_volume_size_in_gbs = 200 # ... with 200 GB of size + postgresql_version = "12" # non-default version of PostgreSQL12 + # OCPUs & memory for flex shape in master node. + postgresql_instance_shape = "VM.Standard.E3.Flex" + postgresql_instance_flex_shape_ocpus = 2 + postgresql_instance_flex_shape_memory = 20 + # OCPUs & memory for flex shape in hotstanby1 node. + postgresql_deploy_hotstandby1 = true + postgresql_hotstandby1_shape = "VM.Standard.E3.Flex" + postgresql_hotstandby1_flex_shape_ocpus = 1 + postgresql_hotstandby1_flex_shape_memory = 10 + # OCPUs & memory for flex shape in hotstanby2 node. + postgresql_deploy_hotstandby2 = true + postgresql_hotstandby2_shape = "VM.Standard.E3.Flex" + postgresql_hotstandby2_flex_shape_ocpus = 1 + postgresql_hotstandby2_flex_shape_memory = 5 +} + diff --git a/examples/remote-module-public-subnet/main.tf b/examples/remote-module-public-subnet/main.tf new file mode 100644 index 0000000..6a3496f --- /dev/null +++ b/examples/remote-module-public-subnet/main.tf @@ -0,0 +1,105 @@ +## Copyright (c) 2021 Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + +variable "tenancy_ocid" {} +variable "user_ocid" {} +variable "fingerprint" {} +variable "private_key_path" {} +variable "region" {} +variable "compartment_ocid" {} +variable "availablity_domain_name" {} +variable "postgresql_password" {} + +provider "oci" { + tenancy_ocid = var.tenancy_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + private_key_path = var.private_key_path + region = var.region +} + +resource "oci_core_virtual_network" "my_vcn" { + cidr_block = "192.168.0.0/16" + compartment_id = var.compartment_ocid + display_name = "myVCN" + dns_label = "myvcn" +} + +resource "oci_core_internet_gateway" "my_igw" { + compartment_id = var.compartment_ocid + display_name = "myIGW" + vcn_id = oci_core_virtual_network.my_vcn.id +} + +resource "oci_core_route_table" "my_rt" { + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.my_vcn.id + display_name = "myRT" + + route_rules { + destination = "0.0.0.0/0" + destination_type = "CIDR_BLOCK" + network_entity_id = oci_core_internet_gateway.my_igw.id + } +} + +resource "oci_core_security_list" "my_securitylist" { + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.my_vcn.id + display_name = "mySecurityList" + + egress_security_rules { + protocol = "6" + destination = "0.0.0.0/0" + } + + ingress_security_rules { + protocol = "6" + source = "0.0.0.0/0" + + tcp_options { + max = "22" + min = "22" + } + } + + ingress_security_rules { + protocol = "6" + source = "0.0.0.0/0" + + tcp_options { + max = "5432" + min = "5432" + } + } +} + +resource "oci_core_subnet" "my_subnet" { + cidr_block = "192.168.1.0/24" + display_name = "mySubnet" + dns_label = "mysubnet" + security_list_ids = [oci_core_security_list.my_securitylist.id] + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.my_vcn.id + route_table_id = oci_core_route_table.my_rt.id + dhcp_options_id = oci_core_virtual_network.my_vcn.default_dhcp_options_id +} + +module "postgres" { + source = "github.com/oracle-devrel/terraform-oci-arch-postgresql" + tenancy_ocid = var.tenancy_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + region = var.region + private_key_path = var.private_key_path + availablity_domain_name = var.availablity_domain_name + compartment_ocid = var.compartment_ocid + use_existing_vcn = true # usage of the external existing VCN + create_in_private_subnet = false # usage of the public subnet + postgresql_vcn = oci_core_virtual_network.my_vcn.id # injecting myVCN + postgresql_subnet = oci_core_subnet.my_subnet.id # injecting public mySubnet + postgresql_password = var.postgresql_password + postgresql_deploy_hotstandby1 = true + postgresql_deploy_hotstandby2 = true +} + diff --git a/images/postgre-oci.png b/images/postgre-oci.png new file mode 100644 index 0000000000000000000000000000000000000000..6ca67bffb3db08bd00d4a1e327cc2f761563fc05 GIT binary patch literal 44623 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 vQLsiT+$=> /etc/fstab\"", + "sudo -u root mount | grep sdb1", + ] + } + +} + +resource "null_resource" "postgresql_master_install_binaries" { + + triggers = { + postgresql_master_id = oci_core_instance.postgresql_master.id + } + + depends_on = [oci_core_instance.postgresql_master, null_resource.postgresql_master_attach_volume] + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "sudo rm -rf ~/postgresql_install_binaries.sh" + ] + } + + provisioner "file" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + + content = data.template_file.postgresql_install_binaries_sh.rendered + destination = "~/postgresql_install_binaries.sh" + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "chmod +x ~/postgresql_install_binaries.sh", + "sudo ~/postgresql_install_binaries.sh" + ] + } +} + +resource "null_resource" "postgresql_master_initdb" { + + triggers = { + postgresql_master_id = oci_core_instance.postgresql_master.id + } + + depends_on = [null_resource.postgresql_master_install_binaries] + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "sudo rm -rf ~/postgresql_master_initdb.sh" + ] + } + + provisioner "file" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + + content = data.template_file.postgresql_master_initdb_sh.rendered + destination = "~/postgresql_master_initdb.sh" + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "chmod +x ~/postgresql_master_initdb.sh", + "sudo ~/postgresql_master_initdb.sh" + ] + } +} + +resource "null_resource" "postgresql_hotstandby1_install_binaries" { + + triggers = { + postgresql_hotstandby1_id = oci_core_instance.postgresql_hotstandby1[0].id + } + + count = var.postgresql_deploy_hotstandby1 ? 1 : 0 + depends_on = [oci_core_instance.postgresql_master, oci_core_instance.postgresql_hotstandby1, null_resource.postgresql_hotstandby1_attach_volume] + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby1_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "sudo rm -rf ~/postgresql_install_binaries.sh" + ] + } + + provisioner "file" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby1_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + + content = data.template_file.postgresql_install_binaries_sh.rendered + destination = "~/postgresql_install_binaries.sh" + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby1_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "chmod +x ~/postgresql_install_binaries.sh", + "sudo ~/postgresql_install_binaries.sh" + ] + } +} + +resource "null_resource" "postgresql_hotstandby2_install_binaries" { + + triggers = { + postgresql_hotstandby2_id = oci_core_instance.postgresql_hotstandby2[0].id + } + + count = var.postgresql_deploy_hotstandby2 ? 1 : 0 + depends_on = [oci_core_instance.postgresql_master, oci_core_instance.postgresql_hotstandby2, null_resource.postgresql_hotstandby2_attach_volume] + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby2_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "sudo rm -rf ~/postgresql_install_binaries.sh" + ] + } + + provisioner "file" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby2_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + + content = data.template_file.postgresql_install_binaries_sh.rendered + destination = "~/postgresql_install_binaries.sh" + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby2_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "chmod +x ~/postgresql_install_binaries.sh", + "sudo ~/postgresql_install_binaries.sh" + ] + } +} + + +resource "null_resource" "postgresql_master_setup" { + + triggers = { + postgresql_master_id = oci_core_instance.postgresql_master.id + } + + count = var.postgresql_deploy_hotstandby1 ? 1 : 0 + depends_on = [null_resource.postgresql_master_initdb, null_resource.postgresql_hotstandby1_install_binaries] + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "sudo rm -rf ~/postgresql_master_setup.sh", + "sudo rm -rf /tmp/postgresql_master_setup_sql", + ] + } + + provisioner "file" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + + content = element(data.template_file.postgresql_master_setup_sh.*.rendered, 0) + destination = "~/postgresql_master_setup.sh" + } + + provisioner "file" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + + content = element(data.template_file.postgresql_master_setup_sql.*.rendered, 0) + destination = "/tmp/postgresql_master_setup.sql" + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "chmod +x ~/postgresql_master_setup.sh", + "sudo ~/postgresql_master_setup.sh" + ] + } +} + +resource "null_resource" "postgresql_master_setup2" { + + triggers = { + postgresql_master_id = oci_core_instance.postgresql_master.id + } + + count = var.postgresql_deploy_hotstandby2 ? 1 : 0 + depends_on = [null_resource.postgresql_master_initdb, null_resource.postgresql_hotstandby2_install_binaries, null_resource.postgresql_master_setup, null_resource.postgresql_hotstandby1_setup] + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "sudo rm -rf ~/postgresql_master_setup2.sh", + ] + } + + provisioner "file" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + + content = element(data.template_file.postgresql_master_setup2_sh.*.rendered, 0) + destination = "~/postgresql_master_setup2.sh" + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_master_primaryvnic.private_ip_address : data.oci_core_vnic.postgresql_master_primaryvnic.public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_master_session[0].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "chmod +x ~/postgresql_master_setup2.sh", + "sudo ~/postgresql_master_setup2.sh" + ] + } +} + + +resource "null_resource" "postgresql_hotstandby1_attach_volume" { + + triggers = { + postgresql_hotstandby1_id = oci_core_instance.postgresql_hotstandby1[0].id + } + + count = (var.postgresql_deploy_hotstandby1 && var.add_iscsi_volume) ? 1 : 0 + depends_on = [oci_core_instance.postgresql_hotstandby1, oci_core_volume.postgresql_hotstandby1_volume, oci_core_volume_attachment.postgresql_hotstandby1_volume_attachment] + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby1_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = ["sudo /bin/su -c \"rm -rf /home/opc/iscsiattach.sh\""] + } + + provisioner "file" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby1_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + source = "${path.module}/scripts/iscsiattach.sh" + destination = "/home/opc/iscsiattach.sh" + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby1_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = ["sudo /bin/su -c \"chown root /home/opc/iscsiattach.sh\"", + "sudo /bin/su -c \"chmod u+x /home/opc/iscsiattach.sh\"", + "sudo /bin/su -c \"/home/opc/iscsiattach.sh\""] + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby1_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "sudo -u root parted /dev/sdb --script -- mklabel gpt", + "sudo -u root parted /dev/sdb --script -- mkpart primary ext4 0% 100%", + "sudo -u root mkfs.ext4 /dev/sdb1 -F", + "sudo -u root mkdir /data", + "sudo -u root mount /dev/sdb1 /data", + "sudo /bin/su -c \"echo '/dev/sdb1 /data ext4 defaults,noatime,_netdev 0 0' >> /etc/fstab\"", + "sudo -u root mount | grep sdb1", + ] + } +} + +resource "null_resource" "postgresql_hotstandby1_setup" { + + triggers = { + postgresql_hotstandby1_id = oci_core_instance.postgresql_hotstandby1[0].id + } + + count = var.postgresql_deploy_hotstandby1 ? 1 : 0 + depends_on = [null_resource.postgresql_master_setup, null_resource.postgresql_hotstandby1_install_binaries, null_resource.postgresql_hotstandby1_attach_volume] + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby1_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "sudo rm -rf ~/postgresql_standby_setup.sh", + ] + } + + provisioner "file" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby1_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + + content = element(data.template_file.postgresql_standby_setup_sh.*.rendered, 0) + destination = "~/postgresql_standby_setup.sh" + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby1_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby1_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "chmod +x ~/postgresql_standby_setup.sh", + "sudo ~/postgresql_standby_setup.sh" + ] + } +} + +resource "null_resource" "postgresql_hotstandby2_attach_volume" { + + triggers = { + postgresql_hotstandby2_id = oci_core_instance.postgresql_hotstandby2[0].id + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby2_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = ["sudo /bin/su -c \"rm -rf /home/opc/iscsiattach.sh\""] + } + + count = (var.postgresql_deploy_hotstandby2 && var.add_iscsi_volume) ? 1 : 0 + depends_on = [oci_core_instance.postgresql_hotstandby2, oci_core_volume.postgresql_hotstandby2_volume, oci_core_volume_attachment.postgresql_hotstandby2_volume_attachment] + + provisioner "file" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby2_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + source = "${path.module}/scripts/iscsiattach.sh" + destination = "/home/opc/iscsiattach.sh" + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby2_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = ["sudo /bin/su -c \"chown root /home/opc/iscsiattach.sh\"", + "sudo /bin/su -c \"chmod u+x /home/opc/iscsiattach.sh\"", + "sudo /bin/su -c \"/home/opc/iscsiattach.sh\""] + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby2_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "sudo -u root parted /dev/sdb --script -- mklabel gpt", + "sudo -u root parted /dev/sdb --script -- mkpart primary ext4 0% 100%", + "sudo -u root mkfs.ext4 /dev/sdb1 -F", + "sudo -u root mkdir /data", + "sudo -u root mount /dev/sdb1 /data", + "sudo /bin/su -c \"echo '/dev/sdb1 /data ext4 defaults,noatime,_netdev 0 0' >> /etc/fstab\"", + "sudo -u root mount | grep sdb1", + ] + } +} + +resource "null_resource" "postgresql_hotstandby2_setup" { + + triggers = { + postgresql_hotstandby2_id = oci_core_instance.postgresql_hotstandby2[0].id + } + + count = var.postgresql_deploy_hotstandby2 ? 1 : 0 + depends_on = [null_resource.postgresql_master_setup2, null_resource.postgresql_hotstandby1_setup, null_resource.postgresql_hotstandby2_install_binaries, null_resource.postgresql_hotstandby2_attach_volume] + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby2_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "sudo rm -rf ~/postgresql_standby_setup.sh", + ] + } + + provisioner "file" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby2_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + + content = element(data.template_file.postgresql_standby_setup_sh.*.rendered, 0) + destination = "~/postgresql_standby_setup.sh" + } + + provisioner "remote-exec" { + connection { + type = "ssh" + user = "opc" + host = var.create_in_private_subnet ? data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].private_ip_address : data.oci_core_vnic.postgresql_hotstandby2_primaryvnic[count.index].public_ip_address + private_key = tls_private_key.public_private_key_pair.private_key_pem + script_path = "/home/opc/myssh.sh" + agent = false + timeout = "10m" + bastion_host = var.create_in_private_subnet ? "host.bastion.${var.region}.oci.oraclecloud.com" : null + bastion_port = var.create_in_private_subnet ? "22" : null + bastion_user = var.create_in_private_subnet ? oci_bastion_session.ssh_postgresql_hotstandby2_session[count.index].id : null + bastion_private_key = var.create_in_private_subnet ? tls_private_key.public_private_key_pair.private_key_pem : null + } + inline = [ + "chmod +x ~/postgresql_standby_setup.sh", + "sudo ~/postgresql_standby_setup.sh" + ] + } +} diff --git a/schema.yaml b/schema.yaml new file mode 100644 index 0000000..d6f3082 --- /dev/null +++ b/schema.yaml @@ -0,0 +1,537 @@ +## Copyright © 2021, Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + + title: "Create three-node deployment of a High Available PostgreSQL database on Oracle Cloud Infrastructure Compute instances." + stackDescription: "Deploy typical three-node deployment of a High Available PostgreSQL database on Oracle Cloud Infrastructure Compute instances." + schemaVersion: 1.1.0 + version: "20190404" + locale: "en" + + variableGroups: + - title: General Configuration + visible: false + variables: + - tenancy_ocid + - region + - release + - use_existing_vcn + - postgresql_vcn + - postgresql_subnet + + - title: Required Configuration + variables: + - compartment_ocid + - availablity_domain_name + - postgresql_version + - postgresql_password + - postgresql_deploy_hotstandby1 + - postgresql_deploy_hotstandby2 + - create_in_private_subnet + - show_advanced + + - title: Network Optional Configuration + visible: + and: + - show_advanced + variables: + - postgresql_vcn_cidr + - postgresql_subnet_cidr + - create_drg_for_private_subnet + + - title: Compute, Storage & Backup Optional Configuration + visible: + and: + - show_advanced + variables: + - ssh_public_key + - instance_os + - linux_os_version + - add_iscsi_volume + - boot_volume_backup_policy_enabled + - boot_volume_backup_policy_level + - boot_volume_initial_backup + - iscsi_volume_size_in_gbs + - block_volume_backup_policy_enabled + - block_volume_backup_policy_level + - block_volume_initial_backup + + - title: PostgreSQL Master Optional Configuration + visible: + and: + - show_advanced + variables: + - postgresql_master_fd + - postgresql_instance_shape + - postgresql_instance_flex_shape_ocpus + - postgresql_instance_flex_shape_memory + - postgresql_replicat_username + + - title: PostgreSQL HotStandby1 Optional Configuration + visible: + and: + - show_advanced + - postgresql_deploy_hotstandby1 + variables: + - postgresql_hotstandby1_ad + - postgresql_hotstandby1_fd + - postgresql_hotstandby1_shape + - postgresql_hotstandby1_flex_shape_ocpus + - postgresql_hotstandby1_flex_shape_memory + + - title: PostgreSQL HotStandby2 Configuration + visible: + and: + - show_advanced + - postgresql_deploy_hotstandby2 + variables: + - postgresql_hotstandby2_ad + - postgresql_hotstandby2_fd + - postgresql_hotstandby2_shape + - postgresql_hotstandby2_flex_shape_ocpus + - postgresql_hotstandby2_flex_shape_memory + + variables: + + show_advanced: + type: boolean + title: "Show advanced options?" + description: "Shows advanced options." + visible: true + default: false + + postgresql_deploy_hotstandby1: + type: boolean + title: "Deploy first PostgreSQL HotStandby?" + description: "Check the box to deploy first PostgreSQL HotStandby." + visible: true + default: true + + postgresql_deploy_hotstandby2: + type: boolean + title: "Deploy second PostgreSQL HotStandby?" + description: "Check the box to deploy second PostgreSQL HotStandby." + visible: true + default: true + + compartment_ocid: + type: oci:identity:compartment:id + required: true + visible: true + title: Compartment + description: "Compartment where you want to create the solution resources" + + region: + type: oci:identity:region:name + required: true + visible: true + title: Region + description: "Region where you want to deploy the resources defined by this stack." + + availablity_domain_name: + type: oci:identity:availabilitydomain:name + required: true + visible: true + title: "Availability Domain for master PostgreSQL" + description: "Availability Domain to be chosen for master PostgreSQL." + dependsOn: + compartmentId: ${compartment_ocid} + + ssh_public_key: + type: oci:core:ssh:publickey + title: "Public SSH Key" + description: "Choose public SSH Key to be uploaded into compute instances." + required: false + + postgresql_password: + type: password + required: true + visible: true + title: "PostgreSQL Password" + description: "The password must start with a letter, and it can contain letters (uppercase, lowercase), numbers, and the symbols _ $ #" + minLength: 12 + maxLength: 30 + pattern: ^[A-Za-z][A-Za-z0-9_#\$]+$ + + postgresql_version: + type: enum + visible: true + required: true + title: "PostgreSQL Version" + description: "Choose PostgreSQL Version." + default: "13" + enum: + - "13" + - "12" + - "11" + - "10" + - "9.6" + + create_in_private_subnet: + type: boolean + visible: true + required: true + title: "Create in Private Subnet" + description: "Providing an option to create PostgreSQL VMs in private or public subnet (for private subnet OCI Bastion Service will be provisioned)." + default: true + + # Optional Configuration + + add_iscsi_volume: + type: boolean + title: "Add iSCSI Volume to compute?" + description: "Check the box to add iSCSI Volume to compute instance." + visible: true + default: true + + iscsi_volume_size_in_gbs: + type: number + title: "iSCSI Volume Size in GB" + description: "Choose the size of iSCSI volume attached to compute instance (default=100GB, min=50GB, max=32000GB)." + required: false + minimum: 50 + maximum: 32000 + multipleOf: 1 + default: 100 + visible: + and: + - add_iscsi_volume + + boot_volume_backup_policy_enabled: + type: boolean + title: "Enable Boot Volume Backup Policy" + description: "Check the box if you want to add Boot Volume Backup Policy." + visible: true + default: true + + boot_volume_backup_policy_level: + type: enum + required: false + title: "Boot Volume Backup Policy" + description: "Choose the value for Boot Volume Backup Policy." + default: "gold" + enum: + - "gold" + - "silver" + - "bronze" + visible: + and: + - boot_volume_backup_policy_enabled + + boot_volume_initial_backup: + type: boolean + title: "Initial FULL backup of the Boot Volume" + description: "Check the box if you want to take initial FULL backup of the Boot Volume." + visible: true + default: true + + block_volume_backup_policy_enabled: + type: boolean + title: "Enable iSCSI Block Volume Backup Policy" + description: "Check the box if you want to add iSCSI Block Volume Backup Policy." + visible: + and: + - add_iscsi_volume + default: true + + block_volume_backup_policy_level: + type: enum + required: false + title: "iSCSI Block Volume Backup Policy" + description: "Choose the value for iSCSI Block Volume Backup Policy." + default: "gold" + enum: + - "gold" + - "silver" + - "bronze" + visible: + and: + - add_iscsi_volume + - block_volume_backup_policy_enabled + + block_volume_initial_backup: + type: boolean + title: "Initial FULL backup of the iSCSI Block Volume" + description: "Check the box if you want to take initial FULL backup of the iSCSI Block Volume." + visible: + and: + - add_iscsi_volume + default: true + + + postgresql_vcn_cidr: + type: string + visible: true + required: false + pattern: "^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]).(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]).(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]).(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\/(3[0-2]|[1-2]?[0-9])$" + title: "VCN CIDR" + description: "Choose VCN CIDR for your PostgreSQL deployments." + default: "10.1.0.0/16" + + postgresql_subnet_cidr: + type: string + visible: true + required: false + pattern: "^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]).(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]).(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]).(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\/(3[0-2]|[1-2]?[0-9])$" + title: "VCN CIDR" + description: "Choose Subnet CIDR for your PostgreSQL deployments." + default: "10.1.20.0/24" + + create_drg_for_private_subnet: + type: boolean + visible: + and: + - create_in_private_subnet + required: false + title: "Create DRG for Private Subnet scenario" + description: "Providing an option to create Dynamic Routing Gateway (DRG) for VCN and afterwards you can connect to your private subnet from on-premise." + default: true + + postgresql_instance_shape: + type: oci:core:instanceshape:name + required: false + title: "Shape for PostgreSQL Master node" + description: "Choose shape for PostgreSQL Master node." + default: "VM.Standard.E3.Flex" + dependsOn: + compartmentId: ${compartment_ocid} + + postgresql_instance_flex_shape_ocpus: + type: number + required: false + minimum: 1 + maximum: 128 + multipleOf: 1 + default: 1 + title: "Flex Shape OCPUs" + description: "Choose number of OCPUs for Flex Shape." + visible: + and: + - or: + - eq: + - postgresql_instance_shape + - "VM.Standard.E3.Flex" + - eq: + - postgresql_instance_shape + - "VM.Standard.E4.Flex" + + postgresql_instance_flex_shape_memory: + type: number + required: false + minimum: 1 + maximum: 128 + multipleOf: 1 + default: 10 + title: "Flex Shape Memory (GB)" + description: "Choose number GB for Flex Shape Memory." + visible: + and: + - or: + - eq: + - postgresql_instance_shape + - "VM.Standard.E3.Flex" + - eq: + - postgresql_instance_shape + - "VM.Standard.E4.Flex" + + + instance_os: + type: enum + required: false + title: "Instance OS" + description: "An Operating System that determines the operating system for the instance." + default: "Oracle Linux" + enum: + - "Oracle Linux" + + linux_os_version: + type: enum + required: false + title: "Instance OS version" + description: "An Operating System version that determines the operating system version for the instance." + default: "7.9" + enum: + - "7.8" + - "7.9" + + postgresql_master_fd: + type: enum + required: false + title: "PostgreSQL Master Fault Domain" + description: "Choose Fault Domain for PostgreSQL Master." + default: "FAULT-DOMAIN-1" + enum: + - "FAULT-DOMAIN-1" + - "FAULT-DOMAIN-2" + - "FAULT-DOMAIN-3" + + postgresql_replicat_username: + type: string + required: false + title: "PostgreSQL Replicat Username" + description: "Type PostgreSQL Replicat Username" + + postgresql_hotstandby1_ad: + type: oci:identity:availabilitydomain:name + required: false + title: "AD for the first PostgreSQL HotStandby" + description: "Availability Domain for the first PostgreSQL HotStandby." + dependsOn: + compartmentId: ${compartment_ocid} + + postgresql_hotstandby1_fd: + type: enum + required: false + title: "The first PostgreSQL HotStandby's Fault Domain" + description: "Choose Fault Domain for the first PostgreSQL HotStandby." + default: "FAULT-DOMAIN-2" + enum: + - "FAULT-DOMAIN-1" + - "FAULT-DOMAIN-2" + - "FAULT-DOMAIN-3" + + postgresql_hotstandby1_shape: + type: oci:core:instanceshape:name + required: false + title: "Shape for the first PostgreSQL HotStandby node" + description: "Choose shape for the first PostgreSQL HotStandby node." + default: "VM.Standard.E3.Flex" + dependsOn: + compartmentId: ${compartment_ocid} + + postgresql_hotstandby1_flex_shape_ocpus: + type: number + required: false + minimum: 1 + maximum: 128 + multipleOf: 1 + default: 1 + title: "Flex Shape OCPUs" + description: "Choose number of OCPUs for Flex Shape." + visible: + and: + - or: + - eq: + - postgresql_hotstandby1_shape + - "VM.Standard.E3.Flex" + - eq: + - postgresql_hotstandby1_shape + - "VM.Standard.E4.Flex" + + postgresql_hotstandby1_flex_shape_memory: + type: number + required: false + minimum: 1 + maximum: 128 + multipleOf: 1 + default: 10 + title: "Flex Shape Memory (GB)" + description: "Choose number GB for Flex Shape Memory." + visible: + and: + - or: + - eq: + - postgresql_hotstandby1_shape + - "VM.Standard.E3.Flex" + - eq: + - postgresql_hotstandby1_shape + - "VM.Standard.E4.Flex" + + postgresql_hotstandby2_ad: + type: oci:identity:availabilitydomain:name + required: false + title: "AD for the second PostgreSQL HotStandby" + description: "Availability Domain for the second PostgreSQL HotStandby." + dependsOn: + compartmentId: ${compartment_ocid} + + postgresql_hotstandby2_fd: + type: enum + required: false + title: "The second PostgreSQL HotStandby's Fault Domain" + description: "Choose Fault Domain for the second PostgreSQL HotStandby." + default: "FAULT-DOMAIN-3" + enum: + - "FAULT-DOMAIN-1" + - "FAULT-DOMAIN-2" + - "FAULT-DOMAIN-3" + + postgresql_hotstandby2_shape: + type: oci:core:instanceshape:name + required: false + title: "Shape for the second PostgreSQL HotStandby node" + description: "Choose shape for the second PostgreSQL HotStandby node." + default: "VM.Standard.E3.Flex" + dependsOn: + compartmentId: ${compartment_ocid} + + postgresql_hotstandby2_flex_shape_ocpus: + type: number + required: false + minimum: 1 + maximum: 128 + multipleOf: 1 + default: 1 + title: "Flex Shape OCPUs" + description: "Choose number of OCPUs for Flex Shape." + visible: + and: + - or: + - eq: + - postgresql_hotstandby2_shape + - "VM.Standard.E3.Flex" + - eq: + - postgresql_hotstandby2_shape + - "VM.Standard.E4.Flex" + + postgresql_hotstandby2_flex_shape_memory: + type: number + required: false + minimum: 1 + maximum: 128 + multipleOf: 1 + default: 10 + title: "Flex Shape Memory (GB)" + description: "Choose number GB for Flex Shape Memory." + visible: + and: + - or: + - eq: + - postgresql_hotstandby2_shape + - "VM.Standard.E3.Flex" + - eq: + - postgresql_hotstandby2_shape + - "VM.Standard.E4.Flex" + + + outputs: + + generated_ssh_private_key: + title: "Generated SSH Private Key" + displayText: "Generated SSH Private Key" + type: copyableString + visible: true + + PostgreSQL_Master_VM_public_IP: + title: "PostgreSQL Master VM public IP" + displayText: "PostgreSQL Master VM public IP" + type: string + visible: true + + PostgreSQL_HotStandby1_VM_public_IP: + title: "PostgreSQL HotStandby1 VM public IP" + displayText: "PostgreSQL HotStandby1 VM public IP" + type: string + visible: true + + PostgreSQL_HotStandby2_VM_public_IP: + title: "PostgreSQL HotStandby2 VM public IP" + displayText: "PostgreSQL HotStandby2 VM public IP" + type: string + visible: true + + PostgreSQL_Username: + title: "PostgreSQL Username" + displayText: "PostgreSQL Username" + type: string + visible: true + diff --git a/scripts/iscsiattach.sh b/scripts/iscsiattach.sh new file mode 100644 index 0000000..f102cc9 --- /dev/null +++ b/scripts/iscsiattach.sh @@ -0,0 +1,78 @@ +#!/bin/bash +# iscsiattach.sh - Scan and automatically attach new iSCSI targets +# +# Author: Steven B. Nelson, Sr. Solutions Architect +# Oracle Cloud Infrastructure +# +# 20 April 2017 +# Copyright Oracle, Inc. All rights reserved. + +BASEADDR="169.254.2.2" + +# Set a base address incrementor so we can loop through all the +# addresses. +addrCount=0 + +#while [ ${addrCount} -le 32 ] +while [ ${addrCount} -le 1 ] +do + + CURRADDR=`echo ${BASEADDR} | awk -F\. '{last=$4+'${addrCount}';print $1"."$2"."$3"."last}'` + + clear + echo "Attempting connection to ${CURRADDR}" + + mkfifo discpipe + # Find all the iSCSI Block Storage volumes attached to the instance but + # not configured for use on the instance. Basically, get a list of the + # volumes that the instance can see, the loop through the ones it has, + # and add volumes not already configured on the instance. + # + # First get the list of volumes visible (attached) to the instance + + iscsiadm -m discovery -t st -p ${CURRADDR}:3260 | grep -v uefi | awk '{print $2}' > discpipe 2> /dev/null & + + # If the result is non-zero, that generally means that there are no targets available or + # that the portal is reachable but not active. We make no distinction between the two + # and simply skip ahead. + result=$? + if [ ${result} -ne 0 ] + then + (( addrCount = addrCount + 1 )) + continue + fi + + # Loop through the list (via the named FIFO pipe below) + while read target + do + mkfifo sesspipe + # Get the list of the currently attached Block Storage volumes + iscsiadm -m session -P 0 | grep -v uefi | awk '{print $4}' > sesspipe 2> /dev/null & + + # Set a flag, and loop through the sessions (attached, but not configured) + # and see if the volumes match. If so, skip to the next until we get + # through the list. Session list is via the pipe. + found="false" + while read session + do + if [ ${target} = ${session} ] + then + found="true" + break + fi + done < sesspipe + + # If the volume is not found, configure it. Get the resulting device file. + if [ ${found} = "false" ] + then + iscsiadm -m node -o new -T ${target} -p ${CURRADDR}:3260 + iscsiadm -m node -o update -T ${target} -n node.startup -v automatic + iscsiadm -m node -T ${target} -p ${CURRADDR}:3260 -l + sleep 10 + fi + done < discpipe + + (( addrCount = addrCount + 1 )) + find . -maxdepth 1 -type p -exec rm {} \; +done +echo "Scan Complete." diff --git a/scripts/postgresql_install_binaries.sh b/scripts/postgresql_install_binaries.sh new file mode 100644 index 0000000..df4e69e --- /dev/null +++ b/scripts/postgresql_install_binaries.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +echo '#####################################' +echo 'Starting PostgreSQL Install Binaries.' +echo '#####################################' + +# Install the repository RPM: +sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm + +# Install PostgreSQL: +sudo yum install -y postgresql${pg_version_no_dot}-server + +# Install PostgreSQL pg_basebackup utility +sudo yum-config-manager --enable ol7_developer +sudo yum-config-manager --enable ol7_developer_EPEL + +sudo yum install -y llvm5.0-devel +sudo yum install -y postgresql${pg_version_no_dot}-devel + +echo '#####################################' +echo 'PostgreSQL Install Binaries finished.' +echo '#####################################' diff --git a/scripts/postgresql_master_initdb.sh b/scripts/postgresql_master_initdb.sh new file mode 100644 index 0000000..2a317c8 --- /dev/null +++ b/scripts/postgresql_master_initdb.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +echo '#####################################' +echo 'Starting PostgreSQL Master initdb.' +echo '#####################################' + +export pg_version='${pg_version}' +export add_iscsi_volume='${add_iscsi_volume}' + +# Optionally initialize the database and enable automatic start: +if [[ $pg_version == "9.6" ]]; then + sudo /usr/pgsql-${pg_version}/bin/postgresql${pg_version_no_dot}-setup initdb +else + sudo /usr/pgsql-${pg_version}/bin/postgresql-${pg_version_no_dot}-setup initdb +fi + +if [[ $add_iscsi_volume == "true" ]]; then + sudo mkdir /data/pgsql + sudo chown -R postgres:postgres /data/pgsql + sudo -u postgres bash -c "/usr/pgsql-${pg_version_no_dot}/bin/initdb --pgdata=/data/pgsql" + sudo sed -i 's/Environment=PGDATA=\/var\/lib\/pgsql\/${pg_version_no_dot}\/data\//Environment=PGDATA=\/data\/pgsql\//g' /usr/lib/systemd/system/postgresql-${pg_version_no_dot}.service +fi + +sudo systemctl enable postgresql-${pg_version} +sudo systemctl start postgresql-${pg_version} +sudo systemctl status postgresql-${pg_version} + +if [[ $pg_version == "9.6" ]]; then + if [[ $add_iscsi_volume == "true" ]]; then + sudo -u root bash -c "tail -5 /data/pgsql/log/postgresql-*.log" + else + sudo -u root bash -c "tail -5 /var/lib/pgsql/${pg_version}/data/pg_log/postgresql-*.log" + fi +else + if [[ $add_iscsi_volume == "true" ]]; then + sudo -u root bash -c "tail -5 /data/pgsql/log/postgresql-*.log" + else + sudo -u root bash -c "tail -5 /var/lib/pgsql/${pg_version}/data/log/postgresql-*.log" + fi +fi + +echo '#####################################' +echo 'PostgreSQL Master initdb finished.' +echo '#####################################' \ No newline at end of file diff --git a/scripts/postgresql_master_setup.sh b/scripts/postgresql_master_setup.sh new file mode 100644 index 0000000..89fc28d --- /dev/null +++ b/scripts/postgresql_master_setup.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +echo '#################################################' +echo 'Starting PostgreSQL Master setup for HotStandby1.' +echo '#################################################' + +export pg_version='${pg_version}' +export add_iscsi_volume='${add_iscsi_volume}' + +# Change password of postgres user +echo "postgres:${pg_password}" | chpasswd + +# Setting firewall rules +sudo -u root bash -c "firewall-cmd --permanent --zone=trusted --add-source=${pg_hotstandby_ip}/32" +sudo -u root bash -c "firewall-cmd --permanent --zone=trusted --add-port=5432/tcp" +sudo -u root bash -c "firewall-cmd --reload" + +# Create replication user +chown postgres /tmp/postgresql_master_setup.sql +sudo -u postgres bash -c "psql -d template1 -f /tmp/postgresql_master_setup.sql" + +if [[ $add_iscsi_volume == "true" ]]; then + # Update the content of postgresql.conf to support WAL + sudo -u root bash -c "echo 'wal_level = replica' | sudo tee -a /data/pgsql/postgresql.conf" + sudo -u root bash -c "echo 'archive_mode = on' | sudo tee -a /data/pgsql/postgresql.conf" + sudo -u root bash -c "echo 'wal_log_hints = on' | sudo tee -a /data/pgsql/postgresql.conf" + sudo -u root bash -c "echo 'max_wal_senders = 3' | sudo tee -a /data/pgsql/postgresql.conf" + if [[ $pg_version == "13" ]]; then + sudo -u root bash -c "echo 'wal_keep_size = 16MB' | sudo tee -a /data/pgsql/postgresql.conf" + else + sudo -u root bash -c "echo 'wal_keep_segments = 8' | sudo tee -a /data/pgsql/postgresql.conf" + fi + sudo -u root bash -c "echo 'hot_standby = on' | sudo tee -a /data/pgsql/postgresql.conf" + sudo -u root bash -c "echo 'listen_addresses = '\''0.0.0.0'\'' ' | sudo tee -a /data/pgsql/postgresql.conf" + sudo -u root bash -c "chown postgres /data/pgsql/postgresql.conf" + + # Update the content of pg_hba to include standby host for replication + sudo -u root bash -c "echo 'host replication ${pg_replicat_username} ${pg_hotstandby_ip}/32 md5' | sudo tee -a /data/pgsql/pg_hba.conf" + sudo -u root bash -c "echo 'host replication ${pg_replicat_username} ${pg_master_ip}/32 md5' | sudo tee -a /data/pgsql/pg_hba.conf" + sudo -u root bash -c "echo 'host all all ${pg_hotstandby_ip}/32 md5' | sudo tee -a /data/pgsql/pg_hba.conf" + sudo -u root bash -c "echo 'host all all ${pg_master_ip}/32 md5' | sudo tee -a /data/pgsql/pg_hba.conf" + sudo -u root bash -c "echo 'host all all ${node_subnet_cidr} md5' | sudo tee -a /data/pgsql/pg_hba.conf" + sudo -u root bash -c "chown postgres /data/pgsql/pg_hba.conf" +else + # Update the content of postgresql.conf to support WAL + sudo -u root bash -c "echo 'wal_level = replica' | sudo tee -a /var/lib/pgsql/${pg_version}/data/postgresql.conf" + sudo -u root bash -c "echo 'archive_mode = on' | sudo tee -a /var/lib/pgsql/${pg_version}/data/postgresql.conf" + sudo -u root bash -c "echo 'wal_log_hints = on' | sudo tee -a /var/lib/pgsql/${pg_version}/data/postgresql.conf" + sudo -u root bash -c "echo 'max_wal_senders = 3' | sudo tee -a /var/lib/pgsql/${pg_version}/data/postgresql.conf" + if [[ $pg_version == "13" ]]; then + sudo -u root bash -c "echo 'wal_keep_size = 16MB' | sudo tee -a /var/lib/pgsql/${pg_version}/data/postgresql.conf" + else + sudo -u root bash -c "echo 'wal_keep_segments = 8' | sudo tee -a /var/lib/pgsql/${pg_version}/data/postgresql.conf" + fi + sudo -u root bash -c "echo 'hot_standby = on' | sudo tee -a /var/lib/pgsql/${pg_version}/data/postgresql.conf" + sudo -u root bash -c "echo 'listen_addresses = '\''0.0.0.0'\'' ' | sudo tee -a /var/lib/pgsql/${pg_version}/data/postgresql.conf" + sudo -u root bash -c "chown postgres /var/lib/pgsql/${pg_version}/data/postgresql.conf" + + # Update the content of pg_hba to include standby host for replication + sudo -u root bash -c "echo 'host replication ${pg_replicat_username} ${pg_hotstandby_ip}/32 md5' | sudo tee -a /var/lib/pgsql/${pg_version}/data/pg_hba.conf" + sudo -u root bash -c "echo 'host replication ${pg_replicat_username} ${pg_master_ip}/32 md5' | sudo tee -a /var/lib/pgsql/${pg_version}/data/pg_hba.conf" + sudo -u root bash -c "echo 'host all all ${pg_hotstandby_ip}/32 md5' | sudo tee -a /var/lib/pgsql/${pg_version}/data/pg_hba.conf" + sudo -u root bash -c "echo 'host all all ${pg_master_ip}/32 md5' | sudo tee -a /var/lib/pgsql/${pg_version}/data/pg_hba.conf" + sudo -u root bash -c "echo 'host all all ${node_subnet_cidr} md5' | sudo tee -a /var/lib/pgsql/${pg_version}/data/pg_hba.conf" + sudo -u root bash -c "chown postgres /var/lib/pgsql/${pg_version}/data/pg_hba.conf" +fi + +# Restart of PostrgreSQL service +sudo systemctl stop postgresql-${pg_version} +sudo systemctl start postgresql-${pg_version} +sudo systemctl status postgresql-${pg_version} + +echo '#################################################' +echo 'PostgreSQL Master setup for HotStandby1 finished.' +echo '#################################################' + diff --git a/scripts/postgresql_master_setup.sql b/scripts/postgresql_master_setup.sql new file mode 100644 index 0000000..f4f9eb5 --- /dev/null +++ b/scripts/postgresql_master_setup.sql @@ -0,0 +1,3 @@ +ALTER SYSTEM SET listen_addresses TO '*'; +CREATE USER ${pg_replicat_username} REPLICATION LOGIN ENCRYPTED PASSWORD '${pg_replicat_password}'; + diff --git a/scripts/postgresql_master_setup2.sh b/scripts/postgresql_master_setup2.sh new file mode 100644 index 0000000..a0aee68 --- /dev/null +++ b/scripts/postgresql_master_setup2.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +echo '#################################################' +echo 'Starting PostgreSQL Master setup for HotStandby2.' +echo '#################################################' + +export pg_version='${pg_version}' +export add_iscsi_volume='${add_iscsi_volume}' + +# Setting firewall rules +sudo -u root bash -c "firewall-cmd --permanent --zone=trusted --add-source=${pg_hotstandby_ip}/32" +sudo -u root bash -c "firewall-cmd --permanent --zone=trusted --add-port=5432/tcp" +sudo -u root bash -c "firewall-cmd --reload" + +if [[ $add_iscsi_volume == "true" ]]; then + # Update the content of pg_hba to include standby host for replication + sudo -u root bash -c "echo 'host replication ${pg_replicat_username} ${pg_hotstandby_ip}/32 md5' | sudo tee -a /data/pgsql/pg_hba.conf" + sudo -u root bash -c "echo 'host all all ${pg_hotstandby_ip}/32 md5' | sudo tee -a /data/pgsql/pg_hba.conf" + sudo -u root bash -c "chown postgres /data/pgsql/pg_hba.conf" +else + # Update the content of pg_hba to include standby host for replication + sudo -u root bash -c "echo 'host replication ${pg_replicat_username} ${pg_hotstandby_ip}/32 md5' | sudo tee -a /var/lib/pgsql/${pg_version}/data/pg_hba.conf" + sudo -u root bash -c "echo 'host all all ${pg_hotstandby_ip}/32 md5' | sudo tee -a /var/lib/pgsql/${pg_version}/data/pg_hba.conf" + sudo -u root bash -c "chown postgres /var/lib/pgsql/${pg_version}/data/pg_hba.conf" +fi + +# Restart of PostrgreSQL service +sudo systemctl stop postgresql-${pg_version} +sudo systemctl start postgresql-${pg_version} +sudo systemctl status postgresql-${pg_version} + +echo '#################################################' +echo 'PostgreSQL Master setup for HotStandby2 finished.' +echo '#################################################' \ No newline at end of file diff --git a/scripts/postgresql_standby_setup.sh b/scripts/postgresql_standby_setup.sh new file mode 100644 index 0000000..c4c5036 --- /dev/null +++ b/scripts/postgresql_standby_setup.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +echo '#################################################' +echo 'Starting PostgreSQL Standby Setup for HotStandby.' +echo '#################################################' + +export pg_version='${pg_version}' +export add_iscsi_volume='${add_iscsi_volume}' + +# Change password of postgres user +echo "postgres:${pg_password}" | chpasswd + +# Setting firewall rules +sudo -u root bash -c "firewall-cmd --permanent --zone=trusted --add-source=${pg_master_ip}/32" +sudo -u root bash -c "firewall-cmd --permanent --zone=trusted --add-port=5432/tcp" +sudo -u root bash -c "firewall-cmd --reload" + +if [[ $add_iscsi_volume == "true" ]]; then + # Create database on the volume + sudo mkdir /data/pgsql + sudo chown -R postgres:postgres /data/pgsql + sudo -u postgres bash -c "/usr/pgsql-${pg_version_no_dot}/bin/initdb --pgdata=/data/pgsql" + sudo sed -i 's/Environment=PGDATA=\/var\/lib\/pgsql\/${pg_version_no_dot}\/data\//Environment=PGDATA=\/data\/pgsql\//g' /usr/lib/systemd/system/postgresql-${pg_version_no_dot}.service + + # Take initial backup of database + sudo -u root bash -c "rm -rf /data/pgsql/*" + sudo -u postgres bash -c "export PGPASSWORD=${pg_replicat_password}; pg_basebackup -D /data/pgsql/ -h ${pg_master_ip} -X stream -c fast -U ${pg_replicat_username}" + # Update the content of recovery.conf + if [[ $pg_version == "13" ]]; then + touch /data/pgsql/standby.signal + touch /data/pgsql/recovery.signal + sudo -u root bash -c "echo 'primary_conninfo = '\''host=${pg_master_ip} port=5432 user=${pg_replicat_username} password=${pg_replicat_password}'\'' ' | sudo tee -a /data/pgsql/postgresql.conf" + sudo -u root bash -c "echo 'recovery_target_timeline = '\''latest'\'' ' | sudo tee -a /data/pgsql/postgresql.conf" + sudo -u root bash -c "chown postgres /data/pgsql/postgresql.conf" + elif [[ $pg_version == "12" ]]; then + touch /data/pgsql/standby.signal + touch /data/pgsql/recovery.signal + sudo -u root bash -c "echo 'primary_conninfo = '\''host=${pg_master_ip} port=5432 user=${pg_replicat_username} password=${pg_replicat_password}'\'' ' | sudo tee -a /data/pgsql/postgresql.conf" + sudo -u root bash -c "echo 'recovery_target_timeline = '\''latest'\'' ' | sudo tee -a /data/pgsql/postgresql.conf" + sudo -u root bash -c "chown postgres /data/pgsql/postgresql.conf" + else + sudo -u root bash -c "echo 'standby_mode = '\''on'\'' ' | sudo tee -a /data/pgsql/recovery.conf" + sudo -u root bash -c "echo 'primary_conninfo = '\''host=${pg_master_ip} port=5432 user=${pg_replicat_username} password=${pg_replicat_password}'\'' ' | sudo tee -a /data/pgsql/recovery.conf" + sudo -u root bash -c "echo 'recovery_target_timeline = '\''latest'\'' ' | sudo tee -a /data/pgsql/recovery.conf" + sudo -u root bash -c "chown postgres /data/pgsql/recovery.conf" + fi +else + # Take initial backup of database + sudo -u root bash -c "rm -rf /var/lib/pgsql/${pg_version}/data/*" + sudo -u postgres bash -c "export PGPASSWORD=${pg_replicat_password}; pg_basebackup -D /var/lib/pgsql/${pg_version}/data/ -h ${pg_master_ip} -X stream -c fast -U ${pg_replicat_username}" + # Update the content of recovery.conf + if [[ $pg_version == "13" ]]; then + touch /var/lib/pgsql/${pg_version}/data/standby.signal + touch /var/lib/pgsql/${pg_version}/data/recovery.signal + sudo -u root bash -c "echo 'primary_conninfo = '\''host=${pg_master_ip} port=5432 user=${pg_replicat_username} password=${pg_replicat_password}'\'' ' | sudo tee -a /var/lib/pgsql/${pg_version}/data/postgresql.conf" + sudo -u root bash -c "echo 'recovery_target_timeline = '\''latest'\'' ' | sudo tee -a /var/lib/pgsql/${pg_version}/data/postgresql.conf" + sudo -u root bash -c "chown postgres /var/lib/pgsql/${pg_version}/data/postgresql.conf" + elif [[ $pg_version == "12" ]]; then + touch /var/lib/pgsql/${pg_version}/data/standby.signal + touch /var/lib/pgsql/${pg_version}/data/recovery.signal + sudo -u root bash -c "echo 'primary_conninfo = '\''host=${pg_master_ip} port=5432 user=${pg_replicat_username} password=${pg_replicat_password}'\'' ' | sudo tee -a /var/lib/pgsql/${pg_version}/data/postgresql.conf" + sudo -u root bash -c "echo 'recovery_target_timeline = '\''latest'\'' ' | sudo tee -a /var/lib/pgsql/${pg_version}/data/postgresql.conf" + sudo -u root bash -c "chown postgres /var/lib/pgsql/${pg_version}/data/postgresql.conf" + else + sudo -u root bash -c "echo 'standby_mode = '\''on'\'' ' | sudo tee -a /var/lib/pgsql/${pg_version}/data/recovery.conf" + sudo -u root bash -c "echo 'primary_conninfo = '\''host=${pg_master_ip} port=5432 user=${pg_replicat_username} password=${pg_replicat_password}'\'' ' | sudo tee -a /var/lib/pgsql/${pg_version}/data/recovery.conf" + sudo -u root bash -c "echo 'recovery_target_timeline = '\''latest'\'' ' | sudo tee -a /var/lib/pgsql/${pg_version}/data/recovery.conf" + sudo -u root bash -c "chown postgres /var/lib/pgsql/${pg_version}/data/recovery.conf" + fi +fi + +# Restart of PostrgreSQL service +sudo systemctl enable postgresql-${pg_version} +sudo systemctl stop postgresql-${pg_version} +sudo systemctl start postgresql-${pg_version} +sudo systemctl status postgresql-${pg_version} + +if [[ $pg_version == "9.6" ]]; then + if [[ $add_iscsi_volume == "true" ]]; then + sudo -u root bash -c "tail -5 /data/pgsql/log/postgresql-*.log" + else + sudo -u root bash -c "tail -5 /var/lib/pgsql/${pg_version}/data/pg_log/postgresql-*.log" + fi +else + if [[ $add_iscsi_volume == "true" ]]; then + sudo -u root bash -c "tail -5 /data/pgsql/log/postgresql-*.log" + else + sudo -u root bash -c "tail -5 /var/lib/pgsql/${pg_version}/data/log/postgresql-*.log" + fi +fi + +echo '#################################################' +echo 'PostgreSQL Standby Setup for HotStandby finished.' +echo '#################################################' diff --git a/scripts/sshkey.tpl b/scripts/sshkey.tpl new file mode 100644 index 0000000..2555a46 --- /dev/null +++ b/scripts/sshkey.tpl @@ -0,0 +1,5 @@ +#!/bin/bash + +cp /home/opc/.ssh/authorized_keys /home/opc/.ssh/authorized_keys.bak +echo "${ssh_public_key}" >> /home/opc/.ssh/authorized_keys +chown -R opc /home/opc/.ssh/authorized_keys diff --git a/security-lists.tf b/security-lists.tf new file mode 100644 index 0000000..1c0becb --- /dev/null +++ b/security-lists.tf @@ -0,0 +1,35 @@ +## Copyright (c) 2021 Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + +resource "oci_core_security_list" "postgresql_securitylist" { + count = !var.use_existing_vcn ? 1 : 0 + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.postgresql_vcn[0].id + display_name = "PostgreSQLSecurityList" + + egress_security_rules { + protocol = "6" + destination = "0.0.0.0/0" + } + + ingress_security_rules { + protocol = "6" + source = "0.0.0.0/0" + + tcp_options { + max = "22" + min = "22" + } + } + + ingress_security_rules { + protocol = "6" + source = "0.0.0.0/0" + + tcp_options { + max = "5432" + min = "5432" + } + } + defined_tags = { "${oci_identity_tag_namespace.ArchitectureCenterTagNamespace.name}.${oci_identity_tag.ArchitectureCenterTag.name}" = var.release } +} diff --git a/tags.tf b/tags.tf new file mode 100644 index 0000000..0f95f0f --- /dev/null +++ b/tags.tf @@ -0,0 +1,34 @@ +## Copyright (c) 2021 Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + +resource "random_id" "tag" { + byte_length = 2 +} + +resource "oci_identity_tag_namespace" "ArchitectureCenterTagNamespace" { + provider = oci.homeregion + compartment_id = var.compartment_ocid + description = "ArchitectureCenterTagNamespace" + name = "ArchitectureCenter\\deploy-postgresql-db-${random_id.tag.hex}" + + provisioner "local-exec" { + command = "sleep 10" + } + +} + +resource "oci_identity_tag" "ArchitectureCenterTag" { + provider = oci.homeregion + description = "ArchitectureCenterTag" + name = "release" + tag_namespace_id = oci_identity_tag_namespace.ArchitectureCenterTagNamespace.id + + validator { + validator_type = "ENUM" + values = ["release", "1.4"] + } + + provisioner "local-exec" { + command = "sleep 120" + } +} diff --git a/tls.tf b/tls.tf new file mode 100644 index 0000000..7e5fa6d --- /dev/null +++ b/tls.tf @@ -0,0 +1,6 @@ +## Copyright (c) 2021 Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + +resource "tls_private_key" "public_private_key_pair" { + algorithm = "RSA" +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..d06f8cb --- /dev/null +++ b/variables.tf @@ -0,0 +1,184 @@ +## Copyright (c) 2021 Oracle and/or its affiliates. +## All rights reserved. The Universal Permissive License (UPL), Version 1.0 as shown at http://oss.oracle.com/licenses/upl + +variable "tenancy_ocid" {} +variable "user_ocid" {} +variable "fingerprint" {} +variable "private_key_path" {} +variable "region" {} +variable "compartment_ocid" {} +variable "availablity_domain_name" {} + +variable "use_existing_vcn" { + default = false +} + +variable "postgresql_vcn" { + default = "" +} + +variable "postgresql_subnet" { + default = "" +} + +variable "show_advanced" { + default = false +} + +variable "create_in_private_subnet" { + default = true +} + +variable "create_drg_for_private_subnet" { + default = true +} + +variable "release" { + description = "Reference Architecture Release (OCI Architecture Center)" + default = "1.4" +} + +variable "ssh_public_key" { + default = "" +} + +variable "postgresql_vcn_cidr" { + default = "10.1.0.0/16" +} + +variable "postgresql_subnet_cidr" { + default = "10.1.20.0/24" +} + +variable "postgresql_instance_shape" { + default = "VM.Standard.E3.Flex" +} + +variable "postgresql_instance_flex_shape_ocpus" { + default = 1 +} + +variable "postgresql_instance_flex_shape_memory" { + default = 10 +} + +variable "instance_os" { + description = "Operating system for compute instances" + default = "Oracle Linux" +} + +variable "linux_os_version" { + description = "Operating system version for all Linux instances" + default = "7.9" +} + +variable "postgresql_master_fd" { + default = "FAULT-DOMAIN-1" +} + +variable "postgresql_replicat_username" { + default = "replicator" +} + +variable "postgresql_password" { + default = "" +} + +variable "postgresql_version" { + default = "13" +} + +variable "add_iscsi_volume" { + default = true +} + +variable "iscsi_volume_size_in_gbs" { + default = 100 +} + +variable "boot_volume_backup_policy_enabled" { + default = true +} + +variable "boot_volume_backup_policy_level" { + default = "gold" +} + +variable "boot_volume_initial_backup" { + default = true +} + +variable "block_volume_backup_policy_enabled" { + default = true +} + +variable "block_volume_backup_policy_level" { + default = "gold" +} + +variable "block_volume_initial_backup" { + default = true +} + +variable "postgresql_deploy_hotstandby1" { + default = false +} + +variable "postgresql_hotstandby1_fd" { + default = "FAULT-DOMAIN-2" +} + +variable "postgresql_hotstandby1_ad" { + default = "" +} + +variable "postgresql_hotstandby1_shape" { + default = "VM.Standard.E3.Flex" +} + +variable "postgresql_hotstandby1_flex_shape_ocpus" { + default = 1 +} + +variable "postgresql_hotstandby1_flex_shape_memory" { + default = 10 +} + +variable "postgresql_deploy_hotstandby2" { + default = false +} + +variable "postgresql_hotstandby2_fd" { + default = "FAULT-DOMAIN-3" +} + +variable "postgresql_hotstandby2_ad" { + default = "" +} + +variable "postgresql_hotstandby2_shape" { + default = "VM.Standard.E3.Flex" +} + +variable "postgresql_hotstandby2_flex_shape_ocpus" { + default = 1 +} + +variable "postgresql_hotstandby2_flex_shape_memory" { + default = 10 +} + +# Dictionary Locals +locals { + compute_flexible_shapes = [ + "VM.Standard.E3.Flex", + "VM.Standard.E4.Flex" + ] +} + +# Checks if is using Flexible Compute Shapes +locals { + is_flexible_postgresql_instance_shape = contains(local.compute_flexible_shapes, var.postgresql_instance_shape) + is_flexible_postgresql_hotstandby1_shape = contains(local.compute_flexible_shapes, var.postgresql_hotstandby1_shape) + is_flexible_postgresql_hotstandby2_shape = contains(local.compute_flexible_shapes, var.postgresql_hotstandby2_shape) +}