Catalog Update Formulary
Background
File-based-catalogs (FBC) and catalog templates (templates) provide operator authors with standardized schemas to express operator upgrade graphs. However, without explicit tooling users require clear examples of how to achieve routine goals. This document is an attempt to establish a formulary of common operations, specifically with the intention of making these pieces automatable. This is in no way an exhaustive list.
Conventions
Formulae will be identified as FBC, basic catalog template (basic template), or semver catalog template (semver template). Schema manipulations will be modeled using YAML and yq. Wherever possible, example input will be limited to the relevant object hierarchies. Truncation is indicated by elipses (…) before and after the text.
Examples
For brevity, all formulae will refer to the same example, for semver template and FBC. For convenience, all semver bundle image pullspecs will express versions which match the bundle version (instead of SHAs).
FBC example
Formulae presume the following content is saved to the file fbc.yaml
---
defaultChannel: stable-v1.0
name: testoperator
schema: olm.package
---
entries:
- name: testoperator.v1.0.0
- name: testoperator.v1.0.1
skips:
- testoperator.v1.0.0
name: candidate-v1.0
package: testoperator
schema: olm.channel
---
entries:
- name: testoperator.v1.1.0
replaces: testoperator.v1.0.1
skips:
- testoperator.v1.0.0
name: candidate-v1.1
package: testoperator
schema: olm.channel
---
entries:
- name: testoperator.v1.0.1
name: fast-v1.0
package: testoperator
schema: olm.channel
---
entries:
- name: testoperator.v1.1.0
replaces: testoperator.v1.0.1
name: fast-v1.1
package: testoperator
schema: olm.channel
---
entries:
- name: testoperator.v1.0.1
name: stable-v1.0
package: testoperator
schema: olm.channel
basic template example
Formulae presume the following context is saved to the file basic.yaml
schema: olm.template.basic
entries:
- schema: olm.package
name: testoperator
defaultChannel: stable
- schema: olm.channel
package: testoperator
name: stable
entries:
- name: testoperator.v0.1.0
- name: testoperator.v0.2.0
replaces: testoperator.v0.1.0
- schema: olm.bundle
image: quay.io/organization/testoperator:v0.1.0
- schema: olm.bundle
image: quay.io/organization/testoperator:v0.2.0
semver template example
Formulae presume the following content is saved to the file semver.yaml
schema: olm.semver
generateMajorChannels: false
generateMinorChannels: true
candidate:
bundles:
- image: quay.io/organization/testoperator:v1.0.0
- image: quay.io/organization/testoperator:v1.0.1
- image: quay.io/organization/testoperator:v1.1.0
fast:
bundles:
- image: quay.io/organization/testoperator:v1.0.1
- image: quay.io/organization/testoperator:v1.1.0
stable:
bundles:
- image: quay.io/organization/testoperator:v1.0.1
Formulae
Adding a new bundle to an existing channel
FBC
Add a new testoperator.v1.1.1
edge to an existing candidate-v1.1
channel
yq eval 'select(.schema=="olm.channel" and .name == "candidate-v1.1").entries += [{"name" : "testoperator.v1.1.1"}]' fbc.yaml
produces updated candidate-v1.1
channel:
...
entries:
- name: testoperator.v1.1.0
replaces: testoperator.v1.0.1
skips:
- testoperator.v1.0.0
- name: testoperator.v1.1.1
name: candidate-v1.1
package: testoperator
schema: olm.channel
...
Warning
This example illustrates how it is possible to inadvertently create multiple channel heads
opm validate
result for this output would be:
FATA[0000] invalid index:
└── invalid package "testoperator":
└── invalid channel "candidate-v1.1":
├── multiple channel heads found in graph: testoperator.v1.1.0, testoperator.v1.1.1
basic
Add a new testoperator.v0.2.1
bundle pullspec to the existing stable
channel
yq eval 'select(.schema == "olm.template.basic").entries[] |= select(.schema == "olm.channel" and .name == "stable").entries += [{"name" : "testoperator.v0.2.1", "replaces": "testoperator.v0.2.0"}]' basic.yaml
produces updated stable
channel:
...
- schema: olm.channel
package: testoperator
name: stable
entries:
- name: testoperator.v0.1.0
- name: testoperator.v0.2.0
replaces: testoperator.v0.1.0
- name: testoperator.v0.2.1
replaces: testoperator.v0.2.0
...
semver
Add a new testoperator.v1.1.1
bundle pullspec to the Candidate
channel archetype
yq eval '.candidate.bundles += [{"image" : "quay.io/organization/testoperator:v1.1.1"}]' semver.yaml
produces updated Candidate
archetype contents:
...
candidate:
bundles:
- image: quay.io/organization/testoperator:v1.0.0
- image: quay.io/organization/testoperator:v1.0.1
- image: quay.io/organization/testoperator:v1.1.0
- image: quay.io/organization/testoperator:v1.1.1
...
Adding a new ‘replaces’ link between two existing bundles
Note
This operation is not possible for the semver template, which exclusively leverages semver ordering to generate an opinonated upgrade graph.FBC
Adding a new testoperator.v1.1.1
bundle version edge with a replaces link to its predecessor testoperator.v1.1.0
version which already exists in the channel.
yq eval 'select(.schema == "olm.channel" and .name == "candidate-v1.1").entries += [{"name" : "testoperator:v1.1.1", "replaces": "testoperator:v1.1.0"}]' fbc.yaml
produces updated candidate-v1.1
channel:
...
entries:
- name: testoperator.v1.1.0
replaces: testoperator.v1.0.1
skips:
- testoperator.v1.0.0
- name: testoperator:v1.1.1
replaces: testoperator:v1.1.0
name: candidate-v1.1
package: testoperator
schema: olm.channel
...
basic
Adding a new testoperator.v0.1.1
bundle version edge with a replaces link to its predecessor testoperator.v0.1.0
version which already exists in the channel.
yq eval 'select(.schema == "olm.template.basic").entries[] |= select(.schema == "olm.channel" and .name == "stable").entries += [{"name" : "testoperator:v0.1.1", "replaces": "testoperator:v0.1.0"}]' basic.yaml
produces updated stable
channel:
...
- schema: olm.channel
package: testoperator
name: stable
entries:
- name: testoperator.v0.1.0
- name: testoperator.v0.2.0
replaces: testoperator.v0.1.0
- name: testoperator:v0.1.1
replaces: testoperator:v0.1.0
...
Removing a specific bundle version
Note
This operation is not possible for the semver template, which exclusively leverages semver ordering to generate an opinonated upgrade graph.FBC
Remove the upgrade edge from the example candidate-v1.1
channel which refers to bundle version testoperator.v1.1.0
.
yq eval 'del(select(.schema == "olm.channel" and .name == "candidate-v1.1" ).entries[]| select(.name == "testoperator.v1.1.0"))' fbc.yaml
produces updated candidate-v1.1
channel:
...
entries: []
name: candidate-v1.1
package: testoperator
schema: olm.channel
...
Warning
Please note that removing the only edge for a channel as in this example will yield an explicitly empty array. This will produce an error inopm validate
.basic
Remove the upgrade edge from the example stable
channel which refers to bundle version testoperator.v0.2.0
.
yq eval 'select(.schema == "olm.template.basic").entries[] |= del(select(.schema == "olm.channel" and .name == "stable").entries[]| select(.name == "testoperator.v0.2.0"))' basic.yaml
produces updated stable
channel:
...
- schema: olm.channel
package: testoperator
name: stable
entries:
- name: testoperator.v0.1.0
...
Substituting a bundle version in the upgrade graph
FBC
For all graph edges, replaces instances of testoperator.v1.1.0
with a different bundle version testoperator.v1.1.0-CVE
yq '(.. | select(has("entries") and .entries[].name == "testoperator.v1.1.0" ).entries[]).name = "testoperator.v1.1.0-cve"' fbc.yaml
produces updated channels:
---
defaultChannel: stable-v1.0
name: testoperator
schema: olm.package
---
entries:
- name: testoperator.v1.0.0
- name: testoperator.v1.0.1
skips:
- testoperator.v1.0.0
name: candidate-v1.0
package: testoperator
schema: olm.channel
---
entries:
- name: testoperator.v1.1.0-cve
replaces: testoperator.v1.0.1
skips:
- testoperator.v1.0.0
name: candidate-v1.1
package: testoperator
schema: olm.channel
---
entries:
- name: testoperator.v1.0.1
name: fast-v1.0
package: testoperator
schema: olm.channel
---
entries:
- name: testoperator.v1.1.0-cve
replaces: testoperator.v1.0.1
name: fast-v1.1
package: testoperator
schema: olm.channel
---
entries:
- name: testoperator.v1.0.1
name: stable-v1.0
package: testoperator
schema: olm.channel
basic
For all channels, replace instances of testoperator:v0.1.0
with testoperator:v0.1.0-CVE
yq '(..| select(. == "testoperator.v0.1.0")) |="testoperator.v0.1.0-CVE"' basic.yaml
produces updated channels:
...
- schema: olm.channel
package: testoperator
name: stable
entries:
- name: testoperator.v0.1.0-CVE
- name: testoperator.v0.2.0
replaces: testoperator.v0.1.0-CVE
...
semver
For all channels, replace instances of quay.io/organization/testoperator:v1.1.0
with quay.io/organization/testoperator:v1.1.0-CVE
yq '(..| select(has("image") and .image == "quay.io/organization/testoperator:v1.1.0")).image = "quay.io/organization/testoperator:v1.1.0-cve"' semver.yaml
produces updated template:
schema: olm.semver
generatemajorchannels: false
generateminorchannels: true
candidate:
bundles:
- image: quay.io/organization/testoperator:v1.0.0
- image: quay.io/organization/testoperator:v1.0.1
- image: quay.io/organization/testoperator:v1.1.0-cve
fast:
bundles:
- image: quay.io/organization/testoperator:v1.0.1
- image: quay.io/organization/testoperator:v1.1.0-cve
stable:
bundles:
- image: quay.io/organization/testoperator:v1.0.1
Introducing a new replacement relationship in the upgrade graph
Note
This operation is not possible for the semver template, which exclusively leverages semver ordering to generate an opinonated upgrade graph.FBC
Substitute an existing ‘replaces’ link target for testoperator.v1.1.0
with a different bundle version testoperator.v1.0.0
.
yq eval 'select(.schema == "olm.channel" and .name == "candidate-v1.1").entries |= [{"name" : "testoperator:v1.1.0", "replaces": "testoperator:v1.0.0"}]' fbc.yaml
produces updated candidate-v1.1
channel:
...
entries:
- name: testoperator:v1.1.0
replaces: testoperator:v1.0.0
name: candidate-v1.1
package: testoperator
schema: olm.channel
...
basic
Substitute an existing ‘replaces’ link target for testoperator.v0.2.0
with a different bundle version testoperator.v0.1.5
.
yq eval '.entries[] |= select(.schema == "olm.channel" and .name == "stable").entries |= [{"name" : "testoperator:v0.2.0", "replaces": "testoperator:v0.1.5"}]' basic.yaml
produces updated stable
channel:
...
- schema: olm.channel
package: testoperator
name: stable
entries:
- name: testoperator:v0.2.0
replaces: testoperator:v0.1.5
...