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

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

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

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

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

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