diff --git a/README.md b/README.md index 20ffacb..4938a0a 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,92 @@ # terraform-oci-arch-drupal -[![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-drupal)](https://sonarcloud.io/dashboard?id=oracle-devrel_terraform-oci-arch-drupal) +This is Terraform module that deploys [Drupal](https://www.drupal.org/) on [Oracle Cloud Infrastructure (OCI)](https://cloud.oracle.com/en_US/cloud-infrastructure). -## THIS IS A NEW, BLANK REPO THAT IS NOT READY FOR USE YET. PLEASE CHECK BACK SOON! +## About +Drupal is one of the most popular content management systems (CMS) available. It is free and open-source, released under the GNU Public License. -## Introduction -MISSING +Drupal is based on the LAMP stack and provides users and enterprises a scalable and robust architecture, low implementation and maintenance efforts, as well as a large community-led knowledge base. Its setup and usage does not require advanced technical skills. It provides the infrastructure for websites worldwide—ranging from personal blogs to corporate, political, and government sites. It is very extensible and modular, making it useful in a large variety of scenarios. -## Getting Started -MISSING +## Prerequisites +1. Download and install Terraform (v1.0 or later) +2. Download and install the OCI Terraform Provider (v4.4.0 or later) +3. Export OCI credentials. (this refer to the https://github.com/oracle/terraform-provider-oci ) -### Prerequisites -MISSING -## Notes/Issues -MISSING +## What's a Module? +A Module is a canonical, reusable, best-practices definition for how to run a single piece of infrastructure, such as a database or server cluster. Each Module is created using Terraform, and includes automated tests, examples, and documentation. It is maintained both by the open source community and companies that provide commercial support. +Instead of figuring out the details of how to run a piece of infrastructure from scratch, you can reuse existing code that has been proven in production. And instead of maintaining all that infrastructure code yourself, you can leverage the work of the Module community to pick up infrastructure improvements through a version number bump. -## URLs -* Nothing at this time +## How to use this Module +This Module has the following folder structure: +* [root](): This folder contains a root module. +* [examples](examples): This folder contains examples of how to use the module: + - [Drupal single-node + custom network injected into module](examples/drupal-single-mds-use-existing-network): This is an example of how to use the oci-arch-drupal module to deploy Drupal (single-node) with MDS and network cloud infrastrucutre elements injected into the module. + - [Drupal multi-node + custom network injected into module](examples/drupal-ha-mds-use-existing-network): This is an example of how to use the oci-arch-drupal module to deploy Drupal HA (multi-node) with MDS and network cloud infrastrucutre elements injected into the module. + +To deploy Drupal using this Module with minimal effort use this: + +```hcl +module "oci-arch-drupal" { + source = "github.com/oracle-devrel/terraform-oci-arch-drupal" + tenancy_ocid = "" + vcn_id = "" + numberOfNodes = 1 + availability_domain_name = "" + compartment_ocid = """ + image_id = "" + shape = "" + flex_shape_ocpus = "" + flex_shape_memory = "" + label_prefix = """ + ssh_authorized_keys = "" + mds_ip = "" + drupal_subnet_id = "" + admin_password = "" + admin_username = "" + drupal_schema = "" + drupal_name = "" + drupal_password = "" + display_name = "" +} +``` + +Argument | Description +--- | --- +compartment_ocid | Compartment's OCID where Drupal will be created +use_existing_vcn | If you want to inject already exisitng VCN then you need to set the value to TRUE. +vcn_cidr | If use_existing_vcn is set to FALSE then you can define VCN CIDR block and then it will used to create VCN within the module. +vcn_id | If use_existing_vcn is set to TRUE then you can pass VCN OCID and module will use it to create Drupal installation. +numberOfNodes | If you need HA configuration with LB and FSS then set the value to 2 or more. +drupal_subnet_id | The OCID of the drupal public (single node) and private (multi node) subnet access. +lb_subnet_id | If numberOfNodes set to 2 or more then you can provide OCID of the Load Balancer subnet. +bastion_subnet_id | If numberOfNodes set to 2 or more then you can use OCID of the Bastion subnet. +fss_subnet_id | If numberOfNodes set to 2 or more then you can use OCID of the File Storage Service subnet. +availability_domain_name | The Availability Domain for deployment. +display_name | The name of the Drupal instance. +shape | Instance shape to use for Drupal node. +flex_shape_ocpus | If shape is set to Flex shape then you can define Flex Shape OCPUs. +flex_shape_memory | If shape is set to Flex shape then you can define Flex Shape Memory (GB). +lb_shape | If numberOfNodes set to 2 or more then you can define Load Balancer shape +flex_lb_min_shape | If numberOfNodes set to 2 or more and lb_shape=flexible then you can define Load Balancer minimum shape. +flex_lb_max_shape | If numberOfNodes set to 2 or more and lb_shape=flexible then you can define Load Balancer maximum shape. +use_bastion_service | If you want to use OCI Bastion Service then you need to set the value to TRUE. +bastion_service_region | If use_bastion_service is set to TRUE then you can define bastion service region. +bastion_image_id | If use_bastion_service is set to FALSE then you can define Bastion VM image id. +bastion_shape | If use_bastion_service is set to FALSE then you can define Bastion VM shape. +bastion_flex_shape_ocpus | If use_bastion_service is set to FALSE and bastion_shape is using Flex shapes then you can define Flex Shape OCPUs. +bastion_flex_shape_memory | If use_bastion_service is set to FALSE and bastion_shape is using Flex shapes then you can define Flex Shape Memory (GB). +use_shared_storage | If numberOfNodes set to 2 or more then you can use shared NFS on OCI FSS (value TRUE). If you want to replicate Drupal by yourself (for example with rsync) then you can you can set the value to FALSE. +drupal_shared_working_dir | If numberOfNodes set to 2 or more then you can define shared mountpoint name. +label_prefix | To create unique identifier for multiple clusters in a compartment. +drupal_name | Drupal Database User Name for MySQL Server. +drupal_schema | Drupal Database User Schema for MySQL Server. +drupal_password | Drupal Database User Password for MySQL Server. +drupal_prefix | Drupal MySQL Prefix for tables (for example drupal_) +admin_username | Admin User Name for MySQL Server. +admin_password | Admin User Password for MySQL Server. +mds_ip | Private IP of the MySQL Server. +defined_tags | Defined tags to be added to compute instances. ## 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,5 +97,3 @@ Copyright (c) 2022 Oracle and/or its affiliates. Licensed under the Universal Permissive License (UPL), Version 1.0. See [LICENSE](LICENSE) for more details. - -ORACLE AND ITS AFFILIATES DO NOT PROVIDE ANY WARRANTY WHATSOEVER, EXPRESS OR IMPLIED, FOR ANY SOFTWARE, MATERIAL OR CONTENT OF ANY KIND CONTAINED OR PRODUCED WITHIN THIS REPOSITORY, AND IN PARTICULAR SPECIFICALLY DISCLAIM ANY AND ALL IMPLIED WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. FURTHERMORE, ORACLE AND ITS AFFILIATES DO NOT REPRESENT THAT ANY CUSTOMARY SECURITY REVIEW HAS BEEN PERFORMED WITH RESPECT TO ANY SOFTWARE, MATERIAL OR CONTENT CONTAINED OR PRODUCED WITHIN THIS REPOSITORY. IN ADDITION, AND WITHOUT LIMITING THE FOREGOING, THIRD PARTIES MAY HAVE POSTED SOFTWARE, MATERIAL OR CONTENT TO THIS REPOSITORY WITHOUT ANY REVIEW. USE AT YOUR OWN RISK. \ No newline at end of file diff --git a/examples/drupal-ha-mds-use-existing-network/LICENSE b/examples/drupal-ha-mds-use-existing-network/LICENSE new file mode 100644 index 0000000..a118f3e --- /dev/null +++ b/examples/drupal-ha-mds-use-existing-network/LICENSE @@ -0,0 +1,35 @@ +Copyright (c) 2022 Oracle and/or its affiliates. + +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 + +(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), + +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 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 diff --git a/examples/drupal-ha-mds-use-existing-network/README.md b/examples/drupal-ha-mds-use-existing-network/README.md new file mode 100644 index 0000000..8bc6f0e --- /dev/null +++ b/examples/drupal-ha-mds-use-existing-network/README.md @@ -0,0 +1,19 @@ +## Create Drupal multi-node + custom network injected into module +This is an example of how to use the oci-arch-drupal module to deploy Drupal HA (multi-node) with MDS and network cloud infrastrucutre elements injected into the module.. + +### Using this example +Update terraform.tfvars with the required information. + +### Deploy the drupal +Initialize Terraform: +``` +$ terraform init +``` +View what Terraform plans do before actually doing it: +``` +$ terraform plan +``` +Use Terraform to Provision resources: +``` +$ terraform apply +``` diff --git a/examples/drupal-ha-mds-use-existing-network/datasources.tf b/examples/drupal-ha-mds-use-existing-network/datasources.tf new file mode 100644 index 0000000..92dceab --- /dev/null +++ b/examples/drupal-ha-mds-use-existing-network/datasources.tf @@ -0,0 +1,47 @@ +## Copyright (c) 2022 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_images" "InstanceImageOCID" { + compartment_id = var.compartment_ocid + operating_system = var.instance_os + operating_system_version = var.linux_os_version + shape = var.node_shape + + filter { + name = "display_name" + values = ["^.*Oracle[^G]*$"] + regex = true + } +} + +data "oci_core_images" "InstanceImageOCID2" { + compartment_id = var.compartment_ocid + operating_system = var.instance_os + operating_system_version = var.linux_os_version + shape = var.bastion_shape + + filter { + name = "display_name" + values = ["^.*Oracle[^G]*$"] + regex = true + } +} + +data "oci_mysql_mysql_configurations" "shape" { + compartment_id = var.compartment_ocid + type = ["DEFAULT"] + shape_name = var.mysql_shape +} + +data "oci_identity_region_subscriptions" "home_region_subscriptions" { + tenancy_id = var.tenancy_ocid + + filter { + name = "is_home_region" + values = [true] + } +} + +data "oci_identity_availability_domains" "ADs" { + compartment_id = var.tenancy_ocid +} diff --git a/examples/drupal-ha-mds-use-existing-network/drupal.tf b/examples/drupal-ha-mds-use-existing-network/drupal.tf new file mode 100644 index 0000000..51e7878 --- /dev/null +++ b/examples/drupal-ha-mds-use-existing-network/drupal.tf @@ -0,0 +1,38 @@ +## Copyright (c) 2022, 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 + +module "drupal" { + source = "github.com/oracle-devrel/terraform-oci-arch-drupal" + tenancy_ocid = var.tenancy_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + numberOfNodes = 2 + availability_domain_name = var.availability_domain_name == "" ? lookup(data.oci_identity_availability_domains.ADs.availability_domains[0], "name") : var.availability_domain_name + compartment_ocid = var.compartment_ocid + image_id = lookup(data.oci_core_images.InstanceImageOCID.images[0], "id") + shape = var.node_shape + label_prefix = var.label_prefix + ssh_authorized_keys = var.ssh_public_key + mds_ip = module.mds-instance.mysql_db_system.ip_address + drupal_subnet_id = oci_core_subnet.drupal_subnet.id + lb_subnet_id = oci_core_subnet.lb_subnet_public.id + bastion_subnet_id = oci_core_subnet.bastion_subnet_public.id + fss_subnet_id = oci_core_subnet.fss_subnet_private.id + admin_password = var.admin_password + admin_username = var.admin_username + drupal_schema = var.drupal_schema + drupal_name = var.drupal_name + drupal_password = var.drupal_password + display_name = var.drupal_instance_name + flex_shape_ocpus = var.node_flex_shape_ocpus + flex_shape_memory = var.node_flex_shape_memory + lb_shape = var.lb_shape + flex_lb_min_shape = var.flex_lb_min_shape + flex_lb_max_shape = var.flex_lb_max_shape + use_bastion_service = var.use_bastion_service + bastion_image_id = lookup(data.oci_core_images.InstanceImageOCID2.images[0], "id") + bastion_shape = var.bastion_shape + bastion_flex_shape_ocpus = var.bastion_flex_shape_ocpus + bastion_flex_shape_memory = var.bastion_flex_shape_memory + bastion_service_region = var.region +} + diff --git a/examples/drupal-ha-mds-use-existing-network/mds.tf b/examples/drupal-ha-mds-use-existing-network/mds.tf new file mode 100644 index 0000000..3a9227c --- /dev/null +++ b/examples/drupal-ha-mds-use-existing-network/mds.tf @@ -0,0 +1,22 @@ +## Copyright (c) 2022, 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 + +module "mds-instance" { + source = "github.com/oracle-devrel/terraform-oci-cloudbricks-mysql-database?ref=v1.0.4.1" + tenancy_ocid = var.tenancy_ocid + region = var.region + mysql_instance_compartment_ocid = var.compartment_ocid + mysql_network_compartment_ocid = var.compartment_ocid + subnet_id = oci_core_subnet.mds_subnet_private.id + mysql_db_system_admin_username = var.admin_username + mysql_db_system_admin_password = var.admin_password + mysql_db_system_availability_domain = var.availability_domain_name == "" ? lookup(data.oci_identity_availability_domains.ADs.availability_domains[0], "name") : var.availability_domain_name + mysql_shape_name = var.mysql_shape + mysql_db_system_data_storage_size_in_gb = var.mysql_db_system_data_storage_size_in_gb + mysql_db_system_description = var.mysql_db_system_description + mysql_db_system_display_name = var.mysql_db_system_display_name + mysql_db_system_fault_domain = var.mysql_db_system_fault_domain + mysql_db_system_hostname_label = var.mysql_db_system_hostname_label + mysql_db_system_is_highly_available = var.mysql_is_highly_available + mysql_db_system_maintenance_window_start_time = var.mysql_db_system_maintenance_window_start_time +} \ No newline at end of file diff --git a/examples/drupal-ha-mds-use-existing-network/network.tf b/examples/drupal-ha-mds-use-existing-network/network.tf new file mode 100644 index 0000000..2f77dc8 --- /dev/null +++ b/examples/drupal-ha-mds-use-existing-network/network.tf @@ -0,0 +1,219 @@ +## Copyright (c) 2022, 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_virtual_network" "drupal_mds_vcn" { + cidr_block = var.vcn_cidr + compartment_id = var.compartment_ocid + display_name = var.vcn + dns_label = "jomdsvcn" +} + + +resource "oci_core_internet_gateway" "internet_gateway" { + compartment_id = var.compartment_ocid + display_name = "internet_gateway" + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id +} + + +resource "oci_core_nat_gateway" "nat_gateway" { + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + display_name = "nat_gateway" +} + + +resource "oci_core_route_table" "public_route_table" { + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + display_name = "RouteTableViaIGW" + route_rules { + destination = "0.0.0.0/0" + destination_type = "CIDR_BLOCK" + network_entity_id = oci_core_internet_gateway.internet_gateway.id + } +} + +resource "oci_core_route_table" "private_route_table" { + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + display_name = "RouteTableViaNATGW" + route_rules { + destination = "0.0.0.0/0" + destination_type = "CIDR_BLOCK" + network_entity_id = oci_core_nat_gateway.nat_gateway.id + } +} + +resource "oci_core_security_list" "public_security_list_ssh" { + compartment_id = var.compartment_ocid + display_name = "Allow Public SSH Connections to WordPress" + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + egress_security_rules { + destination = "0.0.0.0/0" + protocol = "6" + } + ingress_security_rules { + tcp_options { + max = 22 + min = 22 + } + protocol = "6" + source = "0.0.0.0/0" + } +} + +resource "oci_core_security_list" "public_security_list_http" { + compartment_id = var.compartment_ocid + display_name = "Allow HTTP(S) to Drupal" + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + egress_security_rules { + destination = "0.0.0.0/0" + protocol = "6" + } + ingress_security_rules { + tcp_options { + max = 80 + min = 80 + } + protocol = "6" + source = "0.0.0.0/0" + } + ingress_security_rules { + tcp_options { + max = 443 + min = 443 + } + protocol = "6" + source = "0.0.0.0/0" + } +} + +resource "oci_core_security_list" "private_security_list" { + compartment_id = var.compartment_ocid + display_name = "Private" + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + + egress_security_rules { + destination = "0.0.0.0/0" + protocol = "all" + } + ingress_security_rules { + protocol = "1" + source = var.vcn_cidr + } + ingress_security_rules { + tcp_options { + max = 22 + min = 22 + } + protocol = "6" + source = var.vcn_cidr + } + ingress_security_rules { + tcp_options { + max = 3306 + min = 3306 + } + protocol = "6" + source = var.vcn_cidr + } + ingress_security_rules { + tcp_options { + max = 33061 + min = 33060 + } + protocol = "6" + source = var.vcn_cidr + } + + ingress_security_rules { + protocol = "6" + source = var.vcn_cidr + + tcp_options { + min = 2048 + max = 2050 + } + } + + ingress_security_rules { + protocol = "6" + source = var.vcn_cidr + + tcp_options { + source_port_range { + min = 2048 + max = 2050 + } + } + } + + ingress_security_rules { + protocol = "6" + source = var.vcn_cidr + + tcp_options { + min = 111 + max = 111 + } + } +} + +resource "oci_core_subnet" "drupal_subnet" { + cidr_block = cidrsubnet(var.vcn_cidr, 8, 2) + display_name = "drupal_subnet" + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + route_table_id = oci_core_route_table.private_route_table.id + security_list_ids = [oci_core_security_list.public_security_list_ssh.id, oci_core_security_list.public_security_list_http.id] + dhcp_options_id = oci_core_virtual_network.drupal_mds_vcn.default_dhcp_options_id + prohibit_public_ip_on_vnic = true + dns_label = "drusub" +} + +resource "oci_core_subnet" "lb_subnet_public" { + cidr_block = cidrsubnet(var.vcn_cidr, 8, 0) + display_name = "lb_public_subnet" + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + route_table_id = oci_core_route_table.public_route_table.id + security_list_ids = [oci_core_security_list.public_security_list_http.id] + dhcp_options_id = oci_core_virtual_network.drupal_mds_vcn.default_dhcp_options_id + dns_label = "lbpub" +} + +resource "oci_core_subnet" "bastion_subnet_public" { + cidr_block = cidrsubnet(var.vcn_cidr, 8, 1) + display_name = "bastion_public_subnet" + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + route_table_id = oci_core_route_table.public_route_table.id + security_list_ids = [oci_core_security_list.public_security_list_ssh.id] + dhcp_options_id = oci_core_virtual_network.drupal_mds_vcn.default_dhcp_options_id + dns_label = "bastionpub" +} + +resource "oci_core_subnet" "fss_subnet_private" { + cidr_block = cidrsubnet(var.vcn_cidr, 8, 4) + display_name = "fss_private_subnet" + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + route_table_id = oci_core_route_table.private_route_table.id + dhcp_options_id = oci_core_virtual_network.drupal_mds_vcn.default_dhcp_options_id + prohibit_public_ip_on_vnic = "true" + dns_label = "fsspriv" +} + +resource "oci_core_subnet" "mds_subnet_private" { + cidr_block = cidrsubnet(var.vcn_cidr, 8, 3) + display_name = "mds_private_subnet" + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + route_table_id = oci_core_route_table.private_route_table.id + security_list_ids = [oci_core_security_list.private_security_list.id] + dhcp_options_id = oci_core_virtual_network.drupal_mds_vcn.default_dhcp_options_id + prohibit_public_ip_on_vnic = "true" + dns_label = "mdspriv" +} + diff --git a/examples/drupal-ha-mds-use-existing-network/output.tf b/examples/drupal-ha-mds-use-existing-network/output.tf new file mode 100644 index 0000000..7f6dae2 --- /dev/null +++ b/examples/drupal-ha-mds-use-existing-network/output.tf @@ -0,0 +1,28 @@ +## Copyright (c) 2022 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 + +output "drupal_home_URL" { + value = "http://${module.drupal.public_ip[0]}/" +} + +output "generated_ssh_private_key" { + value = module.drupal.generated_ssh_private_key + sensitive = true +} + +output "drupal_name" { + value = var.drupal_name +} + +output "drupal_password" { + value = var.drupal_password +} + +output "drupal_database" { + value = var.drupal_schema +} + +output "mds_instance_ip" { + value = module.mds-instance.mysql_db_system.ip_address + sensitive = true +} \ No newline at end of file diff --git a/examples/drupal-ha-mds-use-existing-network/provider.tf b/examples/drupal-ha-mds-use-existing-network/provider.tf new file mode 100644 index 0000000..85b7308 --- /dev/null +++ b/examples/drupal-ha-mds-use-existing-network/provider.tf @@ -0,0 +1,20 @@ +## Copyright (c) 2022 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 + +provider "oci" { + tenancy_ocid = var.tenancy_ocid + region = var.region + user_ocid = var.user_ocid + fingerprint = var.fingerprint + private_key_path = var.private_key_path +} + +provider "oci" { + alias = "homeregion" + tenancy_ocid = var.tenancy_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + private_key_path = var.private_key_path + region = data.oci_identity_region_subscriptions.home_region_subscriptions.region_subscriptions[0].region_name + disable_auto_retries = "true" +} diff --git a/examples/drupal-ha-mds-use-existing-network/terraform.tfvars.example b/examples/drupal-ha-mds-use-existing-network/terraform.tfvars.example new file mode 100644 index 0000000..7d7e321 --- /dev/null +++ b/examples/drupal-ha-mds-use-existing-network/terraform.tfvars.example @@ -0,0 +1,17 @@ +# Authentication +tenancy_ocid = "" +user_ocid = "" +fingerprint = "" +private_key_path = "" + +# Region +region = "" + +# Compartment +compartment_ocid = "" + +# MySQL admin password +admin_password = "" + +# MYSQL drupal password +drupal_password = "" diff --git a/examples/drupal-ha-mds-use-existing-network/variables.tf b/examples/drupal-ha-mds-use-existing-network/variables.tf new file mode 100644 index 0000000..dd7d570 --- /dev/null +++ b/examples/drupal-ha-mds-use-existing-network/variables.tf @@ -0,0 +1,185 @@ +## Copyright (c) 2022 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 "user_ocid" {} +variable "fingerprint" {} +variable "private_key_path" {} + +variable "ssh_public_key" { + default = "" +} + +variable "availability_domain_name" { + default = "" +} + +variable "tenancy_ocid" { + description = "Tenancy's OCID" +} + +variable "compartment_ocid" { + description = "Compartment's OCID where VCN will be created. " +} + +variable "region" { + description = "OCI Region" +} + +variable "vcn" { + description = "VCN Name" + default = "drupal_mds_vcn" +} + +variable "vcn_cidr" { + description = "VCN's CIDR IP Block" + default = "10.0.0.0/16" +} + +variable "node_image_id" { + description = "The OCID of an image for a node instance to use. " + default = "" +} + +variable "node_shape" { +description = "Instance shape to use for master instance. " + default = "VM.Standard.E4.Flex" +} + +variable "node_flex_shape_ocpus" { + description = "Flex Instance shape OCPUs" + default = 1 +} + +variable "node_flex_shape_memory" { + description = "Flex Instance shape Memory (GB)" + default = 6 +} + +variable "label_prefix" { + description = "To create unique identifier for multiple setup in a compartment." + default = "" +} + +variable "lb_shape" { + default = "flexible" +} + +variable "flex_lb_min_shape" { + default = "10" +} + +variable "flex_lb_max_shape" { + default = "100" +} + +variable "use_bastion_service" { + default = false +} + +variable "bastion_shape" { + default = "VM.Standard.E3.Flex" +} + +variable "bastion_flex_shape_ocpus" { + default = 1 +} + +variable "bastion_flex_shape_memory" { + default = 1 +} + +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 = "8" +} + +variable "admin_password" { + description = "Password for the admin user for MySQL Database Service" +} + +variable "admin_username" { + description = "MySQL Database Service Username" + default = "admin" +} + +variable "ssh_authorized_keys_path" { + description = "Public SSH keys path to be included in the ~/.ssh/authorized_keys file for the default user on the instance. DO NOT FILL WHEN USING REOSURCE MANAGER STACK!" + default = "" +} + +variable "ssh_private_key_path" { + description = "The private key path to access instance. DO NOT FILL WHEN USING RESOURCE MANAGER STACK!" + default = "" +} + +variable "mysql_shape" { + default = "MySQL.VM.Standard.E3.1.8GB" +} + +variable "drupal_name" { + description = "drupal Database User Name." + default = "drupal" +} + +variable "drupal_password" { + description = "drupal Database User Password." + default = "" +} + +variable "drupal_schema" { + description = "drupal MySQL Schema" + default = "drupal" +} + +variable "mds_instance_name" { + description = "Name of the MDS instance" + default = "drupalMDS" +} + +variable "mysql_is_highly_available" { + default = false +} + +variable "mysql_db_system_data_storage_size_in_gb" { + default = 50 +} + +variable "mysql_db_system_description" { + description = "MySQL DB System for Drupal-MDS" + default = "MySQL DB System for Drupal-MDS" +} + +variable "mysql_db_system_display_name" { + description = "MySQL DB System display name" + default = "DrupalMDS" +} + +variable "mysql_db_system_fault_domain" { + description = "The fault domain on which to deploy the Read/Write endpoint. This defines the preferred primary instance." + default = "FAULT-DOMAIN-1" +} + +variable "mysql_db_system_hostname_label" { + description = "The hostname for the primary endpoint of the DB System. Used for DNS. The value is the hostname portion of the primary private IP's fully qualified domain name (FQDN) (for example, dbsystem-1 in FQDN dbsystem-1.subnet123.vcn1.oraclevcn.com). Must be unique across all VNICs in the subnet and comply with RFC 952 and RFC 1123." + default = "DrupalMDS" +} + +variable "mysql_db_system_maintenance_window_start_time" { + description = "The start of the 2 hour maintenance window. This string is of the format: {day-of-week} {time-of-day}. {day-of-week} is a case-insensitive string like mon, tue, etc. {time-of-day} is the Time portion of an RFC3339-formatted timestamp. Any second or sub-second time data will be truncated to zero." + default = "SUNDAY 14:30" +} + +variable "drupal_instance_name" { + description = "Name of the drupal compute instance" + default = "drupalvm" +} + +variable "use_shared_storage" { + description = "Decide if you want to use shared NFS on OCI FSS" + default = true +} diff --git a/examples/drupal-single-mds-use-existing-network/LICENSE b/examples/drupal-single-mds-use-existing-network/LICENSE new file mode 100644 index 0000000..a118f3e --- /dev/null +++ b/examples/drupal-single-mds-use-existing-network/LICENSE @@ -0,0 +1,35 @@ +Copyright (c) 2022 Oracle and/or its affiliates. + +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 + +(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), + +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 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 diff --git a/examples/drupal-single-mds-use-existing-network/README.md b/examples/drupal-single-mds-use-existing-network/README.md new file mode 100644 index 0000000..8bc6f0e --- /dev/null +++ b/examples/drupal-single-mds-use-existing-network/README.md @@ -0,0 +1,19 @@ +## Create Drupal multi-node + custom network injected into module +This is an example of how to use the oci-arch-drupal module to deploy Drupal HA (multi-node) with MDS and network cloud infrastrucutre elements injected into the module.. + +### Using this example +Update terraform.tfvars with the required information. + +### Deploy the drupal +Initialize Terraform: +``` +$ terraform init +``` +View what Terraform plans do before actually doing it: +``` +$ terraform plan +``` +Use Terraform to Provision resources: +``` +$ terraform apply +``` diff --git a/examples/drupal-single-mds-use-existing-network/datasources.tf b/examples/drupal-single-mds-use-existing-network/datasources.tf new file mode 100644 index 0000000..9b10d29 --- /dev/null +++ b/examples/drupal-single-mds-use-existing-network/datasources.tf @@ -0,0 +1,34 @@ +## Copyright (c) 2022 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_images" "InstanceImageOCID" { + compartment_id = var.compartment_ocid + operating_system = var.instance_os + operating_system_version = var.linux_os_version + shape = var.node_shape + + filter { + name = "display_name" + values = ["^.*Oracle[^G]*$"] + regex = true + } +} + +data "oci_mysql_mysql_configurations" "shape" { + compartment_id = var.compartment_ocid + type = ["DEFAULT"] + shape_name = var.mysql_shape +} + +data "oci_identity_region_subscriptions" "home_region_subscriptions" { + tenancy_id = var.tenancy_ocid + + filter { + name = "is_home_region" + values = [true] + } +} + +data "oci_identity_availability_domains" "ADs" { + compartment_id = var.tenancy_ocid +} diff --git a/examples/drupal-single-mds-use-existing-network/drupal.tf b/examples/drupal-single-mds-use-existing-network/drupal.tf new file mode 100644 index 0000000..33266c9 --- /dev/null +++ b/examples/drupal-single-mds-use-existing-network/drupal.tf @@ -0,0 +1,26 @@ +## Copyright (c) 2022, 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 + +module "drupal" { + source = "github.com/oracle-devrel/terraform-oci-arch-drupal" + tenancy_ocid = var.tenancy_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + numberOfNodes = 1 + availability_domain_name = var.availability_domain_name == "" ? lookup(data.oci_identity_availability_domains.ADs.availability_domains[0], "name") : var.availability_domain_name + compartment_ocid = var.compartment_ocid + image_id = lookup(data.oci_core_images.InstanceImageOCID.images[0], "id") + shape = var.node_shape + label_prefix = var.label_prefix + ssh_authorized_keys = var.ssh_public_key + mds_ip = module.mds-instance.mysql_db_system.ip_address + drupal_subnet_id = oci_core_subnet.drupal_subnet.id + admin_password = var.admin_password + admin_username = var.admin_username + drupal_schema = var.drupal_schema + drupal_name = var.drupal_name + drupal_password = var.drupal_password + display_name = var.drupal_instance_name + flex_shape_ocpus = var.node_flex_shape_ocpus + flex_shape_memory = var.node_flex_shape_memory +} + diff --git a/examples/drupal-single-mds-use-existing-network/mds.tf b/examples/drupal-single-mds-use-existing-network/mds.tf new file mode 100644 index 0000000..3a9227c --- /dev/null +++ b/examples/drupal-single-mds-use-existing-network/mds.tf @@ -0,0 +1,22 @@ +## Copyright (c) 2022, 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 + +module "mds-instance" { + source = "github.com/oracle-devrel/terraform-oci-cloudbricks-mysql-database?ref=v1.0.4.1" + tenancy_ocid = var.tenancy_ocid + region = var.region + mysql_instance_compartment_ocid = var.compartment_ocid + mysql_network_compartment_ocid = var.compartment_ocid + subnet_id = oci_core_subnet.mds_subnet_private.id + mysql_db_system_admin_username = var.admin_username + mysql_db_system_admin_password = var.admin_password + mysql_db_system_availability_domain = var.availability_domain_name == "" ? lookup(data.oci_identity_availability_domains.ADs.availability_domains[0], "name") : var.availability_domain_name + mysql_shape_name = var.mysql_shape + mysql_db_system_data_storage_size_in_gb = var.mysql_db_system_data_storage_size_in_gb + mysql_db_system_description = var.mysql_db_system_description + mysql_db_system_display_name = var.mysql_db_system_display_name + mysql_db_system_fault_domain = var.mysql_db_system_fault_domain + mysql_db_system_hostname_label = var.mysql_db_system_hostname_label + mysql_db_system_is_highly_available = var.mysql_is_highly_available + mysql_db_system_maintenance_window_start_time = var.mysql_db_system_maintenance_window_start_time +} \ No newline at end of file diff --git a/examples/drupal-single-mds-use-existing-network/network.tf b/examples/drupal-single-mds-use-existing-network/network.tf new file mode 100644 index 0000000..892bd87 --- /dev/null +++ b/examples/drupal-single-mds-use-existing-network/network.tf @@ -0,0 +1,186 @@ +## Copyright (c) 2022, 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_virtual_network" "drupal_mds_vcn" { + cidr_block = var.vcn_cidr + compartment_id = var.compartment_ocid + display_name = var.vcn + dns_label = "jomdsvcn" +} + + +resource "oci_core_internet_gateway" "internet_gateway" { + compartment_id = var.compartment_ocid + display_name = "internet_gateway" + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id +} + + +resource "oci_core_nat_gateway" "nat_gateway" { + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + display_name = "nat_gateway" +} + + +resource "oci_core_route_table" "public_route_table" { + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + display_name = "RouteTableViaIGW" + route_rules { + destination = "0.0.0.0/0" + destination_type = "CIDR_BLOCK" + network_entity_id = oci_core_internet_gateway.internet_gateway.id + } +} + +resource "oci_core_route_table" "private_route_table" { + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + display_name = "RouteTableViaNATGW" + route_rules { + destination = "0.0.0.0/0" + destination_type = "CIDR_BLOCK" + network_entity_id = oci_core_nat_gateway.nat_gateway.id + } +} + +resource "oci_core_security_list" "public_security_list_ssh" { + compartment_id = var.compartment_ocid + display_name = "Allow Public SSH Connections to WordPress" + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + egress_security_rules { + destination = "0.0.0.0/0" + protocol = "6" + } + ingress_security_rules { + tcp_options { + max = 22 + min = 22 + } + protocol = "6" + source = "0.0.0.0/0" + } +} + +resource "oci_core_security_list" "public_security_list_http" { + compartment_id = var.compartment_ocid + display_name = "Allow HTTP(S) to Drupal" + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + egress_security_rules { + destination = "0.0.0.0/0" + protocol = "6" + } + ingress_security_rules { + tcp_options { + max = 80 + min = 80 + } + protocol = "6" + source = "0.0.0.0/0" + } + ingress_security_rules { + tcp_options { + max = 443 + min = 443 + } + protocol = "6" + source = "0.0.0.0/0" + } +} + +resource "oci_core_security_list" "private_security_list" { + compartment_id = var.compartment_ocid + display_name = "Private" + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + + egress_security_rules { + destination = "0.0.0.0/0" + protocol = "all" + } + ingress_security_rules { + protocol = "1" + source = var.vcn_cidr + } + ingress_security_rules { + tcp_options { + max = 22 + min = 22 + } + protocol = "6" + source = var.vcn_cidr + } + ingress_security_rules { + tcp_options { + max = 3306 + min = 3306 + } + protocol = "6" + source = var.vcn_cidr + } + ingress_security_rules { + tcp_options { + max = 33061 + min = 33060 + } + protocol = "6" + source = var.vcn_cidr + } + + ingress_security_rules { + protocol = "6" + source = var.vcn_cidr + + tcp_options { + min = 2048 + max = 2050 + } + } + + ingress_security_rules { + protocol = "6" + source = var.vcn_cidr + + tcp_options { + source_port_range { + min = 2048 + max = 2050 + } + } + } + + ingress_security_rules { + protocol = "6" + source = var.vcn_cidr + + tcp_options { + min = 111 + max = 111 + } + } +} + +resource "oci_core_subnet" "drupal_subnet" { + cidr_block = cidrsubnet(var.vcn_cidr, 8, 1) + display_name = "drupal_subnet" + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + route_table_id = oci_core_route_table.public_route_table.id + security_list_ids = [oci_core_security_list.public_security_list_ssh.id, oci_core_security_list.public_security_list_http.id] + dhcp_options_id = oci_core_virtual_network.drupal_mds_vcn.default_dhcp_options_id + prohibit_public_ip_on_vnic = false + dns_label = "drusub" +} + +resource "oci_core_subnet" "mds_subnet_private" { + cidr_block = cidrsubnet(var.vcn_cidr, 8, 2) + display_name = "mds_private_subnet" + compartment_id = var.compartment_ocid + vcn_id = oci_core_virtual_network.drupal_mds_vcn.id + route_table_id = oci_core_route_table.private_route_table.id + security_list_ids = [oci_core_security_list.private_security_list.id] + dhcp_options_id = oci_core_virtual_network.drupal_mds_vcn.default_dhcp_options_id + prohibit_public_ip_on_vnic = true + dns_label = "mdspriv" +} + diff --git a/examples/drupal-single-mds-use-existing-network/output.tf b/examples/drupal-single-mds-use-existing-network/output.tf new file mode 100644 index 0000000..7f6dae2 --- /dev/null +++ b/examples/drupal-single-mds-use-existing-network/output.tf @@ -0,0 +1,28 @@ +## Copyright (c) 2022 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 + +output "drupal_home_URL" { + value = "http://${module.drupal.public_ip[0]}/" +} + +output "generated_ssh_private_key" { + value = module.drupal.generated_ssh_private_key + sensitive = true +} + +output "drupal_name" { + value = var.drupal_name +} + +output "drupal_password" { + value = var.drupal_password +} + +output "drupal_database" { + value = var.drupal_schema +} + +output "mds_instance_ip" { + value = module.mds-instance.mysql_db_system.ip_address + sensitive = true +} \ No newline at end of file diff --git a/examples/drupal-single-mds-use-existing-network/provider.tf b/examples/drupal-single-mds-use-existing-network/provider.tf new file mode 100644 index 0000000..85b7308 --- /dev/null +++ b/examples/drupal-single-mds-use-existing-network/provider.tf @@ -0,0 +1,20 @@ +## Copyright (c) 2022 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 + +provider "oci" { + tenancy_ocid = var.tenancy_ocid + region = var.region + user_ocid = var.user_ocid + fingerprint = var.fingerprint + private_key_path = var.private_key_path +} + +provider "oci" { + alias = "homeregion" + tenancy_ocid = var.tenancy_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + private_key_path = var.private_key_path + region = data.oci_identity_region_subscriptions.home_region_subscriptions.region_subscriptions[0].region_name + disable_auto_retries = "true" +} diff --git a/examples/drupal-single-mds-use-existing-network/terraform.tfvars.example b/examples/drupal-single-mds-use-existing-network/terraform.tfvars.example new file mode 100644 index 0000000..7d7e321 --- /dev/null +++ b/examples/drupal-single-mds-use-existing-network/terraform.tfvars.example @@ -0,0 +1,17 @@ +# Authentication +tenancy_ocid = "" +user_ocid = "" +fingerprint = "" +private_key_path = "" + +# Region +region = "" + +# Compartment +compartment_ocid = "" + +# MySQL admin password +admin_password = "" + +# MYSQL drupal password +drupal_password = "" diff --git a/examples/drupal-single-mds-use-existing-network/variables.tf b/examples/drupal-single-mds-use-existing-network/variables.tf new file mode 100644 index 0000000..debfa4f --- /dev/null +++ b/examples/drupal-single-mds-use-existing-network/variables.tf @@ -0,0 +1,153 @@ +## Copyright (c) 2022 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 "user_ocid" {} +variable "fingerprint" {} +variable "private_key_path" {} + +variable "ssh_public_key" { + default = "" +} + +variable "availability_domain_name" { + default = "" +} + +variable "tenancy_ocid" { + description = "Tenancy's OCID" +} + +variable "compartment_ocid" { + description = "Compartment's OCID where VCN will be created. " +} + +variable "region" { + description = "OCI Region" +} + +variable "vcn" { + description = "VCN Name" + default = "drupal_mds_vcn" +} + +variable "vcn_cidr" { + description = "VCN's CIDR IP Block" + default = "10.0.0.0/16" +} + +variable "node_image_id" { + description = "The OCID of an image for a node instance to use. " + default = "" +} + +variable "node_shape" { +description = "Instance shape to use for master instance. " + default = "VM.Standard.E4.Flex" +} + +variable "node_flex_shape_ocpus" { + description = "Flex Instance shape OCPUs" + default = 1 +} + +variable "node_flex_shape_memory" { + description = "Flex Instance shape Memory (GB)" + default = 6 +} + +variable "label_prefix" { + description = "To create unique identifier for multiple setup in a compartment." + default = "" +} + +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 = "8" +} + +variable "admin_password" { + description = "Password for the admin user for MySQL Database Service" +} + +variable "admin_username" { + description = "MySQL Database Service Username" + default = "admin" +} + +variable "ssh_authorized_keys_path" { + description = "Public SSH keys path to be included in the ~/.ssh/authorized_keys file for the default user on the instance. DO NOT FILL WHEN USING REOSURCE MANAGER STACK!" + default = "" +} + +variable "ssh_private_key_path" { + description = "The private key path to access instance. DO NOT FILL WHEN USING RESOURCE MANAGER STACK!" + default = "" +} + +variable "mysql_shape" { + default = "MySQL.VM.Standard.E3.1.8GB" +} + +variable "drupal_name" { + description = "drupal Database User Name." + default = "drupal" +} + +variable "drupal_password" { + description = "drupal Database User Password." + default = "" +} + +variable "drupal_schema" { + description = "drupal MySQL Schema" + default = "drupal" +} + +variable "mds_instance_name" { + description = "Name of the MDS instance" + default = "drupalMDS" +} + +variable "mysql_is_highly_available" { + default = false +} + +variable "mysql_db_system_data_storage_size_in_gb" { + default = 50 +} + +variable "mysql_db_system_description" { + description = "MySQL DB System for Drupal-MDS" + default = "MySQL DB System for Drupal-MDS" +} + +variable "mysql_db_system_display_name" { + description = "MySQL DB System display name" + default = "DrupalMDS" +} + +variable "mysql_db_system_fault_domain" { + description = "The fault domain on which to deploy the Read/Write endpoint. This defines the preferred primary instance." + default = "FAULT-DOMAIN-1" +} + +variable "mysql_db_system_hostname_label" { + description = "The hostname for the primary endpoint of the DB System. Used for DNS. The value is the hostname portion of the primary private IP's fully qualified domain name (FQDN) (for example, dbsystem-1 in FQDN dbsystem-1.subnet123.vcn1.oraclevcn.com). Must be unique across all VNICs in the subnet and comply with RFC 952 and RFC 1123." + default = "DrupalMDS" +} + +variable "mysql_db_system_maintenance_window_start_time" { + description = "The start of the 2 hour maintenance window. This string is of the format: {day-of-week} {time-of-day}. {day-of-week} is a case-insensitive string like mon, tue, etc. {time-of-day} is the Time portion of an RFC3339-formatted timestamp. Any second or sub-second time data will be truncated to zero." + default = "SUNDAY 14:30" +} + +variable "drupal_instance_name" { + description = "Name of the drupal compute instance" + default = "drupalvm" +} + diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..0e96817 --- /dev/null +++ b/main.tf @@ -0,0 +1,853 @@ +## Copyright (c) 2022, 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" +} + +data "oci_identity_availability_domains" "ADs" { + compartment_id = var.tenancy_ocid +} + +data "template_file" "install_php" { + template = file("${path.module}/scripts/install_php74.sh") + + vars = { + mysql_version = var.mysql_version + user = var.vm_user + } +} + +data "template_file" "configure_local_security" { + template = file("${path.module}/scripts/configure_local_security.sh") +} + +data "template_file" "create_drupal_db" { + template = file("${path.module}/scripts/create_drupal_db.sh") + + vars = { + admin_password = var.admin_password + admin_username = var.admin_username + drupal_name = var.drupal_name + drupal_password = var.drupal_password + drupal_schema = var.drupal_schema + mds_ip = var.mds_ip + } +} + +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 + } +} + +locals { + php_script = "~/install_php74.sh" + security_script = "~/configure_local_security.sh" + create_drupal_db = "~/create_drupal_db.sh" + install_drupal = "~/install_drupal.sh" + htaccess = "~/htaccess" + indexhtml = "~/index.html" +} + +data "oci_core_subnet" "drupal_subnet_ds" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + subnet_id = var.drupal_subnet_id +} + + +# FSS NSG +resource "oci_core_network_security_group" "drupalFSSSecurityGroup" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + compartment_id = var.compartment_ocid + display_name = "drupalFSSSecurityGroup" + vcn_id = var.vcn_id +} + +# FSS NSG Ingress TCP Rules +resource "oci_core_network_security_group_security_rule" "drupalFSSSecurityIngressTCPGroupRules1" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + + network_security_group_id = oci_core_network_security_group.drupalFSSSecurityGroup[0].id + direction = "INGRESS" + protocol = "6" + source = data.oci_core_subnet.drupal_subnet_ds[0].cidr_block + source_type = "CIDR_BLOCK" + + tcp_options { + destination_port_range { + max = 111 + min = 111 + } + } +} + +# FSS NSG Ingress TCP Rules +resource "oci_core_network_security_group_security_rule" "drupalFSSSecurityIngressTCPGroupRules2" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + + network_security_group_id = oci_core_network_security_group.drupalFSSSecurityGroup[0].id + direction = "INGRESS" + protocol = "6" + source = data.oci_core_subnet.drupal_subnet_ds[0].cidr_block + source_type = "CIDR_BLOCK" + + tcp_options { + destination_port_range { + max = 2050 + min = 2048 + } + } +} + +# FSS NSG Ingress UDP Rules +resource "oci_core_network_security_group_security_rule" "drupalFSSSecurityIngressUDPGroupRules1" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + + network_security_group_id = oci_core_network_security_group.drupalFSSSecurityGroup[0].id + direction = "INGRESS" + protocol = "17" + source = data.oci_core_subnet.drupal_subnet_ds[0].cidr_block + source_type = "CIDR_BLOCK" + + udp_options { + destination_port_range { + max = 111 + min = 111 + } + } +} + +# FSS NSG Ingress UDP Rules +resource "oci_core_network_security_group_security_rule" "drupalFSSSecurityIngressUDPGroupRules2" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + + network_security_group_id = oci_core_network_security_group.drupalFSSSecurityGroup[0].id + direction = "INGRESS" + protocol = "17" + source = data.oci_core_subnet.drupal_subnet_ds[0].cidr_block + source_type = "CIDR_BLOCK" + + udp_options { + destination_port_range { + max = 2048 + min = 2048 + } + } +} + + +# FSS NSG Egress TCP Rules +resource "oci_core_network_security_group_security_rule" "drupalFSSSecurityEgressTCPGroupRules1" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + + network_security_group_id = oci_core_network_security_group.drupalFSSSecurityGroup[0].id + direction = "EGRESS" + protocol = "6" + destination = data.oci_core_subnet.drupal_subnet_ds[0].cidr_block + destination_type = "CIDR_BLOCK" + + tcp_options { + destination_port_range { + max = 111 + min = 111 + } + } +} + +# FSS NSG Egress TCP Rules +resource "oci_core_network_security_group_security_rule" "drupalFSSSecurityEgressTCPGroupRules2" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + + network_security_group_id = oci_core_network_security_group.drupalFSSSecurityGroup[0].id + direction = "EGRESS" + protocol = "6" + destination = data.oci_core_subnet.drupal_subnet_ds[0].cidr_block + destination_type = "CIDR_BLOCK" + + tcp_options { + destination_port_range { + max = 2050 + min = 2048 + } + } +} + + +# FSS NSG Egress UDP Rules +resource "oci_core_network_security_group_security_rule" "drupalFSSSecurityEgressUDPGroupRules1" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + + network_security_group_id = oci_core_network_security_group.drupalFSSSecurityGroup[0].id + direction = "EGRESS" + protocol = "17" + destination = data.oci_core_subnet.drupal_subnet_ds[0].cidr_block + destination_type = "CIDR_BLOCK" + + udp_options { + destination_port_range { + max = 111 + min = 111 + } + } + +} + +# Mount Target + +resource "oci_file_storage_mount_target" "drupalMountTarget" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + availability_domain = var.availability_domain_name == "" ? lookup(data.oci_identity_availability_domains.ADs.availability_domains[0], "name") : var.availability_domain_name + compartment_id = var.compartment_ocid + subnet_id = var.fss_subnet_id + display_name = "drupalMountTarget" + nsg_ids = [oci_core_network_security_group.drupalFSSSecurityGroup[0].id] +} + +data "oci_core_private_ips" "ip_mount_drupalMountTarget" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + subnet_id = oci_file_storage_mount_target.drupalMountTarget[0].subnet_id + + filter { + name = "id" + values = [oci_file_storage_mount_target.drupalMountTarget[0].private_ip_ids[0]] + } +} + +locals { + mt_ip_address = var.numberOfNodes > 1 && var.use_shared_storage ? data.oci_core_private_ips.ip_mount_drupalMountTarget[0].private_ips[0].ip_address : "" +} + + +# Export Set + +resource "oci_file_storage_export_set" "drupalExportset" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + mount_target_id = oci_file_storage_mount_target.drupalMountTarget[0].id + display_name = "drupalExportset" +} + +# FileSystem + +resource "oci_file_storage_file_system" "drupalFilesystem" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + availability_domain = var.availability_domain_name == "" ? lookup(data.oci_identity_availability_domains.ADs.availability_domains[0], "name") : var.availability_domain_name + compartment_id = var.compartment_ocid + display_name = "drupalFilesystem" +} + +# Export + +resource "oci_file_storage_export" "drupalExport" { + count = var.numberOfNodes > 1 && var.use_shared_storage ? 1 : 0 + export_set_id = oci_file_storage_mount_target.drupalMountTarget[0].export_set_id + file_system_id = oci_file_storage_file_system.drupalFilesystem[0].id + path = var.drupal_shared_working_dir +} + + +resource "oci_core_instance" "drupal" { + availability_domain = var.availability_domain_name == "" ? lookup(data.oci_identity_availability_domains.ADs.availability_domains[0], "name") : var.availability_domain_name + compartment_id = var.compartment_ocid + display_name = "${var.label_prefix}${var.display_name}1" + shape = var.shape + + dynamic "shape_config" { + for_each = local.is_flexible_node_shape ? [1] : [] + content { + memory_in_gbs = var.flex_shape_memory + ocpus = var.flex_shape_ocpus + } + } + + create_vnic_details { + subnet_id = var.drupal_subnet_id + display_name = "${var.label_prefix}${var.display_name}1" + assign_public_ip = false + hostname_label = var.display_name + } + + dynamic "agent_config" { + for_each = var.numberOfNodes > 1 ? [1] : [] + content { + are_all_plugins_disabled = false + is_management_disabled = false + is_monitoring_disabled = false + plugins_config { + desired_state = "ENABLED" + name = "Bastion" + } + } + } + + metadata = { + ssh_authorized_keys = var.ssh_authorized_keys + user_data = data.template_cloudinit_config.cloud_init.rendered + } + + source_details { + source_id = var.image_id + source_type = "image" + } + + defined_tags = var.defined_tags + + provisioner "local-exec" { + command = "sleep 240" + } +} + +data "oci_core_vnic_attachments" "drupal_vnics" { + depends_on = [oci_core_instance.drupal] + compartment_id = var.compartment_ocid + availability_domain = var.availability_domain_name == "" ? lookup(data.oci_identity_availability_domains.ADs.availability_domains[0], "name") : var.availability_domain_name + instance_id = oci_core_instance.drupal.id +} + +data "oci_core_vnic" "drupal_vnic1" { + depends_on = [oci_core_instance.drupal] + vnic_id = data.oci_core_vnic_attachments.drupal_vnics.vnic_attachments[0]["vnic_id"] +} + +data "oci_core_private_ips" "drupal_private_ips1" { + depends_on = [oci_core_instance.drupal] + vnic_id = data.oci_core_vnic.drupal_vnic1.id + #vnic_id = oci_core_instance.drupal.private_ip + subnet_id = var.drupal_subnet_id +} + +resource "oci_core_public_ip" "drupal_public_ip_for_single_node" { + depends_on = [oci_core_instance.drupal] + count = var.numberOfNodes > 1 ? 0 : 1 + compartment_id = var.compartment_ocid + display_name = "drupal_public_ip_for_single_node" + lifetime = "RESERVED" + # private_ip_id = var.numberOfNodes == 1 ? data.oci_core_private_ips.drupal_private_ips1.private_ips[0]["id"] : null + private_ip_id = data.oci_core_private_ips.drupal_private_ips1.private_ips[0]["id"] + defined_tags = var.defined_tags +} + +resource "oci_core_public_ip" "drupal_public_ip_for_multi_node" { + count = var.numberOfNodes > 1 ? 1 : 0 + compartment_id = var.compartment_ocid + display_name = "drupal_public_ip_for_multi_node" + lifetime = "RESERVED" + defined_tags = var.defined_tags +} + +data "template_file" "install_drupal" { + template = file("${path.module}/scripts/install_drupal.sh") + + vars = { + drupal_name = var.drupal_name + drupal_password = var.drupal_password + drupal_schema = var.drupal_schema + mds_ip = var.mds_ip + use_shared_storage = var.numberOfNodes > 1 ? tostring(true) : tostring(false) + drupal_shared_working_dir = var.drupal_shared_working_dir + mt_ip_address = local.mt_ip_address + } +} + +resource "oci_core_instance" "bastion_instance" { + count = var.numberOfNodes > 1 && !var.use_bastion_service ? 1 : 0 + availability_domain = var.availability_domain_name == "" ? data.oci_identity_availability_domains.ADs.availability_domains[0]["name"] : var.availability_domain_name + compartment_id = var.compartment_ocid + display_name = "${var.label_prefix}BastionVM" + shape = var.bastion_shape + + dynamic "shape_config" { + for_each = local.is_flexible_node_shape ? [1] : [] + content { + memory_in_gbs = var.bastion_flex_shape_memory + ocpus = var.bastion_flex_shape_ocpus + } + } + + create_vnic_details { + subnet_id = var.bastion_subnet_id + display_name = "bastionvm" + assign_public_ip = true + } + + source_details { + source_id = var.bastion_image_id + source_type = "image" + } + + defined_tags = var.defined_tags + + metadata = { + ssh_authorized_keys = var.ssh_authorized_keys + user_data = data.template_cloudinit_config.cloud_init.rendered + } +} + + +resource "oci_bastion_bastion" "bastion-service" { + count = var.numberOfNodes > 1 && var.use_bastion_service ? 1 : 0 + bastion_type = "STANDARD" + compartment_id = var.compartment_ocid + target_subnet_id = var.drupal_subnet_id + #target_subnet_id = var.bastion_subnet_id + client_cidr_block_allow_list = ["0.0.0.0/0"] + name = "BastionService4drupal" + max_session_ttl_in_seconds = 10800 +} + +resource "oci_bastion_session" "ssh_via_bastion_service" { + depends_on = [oci_core_instance.drupal] + count = var.numberOfNodes > 1 && var.use_bastion_service ? 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.drupal.id + target_resource_operating_system_user_name = "opc" + target_resource_port = 22 + target_resource_private_ip_address = oci_core_instance.drupal.private_ip + } + + display_name = "ssh_via_bastion_service_to_drupal1" + key_type = "PUB" + session_ttl_in_seconds = 10800 +} + +resource "null_resource" "drupal_provisioner_without_bastion" { + count = var.numberOfNodes > 1 ? 0 : 1 + depends_on = [oci_core_instance.drupal, oci_core_public_ip.drupal_public_ip_for_single_node] + + provisioner "file" { + content = data.template_file.install_php.rendered + destination = local.php_script + + connection { + type = "ssh" + host = oci_core_public_ip.drupal_public_ip_for_single_node[0].ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + } + } + + provisioner "file" { + content = data.template_file.configure_local_security.rendered + destination = local.security_script + + connection { + type = "ssh" + host = oci_core_public_ip.drupal_public_ip_for_single_node[0].ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + } + } + + provisioner "file" { + source = "${path.module}/scripts/htaccess" + destination = local.htaccess + + connection { + type = "ssh" + host = oci_core_public_ip.drupal_public_ip_for_single_node[0].ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + } + } + + provisioner "file" { + source = "${path.module}/scripts/index.html" + destination = local.indexhtml + + connection { + type = "ssh" + host = oci_core_public_ip.drupal_public_ip_for_single_node[0].ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + } + } + + provisioner "file" { + content = data.template_file.create_drupal_db.rendered + destination = local.create_drupal_db + + connection { + type = "ssh" + host = oci_core_public_ip.drupal_public_ip_for_single_node[0].ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + } + } + + provisioner "file" { + content = data.template_file.install_drupal.rendered + destination = local.install_drupal + + connection { + type = "ssh" + host = oci_core_public_ip.drupal_public_ip_for_single_node[0].ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + } + } + + provisioner "remote-exec" { + connection { + type = "ssh" + host = oci_core_public_ip.drupal_public_ip_for_single_node[0].ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + } + + inline = [ + "chmod +x ${local.php_script}", + "sudo ${local.php_script}", + "chmod +x ${local.security_script}", + "sudo ${local.security_script}", + "chmod +x ${local.create_drupal_db}", + "sudo ${local.create_drupal_db}", + "chmod +x ${local.install_drupal}", + "sudo ${local.install_drupal}" + ] + + } + +} + +resource "null_resource" "drupal_provisioner_with_bastion" { + count = var.numberOfNodes > 1 ? 1 : 0 + depends_on = [oci_core_instance.drupal, + oci_core_network_security_group.drupalFSSSecurityGroup, + oci_core_network_security_group_security_rule.drupalFSSSecurityIngressTCPGroupRules1, + oci_core_network_security_group_security_rule.drupalFSSSecurityIngressTCPGroupRules2, + oci_core_network_security_group_security_rule.drupalFSSSecurityIngressUDPGroupRules1, + oci_core_network_security_group_security_rule.drupalFSSSecurityIngressUDPGroupRules2, + oci_core_network_security_group_security_rule.drupalFSSSecurityEgressTCPGroupRules1, + oci_core_network_security_group_security_rule.drupalFSSSecurityEgressTCPGroupRules2, + oci_core_network_security_group_security_rule.drupalFSSSecurityEgressUDPGroupRules1, + oci_file_storage_export.drupalExport, + oci_file_storage_file_system.drupalFilesystem, + oci_file_storage_export_set.drupalExportset, + oci_file_storage_mount_target.drupalMountTarget] + + provisioner "file" { + content = data.template_file.install_php.rendered + destination = local.php_script + + connection { + type = "ssh" + host = data.oci_core_vnic.drupal_vnic1.private_ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + bastion_host = var.use_bastion_service ? "host.bastion.${var.bastion_service_region}.oci.oraclecloud.com" : oci_core_instance.bastion_instance[0].public_ip + bastion_user = var.use_bastion_service ? oci_bastion_session.ssh_via_bastion_service[0].id : var.vm_user + bastion_private_key = tls_private_key.public_private_key_pair.private_key_pem + } + } + + provisioner "file" { + source = "${path.module}/scripts/htaccess" + destination = local.htaccess + + connection { + type = "ssh" + host = data.oci_core_vnic.drupal_vnic1.private_ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + bastion_host = var.use_bastion_service ? "host.bastion.${var.bastion_service_region}.oci.oraclecloud.com" : oci_core_instance.bastion_instance[0].public_ip + bastion_user = var.use_bastion_service ? oci_bastion_session.ssh_via_bastion_service[0].id : var.vm_user + bastion_private_key = tls_private_key.public_private_key_pair.private_key_pem + } + } + + provisioner "file" { + source = "${path.module}/scripts/index.html" + destination = local.indexhtml + + connection { + type = "ssh" + host = data.oci_core_vnic.drupal_vnic1.private_ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + bastion_host = var.use_bastion_service ? "host.bastion.${var.bastion_service_region}.oci.oraclecloud.com" : oci_core_instance.bastion_instance[0].public_ip + bastion_user = var.use_bastion_service ? oci_bastion_session.ssh_via_bastion_service[0].id : var.vm_user + bastion_private_key = tls_private_key.public_private_key_pair.private_key_pem + } + } + + provisioner "file" { + content = data.template_file.configure_local_security.rendered + destination = local.security_script + + connection { + type = "ssh" + host = data.oci_core_vnic.drupal_vnic1.private_ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + bastion_host = var.use_bastion_service ? "host.bastion.${var.bastion_service_region}.oci.oraclecloud.com" : oci_core_instance.bastion_instance[0].public_ip + bastion_user = var.use_bastion_service ? oci_bastion_session.ssh_via_bastion_service[0].id : var.vm_user + bastion_private_key = tls_private_key.public_private_key_pair.private_key_pem + } + } + + provisioner "file" { + content = data.template_file.create_drupal_db.rendered + destination = local.create_drupal_db + + connection { + type = "ssh" + host = data.oci_core_vnic.drupal_vnic1.private_ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + bastion_host = var.use_bastion_service ? "host.bastion.${var.bastion_service_region}.oci.oraclecloud.com" : oci_core_instance.bastion_instance[0].public_ip + bastion_user = var.use_bastion_service ? oci_bastion_session.ssh_via_bastion_service[0].id : var.vm_user + bastion_private_key = tls_private_key.public_private_key_pair.private_key_pem + } + } + + provisioner "file" { + content = data.template_file.install_drupal.rendered + destination = local.install_drupal + + connection { + type = "ssh" + host = data.oci_core_vnic.drupal_vnic1.private_ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + bastion_host = var.use_bastion_service ? "host.bastion.${var.bastion_service_region}.oci.oraclecloud.com" : oci_core_instance.bastion_instance[0].public_ip + bastion_user = var.use_bastion_service ? oci_bastion_session.ssh_via_bastion_service[0].id : var.vm_user + bastion_private_key = tls_private_key.public_private_key_pair.private_key_pem + } + } + + provisioner "remote-exec" { + connection { + type = "ssh" + host = data.oci_core_vnic.drupal_vnic1.private_ip_address + agent = false + timeout = "5m" + user = var.vm_user + private_key = tls_private_key.public_private_key_pair.private_key_pem + bastion_host = var.use_bastion_service ? "host.bastion.${var.bastion_service_region}.oci.oraclecloud.com" : oci_core_instance.bastion_instance[0].public_ip + bastion_user = var.use_bastion_service ? oci_bastion_session.ssh_via_bastion_service[0].id : var.vm_user + bastion_private_key = tls_private_key.public_private_key_pair.private_key_pem + } + + inline = [ + "chmod +x ${local.php_script}", + "sudo ${local.php_script}", + "chmod +x ${local.security_script}", + "sudo ${local.security_script}", + "chmod +x ${local.create_drupal_db}", + "sudo ${local.create_drupal_db}", + "chmod +x ${local.install_drupal}", + "sudo ${local.install_drupal}" + ] + + } + +} + +# Create drupalImage + +resource "oci_core_image" "drupal_instance_image" { + count = var.numberOfNodes > 1 ? 1 : 0 + depends_on = [null_resource.drupal_provisioner_with_bastion] + compartment_id = var.compartment_ocid + instance_id = oci_core_instance.drupal.id + display_name = "drupal_instance_image" + defined_tags = var.defined_tags +} + +resource "oci_core_instance" "drupal_from_image" { + count = var.numberOfNodes > 1 ? var.numberOfNodes - 1 : 0 + availability_domain = var.availability_domain_name == "" ? lookup(data.oci_identity_availability_domains.ADs.availability_domains[0], "name") : var.availability_domain_name + compartment_id = var.compartment_ocid + display_name = "${var.label_prefix}${var.display_name}${count.index + 2}" + shape = var.shape + + dynamic "shape_config" { + for_each = local.is_flexible_node_shape ? [1] : [] + content { + memory_in_gbs = var.flex_shape_memory + ocpus = var.flex_shape_ocpus + } + } + + create_vnic_details { + subnet_id = var.drupal_subnet_id + display_name = "${var.label_prefix}${var.display_name}${count.index + 2}" + assign_public_ip = false + hostname_label = "${var.display_name}${count.index + 2}" + } + + dynamic "agent_config" { + for_each = var.numberOfNodes > 1 ? [1] : [] + content { + are_all_plugins_disabled = false + is_management_disabled = false + is_monitoring_disabled = false + plugins_config { + desired_state = "ENABLED" + name = "Bastion" + } + } + } + + metadata = { + ssh_authorized_keys = var.ssh_authorized_keys + } + + source_details { + source_id = oci_core_image.drupal_instance_image[0].id + source_type = "image" + } + + defined_tags = var.defined_tags + + provisioner "local-exec" { + command = "sleep 240" + } +} + +resource "oci_bastion_session" "ssh_via_bastion_service2plus" { + depends_on = [oci_core_instance.drupal] + count = var.numberOfNodes > 1 && var.use_bastion_service ? var.numberOfNodes - 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.drupal_from_image[count.index].id + target_resource_operating_system_user_name = "opc" + target_resource_port = 22 + target_resource_private_ip_address = oci_core_instance.drupal_from_image[count.index].private_ip + } + + display_name = "ssh_via_bastion_service_to_drupal${count.index + 2}" + key_type = "PUB" + session_ttl_in_seconds = 10800 +} + +resource "oci_load_balancer" "lb01" { + count = var.numberOfNodes > 1 ? 1 : 0 + shape = var.lb_shape + + dynamic "shape_details" { + for_each = local.is_flexible_lb_shape ? [1] : [] + content { + minimum_bandwidth_in_mbps = var.flex_lb_min_shape + maximum_bandwidth_in_mbps = var.flex_lb_max_shape + } + } + + dynamic "reserved_ips" { + for_each = var.numberOfNodes > 1 ? [1] : [] + content { + id = oci_core_public_ip.drupal_public_ip_for_multi_node[0].id + } + } + compartment_id = var.compartment_ocid + + subnet_ids = [ + var.lb_subnet_id, + ] + + display_name = "drupal_lb" + defined_tags = var.defined_tags +} + +resource "oci_load_balancer_backend_set" "lb_bes_drupal" { + count = var.numberOfNodes > 1 ? 1 : 0 + name = "drupalLBBackentSet" + load_balancer_id = oci_load_balancer.lb01[count.index].id + policy = "ROUND_ROBIN" + + health_checker { + port = "80" + protocol = "HTTP" + response_body_regex = ".*" + url_path = "/" + interval_ms = "10000" + return_code = "200" + timeout_in_millis = "3000" + retries = "3" + } +} + +resource "oci_load_balancer_listener" "lb_listener_drupal" { + count = var.numberOfNodes > 1 ? 1 : 0 + load_balancer_id = oci_load_balancer.lb01[count.index].id + name = "http" + default_backend_set_name = oci_load_balancer_backend_set.lb_bes_drupal[count.index].name + port = 80 + protocol = "HTTP" + +} + +resource "oci_load_balancer_backend" "lb_be_drupal1" { + count = var.numberOfNodes > 1 ? 1 : 0 + load_balancer_id = oci_load_balancer.lb01[0].id + backendset_name = oci_load_balancer_backend_set.lb_bes_drupal[0].name + ip_address = oci_core_instance.drupal.private_ip + port = 80 + backup = false + drain = false + offline = false + weight = 1 +} + +resource "oci_load_balancer_backend" "lb_be_drupal2plus" { + count = var.numberOfNodes > 1 ? var.numberOfNodes - 1 : 0 + load_balancer_id = oci_load_balancer.lb01[0].id + backendset_name = oci_load_balancer_backend_set.lb_bes_drupal[0].name + ip_address = oci_core_instance.drupal_from_image[count.index].private_ip + port = 80 + backup = false + drain = false + offline = false + weight = 1 +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..b0a47bb --- /dev/null +++ b/outputs.tf @@ -0,0 +1,31 @@ +## Copyright (c) 2022 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 + +output "drupal_user_name" { + value = var.drupal_name +} + +output "drupal_schema_name" { + value = var.drupal_schema +} + +output "public_ip" { + value = var.numberOfNodes > 1 ? oci_core_public_ip.drupal_public_ip_for_multi_node.*.ip_address : oci_core_public_ip.drupal_public_ip_for_single_node.*.ip_address +} + +output "drupal_nodes_ids" { + value = concat(oci_core_instance.drupal.*.id, oci_core_instance.drupal_from_image.*.id) +} + +output "drupal_host_name" { + value = concat(oci_core_instance.drupal.*.display_name, oci_core_instance.drupal_from_image.*.display_name) +} + +output "generated_ssh_private_key" { + value = tls_private_key.public_private_key_pair.private_key_pem + sensitive = true +} + +output "bastion_ssh_metadata" { + value = concat(oci_bastion_session.ssh_via_bastion_service.*.ssh_metadata, oci_bastion_session.ssh_via_bastion_service2plus.*.ssh_metadata) +} \ No newline at end of file diff --git a/scripts/configure_local_security.sh b/scripts/configure_local_security.sh new file mode 100644 index 0000000..e095996 --- /dev/null +++ b/scripts/configure_local_security.sh @@ -0,0 +1,13 @@ +#!/bin/bash +#set -x + +firewall-cmd --zone=public --permanent --add-port=80/tcp +firewall-cmd --zone=public --permanent --add-port=443/tcp +firewall-cmd --reload + +chcon --type httpd_sys_rw_content_t /var/www/html +chcon --type httpd_sys_rw_content_t /var/www/html/sites/* +chcon --type httpd_sys_rw_content_t /var/www/html/* +setsebool -P httpd_can_network_connect_db 1 + +echo "Local Security Granted !" diff --git a/scripts/create_drupal_db.sh b/scripts/create_drupal_db.sh new file mode 100644 index 0000000..23bbf73 --- /dev/null +++ b/scripts/create_drupal_db.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +drupal_schema="${drupal_schema}" +drupal_name="${drupal_name}" +drupal_password="${drupal_password}" + +mysqlsh --user ${admin_username} --password=${admin_password} --host ${mds_ip} --sql -e "CREATE DATABASE $drupal_schema;" +mysqlsh --user ${admin_username} --password=${admin_password} --host ${mds_ip} --sql -e "CREATE USER $drupal_name identified by '$drupal_password';" +mysqlsh --user ${admin_username} --password=${admin_password} --host ${mds_ip} --sql -e "GRANT ALL PRIVILEGES ON $drupal_schema.* TO $drupal_name;" + +echo "Drupal Database and User created !" +echo "DRUPAL USER = $drupal_name" +echo "DRUPAL SCHEMA = $drupa_schema" diff --git a/scripts/htaccess b/scripts/htaccess new file mode 100644 index 0000000..35e4cab --- /dev/null +++ b/scripts/htaccess @@ -0,0 +1,11 @@ +# BEGIN Drupal + +RewriteEngine On +RewriteBase / +RewriteRule ^index\.php$ - [L] +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule . /index.php [L] + +# END Drupal + diff --git a/scripts/index.html b/scripts/index.html new file mode 100644 index 0000000..916a107 --- /dev/null +++ b/scripts/index.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/scripts/install_drupal.sh b/scripts/install_drupal.sh new file mode 100644 index 0000000..da8c9fc --- /dev/null +++ b/scripts/install_drupal.sh @@ -0,0 +1,54 @@ +#!/bin/bash +#set -x + +export use_shared_storage='${use_shared_storage}' + +if [[ $use_shared_storage == "true" ]]; then + echo "Mount NFS share: ${drupal_shared_working_dir}" + yum install -y -q nfs-utils + mkdir -p ${drupal_shared_working_dir} + echo '${mt_ip_address}:${drupal_shared_working_dir} ${drupal_shared_working_dir} nfs nosharecache,context="system_u:object_r:httpd_sys_rw_content_t:s0" 0 0' >> /etc/fstab + setsebool -P httpd_use_nfs=1 + mount ${drupal_shared_working_dir} + mount + echo "NFS share mounted." + cd ${drupal_shared_working_dir} +else + echo "No mount NFS share. Moving to /var/www/html" + cd /var/www/html +fi + +wget https://www.drupal.org/download-latest/tar.gz + +if [[ $use_shared_storage == "true" ]]; then + tar zxvf tar.gz --directory ${drupal_shared_working_dir} + cp -r ${drupal_shared_working_dir}/drupal-*/* ${drupal_shared_working_dir} + rm -rf ${drupal_shared_working_dir}/drupal-* + cp ${drupal_shared_working_dir}/sites/default/default.settings.php sites/default/settings.php +else + tar zxvf tar.gz --directory /var/www/html + cp -r /var/www/html/drupal-*/* /var/www/html + rm -rf /var/www/html/drupal-* + cp /var/www/html/sites/default/default.settings.php sites/default/settings.php +fi + +if [[ $use_shared_storage == "true" ]]; then + echo "... Changing /etc/httpd/conf/httpd.conf with Document set to new shared NFS space ..." + sed -i 's/"\/var\/www\/html"/"\${drupal_shared_working_dir}"/g' /etc/httpd/conf/httpd.conf + echo "... /etc/httpd/conf/httpd.conf with Document set to new shared NFS space ..." + chown apache:apache -R ${drupal_shared_working_dir} + sed -i '/AllowOverride None/c\AllowOverride All' /etc/httpd/conf/httpd.conf + cp /home/opc/htaccess ${drupal_shared_working_dir}/.htaccess + rm /home/opc/htaccess + cp /home/opc/index.html ${drupal_shared_working_dir}/index.html + rm /home/opc/index.html + chown apache:apache ${drupal_shared_working_dir}/index.html +else + chown apache:apache -R /var/www/html + sed -i '/AllowOverride None/c\AllowOverride All' /etc/httpd/conf/httpd.conf +fi + +systemctl start httpd +systemctl enable httpd + +echo "Drupal installed and Apache started !" diff --git a/scripts/install_php74.sh b/scripts/install_php74.sh new file mode 100644 index 0000000..b6f4757 --- /dev/null +++ b/scripts/install_php74.sh @@ -0,0 +1,32 @@ +#!/bin/bash +#set -x + +yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-$(cat /etc/redhat-release | sed 's/^[^0-9]*\([0-9]\+\).*$/\1/').noarch.rpm +yum -y install https://rpms.remirepo.net/enterprise/remi-release-$(cat /etc/redhat-release | sed 's/^[^0-9]*\([0-9]\+\).*$/\1/').rpm +# Install MySQL Community Edition 8.0 +rpm -ivh https://dev.mysql.com/get/mysql80-community-release-$(uname -r | sed 's/^.*\(el[0-9]\+\).*$/\1/')-1.noarch.rpm +yum install -y mysql-shell-${mysql_version} +mkdir ~${user}/.mysqlsh +cp /usr/share/mysqlsh/prompt/prompt_256pl+aw.json ~${user}/.mysqlsh/prompt.json +echo '{ + "history.autoSave": "true", + "history.maxSize": "5000" +}' > ~${user}/.mysqlsh/options.json +chown -R ${user} ~${user}/.mysqlsh + +echo "MySQL Shell successfully installed !" + +if [[ $(uname -r | sed 's/^.*\(el[0-9]\+\).*$/\1/') == "el8" ]] +then + dnf -y module enable php:remi-7.4 + dnf -y install php php-cli php-mysqlnd php-zip php-gd php-mcrypt php-mbstring php-xml php-json php-opcache +else + yum-config-manager --enable remi-php74 + yum -y install php php-cli php-mysqlnd php-zip php-gd php-mcrypt php-mbstring php-xml php-json php-opcache +fi + +echo "MySQL Shell & PHP successfully installed !" + +yum -y install certbot mod_ssl + +echo "Certbot has been installed !" 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/variables.tf b/variables.tf new file mode 100644 index 0000000..e0b3388 --- /dev/null +++ b/variables.tf @@ -0,0 +1,210 @@ +## Copyright (c) 2022 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 "mysql_version" { + description = "The version of the Mysql Shell." + default = "8.0.26" +} + +variable "tenancy_ocid" { +} + +variable "vcn_id" { + description = "The OCID of the VCN" + default = "" +} + +variable "drupal_subnet_id" { + description = "The OCID of the drupal subnet to create the VNIC for public/private access. " + default = "" +} + +variable "lb_subnet_id" { + description = "The OCID of the Load Balancer subnet to create the VNIC for public access. " + default = "" +} + +variable "bastion_subnet_id" { + description = "The OCID of the Bastion subnet to create the VNIC for public access. " + default = "" +} + +variable "fss_subnet_id" { + description = "The OCID of the File Storage Service subnet to create the VNIC for private access. " + default = "" +} + +variable "compartment_ocid" { + description = "Compartment's OCID where VCN will be created. " +} + +variable "availability_domain_name" { + description = "The Availability Domain of the instance." + default = "" +} + +variable "display_name" { + description = "The name of the instance. " + default = "" +} + +variable "subnet_id" { + description = "The OCID of the Shell subnet to create the VNIC for public access. " + default = "" +} + +variable "shape" { + description = "Instance shape to use for master instance. " + default = "VM.Standard.E4.Flex" +} + +variable "flex_shape_ocpus" { + description = "Flex Instance shape OCPUs" + default = 1 +} + +variable "flex_shape_memory" { + description = "Flex Instance shape Memory (GB)" + default = 6 +} + +variable "lb_shape" { + default = "flexible" +} + +variable "flex_lb_min_shape" { + default = "10" +} + +variable "flex_lb_max_shape" { + default = "100" +} + + +variable "use_bastion_service" { + default = false +} + +variable "bastion_service_region" { + description = "Bastion Service Region" + default = "" +} + +variable "bastion_image_id" { + default = "" +} + +variable "bastion_shape" { + default = "VM.Standard.E4.Flex" +} + +variable "bastion_flex_shape_ocpus" { + default = 1 +} + +variable "bastion_flex_shape_memory" { + default = 1 +} + +variable "use_shared_storage" { + description = "Decide if you want to use shared NFS on OCI FSS" + default = true +} + +variable "drupal_shared_working_dir" { + description = "Decide where to store drupal data" + default = "/shareddrupal" +} + +variable "label_prefix" { + description = "To create unique identifier for multiple clusters in a compartment." + default = "" +} + +variable "assign_public_ip" { + description = "Whether the VNIC should be assigned a public IP address. Default 'false' do not assign a public IP address. " + default = true +} + +variable "ssh_authorized_keys" { + description = "Public SSH keys path to be included in the ~/.ssh/authorized_keys file for the default user on the instance. " + default = "" +} + +variable "image_id" { + description = "The OCID of an image for an instance to use. " + default = "" +} + +variable "vm_user" { + description = "The SSH user to connect to the master host." + default = "opc" +} + +variable "drupal_name" { + description = "drupal Database User Name." +} + +variable "drupal_password" { + description = "drupal Database User Password." +} + +variable "drupal_schema" { + description = "drupal MySQL Schema" +} + +variable "drupal_prefix" { + description = "drupal MySQL Prefix" + default = "drupal_" +} + +variable "admin_username" { + description = "Username od the MDS admin account" +} + +variable "admin_password" { + description = "Password for the admin user for MDS" +} + +variable "mds_ip" { + description = "Private IP of the MDS Instance" +} + +variable "numberOfNodes" { + description = "Amount of Webservers to deploy" + default = 1 +} + +variable "use_AD" { + description = "Using different Availability Domain, by default use of Fault Domain" + type = bool + default = false +} + +variable "dedicated" { + description = "Create a dedicated user and a dedicated database for each Webservers" + type = bool + default = false +} + +# Dictionary Locals +locals { + compute_flexible_shapes = [ + "VM.Standard.E3.Flex", + "VM.Standard.E4.Flex", + "VM.Standard.A1.Flex", + "VM.Optimized3.Flex" + ] +} + +# Checks if is using Flexible Compute Shapes +locals { + is_flexible_node_shape = contains(local.compute_flexible_shapes, var.shape) + is_flexible_lb_shape = var.lb_shape == "flexible" ? true : false +} + +variable "defined_tags" { + description = "Defined tags for WordPress host." + type = map(string) + default = {} +}