---
# System prepended metadata

title: Updating templates / FBC on bundle publish
tags: [fbc]

---

---
tags: fbc
title: Updating templates / FBC on bundle publish
---

# Updating templates / FBC on bundle publish

## Background

We seek to provide an automate-able process for updating authors' FBC on new bundle publish, with the ultimate goal of a fully-automated bundle-publish...catalog-publish pipeline. As catalog templates are a simplification designed to ease maintainance of FBCs, then any solution must also account for them.

Furthermore, we recognize that the goal of dynamic updates can be antithetical to FBC's promise of a declarative paradigm for describing operator upgrade graphs **as well as** resulting in the OLM team's tooling (and by extension the team) becoming responsible for supporting any arbitrary opinionated use-case in future.

## Goals
1. provide an automate-able solution to update upgrade graph which is idempotent
2. provide failure modes which do not require parsing error messaging to interpret
3. provide a solution which works from an author-out direction

## Non-goals
1. provide an OLM-centric approach
2. provide an imperative approach
3. provide a solution which works from an author-in direction (e.g. automated CVE updates by a later pipeline)
4. provide propagation of bundle properties (i.e. CSV) to inform updates

## Problem Domain

Automating bundle publication updates require modification of FBC/precursor catalog templates.  Presently the approach is un-documented and assumed to be manual (more specifically it is assumed that the operator author is sufficiently knowledgeable/opinionated to make necessary updates).



```mermaid
graph TB;
   A[A. publish new bundle];
   B[B. determine destination catalogs];
   C[C. determine destination channels];
   D[D. determine channel position];
   E[E. insert new bundle];
   F[F. publish];
   A -- multi-catalog --> B;
   A -- single-catalog --> C;
   B --> C;
   C --> D;
   D --> E;
   E --> F;   
```



## Candidate approaches

### 1. Formula "cheat sheet"
Capturing common use-cases in a formulary of jq/yq commands to achieve updates.
examples:
   * [`semver template`] adding new v1.2.3 bundle to `candidates` channel archetype [here](https://hackmd.io/i5HuUv2sRi-dWm-m_VYi4w#semver-template-add-new-v123-bundle-to-candidates-channel-archetype)
   * [`basic template` or raw FBC] adding new `replaces` edge for a new v1.2.3 bundle from its predecessor version [here](https://hackmd.io/i5HuUv2sRi-dWm-m_VYi4w#basic-templateFBC-add-new-replaces-edge-for-a-new-v123-bundle-from-its-predecessor-version-both-versions-known)

Please note that a separate action is needed to add the `olm.bundle` object.  This could be via 
* [raw FBC] 
```bash!
opm render -o yaml [bundlepullspec] >> my-fbc.yaml
```

* `basic template` via heredoc: 
```bash=
cat <<EOF >> basic-template.yaml
---
schema: olm.bundle
image: quay.io/exampleowner/exampleoperator:v1.2.3
EOF
```
**Pros:** 
- immediately available
- iterable as new scenarios arise

**Cons:**
- multiple documentation touches
- handles the problem symptomatically, not systemically

### 2. Imperative inputs
parameters passed as a channel selector pattern, or a predecessor pattern, and an ordering mechanism (before, after)

- **Rejected**. Violates non-goal: Results become imperative. 

### 3. Builtin template parameters to inform update actions
ordering parameters as part of the template spec (`addition-policy`: [existing-head, before-head, natural-order, etc.]).  Requires discrete support in all template approaches.  Excludes support for raw FBC approach.  Requires a supported imperative-mode command in `opm` binary to make updates, which means that the opinions it supports are unlikely to be general enough to support likely use-cases.
- **Rejected**.  Violates multiple non-goals.  Mixes imperative influences into a declarative framework.  Opinions are liable to be perceived as restrictive and mis-aimed, leading to concentrated efforts to support. 

### 4. Unopinionated template update
Like kubectl patch, where an input JSON/YAML snippet containing enough information to anchor the updated bundle is supplied.  This is imperative, as for the case where C follows B follows A, C cannot be added to the graph until B is present. Patches would have to be applied to the template before rendering, in order to remain intuitive to the user.  https://github.com/evanphx/json-patch is the library that `kubectl patch` uses for this functionality. This is one example of an imperative approach to modifying declarative elements. 
- **Rejected**. But this is essentially yq/jq.  We will have reinvented (and have to support) yq/jq. :frowning: 

### 5. Tooling to migrate from new bundle's CSV
- **Rejected**.  We're actively attempting to migrate from bundle-based CSV properties as the basis for establishing upgrade graphs.

### 6. Remodeling/Replacing the `basic template`
Since making automated updates to the `semver template` is relatively simple (just requiring channel-archetype+bundle-image), the sweet spot for this becomes users of the `basic template`. If the use-case is really just for that template, then why not evolve the `basic template` to be a fully-expressed schema?

Earlier discussion established fulfillment of the core concepts `which bundles participate` and `how do bundles upgrade` could be separated into separate schemas which could be layered in an informal conglomeration. An author-maintained `olm.package` object combined with the [Bundle Template Proposal](https://hackmd.io/ixIuRBNURV-7K4C1aGkzxQ#Bundles) and the [Covington Template Proposal](https://hackmd.io/ixIuRBNURV-7K4C1aGkzxQ#Covington) would fulfill these use-cases.

Independent-but-informally-associated schemas generate many combinations and edge cases, as well as opening the door to arbitrary combinations of FBC snippets + supported schemas and questions of precedence of repeated objects.

A much less complex approach is to aggregate those as sub-schemas to a comprehensive parent, and then bundles can be automagically detected/added and any graph update becomes one or more simple yq/jq schema operations.

```yaml=
---
schema: olm.template.goodstuff
package:
   name: example
   defaultChannel: stable
bundles:
   repo: quay.io/example-inc/example-bundle
   tagRegex: "^v\d+\.\d+\.\d+$"
   semverRange: ">=0.1.x"
   images:
   - quay.io/example-inc/example-bundle:v0.0.1
   - quay.io/example-inc/example-bundle:v0.0.2
   - quay.io/example-inc/example-bundle:v0.0.3
graph-description:
   package: example
   name: stable
   entries:
   - example.v0.1.0
   - example.v0.2.0
   - example.v0.2.1
   - example.v0.2.2
   - example.v0.2.3
   - example.v0.3.0
   - example.v0.3.1
   - example.v0.3.2
   - example.v1.0.0
   - example.v1.0.1
   tombstones:
   - example.v0.2.0
   - example.v0.2.1
   - example.v0.2.2
   - example.v0.3.0
   - example.v0.3.1
   - example.v1.0.0
   tailEdges:
     skips:
     - example.v0.0.1
     - example.v0.0.2
     - example.v0.0.3
```

`opm alpha render-template goodstuff [infile]`

Output:
```yaml=
---
schema: olm.package
name: example
defaultChannel: stable
---
schema: olm.channel
package: example
name: stable
entries:
- name: example.v0.0.1
- name: example.v0.0.2
  replaces: example.v0.0.1
- name: example.v0.0.3
  replaces: example.v0.0.1
  skips:
  - example.v0.0.2
- name: example.v0.1.0
  skips:
  - example.v0.0.1
  - example.v0.0.2
  - example.v0.0.3
- name: example.v0.2.3
  replaces: example.v0.1.0
  skips: 
  - example.v0.2.0
  - example.v0.2.1
  - example.v0.2.2
- name: example.v0.3.2
  replaces: example.v0.2.3
  skips:
  - example.v0.3.0
  - example.v0.3.1
- name: example.v1.0.1
  replaces: example.v0.3.2
  skips: 
  - example.v1.0.0
---
schema: olm.bundle
package: example
name: example.v0.1.0
image: quay.io/example-inc/example-bundle:v0.1.0
properties:
- type: olm.package
  value:
    name: example
    version: 0.1.0
relatedImages:
- name: ""
  image: quay.io/example-inc/example:v0.1.0
---
schema: olm.bundle
package: example
name: example.v0.2.3
image: quay.io/example-inc/example-bundle:v0.2.3
properties:
- type: olm.package
  value:
    name: example
    version: 0.2.3
relatedImages:
- name: ""
  image: quay.io/example-inc/example:v0.2.3
---
schema: olm.bundle
package: example
name: example.v0.3.2
image: quay.io/example-inc/example-bundle:v0.3.2
properties:
- type: olm.package
  value:
    name: example
    version: 0.3.2
relatedImages:
- name: ""
  image: quay.io/example-inc/example:v0.3.2
---
schema: olm.bundle
package: example
name: example.v1.0.1
image: quay.io/example-inc/example-bundle:v1.0.1
properties:
- type: olm.package
  value:
    name: example
    version: 1.0.1
- type: olm.bundle.object
  value:
    data: <a_whole_bunch_of_base64_data_here>
- type: olm.bundle.object
  value:
    data: <a_whole_bunch_of_base64_data_here>
relatedImages:
- name: ""
  image: quay.io/example-inc/example:v1.0.1
```

**Pros:**
- systemic solution
- graph description strongly resembles Cincinnati 
- if replacing the basic template, all supported schemas would have proper identification and we could simply the opm command to eliminate the template type: 
`opm alpha render-template semver` becomes `opm alpha render-template`

**Cons:**
- non-trivial to implement
- relationship to basic template unclear.  Should this be a replacement for it?


## Conclusion
Given the effort:benefit disparity between the `formulary` and `new template` approaches, let's pursue compilation of a formulary of essential use-cases in a follow-up document. 

-------

## Reviewers
- [x] Joe Lanford, OF staff engineer
- [ ] Ben Parees, OpenShift staff engineer
- [ ] Catherine Chan-tse, OF Ecosystem team lead
- [ ] Lance Galletti, PE team lead
- [x] Bryce Palmer, OF Ecosystem team
- [x] Tony Wu, OF PM

-----

## Appendices
## Appendix 1: What leverage available in pre-existing work?

With existing catalog templates we have the ability to expand/extrapolate some input YAML/JSON which is compliant with our defined schemas to generate FBC. Below is an examination of the various types, identifying any specific concerns/constraints.

### Raw FBC
The basic assumption is that anyone who opts to use raw FBC has already accepted the burden of updating it, manually or via their own toolchain (for e.g. complex yq/jq commands). We should continue to focus efforts on the 'easy button' of catalog templates, where they exist.

### Basic Template
Since this differs from raw FBC only in that it allows shorthanded `bundle.image` references, it means that all channel designations are unrestricted/unopinionated. The only knob available here is the `package.defaultChannel` property. It would be possible to add the new bundle image to the channel indicated by this property and/or all the other defined channels, no direction of the bundle's location in the upgrade graph is derivable.

### Semver Template
A user could possibly specify the channel archetype(s) and the bundle image pullspec. The template expansion would provide all the necessary linkages.

### Composite Template
Basically a conglomeration of other types for the purpose of coordinating multiple contributions, the salient concern here is an approach which would function for any builder type.

#### Basic Builder
See [basic template](#basic_template)

#### Semver Builder
See [semver template](#semver_template)

#### Raw Builder
See [raw FBC](#raw_fbc)

#### Custom Builder
This should be an error scenario.  If the author is already providing the FBC via an opaque process, then they should also handle addition of any new bundles as part of their process.

