diff --git a/docs/designs/object-controller/clusterobjectdeployment.md b/docs/designs/object-controller/clusterobjectdeployment.md index 686ae59497..435f3df1a9 100644 --- a/docs/designs/object-controller/clusterobjectdeployment.md +++ b/docs/designs/object-controller/clusterobjectdeployment.md @@ -1,5 +1,12 @@ # ClusterObjectDeployment contract +> **Historical proposal:** The deadline semantics below describe an earlier design, +> not the current implementation. COD now enforces a total rollout budget from COS +> creation, excludes time waiting for creation, and recalculates that budget when +> the deadline changes—even after timeout. COS no longer exposes a deadline field. +> See [Progress deadlines and recovery](../../draft/concepts/clusterobjectdeployment.md#progress-deadlines-and-recovery) +> for the current behavior. + ClusterObjectDeployment (COD) is a mutable orchestration resource that creates ClusterObjectSet (COS) snapshots and observes their rollout. This proposal defines the template, revision lifecycle, and status contract for COD and COS. diff --git a/docs/draft/concepts/clusterobjectdeployment.md b/docs/draft/concepts/clusterobjectdeployment.md new file mode 100644 index 0000000000..03229a789c --- /dev/null +++ b/docs/draft/concepts/clusterobjectdeployment.md @@ -0,0 +1,269 @@ +# ClusterObjectDeployments + +A `ClusterObjectDeployment` (COD) is an experimental, cluster-scoped API that +manages mutable desired content through immutable +[ClusterObjectSet](clusterobjectsets.md) (COS) revisions. Update the deployment's +template to change what should be deployed; the controller creates a new revision +rather than modifying an existing revision's content. + +For a hands-on walkthrough, see +[Manage standalone ClusterObjectDeployments](../tutorials/manage-clusterobjectdeployments.md). +For field definitions, see the +[COD API reference](../../api-reference/olmv1-api-reference.md#clusterobjectdeployment). + +## Responsibilities + +COD and COS separate rollout orchestration from resource reconciliation: + +| ClusterObjectDeployment | ClusterObjectSet | +| --- | --- | +| Stores the mutable desired template | Records the content of one revision | +| Creates and owns revisions | Applies objects in ordered phases | +| Enforces rollout deadlines | Evaluates readiness and records first completion | +| Reports deployment availability and progress | Reports resource reconciliation through `Ready` | +| Prunes excess archived history | Handles object ownership handoff and teardown | + +Both APIs are reconciled by the experimental object-controller. They can be used +without ClusterExtension or ClusterCatalog resources. See +[Controller deployment](clusterobjectsets.md#controller-deployment) for standalone +installation details. + +## Desired content and rollout policy + +A COD has three main spec fields: + +- `spec.template` contains the desired revision content and revision metadata. +- `spec.progressDeadlineMinutes` configures the rollout budget independently of + revision content. +- `spec.revisionHistoryLimit` controls how much archived history to retain. + +For example, this deployment allows ten minutes for a revision to roll out and +retains two archived revisions: + +```yaml +apiVersion: olm.operatorframework.io/v1 +kind: ClusterObjectDeployment +metadata: + name: my-app +spec: + progressDeadlineMinutes: 10 + revisionHistoryLimit: 2 + template: + metadata: + labels: + app.kubernetes.io/name: my-app + spec: + collisionProtection: Prevent + phases: + - name: configuration + objects: + - type: InlineManifest + inlineManifest: + apiVersion: v1 + kind: ConfigMap + metadata: + name: my-app-settings + namespace: default + data: + message: Hello from revision A +``` + +The template's `spec` contains phases, optional custom progression probes, and +collision protection, with the same semantics as the corresponding COS fields. +Objects can be embedded as `inlineManifest` or stored in immutable Secrets and +referenced with `secretRef`. The controller assigns each revision's group, +revision number, lifecycle state, and controller owner reference; callers cannot +set these through the template. + +`spec.template.metadata` contains labels and annotations propagated to each COS, +not to its managed objects. Set a managed object's metadata in its own manifest. +The reserved `olm.operatorframework.io/template-hash` label is always set by the +controller to identify the template that produced a revision. + +## Revision lifecycle + +The COD's name identifies its COS group. Names must be 1–52 characters long, +start with a lowercase letter, contain only lowercase letters, digits or hyphens, +and end with a letter or digit. + +When a new revision is needed, the controller: + +1. Finds the highest revision number in the group, including archived and + foreign-owned revisions. +2. Allocates the next number (`1` for an empty group) and creates an owned, Active + COS named `-`. +3. Observes that revision's rollout while older revisions can remain Active. +4. Reports completion once the new COS records `status.completedAt`. + +The COS controller handles ownership handoff between revisions and archives +superseded revisions once handoff completes. The COD controller prunes excess +archived history after teardown finishes. + +Revision numbers range from 1 to 9999999999. Once that range is exhausted, the +controller reports an error rather than allocating another revision. + +### Which edits create revisions? + +The controller compares the desired template with the latest owned, active, +non-deleting revision's template identity. A different template, or the absence +of an active revision, causes a new revision to be created, subject to the +[ownership rules](#revision-ownership). + +| Edit | Result | +| --- | --- | +| Objects, Secret references, phases, probes, or collision protection in `spec.template.spec` | A new revision | +| Phase, object, or probe order | A new revision | +| Labels or annotations in `spec.template.metadata` | A new revision | +| `spec.progressDeadlineMinutes` | The existing revision is retained; its rollout budget changes | +| `spec.revisionHistoryLimit` | Retention changes; the existing revision is retained | +| Root COD labels or annotations | The existing revision is retained | + +Reapplying an unchanged template retains the current active revision. Restoring +an earlier template after a different one has been deployed creates a new, +higher-numbered revision; it does not reactivate archived history. For example, +A → B → A produces revisions 1, 2, and 3. + +### Revision ownership + +Group membership determines revision ordering; controller owner references +determine which revisions a COD manages. Sharing a group does not by itself make +a COS owned by the deployment. + +The controller can adopt an ownerless, non-deleting group member only when it +carries the `apps.kubernetes.io/managed-by=object-controller` label. It does not +replace another controller's owner reference. A stale reference to an older UID +of the same deployment is left for Kubernetes garbage collection rather than +rewritten. + +If the highest active, non-deleting group member is controlled by another +controller, the COD reports `Progressing=False/OwnerConflict` and creates no new +revision. If that group member is ownerless but lacks the managed-by label, the +COD reports `Progressing=False/UnmanagedRevision`. Resolve the foreign ownership, +remove the blocking revision, or restore a missing managed-by label only when the +revision was actually created by object-controller. A stale owner reference to an +older UID also blocks new revisions until garbage collection removes it, without +a distinct condition reason. + +`OwnerConflict` concerns ownership of the COS itself; `RevisionObjectCollision` +concerns ownership of Kubernetes objects within a revision. Ownership checks take +precedence over rollout completion and deadline checks. Availability still +reflects only owned active revisions, so an older ready revision can keep the COD +available during a conflict. + +## Status conditions + +COD exposes `Available` and `Progressing`. Its child COSs expose `Ready` and +record first rollout completion in `status.completedAt`. + +### Available + +Availability describes current health across owned, active, non-deleting +revisions, not just the latest revision: + +| Status | Reason | Meaning | +| --- | --- | --- | +| True | `Available` | At least one owned active revision is Ready | +| False | `NoActiveRevision` | No owned active revision exists | +| False | `Unavailable` | Owned active revisions exist, but none are Ready | + +An older ready revision can keep `Available=True` while its successor rolls out, +is stalled, or has exceeded its rollout deadline. + +### Progressing + +Progress describes the desired rollout, including failures that prevent it from +starting or completing: + +| Status | Reason | Meaning | +| --- | --- | --- | +| True | `NewClusterObjectSetProgressing` | Waiting to create or adopt revisions, or the desired revision is rolling out | +| True | `RevisionPreconditionsNotMet` | The desired revision's preconditions are unmet; reconciliation keeps retrying | +| False | `NewClusterObjectSetProgressed` | The desired revision completed rollout at least once | +| False | `ProgressDeadlineExceeded` | An incomplete, still-retrying revision exceeded its rollout budget | +| False | `InvalidSpecification` | Template labels or annotations are invalid; no revision is created until corrected | +| False | `OwnerConflict` | The highest active group member is controlled by another controller | +| False | `UnmanagedRevision` | The highest active group member is ownerless and lacks the object-controller managed-by label | +| False | `RevisionObjectCollision` | The desired revision cannot take ownership of one or more managed objects | +| False | `RevisionInvalidSpecification` | The desired revision's rendered objects are invalid | + +For revision-specific failures, the COD's condition message names the COS to +inspect. Its `Ready` condition provides the specific cause. +`RevisionInvalidSpecification` concerns the revision's rendered objects, while +`InvalidSpecification` concerns the COD's `spec.template.metadata`. + +`RevisionObjectCollision` and `RevisionInvalidSpecification` are hard stalls: +they require user action and take precedence over `ProgressDeadlineExceeded`. +`RevisionPreconditionsNotMet` is a retrying state and remains subject to the +rollout deadline. + +Completion is historical. Once the desired COS records `status.completedAt`, +later health regressions can affect `Available` but do not restart that +revision's rollout or its deadline. A new template starts a new rollout. + +## Progress deadlines and recovery + +`spec.progressDeadlineMinutes` supplies one budget for the whole revision. The +supported range is 1–720 minutes. Omit the field to disable deadline enforcement. +The deadline belongs to the COD; COSs do not carry a deadline field. + +Timing starts at the COS's creation timestamp. Failed or delayed creation +attempts consume no budget. Completing phases, polling, retries, and controller +restarts do not reset the timer. A five-phase revision with a ten-minute deadline +has ten minutes total, not ten minutes per phase. Each new revision receives a +fresh budget. + +Changing the deadline does not create a revision or reset its start time. The new +budget applies to the latest active revision and is still measured from that +COS's original creation timestamp: + +- Extending the budget beyond elapsed rollout time can clear an existing + `ProgressDeadlineExceeded` condition without new rollout progress. +- Shortening the budget below elapsed rollout time can cause immediate expiry. +- Removing the field disables enforcement, including after expiry. + +The COD schedules its own expiry check even if the COS emits no further events. +When an incomplete, retrying revision exceeds the budget, the COD reports +`Progressing=False/ProgressDeadlineExceeded`. The COS's `Ready` condition retains +its resource reconciliation status; for example, it can still report +`PreconditionsNotMet`. Hard stalls and revision ownership conflicts retain their +more actionable condition reasons rather than being replaced by a timeout. + +Reconciliation continues after expiry. A revision that later completes records +`status.completedAt`, and the COD reports +`Progressing=False/NewClusterObjectSetProgressed`. Completing only some phases +does not clear an expired deadline. Once completion is recorded, the deadline no +longer applies to that revision, even if it later becomes unhealthy. + +## Revision history and deletion + +`spec.revisionHistoryLimit` controls how many archived revisions the COD retains. +The default is 5, the supported range is 0–50, and 0 retains no archived history. +Active revisions never count against the limit and are not pruned by it. + +Only owned archived revisions that have finished teardown are eligible for +pruning. The controller deletes the oldest eligible revisions beyond the limit; +revisions still tearing down are left until cleanup completes. Foreign-owned +group members do not count toward the limit and are not pruned by the COD. + +Deleting a COD normally cascades to its owned COSs and their managed objects. +Deleting with orphan propagation leaves the revisions in their existing group; +it does not change revision membership or ownership handoff behavior. + +## Relationship with ClusterExtension + +When `BoxcutterRuntime` is enabled, operator-controller resolves and unpacks a +ClusterExtension's bundle and applies a COD with the same name. The +ClusterExtension owns the COD, the COD owns its COS revisions, and each COS owns +the Kubernetes objects it manages. + +The COD's name also becomes the COS group. Revision lookup uses that group, not +labels or controller owner references. Operator-controller observes COD rollout +status to report the extension's installation and progress. + +For a ClusterExtension, COD `OwnerConflict` maps to `Progressing=True` with reason +`Retrying`, preserving the deployment's message about the conflicting revision +and its controller. A first install reports `Installed=False` with reason +`Failed`. During an upgrade, the previously installed bundle and its +`Installed=True` condition are preserved until the new rollout completes, with +`observedGeneration` updated to acknowledge the current spec. Reconciliation +resumes automatically when the ownership conflict clears. diff --git a/docs/draft/concepts/clusterobjectsets.md b/docs/draft/concepts/clusterobjectsets.md index 4456ba28ed..6498c16d04 100644 --- a/docs/draft/concepts/clusterobjectsets.md +++ b/docs/draft/concepts/clusterobjectsets.md @@ -19,8 +19,10 @@ Each ClusterObjectSet has: ClusterObjectSets can be used by any controller or system that needs to manage the rollout of a set of Kubernetes resources in a controlled, phased manner. Within OLM, when `BoxcutterRuntime` is enabled, operator-controller creates and updates a ClusterObjectDeployment (COD) for each ClusterExtension. The COD controller creates the immutable ClusterObjectSet revisions that deploy and upgrade the extension. -For a standalone walkthrough that manages mutable desired content through COS -revisions, see [Manage standalone ClusterObjectDeployments](../tutorials/manage-clusterobjectdeployments.md). +For deployment-level revision management and rollout policy, see +[ClusterObjectDeployments](clusterobjectdeployment.md). For a standalone walkthrough +that manages mutable desired content through COS revisions, see +[Manage standalone ClusterObjectDeployments](../tutorials/manage-clusterobjectdeployments.md). The `group` value must be 1–52 characters long, start with a lowercase letter, contain only lowercase letters, digits or hyphens, and end with a letter or digit. @@ -247,81 +249,13 @@ Indicates whether all objects in the revision have been successfully rolled out On a revision's first reconciliation the `Ready` condition is initialized to `Unknown`/`Pending`, so it is always present. A transient internal error (e.g. an API read failure) leaves the `Ready` condition unchanged and is retried with backoff; it is not reported as a distinct reason (while the revision is still `Pending`, it stays `Unknown`/`Pending`). -### Progress deadline - -The progress deadline is a ClusterObjectDeployment (COD) concept: the time allowed -for the deployment to progress to its desired new revision. Configure it through -`spec.template.spec.progressDeadlineMinutes`. The COD enforces this budget itself; -the ClusterObjectSets it creates do not carry a deadline. Time spent waiting for -the ClusterObjectSet to be created is not counted, and each new revision receives -its own budget, measured from the revision's creation timestamp until its first -successful rollout (recorded in `status.completedAt`). Completing a phase does not -reset the timer. - -If the desired revision is still incomplete when that budget expires, the COD -reports `Progressing=False` with reason `ProgressDeadlineExceeded`. A five-phase -revision with a ten-minute deadline has ten minutes total, even if four phases -have completed. The COD schedules a deadline check even if the COS emits no -further events. - -The COS's `Ready` condition continues to report readiness failures, such as -`ObjectsNotReady`, `PreconditionsNotMet`, or `InvalidSpecification`. The COD checks -elapsed time independently of the COS's readiness condition. - -Omitting the field disables the deadline. Reconciliation continues after a -timeout, so a revision can still complete later. Once `status.completedAt` is -recorded, the COD reports `Progressing=False` with reason -`NewClusterObjectSetProgressed`. Later health regressions do not restart deadline -timing. The COD can remain `Available=True` if an older active revision is still -ready. - -### ClusterObjectDeployment Progressing - -A ClusterObjectDeployment (COD) reports rollout progress and ownership conflicts -on its `Progressing` condition. While a rollout is incomplete, it also reflects -*why* its head active revision is not yet `Ready`, so you can tell a rollout that -is merely in progress from one that is stalled on something you must fix. -For revision failures, inspect the named ClusterObjectSet for the specific cause. - -| Status | Reason | Meaning | What to do | -| --- | --- | --- | --- | -| True | `NewClusterObjectSetProgressing` | The head revision is rolling out (`Pending`/`ObjectsNotReady`) | Wait | -| True | `RevisionPreconditionsNotMet` | The head revision's precondition is not yet met (e.g. a mutable/invalid referenced Secret, or RBAC/dependency CRDs not yet propagated); it keeps retrying | Satisfy the precondition (grant RBAC, install the dependency, fix the Secret); it recovers automatically | -| False | `RevisionObjectCollision` | The head revision's objects are owned by another controller or already exist; it will not roll out without intervention | Resolve ownership of the conflicting objects | -| False | `RevisionInvalidSpecification` | The head revision's own objects are invalid | Correct the template so the rendered objects are valid | -| False | `ProgressDeadlineExceeded` | A still-retrying revision exceeded its deadline (see [Progress deadline](#progress-deadline)) | See above | -| False | `InvalidSpecification` | The deployment's own `spec.template.metadata` is invalid, so no revision is created | Fix the template labels/annotations | -| False | `OwnerConflict` | The highest active, non-deleting revision in the deployment's group is controlled by another controller; no new revision is created | Resolve the revision's controller ownership, or archive or delete the conflicting revision | -| False | `NewClusterObjectSetProgressed` | The head revision completed its rollout | None | - -`OwnerConflict` concerns ownership of the ClusterObjectSet itself, while -`RevisionObjectCollision` concerns ownership of objects within a revision. -`OwnerConflict` takes precedence even if an owned revision has completed or -exceeded its progress deadline. Availability still depends only on owned active -revisions; a previous ready revision can keep the COD `Available=True` during the -conflict. - -For a ClusterExtension, `OwnerConflict` maps to `Progressing=True` with reason -`Retrying`, preserving the deployment's message about the conflicting revision -and its controller. A first install reports `Installed=False` with reason -`Failed`. During an upgrade, the previously installed bundle and its `Installed=True` -condition are preserved until the new rollout completes, with `observedGeneration` -updated to acknowledge the current spec. Reconciliation resumes automatically when -the ownership conflict clears. - -`RevisionObjectCollision` and `RevisionInvalidSpecification` are *hard stalls*: -they will not resolve on their own, so they report `Progressing=False` and take -precedence over `ProgressDeadlineExceeded` (the actionable cause is more useful -than "the clock ran out"). `RevisionPreconditionsNotMet` keeps retrying, so it -stays `Progressing=True` and the progress deadline still governs it. Note that -`RevisionInvalidSpecification` (the revision's rendered objects) is distinct from -the deployment's own `InvalidSpecification` (invalid `spec.template.metadata`, -reported before any revision is created). - ### Completion (`status.completedAt`) The first time a revision becomes ready, the controller stamps `status.completedAt` with the current time. This timestamp is set once and never changes, marking that this revision successfully rolled out at least once — it persists even if the revision later becomes not ready. The ClusterExtension controller uses it to determine the installed revision. +For deployment-level rollout policy and conditions, see +[ClusterObjectDeployments](clusterobjectdeployment.md#status-conditions). + ## How operator-controller uses ClusterObjectSets With `BoxcutterRuntime` enabled, ClusterObjectSets serve as the deployment mechanism for `ClusterExtensions`. The operator-controller is one consumer of the ClusterObjectSet API. diff --git a/docs/draft/tutorials/manage-clusterobjectdeployments.md b/docs/draft/tutorials/manage-clusterobjectdeployments.md index 7c932ef23b..764a0789fc 100644 --- a/docs/draft/tutorials/manage-clusterobjectdeployments.md +++ b/docs/draft/tutorials/manage-clusterobjectdeployments.md @@ -92,7 +92,7 @@ Change the ConfigMap message to B: ```sh kubectl patch clusterobjectdeployment cod-example --type=json \ - -p='[{"op":"replace","path":"/spec/template/spec/phases/0/objects/0/object/data/message","value":"Hello from revision B"}]' + -p='[{"op":"replace","path":"/spec/template/spec/phases/0/objects/0/inlineManifest/data/message","value":"Hello from revision B"}]' kubectl wait --for=create clusterobjectset/cod-example-2 --timeout=180s kubectl wait --for=condition=Ready clusterobjectset/cod-example-2 --timeout=180s kubectl -n cod-example get configmap cod-example-settings \ @@ -119,44 +119,22 @@ The message returns to `Hello from revision A` through revision 3. Restoring an earlier template creates a new, higher revision; an archived revision cannot become Active again. Reapplying an unchanged template keeps the current revision. -### Which edits create revisions? - -| Edit | Result | -| --- | --- | -| Objects, references, phase/object order, probes, or collision protection in `spec.template.spec` | A new revision | -| Labels or annotations in `spec.template.metadata` | A new revision | -| `spec.template.spec.progressDeadlineMinutes` | A new revision, because the deadline is part of the template | -| Root COD labels or annotations | The current revision is retained | -| `spec.revisionHistoryLimit` | Retention changes; the current revision is retained | - -Template labels and annotations are placed on each generated COS. Set metadata -for a managed object in that object's manifest. The controller assigns COS group, -revision, lifecycle state, ownership, and the reserved -`olm.operatorframework.io/template-hash` label. +Changes to `spec.template`, including its labels and annotations, create a new +revision. Changes to rollout policy, such as `spec.progressDeadlineMinutes` or +`spec.revisionHistoryLimit`, do not. See +[Which edits create revisions?](../concepts/clusterobjectdeployment.md#which-edits-create-revisions) +for the complete rules. ## Read status and diagnose failures The COD exposes `Available` and `Progressing`. A child COS exposes `Ready` with the details of its resource reconciliation. -| COD condition | Status | Reason | Meaning | -| --- | --- | --- | --- | -| `Available` | `True` | `Available` | At least one active, non-deleting COS is Ready | -| `Available` | `False` | `NoActiveRevision` | No active, non-deleting COS exists yet | -| `Available` | `False` | `Unavailable` | Active revisions exist, but none are Ready | -| `Progressing` | `True` | `NewClusterObjectSetProgressing` | Waiting to create the desired revision, or rolling out while the COS reports `Pending` or `ObjectsNotReady` | -| `Progressing` | `True` | `RevisionPreconditionsNotMet` | The desired revision's preconditions are unmet, such as a mutable referenced Secret; reconciliation keeps retrying | -| `Progressing` | `False` | `NewClusterObjectSetProgressed` | The desired revision completed rollout at least once | -| `Progressing` | `False` | `ProgressDeadlineExceeded` | An incomplete, still-retrying revision exceeded its rollout budget | -| `Progressing` | `False` | `InvalidSpecification` | Template labels or annotations are invalid; correct them to allow creation | -| `Progressing` | `False` | `RevisionObjectCollision` | The desired revision's objects are owned by another controller or already exist; resolve the conflicting ownership | -| `Progressing` | `False` | `RevisionInvalidSpecification` | The desired revision's objects are invalid; correct the COD template | - -For revision-specific reasons, the COD's condition message names the latest -active COS. Inspect that COS's `Ready` condition for the specific cause. -`RevisionInvalidSpecification` concerns the revision's objects, while -`InvalidSpecification` concerns the COD's `spec.template.metadata` and prevents -creation of a new revision. +For revision-specific failures, the COD's condition message names the COS to +inspect. See [COD status conditions](../concepts/clusterobjectdeployment.md#status-conditions) +for the available reasons and +[Revision ownership](../concepts/clusterobjectdeployment.md#revision-ownership) +for conflicts that prevent a new rollout. Inspect the parent, the current child, and the controller logs: @@ -179,30 +157,21 @@ and let reconciliation retry. Change the COD template when the desired object content needs to change. See [COS status conditions](../concepts/clusterobjectsets.md#status-conditions) for the child reasons. -### Deadlines and recovery - -`spec.template.spec.progressDeadlineMinutes` supplies one budget for the whole -revision. The sample uses 10 minutes, the minimum; the maximum is 720 minutes. -Omit the field to disable deadline enforcement. +### Adjust the rollout deadline -Timing starts at COS creation. Failed or delayed creation attempts consume no -budget. Completing phases, polling, retries, and controller restarts preserve the -same deadline. A five-phase revision with a ten-minute deadline has ten minutes -total. Each new revision receives a fresh budget. +The sample configures a ten-minute rollout budget with +`spec.progressDeadlineMinutes`. To change that budget without creating another +revision, patch the COD directly: -The COD schedules its own expiry check even when the COS emits no further events. -The deadline still applies while preconditions are unmet: after expiry, the COD -reports `Progressing=False/ProgressDeadlineExceeded` while the COS retains its -readiness failure. `RevisionObjectCollision` and `RevisionInvalidSpecification` -require user action and take precedence over `ProgressDeadlineExceeded`, even -after expiry. The legacy deadline field remains available on directly created -COSs; COD enforces its budget independently. +```sh +kubectl patch clusterobjectdeployment cod-example --type=merge \ + -p='{"spec":{"progressDeadlineMinutes":20}}' +``` -Reconciliation continues after expiry. Completion of the entire revision records -`COS.status.completedAt` and recovers the COD to -`Progressing=False/NewClusterObjectSetProgressed`. Completing only some phases -does not clear an expired deadline. Once completion is recorded, later health regressions -can affect availability but never restart that revision's rollout timer. +The new budget is measured from the current COS's original creation timestamp, +not from the time of the edit. See +[Progress deadlines and recovery](../concepts/clusterobjectdeployment.md#progress-deadlines-and-recovery) +for timing, timeout precedence, and recovery behavior. ## Inspect history and referenced content @@ -211,26 +180,27 @@ objects that were removed from the desired content. COD prunes excess archived history after teardown completes. Active revisions are excluded from the limit. The sample retains two archived revisions with `spec.revisionHistoryLimit: 2`. -The default is 5, the supported range is 0–50, and 0 retains no archived revisions. -After A → B → A, revisions 1 and 2 can remain as archived history while revision 3 -is Active: +See [Revision history and deletion](../concepts/clusterobjectdeployment.md#revision-history-and-deletion) +for retention rules. After A → B → A, revisions 1 and 2 can remain as archived +history while revision 3 is Active: ```sh kubectl get clusterobjectsets --field-selector spec.group=cod-example \ -o custom-columns=NAME:.metadata.name,REVISION:.spec.revision,STATE:.spec.lifecycleState ``` -For larger content, each template object can use the existing COS `ref` mechanism +For larger content, each template object can use the COS `secretRef` mechanism to read a JSON manifest from an immutable Secret. Create the referenced Secret before applying the COD; it must remain available for every retained revision that references it. Changing the intended content requires a new Secret reference in the template. See [Object storage](../concepts/clusterobjectsets.md#object-storage-inline-vs-references). Standalone callers manage the lifetime of these content Secrets. -ClusterExtension integration is separate work tracked by -[OPRUN-4744](https://redhat.atlassian.net/browse/OPRUN-4744). The current -ClusterExtension path still creates COSs directly; this standalone workflow uses -object-controller without bundle resolution or catalog components. +With `BoxcutterRuntime` enabled, operator-controller manages CODs for +ClusterExtensions. This standalone workflow uses object-controller without bundle +resolution or catalog components. See +[Relationship with ClusterExtension](../concepts/clusterobjectdeployment.md#relationship-with-clusterextension) +for the integration. For all fields, see the [COD API reference](../../api-reference/olmv1-api-reference.md#clusterobjectdeployment).