feat(catalog-seed): add bp-cnpg-pair Blueprint + wordpress-tenant active-hot-standby mode (Refs TBD-E8b, TBD-B31) (#1717)
Wave 28-B discovery: the bp-cnpg-pair Catalyst-curated Blueprint chart (platform/cnpg-pair/ @ 0.1.1) was missing from the catalog-seed template added by PR #1697. The chart is published at oci://ghcr.io/openova-io/bp-cnpg-pair, but operators had no way to see it in /api/v1/catalog on a fresh Sovereign — only the 13 entries from PR #1697 rendered. This PR seeds bp-cnpg-pair alongside its bp-cnpg companion in templates/catalog-seed/blueprints.yaml. Render goes from 13 -> 14 Blueprint CRs on a freshly-handed-over Sovereign. Also wires the canonical `database.mode` enum knob on bp-wordpress- tenant (singleton | active-hot-standby), aligning the operator-facing interface with the new bp-cnpg-pair Blueprint: - chart/values.yaml: new `database.mode` (empty default for back-compat). - chart/templates/_helpers.tpl: new `bp-wordpress-tenant.dbMode` helper with resolution precedence (enum wins; legacy `pg.activeHotStandby.enabled` boolean folds as alias for chart 0.3.x overlays). - chart/templates/cnpg-cluster.yaml: reads the resolved enum via the helper instead of the raw boolean. Output is bit-for-bit identical when overlays don't set the new knob (back-compat smoke verified: legacy boolean still renders 2 Cluster CRs). - blueprint.yaml: configSchema exposes `database.mode` so the marketplace voucher -> org wizard (D29) can present a "Postgres topology" picker instead of a boolean. - Chart.yaml: version bump 0.3.0 -> 0.3.1. Status: - chart render: helm lint clean on both charts; 4 invariants pass (singleton/mode=ahs/legacy-bool/mode-overrides-bool). - runtime D31: chart-rendered as of PR #1562; full prov-time runtime verification remains deferred (gated on next Sovereign fresh-prov per docs/SESSION-2026-05-17-CONVERGENCE.md). Refs TBD-E8b, TBD-B31. Co-authored-by: hatiyildiz <hatice.yildiz@openova.io>
This commit is contained in:
parent
a033eb7b15
commit
6685bd7441
@ -6,7 +6,7 @@ metadata:
|
||||
catalyst.openova.io/category: tenant-app
|
||||
catalyst.openova.io/section: pts-7-sme-tenant
|
||||
spec:
|
||||
version: 0.2.0
|
||||
version: 0.3.1
|
||||
card:
|
||||
title: WordPress Tenant
|
||||
summary: |
|
||||
@ -99,6 +99,23 @@ spec:
|
||||
database:
|
||||
type: object
|
||||
properties:
|
||||
mode:
|
||||
type: string
|
||||
enum: ["", "singleton", "active-hot-standby"]
|
||||
default: ""
|
||||
description: |
|
||||
Canonical operator-facing DB topology selector (TBD-E8b).
|
||||
|
||||
- "singleton" (DEFAULT) — single in-vcluster CNPG Cluster CR.
|
||||
- "active-hot-standby" (D31) — primary + replica CNPG Cluster CRs across
|
||||
two regions, WAL streaming over Cilium
|
||||
ClusterMesh (mirrors bp-cnpg-pair shape).
|
||||
|
||||
When set, this enum overrides the legacy
|
||||
`pg.activeHotStandby.enabled` boolean. Empty string falls
|
||||
through to the boolean for back-compat with chart 0.3.x
|
||||
overlays. The marketplace voucher → org wizard (D29)
|
||||
writes this field directly.
|
||||
cnpgClusterName:
|
||||
type: string
|
||||
default: wordpress-db
|
||||
|
||||
@ -42,7 +42,19 @@ name: bp-wordpress-tenant
|
||||
# - New tests/active-hot-standby-render.sh render-gate asserts default
|
||||
# render emits 1 Cluster and enabled render emits 2 Cluster CRs with
|
||||
# the right nodeSelectors + replica.source + externalCluster.host.
|
||||
version: 0.3.0
|
||||
# 0.3.1 (TBD-E8b, 2026-05-18): canonical `database.mode` enum.
|
||||
# - New `database.mode` knob (singleton | active-hot-standby). When
|
||||
# set, overrides the legacy `pg.activeHotStandby.enabled` boolean
|
||||
# (kept as back-compat alias for chart 0.3.0 overlays). Resolution
|
||||
# precedence centralised in _helpers.tpl `bp-wordpress-tenant.dbMode`.
|
||||
# - templates/cnpg-cluster.yaml now reads the resolved enum via the
|
||||
# helper; pre-existing renders bit-for-bit identical when overlays
|
||||
# don't set the new knob (back-compat smoke).
|
||||
# - blueprint.yaml configSchema exposes `database.mode` so the
|
||||
# marketplace voucher → org wizard (D29) can present a
|
||||
# "Postgres topology" picker instead of a boolean.
|
||||
# - Companion to catalog-seed bp-cnpg-pair Blueprint CR (Refs TBD-E8b).
|
||||
version: 0.3.1
|
||||
appVersion: "6"
|
||||
description: |
|
||||
Catalyst Blueprint scratch chart for in-vcluster WordPress, one
|
||||
|
||||
@ -125,6 +125,57 @@ Mirror bp-cnpg-pair's naming + validation pattern (see
|
||||
platform/cnpg-pair/chart/templates/_helpers.tpl).
|
||||
*/}}
|
||||
|
||||
{{/*
|
||||
D31 / TBD-E8b: canonical operator-facing DB topology selector.
|
||||
|
||||
Resolves the chart's DB topology to one of:
|
||||
- "singleton" (default — single in-vcluster CNPG Cluster CR)
|
||||
- "active-hot-standby" (D31 — primary + replica CNPG Cluster CRs,
|
||||
WAL streaming over Cilium ClusterMesh; mirrors
|
||||
bp-cnpg-pair shape — see platform/cnpg-pair/)
|
||||
|
||||
Precedence (operator-supplied `database.mode` wins; legacy
|
||||
`pg.activeHotStandby.enabled` boolean folds as alias for clusters whose
|
||||
orchestrator overlays haven't been re-rendered with the canonical
|
||||
enum):
|
||||
|
||||
1. `database.mode` is "active-hot-standby" → active-hot-standby
|
||||
2. `database.mode` is "singleton" → singleton
|
||||
3. `database.mode` is empty/unset:
|
||||
- `pg.activeHotStandby.enabled=true` → active-hot-standby
|
||||
- otherwise → singleton
|
||||
|
||||
The enum form (`database.mode`) is the canonical interface customers
|
||||
see in the marketplace voucher → org wizard (D29). The boolean form
|
||||
(`pg.activeHotStandby.enabled`) remains a back-compat alias and will
|
||||
be removed in chart 0.4.0.
|
||||
*/}}
|
||||
{{- define "bp-wordpress-tenant.dbMode" -}}
|
||||
{{- $mode := .Values.database.mode | default "" -}}
|
||||
{{- if eq $mode "active-hot-standby" -}}
|
||||
active-hot-standby
|
||||
{{- else if eq $mode "singleton" -}}
|
||||
singleton
|
||||
{{- else if .Values.pg.activeHotStandby.enabled -}}
|
||||
active-hot-standby
|
||||
{{- else -}}
|
||||
singleton
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
D31 / TBD-E8b: boolean convenience predicate — returns "true" when the
|
||||
resolved `dbMode` is "active-hot-standby". Used by cnpg-cluster.yaml
|
||||
in place of the legacy `.Values.pg.activeHotStandby.enabled` boolean
|
||||
so the canonical enum drives template rendering. Empty (falsy) when
|
||||
mode resolves to "singleton".
|
||||
*/}}
|
||||
{{- define "bp-wordpress-tenant.dbModeActiveHotStandby" -}}
|
||||
{{- if eq (include "bp-wordpress-tenant.dbMode" .) "active-hot-standby" -}}
|
||||
true
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
D31: replica Cluster CR name. Suffix `-replica` matches bp-cnpg-pair.
|
||||
Truncated to 63 chars per the K8s resource-name limit.
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
{{- /*
|
||||
─── CNPG Postgres for WordPress ─────────────────────────────────────────
|
||||
|
||||
Two render modes, controlled by `pg.activeHotStandby.enabled`:
|
||||
Two render modes, selected by the canonical operator-facing enum
|
||||
`database.mode` (singleton | active-hot-standby). Legacy boolean
|
||||
`pg.activeHotStandby.enabled` is folded in by _helpers.tpl's
|
||||
`bp-wordpress-tenant.dbMode` for back-compat with chart 0.3.x
|
||||
orchestrator overlays (see TBD-E8b).
|
||||
|
||||
1. SINGLE-CLUSTER mode (default):
|
||||
1. SINGLE-CLUSTER mode (database.mode=singleton, DEFAULT):
|
||||
Renders ONE Cluster.postgresql.cnpg.io named `<cnpgClusterName>` in
|
||||
the tenant namespace. Mirrors bp-gitea / bp-harbor patterns.
|
||||
|
||||
2. ACTIVE-HOT-STANDBY mode (Sovereign DoD D31):
|
||||
2. ACTIVE-HOT-STANDBY mode (database.mode=active-hot-standby, DoD D31):
|
||||
Renders TWO Cluster CRs mirroring the bp-cnpg-pair pattern (see
|
||||
platform/cnpg-pair/chart/templates/{primary,replica}-cluster.yaml):
|
||||
- PRIMARY `<cnpgClusterName>` in `primaryRegion`
|
||||
@ -42,7 +46,13 @@ namespaces (issue #584; bp-gitea precedent).
|
||||
*/ -}}
|
||||
{{- if and .Values.wordpress.enabled .Values.database.cluster.enabled }}
|
||||
{{- if .Capabilities.APIVersions.Has "postgresql.cnpg.io/v1" }}
|
||||
{{- $haEnabled := .Values.pg.activeHotStandby.enabled -}}
|
||||
{{- /* D31 / TBD-E8b: read the canonical `database.mode` enum (with
|
||||
back-compat fold from the legacy `pg.activeHotStandby.enabled`
|
||||
boolean). When mode resolves to "active-hot-standby" this template
|
||||
renders TWO Cluster CRs (primary + replica) mirroring bp-cnpg-pair;
|
||||
"singleton" (default) renders ONE Cluster CR. See _helpers.tpl
|
||||
`bp-wordpress-tenant.dbMode` for the resolution precedence. */ -}}
|
||||
{{- $haEnabled := eq (include "bp-wordpress-tenant.dbMode" .) "active-hot-standby" -}}
|
||||
{{- if $haEnabled }}
|
||||
{{- include "bp-wordpress-tenant.validateActiveHotStandbyRegions" . }}
|
||||
{{- end }}
|
||||
|
||||
@ -122,6 +122,29 @@ wordpress:
|
||||
# platform/gitea/chart/templates/database-secret-sync-job.yaml for
|
||||
# the rationale on Reflector vs. post-install Job.
|
||||
database:
|
||||
# ─── D31 / TBD-E8b — canonical DB topology selector ──────────────────
|
||||
# Operator-facing enum: "singleton" (default) | "active-hot-standby".
|
||||
# When set, this is the canonical interface and overrides the legacy
|
||||
# boolean `pg.activeHotStandby.enabled` (kept as a back-compat alias
|
||||
# for chart 0.3.x orchestrator overlays — removal slated for 0.4.0).
|
||||
#
|
||||
# The marketplace voucher → org wizard (D29) writes this field
|
||||
# directly when the customer ticks the "cross-region HA database"
|
||||
# checkbox; the catalog-seed Blueprint `bp-cnpg-pair` is the
|
||||
# standalone equivalent customers can install side-by-side for any
|
||||
# non-WordPress tenant-app.
|
||||
#
|
||||
# When mode=active-hot-standby:
|
||||
# - `pg.activeHotStandby.{primaryRegion,replicaRegion}` MUST be set
|
||||
# AND differ (templates/_helpers.tpl validateActiveHotStandbyRegions
|
||||
# fail-fasts at render time).
|
||||
# - bp-cnpg MUST be installed in BOTH regions (bootstrap-kit does
|
||||
# this in every region — verified on t132).
|
||||
# - DoD D11 (Cilium ClusterMesh via LoadBalancer) MUST be reconciled.
|
||||
#
|
||||
# Empty default → fall through to the legacy boolean for back-compat.
|
||||
mode: ""
|
||||
|
||||
# CNPG Cluster name & topology — operator-overridable via cluster
|
||||
# overlay. Defaults to a tenant-isolated cluster sized for SME usage.
|
||||
cnpgClusterName: "wordpress-db"
|
||||
|
||||
@ -59,6 +59,7 @@ Files
|
||||
blueprint-bp-prometheus.yaml — Tenant metrics scraping
|
||||
blueprint-bp-keycloak.yaml — Per-tenant Identity Provider
|
||||
blueprint-bp-cnpg.yaml — CloudNative-PG Postgres operator
|
||||
blueprint-bp-cnpg-pair.yaml — Active-hotstandby CNPG cluster-pair (D31 DR, Refs TBD-E8b)
|
||||
blueprint-bp-redis.yaml — In-memory key/value store
|
||||
blueprint-bp-clickhouse.yaml — Column-oriented analytics DB
|
||||
blueprint-bp-opensearch.yaml — Search + log analytics
|
||||
|
||||
@ -137,6 +137,142 @@ spec:
|
||||
type: string
|
||||
default: 10Gi
|
||||
---
|
||||
# bp-cnpg-pair — D31 active-hot-standby CNPG cluster-pair (companion to
|
||||
# bp-cnpg). Catalyst-curated Blueprint chart published at
|
||||
# oci://ghcr.io/openova-io/bp-cnpg-pair (Chart.yaml: platform/cnpg-pair/
|
||||
# chart/Chart.yaml @ 0.1.1). Renders TWO postgresql.cnpg.io/v1.Cluster
|
||||
# CRs (primary + replica) pinned to two regions, WAL streaming over
|
||||
# Cilium ClusterMesh per ADR-0001 §9 (never public TLS). Per Wave 28-B
|
||||
# discovery this Blueprint was missing from the catalog-seed even
|
||||
# though the chart is published and the wordpress-tenant chart's
|
||||
# `pg.activeHotStandby.enabled` knob already renders the same shape
|
||||
# inline (DoD D31). Seeding here lets operators install the pair
|
||||
# standalone (companion DB for any tenant-app) AND lets the install
|
||||
# flow render a stable reference target when wordpress-tenant.db.mode
|
||||
# = active-hot-standby. Refs TBD-E8b, TBD-B31.
|
||||
apiVersion: catalyst.openova.io/v1
|
||||
kind: Blueprint
|
||||
metadata:
|
||||
name: bp-cnpg-pair
|
||||
labels:
|
||||
catalyst.openova.io/managed-by: catalog-seed
|
||||
catalyst.openova.io/origin: openova-public
|
||||
catalyst.openova.io/curation: openova-public
|
||||
catalyst.openova.io/category: database
|
||||
catalyst.openova.io/section: pts-9-disaster-recovery
|
||||
catalyst.openova.io/companion: bp-cnpg
|
||||
app.kubernetes.io/managed-by: {{ $managedBy }}
|
||||
app.kubernetes.io/instance: {{ $instance }}
|
||||
spec:
|
||||
version: "0.1.1"
|
||||
visibility: listed
|
||||
card:
|
||||
title: "CNPG Cluster-Pair (Active-Hotstandby DR)"
|
||||
category: database
|
||||
family: postgres
|
||||
summary: "Active-hot-standby CNPG cluster-pair across two regions. WAL streams over Cilium ClusterMesh for cross-region DR."
|
||||
description: "Catalyst-curated Blueprint that renders a primary postgresql.cnpg.io/v1.Cluster CR in region A + a replica Cluster CR in region B configured as a CNPG replica cluster (replica.enabled=true + externalCluster) streaming WAL over a Cilium ClusterMesh-shared Service. Failover-readiness probe Pod flips Ready when WAL lag < threshold so Continuum K-Cont-2 can promote on operator-triggered switchover."
|
||||
icon: cnpg-pair.svg
|
||||
license: "Apache-2.0"
|
||||
tags: [database, postgres, ha, dr, disaster-recovery, multi-region, active-hotstandby, clustermesh, cnpg]
|
||||
docs: "https://cloudnative-pg.io/documentation/"
|
||||
placementSchema:
|
||||
# The cluster-pair IS the placement — primary + replica are the
|
||||
# two regions. CNPG's replication model is asynchronous-streaming
|
||||
# primary + 1 replica region; multi-replica-region is out of scope.
|
||||
modes: [active-hotstandby]
|
||||
default: active-hotstandby
|
||||
minRegions: 2
|
||||
maxRegions: 2
|
||||
manifests:
|
||||
chart: bp-cnpg-pair
|
||||
source:
|
||||
kind: HelmRepository
|
||||
type: oci
|
||||
url: oci://ghcr.io/openova-io
|
||||
chart: bp-cnpg-pair
|
||||
version: 0.1.1
|
||||
configSchema:
|
||||
type: object
|
||||
required: [primary, replica, image]
|
||||
properties:
|
||||
primary:
|
||||
type: object
|
||||
required: [region]
|
||||
properties:
|
||||
region:
|
||||
type: string
|
||||
description: "Region key for the primary CNPG Cluster (e.g. hz-fsn-rtz-prod). Must differ from replica.region."
|
||||
instances:
|
||||
type: integer
|
||||
default: 3
|
||||
minimum: 3
|
||||
maximum: 5
|
||||
storage:
|
||||
type: object
|
||||
properties:
|
||||
size:
|
||||
type: string
|
||||
default: "100Gi"
|
||||
storageClass:
|
||||
type: string
|
||||
default: hcloud-volumes
|
||||
replica:
|
||||
type: object
|
||||
required: [region]
|
||||
properties:
|
||||
region:
|
||||
type: string
|
||||
description: "Region key for the replica CNPG Cluster. Must differ from primary.region."
|
||||
instances:
|
||||
type: integer
|
||||
default: 3
|
||||
minimum: 3
|
||||
maximum: 5
|
||||
storage:
|
||||
type: object
|
||||
properties:
|
||||
size:
|
||||
type: string
|
||||
default: "100Gi"
|
||||
storageClass:
|
||||
type: string
|
||||
default: hcloud-volumes
|
||||
walStreaming:
|
||||
type: object
|
||||
properties:
|
||||
targetLagSeconds:
|
||||
type: integer
|
||||
default: 30
|
||||
minimum: 1
|
||||
maximum: 600
|
||||
timeoutSeconds:
|
||||
type: integer
|
||||
default: 60
|
||||
minimum: 5
|
||||
maximum: 600
|
||||
clusterMesh:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
default: true
|
||||
description: "Cilium ClusterMesh transport for WAL. Disabling is FORENSIC ONLY — public-TLS replication is unsupported per ADR-0001 §9."
|
||||
affinity:
|
||||
type: string
|
||||
default: local
|
||||
description: "ClusterMesh affinity hint (local|remote|none)."
|
||||
image:
|
||||
type: object
|
||||
required: [tag]
|
||||
properties:
|
||||
repository:
|
||||
type: string
|
||||
default: ghcr.io/cloudnative-pg/postgresql
|
||||
tag:
|
||||
type: string
|
||||
description: "REQUIRED — empty triggers a template-time fail-fast. Example: '16.3-23' or 'sha256:<digest>'."
|
||||
---
|
||||
apiVersion: catalyst.openova.io/v1
|
||||
kind: Blueprint
|
||||
metadata:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user