diff --git a/_examples/MariaDb/main.tf b/_examples/MariaDb/main.tf new file mode 100644 index 0000000..acd0623 --- /dev/null +++ b/_examples/MariaDb/main.tf @@ -0,0 +1,92 @@ +provider "aws" { + region = "ap-south-1" +} + +module "vpc" { + source = "clouddrove/vpc/aws" + version = "0.15.0" + + name = "vpc" + environment = "test" + label_order = ["environment", "name"] + + cidr_block = "10.0.0.0/16" +} + +module "private_subnets" { + source = "clouddrove/subnet/aws" + version = "0.15.3" + + name = "subnets" + environment = "test" + label_order = ["environment", "name"] + + availability_zones = ["ap-south-1a", "ap-south-1b"] + vpc_id = module.vpc.vpc_id + type = "public-private" + igw_id = module.vpc.igw_id + cidr_block = module.vpc.vpc_cidr_block + ipv6_cidr_block = module.vpc.ipv6_cidr_block +} + +module "security_group" { + source = "clouddrove/security-group/aws" + version = "0.15.0" + + name = "security-group" + environment = "test" + protocol = "tcp" + label_order = ["environment", "name"] + vpc_id = module.vpc.vpc_id + allowed_ip = ["0.0.0.0/0"] + allowed_ports = [3306] +} + + +module "mariadb" { + source = "../../" + + name = "sg" + application = "clouddrove" + environment = "test" + label_order = ["environment", "name"] + + engine = "mariadb" + engine_version = "10.6.7" + instance_class = "db.t2.small" + allocated_storage = 50 + + # kms_key_id = "arm:aws:kms:::key/" + + # DB Details + database_name = "test" + username = "user" + password = "esfsgcGdfawAhdxtfjm!" + port = "3306" + + vpc_security_group_ids = [module.security_group.security_group_ids] + + maintenance_window = "Mon:00:00-Mon:03:00" + backup_window = "03:00-06:00" + multi_az = false + + family = "mariadb10.6" + # disable backups to create DB faster + backup_retention_period = 0 + + enabled_cloudwatch_logs_exports = ["audit", "general"] + + # DB subnet group + subnet_ids = module.private_subnets.public_subnet_id + publicly_accessible = true + + # DB parameter group + + # DB option group + major_engine_version = "10.6" + + # Snapshot name upon DB deletion + + # Database Deletion Protection + deletion_protection = false +} diff --git a/_examples/PostgreSQL/main.tf b/_examples/PostgreSQL/main.tf new file mode 100644 index 0000000..709d030 --- /dev/null +++ b/_examples/PostgreSQL/main.tf @@ -0,0 +1,94 @@ +provider "aws" { + region = "ap-south-1" +} + +module "vpc" { + source = "clouddrove/vpc/aws" + version = "0.15.0" + + name = "vpc" + environment = "test" + label_order = ["environment", "name"] + + cidr_block = "10.0.0.0/16" +} + +module "private_subnets" { + source = "clouddrove/subnet/aws" + version = "0.15.3" + + name = "subnets" + environment = "test" + label_order = ["name", "environment"] + + nat_gateway_enabled = true + + availability_zones = ["ap-south-1a", "ap-south-1b"] + vpc_id = module.vpc.vpc_id + type = "public-private" + igw_id = module.vpc.igw_id + cidr_block = module.vpc.vpc_cidr_block + ipv6_cidr_block = module.vpc.ipv6_cidr_block + assign_ipv6_address_on_creation = false +} + + +module "security_group" { + source = "clouddrove/security-group/aws" + version = "0.15.0" + + name = "security-group" + environment = "test" + protocol = "tcp" + label_order = ["environment", "name"] + vpc_id = module.vpc.vpc_id + allowed_ip = ["0.0.0.0/0"] + allowed_ports = [5432] +} + +module "postgresql" { + source = "../../" + + name = "sg" + application = "clouddrove" + environment = "test" + label_order = ["environment", "name"] + + engine = "postgres" + engine_version = "14.1" + instance_class = "db.t3.medium" + allocated_storage = 50 + storage_encrypted = true + # kms_key_id = "arm:aws:kms:::key/" + family = "postgres14" + # DB Details + database_name = "test" + username = "dbname" + password = "esfsgcGdfawAhdxtfjm!" + port = "5432" + + vpc_security_group_ids = [module.security_group.security_group_ids] + + maintenance_window = "Mon:00:00-Mon:03:00" + backup_window = "03:00-06:00" + multi_az = false + + + # disable backups to create DB faster + backup_retention_period = 0 + + enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"] + + # DB subnet group + subnet_ids = module.private_subnets.public_subnet_id + publicly_accessible = true + + # DB option group + major_engine_version = "14" + + # Snapshot name upon DB deletion + + # Database Deletion Protection + deletion_protection = false + +} diff --git a/_examples/complete-mysql/main.tf b/_examples/complete-mysql/main.tf index 52d557f..a7f2aaa 100644 --- a/_examples/complete-mysql/main.tf +++ b/_examples/complete-mysql/main.tf @@ -15,13 +15,13 @@ module "vpc" { module "subnets" { source = "clouddrove/subnet/aws" - version = "0.15.0" + version = "0.15.3" name = "subnets" environment = "test" label_order = ["environment", "name"] - availability_zones = ["ap-south-1a", "ap-south-1b", "ap-south-1c"] + availability_zones = ["ap-south-1a", "ap-south-1b"] vpc_id = module.vpc.vpc_id type = "public" igw_id = module.vpc.igw_id @@ -91,7 +91,6 @@ module "mysql" { # Database Deletion Protection deletion_protection = false - parameters = [ { name = "character_set_client" diff --git a/_examples/oracle_db/main.tf b/_examples/oracle_db/main.tf index 32c8776..51bdd71 100644 --- a/_examples/oracle_db/main.tf +++ b/_examples/oracle_db/main.tf @@ -1,5 +1,5 @@ provider "aws" { - region = "eu-west-1" + region = "ap-south-1" } module "vpc" { @@ -23,7 +23,7 @@ module "private_subnets" { nat_gateway_enabled = true - availability_zones = ["eu-west-1a", "eu-west-1b"] + availability_zones = ["ap-south-1a", "ap-south-1b"] vpc_id = module.vpc.vpc_id type = "public-private" igw_id = module.vpc.igw_id @@ -43,7 +43,7 @@ module "security_group" { label_order = ["environment", "name"] vpc_id = module.vpc.vpc_id allowed_ip = ["0.0.0.0/0"] - allowed_ports = [3306] + allowed_ports = [1521] } module "oracle" { @@ -58,9 +58,9 @@ module "oracle" { engine_version = "19.0.0.0.ru-2021-10.rur-2021-10.r1" instance_class = "db.t3.medium" allocated_storage = 50 - + storage_encrypted = true # kms_key_id = "arm:aws:kms:::key/" - + family = "oracle-se2-19" # DB Details database_name = "test" username = "admin" @@ -82,18 +82,12 @@ module "oracle" { # DB subnet group subnet_ids = module.private_subnets.public_subnet_id publicly_accessible = true - - # DB parameter group - parameter_group_name = "default.oracle-se2-19" - option_group_name = "default:oracle-se2-19" - # DB option group - major_engine_version = "12.1" + major_engine_version = "19" # Snapshot name upon DB deletion # Database Deletion Protection deletion_protection = false - } diff --git a/_examples/replica-mysql/main.tf b/_examples/replica-mysql/main.tf index 339a74f..c639f9a 100644 --- a/_examples/replica-mysql/main.tf +++ b/_examples/replica-mysql/main.tf @@ -15,7 +15,7 @@ module "vpc" { module "subnets" { source = "clouddrove/subnet/aws" - version = "0.15.0" + version = "0.15.3" name = "subnets" environment = "test" @@ -142,7 +142,7 @@ module "master" { module "replica" { source = "../../" - identifier = "demodb-replica-mysql" + # identifier = "demodb-replica-mysql" # Source database. For cross-region use this_db_instance_arn replicate_source_db = module.master.id diff --git a/main.tf b/main.tf index 753ea1e..a357a50 100644 --- a/main.tf +++ b/main.tf @@ -14,67 +14,136 @@ module "labels" { label_order = var.label_order } -resource "aws_db_subnet_group" "main" { +locals { + family = coalesce(var.family, join(local.family_separator, [var.engine, local.major_version_substring])) + family_separator = local.is_mssql || local.is_oracle || local.is_postgres || local.is_mariadb ? "-" : "" + major_version_substring = local.is_mssql ? substr(local.major_version, 0, length(local.major_version) - 1) : local.major_version + is_mssql = local.engine_class == "sqlserver" + is_oracle = local.engine_class == "oracle" + is_mariadb = local.engine_class == "mariadb" + is_postgres = local.engine_class == "postgres" + major_version = join(".", local.version_chunk[0]) + engine_class = element(split("-", var.engine), 0) + version_chunk = chunklist(split(".", local.engine_version), local.is_single_major_version ? 1 : 2) + engine_version = coalesce(var.engine_version, local.engine_defaults[local.engine_class]["version"]) + options = [] + subnet_group = length(aws_db_subnet_group.db_subnet_group.*.id) > 0 ? aws_db_subnet_group.db_subnet_group[0].id : var.existing_subnet_group + parameter_group = length(aws_db_parameter_group.main.*.id) > 0 ? aws_db_parameter_group.main[0].id : var.existing_parameter_group_name + option_group = length(aws_db_option_group.db_option_group.*.id) > 0 ? aws_db_option_group.db_option_group[0].id : var.existing_option_group_name + performance_insights_enabled = var.performance_insights_retention_period == 0 ? false : true + performance_insights_retention_period = var.performance_insights_retention_period > 7 ? 731 : 7 + storage_size = coalesce(var.storage_size, lookup(local.engine_defaults[local.engine_class], "storage_size", 10)) + license_model = lookup(local.engine_defaults[local.engine_class], "license", null) + port = coalesce(var.port, lookup(local.engine_defaults[local.engine_class], "port", "3306")) + + is_single_major_version = contains( + lookup(local.engine_defaults[local.engine_class], "single_major_version", []), + element(split(".", local.engine_version), 0) + ) + engine_defaults = { + mariadb = { + version = "10.4.13" + } + mysql = { + version = "8.0.21" + } + oracle = { + port = "1521" + version = "19.0.0.0.ru-2020-10.rur-2020-10.r1" + storage_size = "100" + license = "license-included" + jdbc_proto = "oracle:thin" + single_major_version = ["18", "19"] + } + postgres = { + port = "5432" + version = "12.4" + jdbc_proto = "postgresql" + single_major_version = ["10", "11", "12"] + } + sqlserver = { + port = "1433" + version = "15.00.4043.16.v1" + storage_size = "200" + license = "license-included" + jdbc_proto = "sqlserver" + } + } + parameter_lookup = var.timezone == "" || local.is_mssql ? "none" : "timezone" + parameters = { + "none" = [] + "timezone" = [ + { + name = local.is_postgres ? "timezone" : "time_zone" + value = var.timezone + }, + ] + } + same_region_replica = var.read_replica && length(split(":", var.source_db)) == 1 +} + +resource "aws_db_subnet_group" "db_subnet_group" { count = var.enabled ? 1 : 0 - name_prefix = format("subnet%s%s", var.delimiter, module.labels.id) description = format("Database subnet group for%s%s", var.delimiter, module.labels.id) - subnet_ids = var.subnet_ids - tags = merge( - module.labels.tags, - { - "Name" = format("%s%ssubnet", module.labels.id, var.delimiter) - } - ) + # name_prefix = format("subnet%s%s", var.delimiter, module.labels.id) + subnet_ids = var.subnet_ids + tags = module.labels.tags + + + lifecycle { + create_before_destroy = true + } + } resource "aws_db_parameter_group" "main" { - count = var.enabled && var.engine == "mysql" ? 1 : 0 + count = var.enabled ? 1 : 0 - name_prefix = format("subnet%s%s", module.labels.id, var.delimiter) description = format("Database parameter group for%s%s", var.delimiter, module.labels.id) + name_prefix = format("subnet%s%s", module.labels.id, var.delimiter) family = var.family dynamic "parameter" { - for_each = var.parameters + for_each = concat(var.parameters, local.parameters[local.parameter_lookup]) content { + apply_method = lookup(parameter.value, "apply_method", null) name = parameter.value.name value = parameter.value.value - apply_method = lookup(parameter.value, "apply_method", null) } } + lifecycle { + create_before_destroy = true + } + tags = merge( module.labels.tags, { "Name" = format("%s%sparameter", module.labels.id, var.delimiter) } ) - - lifecycle { - create_before_destroy = true - } } -resource "aws_db_option_group" "main" { +resource "aws_db_option_group" "db_option_group" { count = var.enabled ? 1 : 0 - name_prefix = format("subnet%s%s", module.labels.id, var.delimiter) - option_group_description = var.option_group_description == "" ? format("Option group for %s", module.labels.id) : var.option_group_description engine_name = var.engine major_engine_version = var.major_engine_version + name_prefix = format("subnet%s%s", module.labels.id, var.delimiter) + option_group_description = var.option_group_description == "" ? format("Option group for %s", module.labels.id) : var.option_group_description dynamic "option" { - for_each = var.options + for_each = concat(var.options, local.options) content { + db_security_group_memberships = lookup(option.value, "db_security_group_memberships", null) option_name = option.value.option_name port = lookup(option.value, "port", null) version = lookup(option.value, "version", null) - db_security_group_memberships = lookup(option.value, "db_security_group_memberships", null) vpc_security_group_memberships = lookup(option.value, "vpc_security_group_memberships", null) dynamic "option_settings" { - for_each = lookup(option.value, "option_settings", []) + for_each = lookup(option.value, "option_settings", null) content { name = lookup(option_settings.value, "name", null) value = lookup(option_settings.value, "value", null) @@ -83,7 +152,9 @@ resource "aws_db_option_group" "main" { } } - + lifecycle { + create_before_destroy = true + } tags = merge( module.labels.tags, { @@ -91,16 +162,12 @@ resource "aws_db_option_group" "main" { } ) - timeouts { delete = lookup(var.option_group_timeouts, "delete", null) } - - lifecycle { - create_before_destroy = true - } } + resource "aws_db_instance" "this" { count = var.enabled ? 1 : 0 @@ -109,24 +176,24 @@ resource "aws_db_instance" "this" { engine = var.engine engine_version = var.engine_version instance_class = var.instance_class - allocated_storage = var.allocated_storage + allocated_storage = local.storage_size storage_type = var.storage_type - storage_encrypted = true + storage_encrypted = var.storage_encrypted kms_key_id = var.kms_key_id - license_model = var.engine != "mysql" ? "bring-your-own-license" : null + license_model = var.license_model == "" ? local.license_model : var.license_model name = var.database_name username = var.username password = var.password - port = var.port + port = local.port iam_database_authentication_enabled = var.iam_database_authentication_enabled snapshot_identifier = var.snapshot_identifier vpc_security_group_ids = var.vpc_security_group_ids - db_subnet_group_name = join("", aws_db_subnet_group.main.*.id) - parameter_group_name = var.engine == "mysql" ? join("", aws_db_parameter_group.main.*.id) : var.parameter_group_name - option_group_name = var.engine == "mysql" ? join("", aws_db_option_group.main.*.id) : var.option_group_name + db_subnet_group_name = join("", aws_db_subnet_group.db_subnet_group.*.id) + parameter_group_name = join("", aws_db_parameter_group.main.*.id) + option_group_name = join("", aws_db_option_group.db_option_group.*.id) availability_zone = var.availability_zone multi_az = var.multi_az @@ -144,15 +211,13 @@ resource "aws_db_instance" "this" { final_snapshot_identifier = module.labels.id max_allocated_storage = var.max_allocated_storage - performance_insights_enabled = var.performance_insights_enabled - performance_insights_retention_period = var.performance_insights_enabled == true ? var.performance_insights_retention_period : null + performance_insights_enabled = local.performance_insights_enabled + performance_insights_retention_period = local.performance_insights_enabled ? local.performance_insights_retention_period : null backup_retention_period = var.backup_retention_period backup_window = var.backup_window - - character_set_name = var.character_set_name - - ca_cert_identifier = var.ca_cert_identifier + character_set_name = local.is_oracle ? var.character_set_name : null + ca_cert_identifier = var.ca_cert_identifier enabled_cloudwatch_logs_exports = var.enabled_cloudwatch_logs_exports @@ -166,4 +231,10 @@ resource "aws_db_instance" "this" { delete = lookup(var.timeouts, "delete", null) update = lookup(var.timeouts, "update", null) } + + depends_on = [ + aws_db_option_group.db_option_group, + aws_db_parameter_group.main, + aws_db_subnet_group.db_subnet_group, + ] } diff --git a/outputs.tf b/outputs.tf index 549e09b..127f06a 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,4 +1,4 @@ output "id" { - value = aws_db_option_group.main.*.id + value = aws_db_option_group.db_option_group.*.id description = "The ID of the cluster." } diff --git a/variables.tf b/variables.tf index 122278b..d925dff 100644 --- a/variables.tf +++ b/variables.tf @@ -67,12 +67,36 @@ variable "storage_type" { default = "gp2" description = "One of 'standard' (magnetic), 'gp2' (general purpose SSD), or 'io1' (provisioned IOPS SSD). The default is 'io1' if iops is specified, 'standard' if not. Note that this behaviour is different from the AWS web console, where the default is 'gp2'." } +variable "existing_subnet_group" { + type = string + default = "" + description = "The existing DB subnet group to use for this instance (OPTIONAL)" +} +variable "existing_parameter_group_name" { + type = string + default = "" + description = "The existing parameter group to use for this instance. (OPTIONAL)" +} + +variable "existing_option_group_name" { + type = string + default = "" + description = "The existing option group to use for this instance. (OPTIONAL)" + +} variable "kms_key_id" { - description = "The ARN for the KMS encryption key. If creating an encrypted replica, set this to the destination KMS ARN. If storage_encrypted is set to true and kms_key_id is not specified the default KMS key created in your account will be used" type = string default = "" + description = "The ARN for the KMS encryption key. If creating an encrypted replica, set this to the destination KMS ARN. If storage_encrypted is set to true and kms_key_id is not specified the default KMS key created in your account will be used" + +} +variable "storage_encrypted" { + type = bool + default = true + description = "The ARN for the KMS encryption key. If creating an encrypted replica, set this to the destination KMS ARN. If storage_encrypted is set to true and kms_key_id is not specified the default KMS key created in your account will be used" + } variable "replicate_source_db" { @@ -91,7 +115,6 @@ variable "license_model" { type = string default = "" description = "License model information for this DB instance. Optional, but required for some DB engines, i.e. Oracle SE1" - } variable "iam_database_authentication_enabled" { @@ -122,14 +145,12 @@ variable "instance_class" { type = string default = "" description = "The instance type of the RDS instance" - } variable "database_name" { type = string default = "test" description = "database name for the master DB" - } variable "username" { @@ -155,13 +176,23 @@ variable "vpc_security_group_ids" { default = [] description = "List of VPC security groups to associate" } - +variable "read_replica" { + description = "Specifies whether this RDS instance is a read replica." + type = string + default = false +} variable "db_subnet_group_name" { type = string default = "" description = "Name of DB subnet group. DB instance will be created in the VPC associated with the DB subnet group. If unspecified, will be created in the default VPC" } +variable "source_db" { + default = "" + type = string + description = "The ID of the source DB instance. For cross region replicas, the full ARN should be provided" +} + variable "parameter_group_description" { type = string default = "" @@ -211,6 +242,11 @@ variable "monitoring_role_arn" { description = "The ARN for the IAM role that permits RDS to send enhanced monitoring metrics to CloudWatch Logs. Must be specified if monitoring_interval is non-zero." } +variable "storage_size" { + type = string + default = "" + description = "Select RDS Volume Size in GB." +} variable "monitoring_role_name" { type = string @@ -391,7 +427,7 @@ variable "performance_insights_enabled" { variable "performance_insights_retention_period" { type = number - default = 7 + default = 0 description = "The amount of time in days to retain Performance Insights data. Either 7 (7 days) or 731 (2 years)." } diff --git a/versions.tf b/versions.tf index 5e90985..4ce185f 100644 --- a/versions.tf +++ b/versions.tf @@ -1,4 +1,10 @@ # Terraform version terraform { required_version = ">= 0.12" + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.1.15" + } + } }