This guide outlines dependency resolution and Custom Resource Definition (CRD) upgrade lifecycles within the Operator Lifecycle Manager (OLM) in OpenShift Container Platform.

About dependency resolution

OLM manages the dependency resolution and upgrade lifecycle of running Operators. In many ways, the problems OLM faces are similar to other operating system package managers like yum and rpm.

However, there is one constraint that similar systems do not generally have that OLM does: because Operators are always running, OLM attempts to ensure that you are never left with a set of Operators that do not work with each other.

This means that OLM must never:

  • install a set of Operators that require APIs that cannot be provided, or

  • update an Operator in a way that breaks another that depends upon it.

Custom Resource Definition (CRD) upgrades

OLM upgrades a Custom Resource Definition (CRD) immediately if it is owned by a singular Cluster Service Version (CSV). If a CRD is owned by multiple CSVs, then the CRD is upgraded when it has satisfied all of the following backward compatible conditions:

  • All existing serving versions in the current CRD are present in the new CRD.

  • All existing instances, or Custom Resources (CRs), that are associated with the serving versions of the CRD are valid when validated against the new CRD’s validation schema.

Adding a new CRD version

Procedure

To add a new version of a CRD:

  1. Add a new entry in the CRD resource under the versions section.

    For example, if the current CRD has one version v1alpha1 and you want to add a new version v1beta1 and mark it as the new storage version:

    versions:
      - name: v1alpha1
        served: true
        storage: false
      - name: v1beta1 (1)
        served: true
        storage: true
    1 Add a new entry for v1beta1.
  2. Ensure the referencing version of the CRD in your CSV’s owned section is updated if the CSV intends to use the new version:

    customresourcedefinitions:
      owned:
      - name: cluster.example.com
        version: v1beta1 (1)
        kind: cluster
        displayName: Cluster
    1 Update the version.
  3. Push the updated CRD and CSV to your bundle.

Deprecating or removing a CRD version

OLM does not allow a serving version of a CRD to be removed right away. Instead, a deprecated version of the CRD must be first disabled by setting the served field in the CRD to false. Then, the non-serving version can be removed on the subsequent CRD upgrade.

Procedure

To deprecate and remove a specific version of a CRD:

  1. Mark the deprecated version as non-serving to indicate this version is no longer in use and may be removed in a subsequent upgrade. For example:

    versions:
      - name: v1alpha1
        served: false (1)
        storage: true
    1 Set to false.
  2. Switch the storage version to a serving version if the version to be deprecated is currently the storage version. For example:

    versions:
      - name: v1alpha1
        served: false
        storage: false (1)
      - name: v1beta1
        served: true
        storage: true (1)
    1 Update the storage fields accordingly.

    In order to remove a specific version that is or was the storage version from a CRD, that version must be removed from the storedVersion in the CRD’s status. OLM will attempt to do this for you if it detects a stored version no longer exists in the new CRD.

  3. Upgrade the CRD with the above changes.

  4. In subsequent upgrade cycles, the non-serving version can be removed completely from the CRD. For example:

    versions:
      - name: v1beta1
        served: true
        storage: true
  5. Ensure the referencing version of the CRD in your CSV’s owned section is updated accordingly if that version is removed from the CRD.

Example dependency resolution scenarios

In the following examples, a provider is an Operator which "owns" a CRD or APIService.

Example: Deprecating dependent APIs

A and B are APIs (e.g., CRDs):

  • A’s provider depends on B.

  • B’s provider has a Subscription.

  • B’s provider updates to provide C but deprecates B.

This results in:

  • B no longer has a provider.

  • A no longer works.

This is a case OLM prevents with its upgrade strategy.

Example: Version deadlock

A and B are APIs:

  • A’s provider requires B.

  • B’s provider requires A.

  • A’s provider updates to (provide A2, require B2) and deprecate A.

  • B’s provider updates to (provide B2, require A2) and deprecate B.

If OLM attempts to update A without simultaneously updating B, or vice-versa, it is unable to progress to new versions of the Operators, even though a new compatible set can be found.

This is another case OLM prevents with its upgrade strategy.