Skip to content
Merged
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ raptor import project-type --managed facets/aws --name "My Platform"
`Cloud Account (aws_provider)` `Network/VPC (aws_network)` `EKS Standard (eks_standard)` `EKS Automode (eks_automode)` `Node Pool/Karpenter (karpenter)` `Node Pool/Automode (eks_automode)` `Karpenter (default)` `AWS ALB Controller (standard)` `EFS CSI Driver (standard)` `AWS EFS (standard)` `StorageClass/EBS (aws_ebs)` `StorageClass/EFS (aws_efs)` `Service (aws)` `AWS IAM Policy (standard)` `AWS IAM Role (standard)`

**Managed Datastores**
`PostgreSQL/RDS (aws-rds)` `PostgreSQL/Aurora (aws-aurora)` `MySQL/RDS (aws-rds)` `MySQL/Aurora (aws-aurora)` `MongoDB/DocumentDB (aws-documentdb)` `Redis/ElastiCache (aws-elasticache)` `Kafka/MSK (aws-msk)`
`PostgreSQL/RDS (aws-rds)` `PostgreSQL/Aurora (aws-aurora)` `PostgreSQL/Logical (logical)` `MySQL/RDS (aws-rds)` `MySQL/Aurora (aws-aurora)` `MongoDB/DocumentDB (aws-documentdb)` `Redis/ElastiCache (aws-elasticache)` `Kafka/MSK (aws-msk)`

**Self-hosted via KubeBlocks**
`PostgreSQL` `MySQL` `MongoDB` `Redis`
Expand Down Expand Up @@ -91,7 +91,7 @@ raptor import project-type --managed facets/gcp --name "My Platform"
`Cloud Account (gcp_provider)` `Network/VPC (gcp_network)` `GKE (gke)` `Node Pool (gcp)` `Node Fleet (gcp_node_fleet)` `Service (gcp)` `Workload Identity (gcp)` `Pub/Sub (gcp)` `GCP Secret Manager (gcp)`

**Managed Datastores**
`PostgreSQL/Cloud SQL (gcp-cloudsql)` `MySQL/Cloud SQL (gcp-cloudsql)` `Redis/Memorystore (gcp-memorystore)`
`PostgreSQL/Cloud SQL (gcp-cloudsql)` `PostgreSQL/Logical (logical)` `MySQL/Cloud SQL (gcp-cloudsql)` `Redis/Memorystore (gcp-memorystore)`

**Self-hosted via KubeBlocks**
`PostgreSQL` `MySQL` `MongoDB` `Redis`
Expand Down Expand Up @@ -137,7 +137,7 @@ raptor import project-type --managed facets/azure --name "My Platform"
`Cloud Account (azure_provider)` `Network/VNet (azure_network)` `AKS (aks)` `Node Pool (azure)` `Service (azure)` `Workload Identity (azure)`

**Managed Datastores**
`PostgreSQL/Flexible Server (azure-flexible-server)` `MySQL/Flexible Server (azure-flexible-server)` `MongoDB/Cosmos DB (cosmosdb)` `Redis/Azure Cache (azure_cache_custom)`
`PostgreSQL/Flexible Server (azure-flexible-server)` `PostgreSQL/Logical (logical)` `MySQL/Flexible Server (azure-flexible-server)` `MongoDB/Cosmos DB (cosmosdb)` `Redis/Azure Cache (azure_cache_custom)`

**Self-hosted via KubeBlocks**
`PostgreSQL` `MySQL` `MongoDB` `Redis`
Expand Down
5 changes: 3 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,7 @@ <h3 class="template-card-name">NGINX Gateway Fabric Ingress (AWS) <span class="t
"AWS IAM Policy (standard)", "AWS IAM Role (standard)"
],
"Managed Datastores": [
"PostgreSQL/RDS (aws-rds)", "PostgreSQL/Aurora (aws-aurora)", "MySQL/RDS (aws-rds)",
"PostgreSQL/RDS (aws-rds)", "PostgreSQL/Aurora (aws-aurora)", "PostgreSQL/Logical (logical)", "MySQL/RDS (aws-rds)",
"MySQL/Aurora (aws-aurora)", "MongoDB/DocumentDB (aws-documentdb)",
"Redis/ElastiCache (aws-elasticache)", "Kafka/MSK (aws-msk)"
],
Expand Down Expand Up @@ -1164,7 +1164,7 @@ <h3 class="template-card-name">NGINX Gateway Fabric Ingress (AWS) <span class="t
"Workload Identity (gcp)", "Pub/Sub (gcp)", "GCP Secret Manager (gcp)"
],
"Managed Datastores": [
"PostgreSQL/Cloud SQL (gcp-cloudsql)", "MySQL/Cloud SQL (gcp-cloudsql)",
"PostgreSQL/Cloud SQL (gcp-cloudsql)", "PostgreSQL/Logical (logical)", "MySQL/Cloud SQL (gcp-cloudsql)",
"Redis/Memorystore (gcp-memorystore)"
],
"Self-hosted via KubeBlocks": [
Expand Down Expand Up @@ -1194,6 +1194,7 @@ <h3 class="template-card-name">NGINX Gateway Fabric Ingress (AWS) <span class="t
],
"Managed Datastores": [
"PostgreSQL/Flexible Server (azure-flexible-server)",
"PostgreSQL/Logical (logical)",
"MySQL/Flexible Server (azure-flexible-server)",
"MongoDB/Cosmos DB (cosmosdb)", "Redis/Azure Cache (azure_cache_custom)"
],
Expand Down
63 changes: 63 additions & 0 deletions modules/datastore/postgres/logical/1.0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# PostgreSQL Logical Module

![Version](https://img.shields.io/badge/version-1.0-blue) ![Cloud](https://img.shields.io/badge/cloud-AWS%20%7C%20GCP%20%7C%20Azure-lightgrey)

## Overview

This flavour creates **no cloud resources**. It models a **logical database
hosted on an existing/shared PostgreSQL instance** (selected via `spec.source`):
a pure passthrough that re-exposes that instance's connection outputs under the
`@facets/postgres` contract.

The primary use case is **staging DB consolidation**: a logical database
co-located on a shared physical instance. A blueprint can declare one logical
`postgres` resource per service while each one points at the same shared
instance — optionally re-targeting the connection string at a different logical
database name.

## Resources Created

None. `main.tf` declares no resources and no providers. The module is a
stateless transform over `var.instance.spec.source`.

## Spec

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `source` | `@facets/postgres` (via `x-ui-output-type`) | yes | The existing/shared postgres instance hosting this logical database. Resolves to the selected resource's full outputs (interfaces + attributes). Selectable per environment, so it is override-able. |
| `database_name` | string | no (override-only) | Logical database to target on the shared host. When set, the `connection_string` is rebuilt to point at this database; otherwise the source connection string passes through unchanged. |

## Outputs

Emits `@facets/postgres` with `reader` and `writer` interfaces
(`host`, `port`, `username`, `password`, `connection_string`, `secrets`)
carried over from the source. Any source `attributes` (e.g.
`db_instance_identifier`, `arn`) are passed through. This matches the output
contract of `aws-rds` and `aws-aurora`, so consumers cannot tell the
difference between a dedicated instance and a logical database.

## Connection string re-targeting

When `database_name` is set, both reader and writer `connection_string`
values are rebuilt as:

```
postgres://<source-username>:<source-password>@<source-host>:<source-port>/<database_name>
```

Credentials, host and port are inherited from the source; only the database
path segment is replaced. When `database_name` is unset, the source's own
`connection_string` is passed through verbatim.

## Use case: staging DB consolidation

In staging it is common to run a single shared physical PostgreSQL instance
and give each service its own logical database. Model this by:

1. Deploying one real postgres datastore (e.g. `aws-rds`) — the shared instance.
2. Adding a `postgres/logical` resource per service, with `spec.source`
pointing (per environment, via `--flavor`/override) at the shared instance
and `database_name` set to the service's logical database.

This keeps blueprints identical across environments while consolidating
physical infrastructure in non-production.
62 changes: 62 additions & 0 deletions modules/datastore/postgres/logical/1.0/facets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
intent: postgres
flavor: logical
version: '1.0'
clouds:
- aws
- gcp
- azure
description: Logical — a logical database hosted on an existing/shared postgres instance;
re-exposes its connection outputs (no resources created)
intentDetails:
type: Datastores
description: A logical database hosted on an existing/shared PostgreSQL instance (no resources created)
displayName: PostgreSQL
iconUrl: https://raw.githubusercontent.com/Facets-cloud/facets-modules-redesign/main/icons/postgres.svg
spec:
title: PostgreSQL Logical
description: A logical database hosted on an existing/shared postgres instance.
Re-exposes the shared instance's connection outputs and creates no cloud
resources. Use for staging DB consolidation, optionally overriding the
target database name in the connection string.
type: object
x-ui-order:
- source
- database_name
properties:
source:
type: object
title: Source PostgreSQL Datastore
description: The existing/shared postgres instance hosting this logical
database, whose connection outputs are re-exposed. Resolves to the
selected resource's full outputs (interfaces and attributes).
x-ui-output-type: '@facets/postgres'
database_name:
type: string
title: Logical Database Name
description: Optional logical database name to target on the shared host. When
set, the connection string is rebuilt to point at this database instead of
the source's default database. Leave empty to pass the source connection
through unchanged.
x-ui-overrides-only: true
pattern: ^[a-zA-Z][a-zA-Z0-9_]*$
minLength: 1
maxLength: 63
required:
- source
outputs:
default:
type: '@facets/postgres'
title: PostgreSQL Logical
iac:
validated_files:
- main.tf
- variables.tf
- outputs.tf
sample:
kind: postgres
flavor: logical
version: '1.0'
disabled: true
spec:
source: {}
database_name: app_logical
17 changes: 17 additions & 0 deletions modules/datastore/postgres/logical/1.0/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# PostgreSQL Logical flavour
#
# This flavour creates NO cloud resources and declares NO providers.
# It is a pure passthrough: it re-exposes the connection outputs of an
# existing postgres datastore (selected via spec.source), optionally
# re-targeting the connection string at a different logical database.
#
# Use case: staging DB consolidation, where a logical database points at a
# shared physical instance. The source datastore is selected per-environment
# (override-able), so the same blueprint resource can fan out to different
# shared instances across environments.

terraform {
required_version = ">= 1.0"
}

# Intentionally no resources.
52 changes: 52 additions & 0 deletions modules/datastore/postgres/logical/1.0/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
locals {
# Full outputs of the referenced postgres datastore.
source_interfaces = var.instance.spec.source.interfaces
source_reader = local.source_interfaces.reader
source_writer = local.source_interfaces.writer

# Optional logical database to re-target the connection string at.
override_db = lookup(var.instance.spec, "database_name", null)

# Rebuild the connection string against the overridden logical database when
# one is supplied, otherwise pass the source connection string through.
reader_connection_string = local.override_db != null ? format(
"postgres://%s:%s@%s:%s/%s",
local.source_reader.username,
local.source_reader.password,
local.source_reader.host,
local.source_reader.port,
local.override_db,
) : local.source_reader.connection_string

writer_connection_string = local.override_db != null ? format(
"postgres://%s:%s@%s:%s/%s",
local.source_writer.username,
local.source_writer.password,
local.source_writer.host,
local.source_writer.port,
local.override_db,
) : local.source_writer.connection_string

# Passthrough of any source attributes (e.g. db_instance_identifier, arn)
# when the source datastore emits them.
output_attributes = lookup(var.instance.spec.source, "attributes", {})

output_interfaces = {
reader = {
host = local.source_reader.host
port = local.source_reader.port
username = local.source_reader.username
password = local.source_reader.password
connection_string = local.reader_connection_string
secrets = ["password", "connection_string"]
}
writer = {
host = local.source_writer.host
port = local.source_writer.port
username = local.source_writer.username
password = local.source_writer.password
connection_string = local.writer_connection_string
secrets = ["password", "connection_string"]
}
}
}
54 changes: 54 additions & 0 deletions modules/datastore/postgres/logical/1.0/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
variable "instance" {
description = "A logical database hosted on an existing/shared PostgreSQL instance — re-exposes its connection outputs (no resources created)"
type = object({
kind = string
flavor = string
version = string
spec = object({
# Resolves to the selected postgres resource's FULL outputs
# (interfaces + attributes) injected by the platform via x-ui-output-type.
source = object({
attributes = optional(any, {})
interfaces = object({
reader = object({
host = string
port = string
username = string
password = string
connection_string = string
secrets = optional(list(string), [])
})
writer = object({
host = string
port = string
username = string
password = string
connection_string = string
secrets = optional(list(string), [])
})
})
})
# Optional logical DB name to target on the shared host (override-only).
database_name = optional(string)
})
})
}

variable "instance_name" {
description = "The architectural name for the resource as added in the Facets blueprint designer."
type = string
}

variable "environment" {
description = "An object containing details about the environment."
type = object({
name = string
unique_name = string
cloud_tags = map(string)
})
}

variable "inputs" {
description = "A map of inputs requested by the module developer. This logical flavour provisions nothing and requires no inputs."
type = object({})
}
2 changes: 2 additions & 0 deletions project-type/aws/project-type.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ modules:
flavor: aws-aurora
- intent: postgres
flavor: aws-rds
- intent: postgres
flavor: logical
- intent: redis
flavor: aws-elasticache
- intent: keda
Expand Down
2 changes: 2 additions & 0 deletions project-type/azure/project-type.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ modules:
flavor: azure-flexible-server
- intent: postgres
flavor: azure-flexible-server
- intent: postgres
flavor: logical
- intent: redis
flavor: azure_cache_custom

Expand Down
2 changes: 2 additions & 0 deletions project-type/gcp/project-type.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ modules:
flavor: gcp-cloudsql
- intent: postgres
flavor: gcp-cloudsql
- intent: postgres
flavor: logical
- intent: redis
flavor: gcp-memorystore
# - intent: kafka_topic
Expand Down