Refactorin'

This commit is contained in:
Greyscale 2024-12-26 22:55:39 +01:00
parent d806336734
commit e5560e39d5
Signed by: grey
GPG key ID: DDB392AE64B32D89
24 changed files with 175 additions and 339 deletions

3
cloud/aws/rds/admin.tf Normal file
View file

@ -0,0 +1,3 @@
module "admin_identity" {
source = "github.com/matthewbaggett/terraform_modules//utils/identity"
}

32
cloud/aws/rds/commons.tf Normal file
View file

@ -0,0 +1,32 @@
locals {
supported_mysql = ["5.7", "8.0"]
supported_postgres = [
"11.9", "11.21",
"12.9", "12.11", "12.12", "12.13", "12.14", "12.15", "12.16", "12.17", "12.18", "12.19", "12.20", "12.22",
"13.7", "13.8", "13.9", "13.10", "13.11", "13.12", "13.12", "13.13", "13.14", "13.15", "13.16", "13.18",
"14.3", "14.4", "14.5", "14.6", "14.7", "14.8", "14.9", "14.10", "14.11", "14.12", "14.13", "14.15",
"15.2", "15.3", "15.4", "15.5", "15.6", "15.7", "15.8", "15.10",
"16.1", "16.2", "16.3", "16.4", "16.6",
]
engines_supporting_local_write_forwarding = {
"aurora-mysql" = ["8.0"]
"aurora-postgresql" = [
"14.13", "14.15",
"15.8", "15.10",
"16.4", "16.6",
]
}
# MB: This is a hack until I get my patch into terraform's aws provider: https://github.com/hashicorp/terraform-provider-aws/pull/40700
supports_local_write_forwarding = (
local.is_mysql && contains(local.engines_supporting_local_write_forwarding.aurora-mysql, local.engine_version) ||
local.is_postgres && contains(local.engines_supporting_local_write_forwarding.aurora-postgresql, local.engine_version)
)
engine_version = (
local.is_mysql
? (var.engine_version != null ? element(local.supported_mysql, length(local.supported_mysql) - 1) : false)
: (local.is_postgres
? (var.engine_version != null ? element(local.supported_postgres, length(local.supported_postgres) - 1) : false)
: false
)
)
}

18
cloud/aws/rds/data.tf Normal file
View file

@ -0,0 +1,18 @@
data "aws_rds_engine_version" "latest" {
engine = var.engine
latest = true
filter {
name = "engine-mode"
values = ["provisioned"]
}
dynamic "filter" {
# MB: We're doing this instead of using the engine_version directly to avoid passing an empty string to the AWS API
for_each = var.engine_version != null ? [var.engine_version] : []
content {
name = "engine-version"
values = [var.engine_version]
}
}
}

View file

@ -21,14 +21,11 @@ resource "local_file" "debug" {
# write = aws_rds_cluster_endpoint.endpoint["write"].endpoint,
# read = aws_rds_cluster_endpoint.endpoint["read"].endpoint
#}
admin = {
username = module.admin_identity.username
password = nonsensitive(module.admin_identity.password)
}
admin = module.admin_identity
}
tenants = var.tenants
}))
filename = "${path.root}/.debug/aws/rds/${var.instance_name}.provided.json"
filename = "${local.debug_path}/${var.instance_name}.provided.json"
file_permission = "0600"
}
resource "local_file" "debug_result" {
@ -56,6 +53,6 @@ resource "local_file" "debug_result" {
password = nonsensitive(module.admin_identity.password)
} }, local.output_tenants)
}))
filename = "${path.root}/.debug/aws/rds/${var.instance_name}.result.json"
filename = "${local.debug_path}/${var.instance_name}.result.json"
file_permission = "0600"
}
}

View file

@ -0,0 +1,3 @@
output "endpoints" {
value = aws_db_instance.instance.endpoint
}

View file

@ -26,7 +26,7 @@ variable "application" {
}
variable "engine" {
type = string
description = "The database engine to use. This must be either aurora-mysql or aurora-postgresql"
description = "The database engine to use. This must be either mysql or postgresql"
default = "mysql"
validation {
error_message = "Must be either ${join(" or ", local.supported_engines)}."
@ -34,14 +34,22 @@ variable "engine" {
}
}
locals {
supported_engines = ["mysql", "postgresql", "mariadb", ]
is_mysql = var.engine == "mysql"
is_postgres = var.engine == "postgresql"
is_mariadb = var.engine == "mariadb"
is_mysql = var.engine == "mysql"
is_postgres = var.engine == "postgresql"
is_mariadb = var.engine == "mariadb"
}
variable "engine_version" {
type = string
default = null
validation {
error_message = "If the engine is mysql_aurora, the engine_version must be one of ${join(", ", local.supported_mysql)}."
condition = var.engine_version == null ? true : (local.is_mysql ? contains(local.supported_mysql, var.engine_version) : true)
}
validation {
error_message = "If the engine is aurora-postgresql, the engine_version must be one of ${join(", ", local.supported_postgres)}."
condition = var.engine_version == null ? true : (local.is_postgres ? contains(local.supported_postgres, var.engine_version) : true)
}
}
variable "backup_window" {
type = string

9
cloud/aws/rds/kms.tf Normal file
View file

@ -0,0 +1,9 @@
resource "aws_kms_key" "db_key" {
description = "RDS ${var.instance_name} Encryption Key"
tags = merge(
try(var.application.application_tag, {}),
{
TerraformSecretType = "RDSMasterEncryptionKey"
}
)
}

View file

@ -1,11 +1,11 @@
locals {
output_tenants = {
#for key, tenant in module.tenants : key => {
# username = tenant.username
# database = tenant.database
# password = tenant.password
# connection_string = tenant.connection_string
#}
for key, tenant in module.tenants : key => {
username = tenant.username
database = tenant.database
password = tenant.password
connection_string = tenant.connection_string
}
}
}
output "tenants" {
@ -13,4 +13,4 @@ output "tenants" {
}
output "admin" {
value = module.admin_identity
}
}

View file

@ -1,5 +1,5 @@
data "aws_rds_certificate" "default" {
id = aws_db_instance.instance.ca_cert_identifier
id = local.ca_cert_identifier
latest_valid_till = true
}
data "http" "cert_data" {

View file

@ -1,26 +1,3 @@
data "aws_rds_engine_version" "latest" {
engine = var.engine
version = var.engine_version
latest = true
}
resource "aws_kms_key" "db_key" {
description = "RDS ${var.instance_name} Encryption Key"
tags = merge(
try(var.application.application_tag, {}),
{
TerraformSecretType = "RDSMasterEncryptionKey"
}
)
}
variable "instance_class" {
type = string
description = "The instance class to use for the RDS instance"
default = "db.t4g.small"
}
module "admin_identity" {
source = "../../../utils/identity"
username_words = 2
}
variable "allocated_storage_gb" {
type = number
default = 5
@ -63,6 +40,3 @@ resource "aws_db_instance" "instance" {
{}
)
}
output "endpoints" {
value = aws_db_instance.instance.endpoint
}

View file

@ -1,5 +0,0 @@
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
data "aws_vpc" "current" {
id = data.aws_security_group.source.vpc_id
}

View file

@ -0,0 +1 @@
../aws.tf

View file

@ -0,0 +1 @@
../commons.tf

View file

@ -2,6 +2,7 @@ resource "local_file" "debug" {
content = nonsensitive(jsonencode({
rds = {
instance_name = var.instance_name,
sanitised_name = local.sanitised_name
tennants = var.tenants,
application_arn = try(var.application.arn, null),
application_name = try(var.application.name, null),
@ -11,8 +12,8 @@ resource "local_file" "debug" {
version = var.engine_version
}
resolved = {
engine = data.aws_rds_engine_version.latest[var.engine_version].engine,
version = data.aws_rds_engine_version.latest[var.engine_version].version,
engine = data.aws_rds_engine_version.latest.engine,
version = data.aws_rds_engine_version.latest.version,
match = data.aws_rds_engine_version.latest,
}
}
@ -24,7 +25,7 @@ resource "local_file" "debug" {
}
tenants = var.tenants
}))
filename = "${path.root}/.debug/aws/rds/serverless/${var.instance_name}.provided.json"
filename = "${local.debug_path}/${var.instance_name}.provided.json"
file_permission = "0600"
}
resource "local_file" "debug_result" {
@ -40,9 +41,9 @@ resource "local_file" "debug_result" {
version = var.engine_version
}
resolved = {
engine = data.aws_rds_engine_version.latest[var.engine_version].engine,
version = data.aws_rds_engine_version.latest[var.engine_version].version,
match = data.aws_rds_engine_version.latest[var.engine_version],
engine = data.aws_rds_engine_version.latest.engine,
version = data.aws_rds_engine_version.latest.version,
match = data.aws_rds_engine_version.latest,
}
}
endpoints = {
@ -54,8 +55,7 @@ resource "local_file" "debug_result" {
username = module.admin_identity.username
password = nonsensitive(module.admin_identity.password)
} }, local.output_tenants)
}))
filename = "${path.root}/.debug/aws/rds/serverless/${var.instance_name}.result.json"
filename = "${local.debug_path}/${var.instance_name}.result.json"
file_permission = "0600"
}
}

View file

@ -0,0 +1,16 @@
resource "aws_rds_cluster_endpoint" "endpoint" {
depends_on = [aws_rds_cluster_instance.instance]
for_each = { "write" = "ANY", "read" = "READER" }
cluster_endpoint_identifier = join("-", [local.sanitised_name, each.key, "endpoint"])
cluster_identifier = aws_rds_cluster.cluster.id
custom_endpoint_type = each.value
tags = merge(
try(var.application.application_tag, {}),
{}
)
}
output "endpoints" {
value = aws_rds_cluster_endpoint.endpoint
}

View file

@ -0,0 +1,33 @@
variable "scaling" {
type = object({
max_capacity = optional(number, 1)
min_capacity = optional(number, 0)
})
default = {
max_capacity = 1
min_capacity = 0
}
validation {
error_message = "max_capacity must be greater or equal to min_capacity."
condition = var.scaling.max_capacity >= var.scaling.min_capacity
}
validation {
error_message = "min_capacity must be one of 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 384."
condition = contains([0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 384], var.scaling.min_capacity)
}
validation {
error_message = "max_capacity must be one of 1, 2, 4, 8, 16, 32, 64, 128, 256, 384."
condition = contains([1, 2, 4, 8, 16, 32, 64, 128, 256, 384], var.scaling.max_capacity)
}
}
locals {
scaling = merge(var.scaling, {
min_capacity = local.is_mysql && var.engine_version == "5.7" && var.scaling.min_capacity == 0 ? 1 : var.scaling.min_capacity
})
}
variable "instance_class" {
type = string
description = "The instance class to use for the RDS instance"
default = "db.t4g.small"
}

View file

@ -1,138 +0,0 @@
variable "instance_name" {
type = string
description = "The name of the RDS serverless instance"
default = "serverless-multitennant"
}
locals {
sanitised_name = lower(replace(var.instance_name, "[^a-zA-Z0-9_ ]", "-"))
}
variable "tenants" {
type = map(object({
username = string
database = string
active = optional(bool, true)
}))
default = null
}
variable "application" {
description = "The AWS myApplication to be associated with this cluster"
type = object({
arn = string
name = string
description = string
application_tag = map(string)
})
default = null
}
variable "engine" {
type = string
description = "The database engine to use. This must be either aurora-mysql or aurora-postgresql"
default = "aurora-mysql"
validation {
error_message = "Must be either aurora-mysql or aurora-postgresql"
condition = contains(["aurora-mysql", "aurora-postgresql"], var.engine)
}
}
locals {
is_mysql = var.engine == "aurora-mysql"
is_postgres = var.engine == "aurora-postgresql"
supported_mysql = ["5.7", "8.0"]
supported_postgres = [
"11.9", "11.21",
"12.9", "12.11", "12.12", "12.13", "12.14", "12.15", "12.16", "12.17", "12.18", "12.19", "12.20", "12.22",
"13.7", "13.8", "13.9", "13.10", "13.11", "13.12", "13.12", "13.13", "13.14", "13.15", "13.16", "13.18",
"14.3", "14.4", "14.5", "14.6", "14.7", "14.8", "14.9", "14.10", "14.11", "14.12", "14.13", "14.15",
"15.2", "15.3", "15.4", "15.5", "15.6", "15.7", "15.8", "15.10",
"16.1", "16.2", "16.3", "16.4", "16.6",
]
engines_supporting_local_write_forwarding = {
"aurora-mysql" = ["8.0"]
"aurora-postgresql" = [
"14.13", "14.15",
"15.8", "15.10",
"16.4", "16.6",
]
}
# MB: This is a hack until I get my patch into terraform's aws provider: https://github.com/hashicorp/terraform-provider-aws/pull/40700
supports_local_write_forwarding = (
local.is_mysql && contains(local.engines_supporting_local_write_forwarding.aurora-mysql, local.engine_version) ||
local.is_postgres && contains(local.engines_supporting_local_write_forwarding.aurora-postgresql, local.engine_version)
)
}
variable "engine_version" {
type = string
default = null
validation {
error_message = "If the engine is mysql_aurora, the engine_version must be one of ${join(", ", local.supported_mysql)}."
condition = local.is_mysql ? contains(local.supported_mysql, var.engine_version) : true
}
validation {
error_message = "If the engine is aurora-postgresql, the engine_version must be one of ${join(", ", local.supported_postgres)}."
condition = local.is_postgres ? contains(local.supported_postgres, var.engine_version) : true
}
}
locals {
engine_version = (
local.is_mysql
? (var.engine_version != null ? element(local.supported_mysql, length(local.supported_mysql) - 1) : false)
: (local.is_postgres
? (var.engine_version != null ? element(local.supported_postgres, length(local.supported_postgres) - 1) : false)
: false
)
)
}
variable "scaling" {
type = object({
max_capacity = optional(number, 1)
min_capacity = optional(number, 0)
})
default = {
max_capacity = 1
min_capacity = 0
}
validation {
error_message = "max_capacity must be greater or equal to min_capacity."
condition = var.scaling.max_capacity >= var.scaling.min_capacity
}
validation {
error_message = "min_capacity must be one of 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 384."
condition = contains([0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 384], var.scaling.min_capacity)
}
validation {
error_message = "max_capacity must be one of 1, 2, 4, 8, 16, 32, 64, 128, 256, 384."
condition = contains([1, 2, 4, 8, 16, 32, 64, 128, 256, 384], var.scaling.max_capacity)
}
}
locals {
scaling = merge(var.scaling, {
min_capacity = local.is_mysql && var.engine_version == "5.7" && var.scaling.min_capacity == 0 ? 1 : var.scaling.min_capacity
})
}
variable "backup_window" {
type = string
description = "The daily time range during which automated backups are created if automated backups are enabled."
default = "03:00-05:00"
}
variable "backup_retention_period_days" {
type = number
default = 30
validation {
error_message = "backup_retention_period_days must be between 1 and 35."
condition = var.backup_retention_period_days >= 1 && var.backup_retention_period_days <= 35
}
}
variable "skip_final_snapshot" {
type = bool
description = "Determines whether a final DB snapshot is created before the DB cluster is deleted."
default = false
}
variable "enable_performance_insights" {
type = bool
default = false
}

View file

@ -0,0 +1 @@
../inputs.tf

View file

@ -1,16 +0,0 @@
locals {
output_tenants = {
for key, tenant in module.tenants : key => {
username = tenant.username
database = tenant.database
password = tenant.password
connection_string = tenant.connection_string
}
}
}
output "tenants" {
value = local.output_tenants
}
output "admin" {
value = module.admin_identity
}

View file

@ -0,0 +1 @@
../outputs.tf

View file

@ -1,14 +0,0 @@
data "aws_rds_certificate" "default" {
id = aws_rds_cluster_instance.instance.ca_cert_identifier
latest_valid_till = true
}
data "http" "cert_data" {
url = "https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem"
}
output "cert" {
value = data.aws_rds_certificate.default
}
output "cert_data" {
value = data.http.cert_data.response_body
}

View file

@ -0,0 +1 @@
../rds.certificate.tf

View file

@ -1,30 +1,8 @@
data "aws_rds_engine_version" "latest" {
for_each = toset([var.engine_version])
engine = var.engine
version = local.engine_version
latest = true
filter {
name = "engine-mode"
values = ["provisioned"]
}
}
resource "aws_kms_key" "db_key" {
description = "RDS ${var.instance_name} Encryption Key"
tags = merge(
try(var.application.application_tag, {}),
{
TerraformSecretType = "RDSMasterEncryptionKey"
}
)
}
module "admin_identity" {
source = "../../../../utils/identity"
}
resource "aws_rds_cluster" "cluster" {
cluster_identifier = local.sanitised_name
engine_mode = "provisioned"
engine = data.aws_rds_engine_version.latest[var.engine_version].engine
engine_version = data.aws_rds_engine_version.latest[var.engine_version].version
engine = data.aws_rds_engine_version.latest.engine
engine_version = data.aws_rds_engine_version.latest.version
database_name = module.admin_identity.username
master_username = module.admin_identity.username
master_password = module.admin_identity.password
@ -83,19 +61,4 @@ resource "aws_rds_cluster_instance" "instance" {
)
}
resource "aws_rds_cluster_endpoint" "endpoint" {
depends_on = [aws_rds_cluster_instance.instance]
for_each = { "write" = "ANY", "read" = "READER" }
cluster_endpoint_identifier = join("-", [local.sanitised_name, each.key, "endpoint"])
cluster_identifier = aws_rds_cluster.cluster.id
custom_endpoint_type = each.value
tags = merge(
try(var.application.application_tag, {}),
{}
)
}
output "endpoints" {
value = aws_rds_cluster_endpoint.endpoint
}

View file

@ -1,24 +0,0 @@
resource "aws_security_group" "rds" {
name = join("-", [var.instance_name, "rds"])
description = "RDS Security Group for ${var.instance_name}"
vpc_id = data.aws_vpc.current.id
tags = merge(
try(var.application.application_tag, {}),
{}
)
}
variable "source_security_group_id" {
type = string
description = "The security group ID to allow access to the RDS instance"
}
data "aws_security_group" "source" {
id = var.source_security_group_id
}
resource "aws_security_group_rule" "sgr" {
security_group_id = aws_security_group.rds.id
type = "ingress"
protocol = "tcp"
from_port = var.engine == "aurora-postgres" ? 5432 : 3306
to_port = var.engine == "aurora-postgres" ? 5432 : 3306
source_security_group_id = var.source_security_group_id
}

View file

@ -0,0 +1 @@
../security-groups.tf

View file

@ -0,0 +1,9 @@
locals {
supported_engines = ["aurora-mysql", "aurora-postgresql", ]
ca_cert_identifier = aws_rds_cluster_instance.instance.ca_cert_identifier
debug_path = "${path.root}/.debug/aws/rds/serverless/${var.instance_name}"
endpoints = {
write = aws_rds_cluster_endpoint.endpoint["write"].endpoint
read = aws_rds_cluster_endpoint.endpoint["read"].endpoint
}
}

View file

@ -1,22 +0,0 @@
variable "aws_subnets" {
description = "Pass an aws_subnets data object to the module"
type = object({
ids = list(string)
})
}
data "aws_subnets" "subnets" {
filter {
name = "subnet-id"
values = var.aws_subnets.ids
}
}
resource "aws_db_subnet_group" "sg" {
name = lower(join("-", [var.instance_name, "subnet-group"]))
subnet_ids = data.aws_subnets.subnets.ids
tags = merge(
try(var.application.application_tag, {}),
{
Name = "${var.instance_name} Subnet Group"
}
)
}

View file

@ -0,0 +1 @@
../subnets.tf

View file

@ -1,26 +0,0 @@
terraform {
required_version = "~> 1.6"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.0"
}
local = {
source = "hashicorp/local"
version = "~> 2.0"
}
null = {
source = "hashicorp/null"
version = "~> 3.0"
}
ssh = {
source = "matthewbaggett/ssh"
version = "~> 0.1"
}
}
}

View file

@ -0,0 +1 @@
../terraform.tf

View file

@ -0,0 +1,8 @@
locals {
supported_engines = ["mysql", "postgresql", "mariadb", ]
ca_cert_identifier = aws_db_instance.instance.ca_cert_identifier
debug_path = "${path.root}/.debug/aws/rds/${var.instance_name}"
endpoints = {
write = aws_db_instance.instance.endpoint
}
}