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
46 changes: 25 additions & 21 deletions generated/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
},
"/overview/architecture": {
"relPath": "/overview/architecture.md",
"lastmod": "2025-03-12T14:59:41.000Z"
"lastmod": "2026-01-05T19:57:57.000Z"
},
"/overview/management-api-reference": {
"relPath": "/overview/management-api-reference.md",
"lastmod": "2025-12-22T07:46:07.000Z"
"lastmod": "2026-01-14T08:27:46.000Z"
},
"/overview/agent-api-reference": {
"relPath": "/overview/agent-api-reference.md",
"lastmod": "2025-12-29T11:00:04.000Z"
"lastmod": "2026-01-14T08:27:46.000Z"
},
"/getting-started": {
"relPath": "/getting-started/index.md",
Expand Down Expand Up @@ -117,44 +117,48 @@
},
"/plural-features/continuous-deployment/git-service": {
"relPath": "/plural-features/continuous-deployment/git-service.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/plural-features/continuous-deployment/helm-service": {
"relPath": "/plural-features/continuous-deployment/helm-service.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/plural-features/continuous-deployment/resource-application-logic": {
"relPath": "/plural-features/continuous-deployment/resource-application-logic.md",
"lastmod": "2025-12-22T19:54:38.000Z"
},
"/plural-features/continuous-deployment/service-templating": {
"relPath": "/plural-features/continuous-deployment/service-templating/index.md",
"lastmod": "2025-12-30T05:57:04.477Z"
"lastmod": "2026-01-16T15:43:05.678Z"
},
"/plural-features/continuous-deployment/service-templating/supporting-liquid-filters": {
"relPath": "/plural-features/continuous-deployment/service-templating/supporting-liquid-filters.md",
"lastmod": "2025-12-30T05:57:04.494Z"
"lastmod": "2026-01-16T15:43:05.697Z"
},
"/plural-features/continuous-deployment/lua": {
"relPath": "/plural-features/continuous-deployment/lua.md",
"lastmod": "2025-07-15T12:44:58.000Z"
},
"/plural-features/continuous-deployment/global-service": {
"relPath": "/plural-features/continuous-deployment/global-service.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/plural-features/continuous-deployment/observer": {
"relPath": "/plural-features/continuous-deployment/observer.md",
"lastmod": "2025-12-15T20:59:31.000Z"
},
"/plural-features/continuous-deployment/pipelines": {
"relPath": "/plural-features/continuous-deployment/pipelines.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/plural-features/continuous-deployment/github-actions-ci": {
"relPath": "/plural-features/continuous-deployment/github-actions-ci.md",
"lastmod": "2025-08-04T17:41:39.000Z"
},
"/plural-features/continuous-deployment/management-controllers-reconciliation-logic": {
"relPath": "/plural-features/continuous-deployment/management-controllers-reconciliation-logic.md",
"lastmod": "2026-01-16T15:43:05.767Z"
},
"/plural-features/k8s-upgrade-assistant": {
"relPath": "/plural-features/k8s-upgrade-assistant/index.md",
"lastmod": "2025-05-11T23:04:59.000Z"
Expand Down Expand Up @@ -241,7 +245,7 @@
},
"/plural-features/plural-ai/arch-diagram": {
"relPath": "/plural-features/plural-ai/arch-diagram.md",
"lastmod": "2025-11-08T16:45:39.000Z"
"lastmod": "2026-01-05T19:58:20.000Z"
},
"/plural-features/plural-ai/cost": {
"relPath": "/plural-features/plural-ai/cost.md",
Expand All @@ -253,7 +257,7 @@
},
"/plural-features/flows": {
"relPath": "/plural-features/flows/index.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/plural-features/flows/create-a-flow": {
"relPath": "/plural-features/flows/create-a-flow.md",
Expand All @@ -273,7 +277,7 @@
},
"/plural-features/flows/mcp-auth": {
"relPath": "/plural-features/flows/mcp-auth.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/plural-features/flows/scm-webhooks-and-pr-linking": {
"relPath": "/plural-features/flows/scm-webhooks-and-pr-linking.md",
Expand Down Expand Up @@ -349,19 +353,19 @@
},
"/examples/continuous-deployment/helm-basic-with-inline-values": {
"relPath": "/examples/continuous-deployment/helm-basic-with-inline-values.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/examples/continuous-deployment/helm-basic-with-values-file": {
"relPath": "/examples/continuous-deployment/helm-basic-with-values-file.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/examples/continuous-deployment/kustomize-inflate-helm": {
"relPath": "/examples/continuous-deployment/kustomize-inflate-helm.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/examples/continuous-deployment/kustomize-stack-with-liquid": {
"relPath": "/examples/continuous-deployment/kustomize-stack-with-liquid.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/resources": {
"relPath": "/resources/index.md",
Expand Down Expand Up @@ -389,7 +393,7 @@
},
"/getting-started/agent-api-reference": {
"relPath": "/overview/agent-api-reference.md",
"lastmod": "2025-12-29T11:00:04.000Z"
"lastmod": "2026-01-14T08:27:46.000Z"
},
"/getting-started/readme": {
"relPath": "/getting-started/index.md",
Expand All @@ -401,7 +405,7 @@
},
"/deployments/architecture": {
"relPath": "/overview/architecture.md",
"lastmod": "2025-03-12T14:59:41.000Z"
"lastmod": "2026-01-05T19:57:57.000Z"
},
"/reference/architecture": {
"relPath": null,
Expand Down Expand Up @@ -477,15 +481,15 @@
},
"/deployments/operator/git-service": {
"relPath": "/plural-features/continuous-deployment/git-service.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/deployments/operator/helm-service": {
"relPath": "/plural-features/continuous-deployment/helm-service.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/deployments/operator/global-service": {
"relPath": "/plural-features/continuous-deployment/global-service.md",
"lastmod": "2025-12-30T05:54:16.000Z"
"lastmod": "2025-12-30T16:00:47.000Z"
},
"/deployments/using-operator": {
"relPath": "/plural-features/continuous-deployment/index.md",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Controller Reconciliation Logic

This document describes the reconciliation patterns used by our controllers to synchronize Kubernetes Custom Resources (CRDs) with the Console API.

## Reconciliation Modes

Controllers operate in one of three primary modes depending on the initial state of the resource and the configuration provided.

### 1. Creation Mode (Standard)
This is the standard lifecycle for a resource managed entirely by the controller.

* **Trigger**: A new CRD is created, and no matching resource exists in the Console API.
* **Action**: The controller creates the resource in the Console API using the attributes defined in the CRD `Spec`.
* **Result**: The `Status.ID` is populated with the new Console ID. The controller manages updates to the resource and ensures it is deleted from the Console API when the CRD is removed (via finalizers).

### 2. Read-Only Mode
This mode is used when a resource already exists in the Console API, and the operator is configured to observe rather than manage it.

* **Trigger**: A matching resource is found in the Console API, but the controller determines it should not take ownership (e.g., `driftDetection` is disabled).
* **Action**: The controller reads the existing ID from the Console API and populates `Status.ID`.
* **Result**: The resource state in the Console API is **not** modified by the controller, even if the CRD `Spec` differs. Deleting the CRD will **not** delete the resource from the Console API.

### 3. Adoption Mode
Adoption allows the controller to take ownership of a resource that was originally created outside of the current Kubernetes context (e.g., via the UI or a different cluster).

* **Trigger**: A matching resource is found, and the controller is configured to manage it (see "Ownership and Drift Detection" below).
* **Action**: The controller "links" to the existing resource by ID and immediately synchronizes the Console API state to match the CRD `Spec`.
* **Result**: Once adopted, the resource behaves exactly like one in **Creation Mode**. The controller assumes full responsibility for its lifecycle, updates, and deletion.

---

## Ownership and Drift Detection

The `reconciliation` block in the CRD `Spec` controls how the controller handles existing resources and ongoing synchronization.

### Adoption Logic for Specific Resources
For the following 7 resource types, the controller follows a specific adoption logic based on the `reconciliation.driftDetection` setting:

* **Project**
* **Catalog**
* **GitRepository**
* **NotificationSink**
* **ServiceAccount**
* **PRAutomation**
* **ServiceContext**

#### Behavior:
* **If `driftDetection: true` (Default)**: If a resource with the same name already exists in the Console API, the controller **will not** enter Read-Only mode. Instead, it will **take ownership** (Adoption Mode), synchronize the attributes, and handle future deletions.
* **If `driftDetection: false`**: The controller will enter **Read-Only Mode**. It will fetch the ID for dependency resolution but will not attempt to correct drift or manage the external resource's lifecycle.

### Requeue and Jitter
To maintain system stability and prevent API rate-limiting, the controllers use a jittered requeue mechanism for drift detection.

* **Interval**: Configured via `reconciliation.interval` (defaults to 30 minutes).
* **Jitter**: The actual requeue time is randomized between 50% and 150% of the configured interval.

| Parameter | Default | Description |
| :--- | :--- | :--- |
| `driftDetection` | `true` | Whether to sync changes from CRD to API periodically and adopt existing resources. |
| `interval` | `30m` | The base frequency for drift detection runs. |


## Resource Reconciliation Modes Table
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm pretty sure this table is wrong, for instance stacks and servicedeployments always adopt (globalservice should too, or at least support it)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right. I suggested read-only mode. I will fix it.


The following table categorizes resources based on their supported reconciliation behavior.

| Resource | Standard Creation | Read-Only Support | Adoption Mode Support |
|:---------------------------------|:-----------------:|:-----------------:|:------------------------------------:|
| **Project** | ✅ | ✅ | **Yes** (via `driftDetection: true`) |
| **Catalog** | ✅ | ✅ | **Yes** (via `driftDetection: true`) |
| **GitRepository** | ✅ | ✅ | **Yes** (via `driftDetection: true`) |
| **NotificationSink** | ✅ | ✅ | **Yes** (via `driftDetection: true`) |
| **ServiceAccount** | ✅ | ✅ | **Yes** (via `driftDetection: true`) |
| **PRAutomation** | ✅ | ✅ | **Yes** (via `driftDetection: true`) |
| **ServiceContext** | ✅ | ✅ | **Yes** (via `driftDetection: true`) |
| **BootstrapToken** | ✅ | No | No |
| **Cluster** | No | ✅ | ✅ |
| **ClusterRestore** | ✅ | ✅ | No |
| **ClusterRestoreTrigger** | ✅ | No | No |
| **CloudConnection** | ✅ | ✅ | No |
| **ComplianceReportGenerator** | ✅ | No | No |
| **CustomCompatibilityMatrix** | ✅ | No | ✅ |
| **CustomStackRun** | ✅ | No | No |
| **DeploymentSettings** | ✅ | No | No |
| **FederatedCredential** | ✅ | No | No |
| **Flow** | ✅ | No | ✅ |
| **GlobalService** | ✅ | No | ✅ |
| **Group** | ✅ | ✅ | No |
| **HelmRepository** | ✅ | No | ✅ |
| **InfrastructureStack** | ✅ | No | ✅ |
| **ManagedNamespace** | ✅ | ✅ | ✅ |
| **MCPServer** | ✅ | No | ✅ |
| **NamespaceCredentials** | No | ✅ | No |
| **NotificationRouter** | ✅ | No | ✅ |
| **ObservabilityProvider** | ✅ | ✅ | No |
| **Observer** | ✅ | No | ✅ |
| **OIDCProvider** | ✅ | No | ✅ |
| **Persona** | ✅ | No | No |
| **Pipeline** | ✅ | No | No |
| **PipelineContext** | ✅ | No | No |
| **PrAutomationTrigger** | ✅ | No | No |
| **PreviewEnvironmentTemplate** | ✅ | No | ✅ |
| **PrGovernance** | ✅ | No | ✅ |
| **SCMConnection** | ✅ | ✅ | No |
| **Sentinel** | ✅ | No | No |
| **ServiceDeployment** | ✅ | No | ✅ |
| **StackDefinition** | ✅ | No | No |
| **UpgradePlanCallout** | ✅ | No | ✅ |



### Legend:
* **Standard Creation**: Controller creates the resource if it doesn't exist.
* **Read-Only Support**: Controller can link to an existing resource by name/ID without modifying it.
* **Adoption Mode Support**: Controller can transition from Read-Only to Ownership if `driftDetection` is enabled or if the logic allows to upsert the resource.
4 changes: 4 additions & 0 deletions src/routing/docs-structure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ export const docsStructure: DocSection[] = [
path: 'github-actions-ci',
title: 'Integration with Github Actions/CI',
},
{
path: 'management-controllers-reconciliation-logic',
title: 'Management Controllers Reconciliation Logic',
},
],
},
{
Expand Down
Loading