Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions datastore/mongo/aws-documentdb/1.0/facets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ spec:
restore_config:
type: object
title: Restore Operations
x-ui-overrides-only: true
properties:
restore_from_snapshot:
type: boolean
Expand Down Expand Up @@ -90,6 +91,7 @@ spec:
imports:
type: object
title: Import Existing Resources
x-ui-overrides-only: true
properties:
cluster_identifier:
type: string
Expand All @@ -103,6 +105,11 @@ spec:
type: string
title: Subnet Group Name
description: Name of existing DocumentDB subnet group to import
master_password:
type: string
title: Master Password
description: Master password for the imported cluster (8+ characters)
minLength: 8
required:
- version_config
- sizing
Expand Down Expand Up @@ -133,6 +140,9 @@ imports:
- name: subnet_group_name
resource_address: aws_docdb_subnet_group.main
required: true
- name: master_password
resource_address: random_password.master[0]
required: true
iac:
validated_files:
- main.tf
Expand Down
10 changes: 6 additions & 4 deletions datastore/mongo/aws-documentdb/1.0/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ locals {


# Security group ID - use imported one if importing, otherwise use created one
security_group_id = local.is_import ? var.instance.spec.imports.security_group_id : aws_security_group.documentdb[0].id
security_group_id = local.is_import ? var.instance.spec.imports.security_group_id : aws_security_group.documentdb.id

# Extract cluster information
cluster_endpoint = aws_docdb_cluster.main.endpoint
cluster_port = aws_docdb_cluster.main.port
master_username = aws_docdb_cluster.main.master_username

# Handle password for imported vs new clusters
# For imported clusters, we can't access the actual password
master_password = local.is_import ? "*** IMPORTED - PASSWORD NOT ACCESSIBLE ***" : (try(var.instance.spec.restore_config.restore_from_snapshot, false) ? var.instance.spec.restore_config.master_password : random_password.master[0].result)
# Handle password logic:
# - restore_from_snapshot → use restore password
# - import → use imported master password
# - new cluster → use generated random password
master_password = (var.instance.spec.restore_config.restore_from_snapshot ? var.instance.spec.restore_config.master_password : random_password.master[0].result)

# Connection string for MongoDB
connection_string = "mongodb://${local.master_username}:${local.master_password}@${local.cluster_endpoint}:${local.cluster_port}/?tls=true&replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false"
Expand Down
21 changes: 13 additions & 8 deletions datastore/mongo/aws-documentdb/1.0/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@

# Random password generation for new clusters (when not restoring or importing)
resource "random_password" "master" {
count = local.is_import || var.instance.spec.restore_config.restore_from_snapshot ? 0 : 1
count = var.instance.spec.restore_config.restore_from_snapshot ? 0 : 1
length = 16
special = true
override_special = "!#$%&*+-=?^_`{|}~" # Exclude problematic characters: /, @, ", and space

lifecycle {
ignore_changes = [
length,
override_special,
]
}
}

# DocumentDB Subnet Group (only for new clusters, not imported)
resource "aws_docdb_subnet_group" "main" {
count = local.is_import ? 0 : 1
name = "${var.instance_name}-${var.environment.unique_name}"
subnet_ids = var.inputs.vpc_details.attributes.private_subnet_ids

Expand All @@ -21,13 +27,13 @@ resource "aws_docdb_subnet_group" "main" {
lifecycle {
ignore_changes = [
name,
subnet_ids,
]
}
}

# Security Group for DocumentDB (only for new clusters, not imported)
resource "aws_security_group" "documentdb" {
count = local.is_import ? 0 : 1
name_prefix = "${var.instance_name}-${var.environment.unique_name}-"
vpc_id = var.inputs.vpc_details.attributes.vpc_id

Expand All @@ -54,6 +60,7 @@ resource "aws_security_group" "documentdb" {
ignore_changes = [
name_prefix,
name,
vpc_id,
]
}
}
Expand All @@ -80,7 +87,7 @@ resource "aws_docdb_cluster" "main" {
engine = "docdb"
engine_version = var.instance.spec.version_config.engine_version == "6.0.0" ? "5.0.0" : var.instance.spec.version_config.engine_version
master_username = var.instance.spec.restore_config.restore_from_snapshot ? var.instance.spec.restore_config.master_username : "docdbadmin"
master_password = local.is_import ? null : (var.instance.spec.restore_config.restore_from_snapshot ? var.instance.spec.restore_config.master_password : random_password.master[0].result)
master_password = local.master_password
port = var.instance.spec.version_config.port
backup_retention_period = 7
preferred_backup_window = "07:00-09:00"
Expand All @@ -91,8 +98,8 @@ resource "aws_docdb_cluster" "main" {
snapshot_identifier = var.instance.spec.restore_config.restore_from_snapshot ? var.instance.spec.restore_config.snapshot_identifier : null

# Network configuration
db_subnet_group_name = local.is_import ? var.instance.spec.imports.subnet_group_name : aws_docdb_subnet_group.main[0].name
vpc_security_group_ids = local.is_import ? [var.instance.spec.imports.security_group_id] : [aws_security_group.documentdb[0].id]
db_subnet_group_name = local.is_import ? var.instance.spec.imports.subnet_group_name : aws_docdb_subnet_group.main.name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try to import it to tf state

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deploy the resource initially through facets, state rm it, then add the import attributes, and do the release to import the resource back.

vpc_security_group_ids = local.is_import ? [var.instance.spec.imports.security_group_id] : [aws_security_group.documentdb.id]

# Parameter group (only for new clusters)
db_cluster_parameter_group_name = local.is_import ? null : aws_docdb_cluster_parameter_group.main[0].name
Expand Down Expand Up @@ -124,7 +131,6 @@ resource "aws_docdb_cluster" "main" {
skip_final_snapshot,
final_snapshot_identifier,
storage_encrypted,
tags,
]
}
}
Expand All @@ -146,7 +152,6 @@ resource "aws_docdb_cluster_instance" "cluster_instances" {
identifier,
instance_class,
cluster_identifier,
tags,
]
}
}
1 change: 1 addition & 0 deletions datastore/mongo/aws-documentdb/1.0/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ variable "instance" {
cluster_identifier = optional(string)
security_group_id = optional(string)
subnet_group_name = optional(string)
master_password = optional(string)
}), {})
})
})
Expand Down
2 changes: 2 additions & 0 deletions datastore/mongo/cosmosdb/1.0/facets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ spec:
restore_config:
type: object
title: Restore Operations
x-ui-overrides-only: true
properties:
restore_from_backup:
type: boolean
Expand Down Expand Up @@ -106,6 +107,7 @@ spec:
imports:
type: object
title: Import Existing Resources
x-ui-overrides-only: true
properties:
account_name:
type: string
Expand Down
10 changes: 10 additions & 0 deletions datastore/mysql/aws-aurora/1.0/facets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ spec:
restore_config:
type: object
title: Restore Operations
x-ui-overrides-only: true
x-ui-toggle: true
properties:
restore_from_backup:
Expand Down Expand Up @@ -121,6 +122,7 @@ spec:
imports:
type: object
title: Import Existing Resources
x-ui-overrides-only: true
x-ui-toggle: true
properties:
cluster_identifier:
Expand All @@ -135,6 +137,11 @@ spec:
type: string
title: Reader Instance Identifiers
description: Existing reader instance identifiers to import (comma-separated)
master_password:
type: string
title: Master Password
description: Master password for the imported cluster (8+ characters)
minLength: 8
required:
- version_config
- sizing
Expand Down Expand Up @@ -166,6 +173,9 @@ imports:
- name: reader_instance_identifiers
resource_address: aws_rds_cluster_instance.aurora_readers[0]
required: false
- name: master_password
resource_address: random_password.master_password[0]
required: true
iac:
validated_files:
- main.tf
Expand Down
21 changes: 14 additions & 7 deletions datastore/mysql/aws-aurora/1.0/main.tf
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# Generate a random password only when NOT restoring from backup AND NOT importing
# Excludes characters not allowed by Aurora MySQL: '/', '@', '"', ' ' (space)
resource "random_password" "master_password" {
count = (var.instance.spec.restore_config.restore_from_backup || try(var.instance.spec.imports.cluster_identifier, null) != null) ? 0 : 1
count = var.instance.spec.restore_config.restore_from_backup ? 0 : 1
length = 16
special = true
override_special = "!#$%&*+-=?^_`{|}~" # Safe special characters for Aurora MySQL

lifecycle {
ignore_changes = [
length,
override_special,
]
}
}

# Generate unique cluster identifier
Expand All @@ -21,8 +28,8 @@ locals {
imported_writer_id = try(var.instance.spec.imports.writer_instance_identifier, null)

# Handle password - don't create for restore or import
master_password = local.restore_from_backup ? var.instance.spec.restore_config.master_password : (local.is_import ? null : random_password.master_password[0].result)
master_username = local.restore_from_backup ? var.instance.spec.restore_config.master_username : (local.is_import ? null : "admin")
master_password = local.restore_from_backup ? var.instance.spec.restore_config.master_password : random_password.master_password[0].result
master_username = local.restore_from_backup ? var.instance.spec.restore_config.master_username : "admin"

# Split reader instance identifiers if provided for import
reader_instance_ids = try(var.instance.spec.imports.reader_instance_identifiers, null) != null && var.instance.spec.imports.reader_instance_identifiers != "" ? split(",", trimspace(var.instance.spec.imports.reader_instance_identifiers)) : []
Expand Down Expand Up @@ -83,10 +90,10 @@ resource "aws_rds_cluster" "aurora" {
engine = "aurora-mysql"

# When restoring from snapshot or importing, these fields must be omitted or ignored
engine_version = (local.restore_from_backup || local.is_import) ? null : var.instance.spec.version_config.engine_version
database_name = (local.restore_from_backup || local.is_import) ? null : var.instance.spec.version_config.database_name
master_username = (local.restore_from_backup || local.is_import) ? null : local.master_username
master_password = (local.restore_from_backup || local.is_import) ? null : local.master_password
engine_version = var.instance.spec.version_config.engine_version
database_name = var.instance.spec.version_config.database_name
master_username = local.master_username
master_password = local.master_password

# Backup configuration
backup_retention_period = 7 # Hardcoded - 7 days retention
Expand Down
25 changes: 4 additions & 21 deletions datastore/mysql/aws-aurora/1.0/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,9 @@ locals {
host = aws_rds_cluster.aurora.reader_endpoint
username = aws_rds_cluster.aurora.master_username
port = tostring(aws_rds_cluster.aurora.port)
password = local.is_import ? "<imported-password-not-available>" : (
local.restore_from_backup ? var.instance.spec.restore_config.master_password : local.master_password
)
password = local.restore_from_backup ? var.instance.spec.restore_config.master_password : local.master_password
database = aws_rds_cluster.aurora.database_name

connection_string = local.is_import ? format(
"mysql://%s:<password>@%s:%d/%s",
aws_rds_cluster.aurora.master_username,
aws_rds_cluster.aurora.reader_endpoint,
aws_rds_cluster.aurora.port,
coalesce(aws_rds_cluster.aurora.database_name, "")
) : format(
connection_string = format(
"mysql://%s:%s@%s:%d/%s",
aws_rds_cluster.aurora.master_username,
local.restore_from_backup ? var.instance.spec.restore_config.master_password : local.master_password,
Expand All @@ -31,17 +22,9 @@ locals {
host = aws_rds_cluster.aurora.endpoint
port = tostring(aws_rds_cluster.aurora.port)
username = aws_rds_cluster.aurora.master_username
password = local.is_import ? "<imported-password-not-available>" : (
local.restore_from_backup ? var.instance.spec.restore_config.master_password : local.master_password
)
password = local.restore_from_backup ? var.instance.spec.restore_config.master_password : local.master_password
database = aws_rds_cluster.aurora.database_name
connection_string = local.is_import ? format(
"mysql://%s:<password>@%s:%d/%s",
aws_rds_cluster.aurora.master_username,
aws_rds_cluster.aurora.endpoint,
aws_rds_cluster.aurora.port,
coalesce(aws_rds_cluster.aurora.database_name, "")
) : format(
connection_string = format(
"mysql://%s:%s@%s:%d/%s",
aws_rds_cluster.aurora.master_username,
local.restore_from_backup ? var.instance.spec.restore_config.master_password : local.master_password,
Expand Down
1 change: 1 addition & 0 deletions datastore/mysql/aws-aurora/1.0/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ variable "instance" {
cluster_identifier = optional(string)
writer_instance_identifier = optional(string)
reader_instance_identifiers = optional(string)
master_password = optional(string)
}), {})
})
})
Expand Down
19 changes: 10 additions & 9 deletions datastore/mysql/aws-rds/1.0/facets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,6 @@ spec:
minLength: 1
maxLength: 64
default: myapp
master_username:
type: string
title: Master Username
description: Master username for database access
pattern: ^[a-zA-Z][a-zA-Z0-9_]*$
minLength: 1
maxLength: 16
default: admin
sizing:
type: object
title: Sizing & Performance
Expand Down Expand Up @@ -91,6 +83,7 @@ spec:
restore_config:
type: object
title: Restore Operations
x-ui-overrides-only: true
properties:
restore_from_backup:
type: boolean
Expand Down Expand Up @@ -131,6 +124,7 @@ spec:
imports:
type: object
title: Import Existing Resources
x-ui-overrides-only: true
properties:
db_instance_identifier:
type: string
Expand All @@ -144,6 +138,11 @@ spec:
type: string
title: Security Group ID
description: ID of existing security group to import
master_password:
type: string
title: Master Password
description: Master password for the imported resource (8+ characters)
minLength: 8
required:
- version_config
imports:
Expand All @@ -156,6 +155,9 @@ imports:
- name: security_group_id
resource_address: aws_security_group.mysql
required: false
- name: master_password
resource_address: random_password.master_password[0]
required: true
inputs:
aws_cloud_account:
type: '@facets/aws_cloud_account'
Expand Down Expand Up @@ -187,7 +189,6 @@ sample:
version_config:
version: '8.4'
database_name: myapp
master_username: admin
sizing:
instance_class: db.t3.small
allocated_storage: 100
Expand Down
11 changes: 5 additions & 6 deletions datastore/mysql/aws-rds/1.0/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@ locals {
# Database configuration
is_restore_operation = var.instance.spec.restore_config.restore_from_backup

# Master credentials - don't set when importing (set to null)
# When importing, username and password should be null to avoid overriding existing values
master_username = local.is_db_instance_import ? null : (local.is_restore_operation ? var.instance.spec.restore_config.restore_master_username : var.instance.spec.version_config.master_username)
master_password = local.is_db_instance_import ? null : (local.is_restore_operation ? var.instance.spec.restore_config.restore_master_password : (length(random_password.master_password) > 0 ? random_password.master_password[0].result : ""))
# When importing, username and password should be same as the original to avoid overriding existing values
master_username = local.is_restore_operation ? var.instance.spec.restore_config.restore_master_username : "admin"
master_password = local.is_restore_operation ? var.instance.spec.restore_config.restore_master_password : random_password.master_password[0].result

# Database name - don't set when importing
database_name = local.is_db_instance_import ? null : var.instance.spec.version_config.database_name
# Database name - should be same when importing
database_name = var.instance.spec.version_config.database_name

# Max allocated storage (0 means disabled)
max_allocated_storage = var.instance.spec.sizing.max_allocated_storage > 0 ? var.instance.spec.sizing.max_allocated_storage : null
Expand Down
Loading