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 pertaining to either FBC or semver catalog template (semver template). Since FBC and the basic catalog template (basic template) both represent the upgrade graph in the set of olm.channel objects, instructions for FBC will also be applicable to the basic template. Manipulations of olm.bundle attributes are limited to FBC representation only. 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).

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

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

Formulae

Adding a new bundle to an existing channel

semver

Add a new testoperatorv1.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
...

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
...

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

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
...

Removing a specific bundle version

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
...

Substituting a bundle version in the upgrade graph

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

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

Introducing a new replacement relationship in the 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
...