Skip to content

Commit 4e62b89

Browse files
authored
feat(canopy): materialise PostgresPhysicalReplica CRs from worklist (#82)
2 parents e0d9424 + 696fc6c commit 4e62b89

22 files changed

Lines changed: 2566 additions & 1991 deletions

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ Defines a continuously-refreshed replica of a PostgreSQL database restored from
8383

8484
| Field | Type | Required | Default | Description |
8585
|-------|------|----------|---------|-------------|
86-
| `kopiaSecretRef` | `SecretReference` | Yes | — | Reference to a Secret containing Kopia repository credentials (`bucket`, `region`, `repositoryPassword`, `accessKeyId`, `secretAccessKey`). |
86+
| `kopiaSecretRef` | `SecretReference` | One of | — | Reference to a Secret containing Kopia repository credentials (`bucket`, `region`, `repositoryPassword`, `accessKeyId`, `secretAccessKey`). Mutually exclusive with `canopySource`. |
87+
| `canopySource` | `CanopySource` | One of | — | Route kopia through the canopy-mediated proxy sidecar instead of a static Secret. `{ group, type }`. Managed by the canopy worklist syncer; humans usually don't hand-author these. Mutually exclusive with `kopiaSecretRef`. |
8788
| `snapshotFilter` | `SnapshotFilter` | No | — | Filter criteria to select which Kopia snapshot to restore. |
8889
| `schedule` | `string` | Yes | — | Cron expression controlling how often new restores are triggered. |
8990
| `scheduleJitter` | `string` | No | `"10m"` | Random jitter added to scheduled restores (friendly duration, e.g. `"5m"`, `"1h"`). |
@@ -175,6 +176,7 @@ Additional fields for `target: graphQL`:
175176
| `lastRestoreCompletedAt` | `Time` | When the last restore completed. |
176177
| `nextScheduledRestore` | `Time` | When the next scheduled restore will occur. |
177178
| `latestAvailableSnapshot` | `string` | Snapshot ID of the latest available snapshot matching the filter. |
179+
| `canopyDesiredSnapshotId` | `string` | For canopy-sourced replicas: the snapshot the canopy worklist syncer wants restored. The reconciler triggers a new restore when this differs from the current one. |
178180
| `connectionInfo` | `ConnectionInfo` | Connection details (host, port, database, username, password secret). |
179181
| `queuePosition` | `uint32` | Position in the global restore queue. |
180182
| `notifications` | `[]NotificationStatus` | Status of each configured notification target. |

_typos.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
[default.extend-words]
22
# BRIN: postgres "Block Range Index" type.
33
BRIN = "BRIN"
4+
5+
[files]
6+
# Generated from k8s-openapi schemas; upstream docstrings use
7+
# "ANDed" / "ORed" style jargon typos flags as misspellings.
8+
extend-exclude = ["crds.yaml"]

crds.yaml

Lines changed: 1104 additions & 0 deletions
Large diffs are not rendered by default.

operator.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,6 @@ spec:
222222
# operators can pin to a specific tag.
223223
# - name: CANOPY_PROXY_IMAGE
224224
# value: ghcr.io/beyondessential/pgro-canopy-proxy:latest
225-
# Default PVC size for canopy-provisioned pgdata.
226-
# - name: CANOPY_PGDATA_PVC_SIZE
227-
# value: "20Gi"
228225
ports:
229226
- name: http
230227
containerPort: 8080

src/bin/operator.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ use tracing::{debug, info, warn};
2222
use postgres_restore_operator::{
2323
canopy::{self, DEFAULT_SOCKS5_PROXY},
2424
context::{
25-
Context, DEFAULT_CANOPY_PGDATA_PVC_SIZE, DEFAULT_CANOPY_PROXY_IMAGE,
26-
DEFAULT_DEPLOYMENT_READY_TIMEOUT_SECS, DEFAULT_KOPIA_IMAGE,
25+
Context, DEFAULT_CANOPY_PROXY_IMAGE, DEFAULT_DEPLOYMENT_READY_TIMEOUT_SECS,
26+
DEFAULT_KOPIA_IMAGE,
2727
},
28-
controllers,
28+
controllers::{self, canopy::intent::SUPPORTED as PGRO_SUPPORTED_INTENTS},
2929
types::{PostgresPhysicalReplica, PostgresPhysicalRestore},
3030
};
3131

@@ -44,12 +44,6 @@ const DEFAULT_BROKER_ADDR: &str = "[::]:9091";
4444
const DEFAULT_CANOPY_RECONCILE_INTERVAL_SECS: u64 = 30;
4545
const CONFIGMAP_NAME: &str = "postgres-restore-operator-config";
4646

47-
/// Intent set pgro registers with canopy on startup; only worklist entries
48-
/// with a matching intent will be dispatched. `disaster-recovery` is not
49-
/// yet supported — the code has no rehearsal lifecycle beyond "make it
50-
/// writable", which is not what DR actually needs.
51-
const PGRO_SUPPORTED_INTENTS: &[&str] = &["verify", "analytics"];
52-
5347
/// Annotate the operator's own pod with the running version.
5448
async fn annotate_own_pod(client: &Client, namespace: &str) {
5549
let pod_name = match std::env::var("HOSTNAME") {
@@ -220,8 +214,6 @@ async fn main() -> anyhow::Result<()> {
220214
});
221215
ctx.canopy_proxy_image = std::env::var("CANOPY_PROXY_IMAGE")
222216
.unwrap_or_else(|_| DEFAULT_CANOPY_PROXY_IMAGE.to_string());
223-
ctx.canopy_pgdata_pvc_size = std::env::var("CANOPY_PGDATA_PVC_SIZE")
224-
.unwrap_or_else(|_| DEFAULT_CANOPY_PGDATA_PVC_SIZE.to_string());
225217
ctx.canopy_broker_base_url = if let Ok(url) = std::env::var("CANOPY_BROKER_BASE_URL") {
226218
url
227219
} else if let Ok(svc) = std::env::var("OPERATOR_SERVICE_NAME") {
@@ -564,8 +556,8 @@ async fn post_cache_pressure(
564556
}
565557

566558
/// Accept the canopy-proxy sidecar's final TrafficStats POST on shutdown.
567-
/// The body is opaque JSON — the reporter deserializes it when building
568-
/// the RestoreVerification.
559+
/// The body is opaque JSON — the canopy notification target deserializes
560+
/// it when building the RestoreVerification.
569561
async fn post_canopy_stats(
570562
State(state): State<ServerState>,
571563
Path((namespace, job)): Path<(String, String)>,

src/context.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ pub const DEFAULT_DEPLOYMENT_READY_TIMEOUT_SECS: u64 = 30 * 60;
1717
/// sidecar to a different tag from the operator itself.
1818
pub const DEFAULT_CANOPY_PROXY_IMAGE: &str =
1919
"ghcr.io/beyondessential/postgres-restore-operator:latest";
20-
pub const DEFAULT_CANOPY_PGDATA_PVC_SIZE: &str = "20Gi";
2120

2221
pub struct Context {
2322
pub client: Client,
@@ -39,17 +38,14 @@ pub struct Context {
3938
/// Image reference for the pgro-canopy-proxy sidecar container. Set
4039
/// by the operator startup from `CANOPY_PROXY_IMAGE`.
4140
pub canopy_proxy_image: String,
42-
/// Default pgdata PVC size used when the operator provisions a
43-
/// canopy-backed replica (per intent).
44-
pub canopy_pgdata_pvc_size: String,
4541
/// In-memory store for snapshot-list results POSTed by jobs.
4642
pub snapshot_results: Arc<CallbackStore>,
4743
/// In-memory store for schema migration results POSTed by jobs.
4844
pub schema_migration_results: Arc<CallbackStore>,
4945
/// In-memory store for canopy-proxy sidecar TrafficStats keyed by
5046
/// `{namespace}/{job}`. Written on sidecar exit via the operator's
51-
/// `/api/v1/canopy-stats/...` callback; read by the reporter when
52-
/// building `RestoreVerification.s3_*_bytes`.
47+
/// `/api/v1/canopy-stats/...` callback; read by the canopy
48+
/// notification target when building `RestoreVerification.s3_*_bytes`.
5349
pub canopy_stats: Arc<CallbackStore>,
5450
/// Base URL the operator is reachable at from within the cluster,
5551
/// e.g. `http://postgres-restore-operator.pgro-system.svc:8080`.
@@ -89,7 +85,6 @@ impl Context {
8985
canopy: None,
9086
canopy_broker_base_url: String::new(),
9187
canopy_proxy_image: DEFAULT_CANOPY_PROXY_IMAGE.to_string(),
92-
canopy_pgdata_pvc_size: DEFAULT_CANOPY_PGDATA_PVC_SIZE.to_string(),
9388
snapshot_results: Arc::new(CallbackStore::default()),
9489
schema_migration_results: Arc::new(CallbackStore::default()),
9590
canopy_stats: Arc::new(CallbackStore::default()),

0 commit comments

Comments
 (0)