github.com/operator-framework/operator-lifecycle-manager@v0.30.0/doc/design/dependency-resolution.md (about) 1 # Dependency Resolution and Upgrades 2 3 OLM manages the dependency resolution and upgrade lifecycle of running operators. In many ways, these problems OLM faces are similar to other OS package managers like `apt`/`dkpg` and `yum`/`rpm`. 4 5 However, there is one constraint that similar systems don't generally have that OLM does: because operators are always running, OLM attempts to ensure that at no point in time are you left with a set of operators that do not work with each other. 6 7 This means that OLM needs to never: 8 9 - install a set of operators that require APIs that can't be provided 10 - update an operator in a way that breaks another that depends upon it 11 12 The following examples motivate why OLM's dependency resolution and upgrade strategy works as it does, followed by a description of the current algorithm. 13 14 ## CustomResourceDefinition (CRD) Upgrade 15 16 OLM will upgrade CRD right away if it is owned by singular CSV. If CRD is owned by multiple CSVs, then CRD is upgraded when it is 17 satisfied all of the following backward compatible conditions: 18 19 - All existing serving versions in current CRD are present in new CRD 20 - All existing instances (Custom Resource) that are associated with serving versions of CRD are valid when validated against new CRD's validation schema 21 22 ### Add a new version to CRD 23 24 The recommended procedure to add a new version in CRD: 25 26 1. For example, the current CRD has one version `v1alpha1` and you want to add a new version `v1beta1` and mark it as the new storage version: 27 28 ``` 29 versions: 30 - name: v1alpha1 31 served: true 32 storage: false 33 - name: v1beta1 34 served: true 35 storage: true 36 ``` 37 38 Note: In `apiextensions.k8s.io/v1beta1`, there was a version field instead of versions. The version field is deprecated and optional, but if it is not empty, it must match the first item in the versions field. 39 40 ``` 41 version: v1beta1 42 versions: 43 - name: v1beta1 44 served: true 45 storage: true 46 - name: v1alpha1 47 served: true 48 storage: false 49 ``` 50 51 2. Ensure the referencing version of CRD in CSV is updated if CSV intends to use the new version in `owned` section: 52 53 ``` 54 customresourcedefinitions: 55 owned: 56 - name: cluster.example.com 57 version: v1beta1 58 kind: cluster 59 displayName: Cluster 60 ``` 61 62 3. Push the updated CRD and CSV to your bundle 63 64 ### Deprecate/Remove a version of CRD 65 66 OLM will not allow a serving version of CRD to be removed right away. Instead, a deprecated version of CRD should have been disabled first by marking `Served` field in CRD to `false` first. Then, the non-serving version can be removed on the subsequent CRD upgrade. 67 68 The recommended procedure to deprecate and remove a specific version in CRD: 69 70 1. Mark the deprecated version as non-serving to indicate this version is no longer in use and may be removed in subsequent upgrade. For example: 71 72 ``` 73 versions: 74 - name: v1alpha1 75 served: false 76 storage: true 77 ``` 78 79 2. Switch storage version to a serving version if soon-to-deprecated version is currently the storage version. 80 For example: 81 82 ``` 83 versions: 84 - name: v1alpha1 85 served: false 86 storage: false 87 - name: v1beta1 88 served: true 89 storage: true 90 ``` 91 92 3. Upgrade CRD with above changes. 93 94 4. In subsequent upgrade cycles, the non-serving version can be removed completely from CRD. For example: 95 96 ``` 97 versions: 98 - name: v1beta1 99 served: true 100 storage: true 101 ``` 102 103 Note: 104 105 1. In order to remove a specific version that is or was storage version from CRD, that version needs to be removed from 106 `storedVersion` in CRD's status. OLM will attempt to do this for you if it detects a stored version no longer exists in new CRD. 107 108 2. Ensure referencing CRD's version in CSV is updated if that version is removed from the CRD. 109 110 # Example: Deprecate dependant API 111 112 A and B are APIs (e.g. CRDs) 113 114 * A's provider depends on B 115 * B’s provider has a Subscription 116 * B’s provider updates to provide C but deprecates B 117 118 This results in: 119 120 * B no longer has a provider 121 * A no longer works 122 123 This is a case we prevent with OLM's upgrade strategy. 124 125 126 # Example: Version deadlock 127 128 A and B are APIs 129 130 * A's provider requires B 131 * B's provider requires A 132 * A's provider updates to (provide A2, require B2) and deprecate A 133 * B's provider updates to (provide B2, require A2) and deprecate B 134 135 If we attempt to update A without simultaneously updating B, or vice-versa, we won't be able to progress to new versions of the operators, even though a new compatible set can be found. 136 137 This is another case we prevent with OLM's upgrade strategy. 138 139 140 # Dependency resolution 141 142 A Provider is an operator which "Owns" a CRD or APIService. 143 144 This algorithm will result in a successful update of a generation (in which as many operators which can be updated have been): 145 146 ``` 147 Consider the set of operators defined by running operators in a namespace: 148 149 For each subscription in the namespace: 150 if the subscription hasn't been checked before, find the latest CSV in the source/package/channel 151 provisionally add the operator to the generation 152 else 153 check for a replacement in the source/package/channel 154 155 // Generation resolution 156 For each required API with no provider in gen: 157 search through prioritized sources to pick a provider 158 provisionally add any new operators found to the generation, this could also add to the required APIs without providers 159 160 // Downgrade 161 if there are still required APIs that can't be satisfied by sources: 162 downgrade the operator(s) that require the APIs that can't be satisfied 163 164 // Apply 165 for each new operator required, install it into the cluster. Any newly resolved operator will be given a subscription to the channel/package/source it was discovered in. 166 ``` 167 168 The operator expansion loop is bounded by the total number of provided apis across sources (because a generation may not have multiple providers) 169 170 The downgrade loop will eventually stop, though it may contract back down to the original generation in the namespace. Downgrading an operator means it was in the previous generation. By definition, either its required apis are satisfied, or will be satisfied by the downgrade of another operator.