From be2a0af9b8fd83ca21cb9a8d952e0add79854d2a Mon Sep 17 00:00:00 2001 From: Anshul Sao Date: Mon, 22 Jun 2026 11:37:40 +0530 Subject: [PATCH 1/2] =?UTF-8?q?feat(datastore/postgres):=20add=20reference?= =?UTF-8?q?=20flavour=20=E2=80=94=20passthrough=20of=20an=20existing=20pos?= =?UTF-8?q?tgres=20datastore's=20outputs=20(no=20resources);=20enables=20p?= =?UTF-8?q?er-env=20DB=20consolidation=20references?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01PKZUrLtUbJS5GuEyRA8Vd5 --- README.md | 6 +- index.html | 5 +- .../postgres/reference/1.0/README.md | 62 ++++++++++++++++++ .../postgres/reference/1.0/facets.yaml | 63 +++++++++++++++++++ .../datastore/postgres/reference/1.0/main.tf | 17 +++++ .../postgres/reference/1.0/outputs.tf | 52 +++++++++++++++ .../postgres/reference/1.0/variables.tf | 54 ++++++++++++++++ project-type/aws/project-type.yml | 2 + project-type/azure/project-type.yml | 2 + project-type/gcp/project-type.yml | 2 + 10 files changed, 260 insertions(+), 5 deletions(-) create mode 100644 modules/datastore/postgres/reference/1.0/README.md create mode 100644 modules/datastore/postgres/reference/1.0/facets.yaml create mode 100644 modules/datastore/postgres/reference/1.0/main.tf create mode 100644 modules/datastore/postgres/reference/1.0/outputs.tf create mode 100644 modules/datastore/postgres/reference/1.0/variables.tf diff --git a/README.md b/README.md index 9f38ea6a..1298615f 100644 --- a/README.md +++ b/README.md @@ -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/Reference (reference)` `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` @@ -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/Reference (reference)` `MySQL/Cloud SQL (gcp-cloudsql)` `Redis/Memorystore (gcp-memorystore)` **Self-hosted via KubeBlocks** `PostgreSQL` `MySQL` `MongoDB` `Redis` @@ -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/Reference (reference)` `MySQL/Flexible Server (azure-flexible-server)` `MongoDB/Cosmos DB (cosmosdb)` `Redis/Azure Cache (azure_cache_custom)` **Self-hosted via KubeBlocks** `PostgreSQL` `MySQL` `MongoDB` `Redis` diff --git a/index.html b/index.html index 1ed4eed6..2f1c0a06 100644 --- a/index.html +++ b/index.html @@ -1133,7 +1133,7 @@

NGINX Gateway Fabric Ingress (AWS) NGINX Gateway Fabric Ingress (AWS) NGINX Gateway Fabric Ingress (AWS) :@:/ +``` + +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/reference` 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. diff --git a/modules/datastore/postgres/reference/1.0/facets.yaml b/modules/datastore/postgres/reference/1.0/facets.yaml new file mode 100644 index 00000000..6d6ba4ad --- /dev/null +++ b/modules/datastore/postgres/reference/1.0/facets.yaml @@ -0,0 +1,63 @@ +intent: postgres +flavor: reference +version: '1.0' +clouds: +- aws +- gcp +- azure +description: Reference — points at an existing postgres datastore and re-exposes its + connection outputs (no resources created); use to model a logical DB co-located + on a shared instance +intentDetails: + type: Datastores + description: Reference to an existing PostgreSQL datastore (no resources created) + displayName: PostgreSQL + iconUrl: https://raw.githubusercontent.com/Facets-cloud/facets-modules-redesign/main/icons/postgres.svg +spec: + title: PostgreSQL Reference + description: Points at an existing postgres datastore and re-exposes its connection + outputs. Creates no cloud resources. Use to model a logical database co-located + on a shared physical instance (e.g. 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 postgres datastore whose connection outputs are + re-exposed by this reference. 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 Reference +iac: + validated_files: + - main.tf + - variables.tf + - outputs.tf +sample: + kind: postgres + flavor: reference + version: '1.0' + disabled: true + spec: + source: {} + database_name: app_logical diff --git a/modules/datastore/postgres/reference/1.0/main.tf b/modules/datastore/postgres/reference/1.0/main.tf new file mode 100644 index 00000000..7caca453 --- /dev/null +++ b/modules/datastore/postgres/reference/1.0/main.tf @@ -0,0 +1,17 @@ +# PostgreSQL Reference 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. diff --git a/modules/datastore/postgres/reference/1.0/outputs.tf b/modules/datastore/postgres/reference/1.0/outputs.tf new file mode 100644 index 00000000..1b8e2a00 --- /dev/null +++ b/modules/datastore/postgres/reference/1.0/outputs.tf @@ -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"] + } + } +} diff --git a/modules/datastore/postgres/reference/1.0/variables.tf b/modules/datastore/postgres/reference/1.0/variables.tf new file mode 100644 index 00000000..1009dda9 --- /dev/null +++ b/modules/datastore/postgres/reference/1.0/variables.tf @@ -0,0 +1,54 @@ +variable "instance" { + description = "Reference to an existing PostgreSQL datastore — 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 reference flavour provisions nothing and requires no inputs." + type = object({}) +} diff --git a/project-type/aws/project-type.yml b/project-type/aws/project-type.yml index a9f35545..fdcb8bd4 100644 --- a/project-type/aws/project-type.yml +++ b/project-type/aws/project-type.yml @@ -62,6 +62,8 @@ modules: flavor: aws-aurora - intent: postgres flavor: aws-rds + - intent: postgres + flavor: reference - intent: redis flavor: aws-elasticache - intent: keda diff --git a/project-type/azure/project-type.yml b/project-type/azure/project-type.yml index 555b5009..8e55ba4e 100644 --- a/project-type/azure/project-type.yml +++ b/project-type/azure/project-type.yml @@ -34,6 +34,8 @@ modules: flavor: azure-flexible-server - intent: postgres flavor: azure-flexible-server + - intent: postgres + flavor: reference - intent: redis flavor: azure_cache_custom diff --git a/project-type/gcp/project-type.yml b/project-type/gcp/project-type.yml index c5c253dd..1cb0cb82 100644 --- a/project-type/gcp/project-type.yml +++ b/project-type/gcp/project-type.yml @@ -53,6 +53,8 @@ modules: flavor: gcp-cloudsql - intent: postgres flavor: gcp-cloudsql + - intent: postgres + flavor: reference - intent: redis flavor: gcp-memorystore # - intent: kafka_topic From f342357d9c43de70162e9617793332de31149f93 Mon Sep 17 00:00:00 2001 From: Anshul Sao Date: Mon, 22 Jun 2026 12:10:56 +0530 Subject: [PATCH 2/2] refactor(datastore/postgres): rename reference flavour to logical 'reference' clashed with Facets' cross-blueprint reference concept. 'logical' better names the use case: a logical database hosted on an existing/shared physical postgres instance. Renames the flavour dir, flavor field, titles, descriptions, and catalog/README/index.html/project-type entries. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01PKZUrLtUbJS5GuEyRA8Vd5 --- README.md | 6 ++-- index.html | 6 ++-- .../{reference => logical}/1.0/README.md | 25 ++++++++-------- .../{reference => logical}/1.0/facets.yaml | 29 +++++++++---------- .../{reference => logical}/1.0/main.tf | 2 +- .../{reference => logical}/1.0/outputs.tf | 0 .../{reference => logical}/1.0/variables.tf | 4 +-- project-type/aws/project-type.yml | 2 +- project-type/azure/project-type.yml | 2 +- project-type/gcp/project-type.yml | 2 +- 10 files changed, 39 insertions(+), 39 deletions(-) rename modules/datastore/postgres/{reference => logical}/1.0/README.md (67%) rename modules/datastore/postgres/{reference => logical}/1.0/facets.yaml (55%) rename modules/datastore/postgres/{reference => logical}/1.0/main.tf (95%) rename modules/datastore/postgres/{reference => logical}/1.0/outputs.tf (100%) rename modules/datastore/postgres/{reference => logical}/1.0/variables.tf (87%) diff --git a/README.md b/README.md index 1298615f..bb586d52 100644 --- a/README.md +++ b/README.md @@ -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)` `PostgreSQL/Reference (reference)` `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` @@ -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)` `PostgreSQL/Reference (reference)` `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` @@ -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)` `PostgreSQL/Reference (reference)` `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` diff --git a/index.html b/index.html index 2f1c0a06..6c2f6378 100644 --- a/index.html +++ b/index.html @@ -1133,7 +1133,7 @@

NGINX Gateway Fabric Ingress (AWS) NGINX Gateway Fabric Ingress (AWS) NGINX Gateway Fabric Ingress (AWS)