|
| 1 | +//! Server-side-apply the operator's own CRDs at startup. |
| 2 | +//! |
| 3 | +//! Same source of truth as the `gen-crds` binary — both call |
| 4 | +//! `CustomResourceExt::crd()` on the derived types. The operator applies |
| 5 | +//! them on boot so a fresh cluster only needs `kubectl apply -f |
| 6 | +//! operator.yaml` to be functional; `crds.yaml` stays around for CI / |
| 7 | +//! debugging / operators who prefer to manage CRD lifecycle out-of-band. |
| 8 | +
|
| 9 | +use k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomResourceDefinition; |
| 10 | +use kube::{ |
| 11 | + Api, Client, CustomResourceExt, ResourceExt, |
| 12 | + api::{Patch, PatchParams}, |
| 13 | +}; |
| 14 | +use tracing::{info, warn}; |
| 15 | + |
| 16 | +use crate::{ |
| 17 | + error::Result, |
| 18 | + types::{PostgresPhysicalReplica, PostgresPhysicalRestore}, |
| 19 | +}; |
| 20 | + |
| 21 | +/// Field manager used for the SSA patch. Distinct from |
| 22 | +/// `postgres-restore-operator` so a manual `kubectl edit` doesn't fight |
| 23 | +/// the operator on CRD ownership — humans overriding CRD fields at |
| 24 | +/// runtime is legitimate (e.g. temporary preservation policy changes). |
| 25 | +const FIELD_MANAGER: &str = "postgres-restore-operator/crd"; |
| 26 | + |
| 27 | +/// SSA-apply the two pgro CRDs. Idempotent — safe to call every startup |
| 28 | +/// and safe to run concurrently with itself across replicas. |
| 29 | +/// |
| 30 | +/// Fails hard on RBAC / apiserver errors: without the CRDs the operator |
| 31 | +/// can't watch anything, so surfacing the error at boot beats a |
| 32 | +/// mysteriously-silent operator later. |
| 33 | +pub async fn ensure_crds(client: &Client) -> Result<()> { |
| 34 | + let api: Api<CustomResourceDefinition> = Api::all(client.clone()); |
| 35 | + for crd in [ |
| 36 | + PostgresPhysicalReplica::crd(), |
| 37 | + PostgresPhysicalRestore::crd(), |
| 38 | + ] { |
| 39 | + let name = crd.name_any(); |
| 40 | + let value = serde_json::to_value(&crd)?; |
| 41 | + match api |
| 42 | + .patch( |
| 43 | + &name, |
| 44 | + &PatchParams::apply(FIELD_MANAGER).force(), |
| 45 | + &Patch::Apply(&value), |
| 46 | + ) |
| 47 | + .await |
| 48 | + { |
| 49 | + Ok(_) => info!(crd = %name, "applied CRD"), |
| 50 | + Err(err) => { |
| 51 | + warn!(crd = %name, error = %err, "failed to apply CRD"); |
| 52 | + return Err(err.into()); |
| 53 | + } |
| 54 | + } |
| 55 | + } |
| 56 | + Ok(()) |
| 57 | +} |
0 commit comments