# In-cluster PostgreSQL implementation of the `databases` entity contract. # Same `databases` list + same output maps as modules/yc-database, so the shared # k8s-secret module resolves credentials identically. `cluster_id` is a logical # key only (all databases are created on the single server the root provider # points at); host/port in outputs come from the database's own host or default_*. locals { databases_map = { for db in var.databases : "${db.cluster_id}:${db.database.name}:${db.user.name}" => db } db_extensions = merge([ for key, db in local.databases_map : { for ext in try(db.database.extensions, []) : "${key}:${ext}" => { key = key, ext = ext } } ]...) db_grants = merge([ for key, db in local.databases_map : { for perm in distinct(compact(try(db.user.permissions, []))) : "${key}:${perm}" => { key = key, db = perm } } ]...) } resource "random_password" "user_password" { for_each = local.databases_map length = try(each.value.user.password_length, 32) special = try(each.value.user.password_special, false) upper = true lower = true numeric = true lifecycle { ignore_changes = all } } resource "postgresql_role" "this" { for_each = local.databases_map name = each.value.user.name login = true password = random_password.user_password[each.key].result connection_limit = try(each.value.user.conn_limit, 10) lifecycle { ignore_changes = [password] } } resource "postgresql_database" "this" { for_each = local.databases_map name = each.value.database.name owner = postgresql_role.this[each.key].name lc_collate = try(each.value.database.lc_collate, "en_US.UTF-8") lc_ctype = try(each.value.database.lc_type, "en_US.UTF-8") # template0 is required when the collation/ctype differ from the server default. template = "template0" depends_on = [postgresql_role.this] } resource "postgresql_extension" "this" { for_each = local.db_extensions name = each.value.ext database = postgresql_database.this[each.value.key].name } # CONNECT grants to OTHER existing databases (declared in user.permissions); # the owner already has full access to its own database. resource "postgresql_grant" "connect" { for_each = local.db_grants role = postgresql_role.this[each.value.key].name database = each.value.db object_type = "database" privileges = ["CONNECT"] }