Skip to content

Initial proposal for mutable operator registry#95

Closed
gallettilance wants to merge 1 commit into
operator-framework:masterfrom
gallettilance:mutable-opreg
Closed

Initial proposal for mutable operator registry#95
gallettilance wants to merge 1 commit into
operator-framework:masterfrom
gallettilance:mutable-opreg

Conversation

@gallettilance
Copy link
Copy Markdown
Member

Description of the change:

Initial proposal for mutable operator registry. As an operator author, I want to modify operator registry so that I don't have to rebuild the database from scratch during iterative development.

Motivation for the change:

Reviewer Checklist

  • Docs updated or added to /docs
  • Commit messages sensible and descriptive

@openshift-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: gallettilance
To complete the pull request process, please assign ecordell
You can assign the PR to them by writing /assign @ecordell in a comment when ready.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci-robot openshift-ci-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Oct 3, 2019
@openshift-ci-robot
Copy link
Copy Markdown

@gallettilance: The following test failed, say /retest to rerun them all:

Test name Commit Details Rerun command
ci/prow/unit 6e4c681 link /test unit

Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.


We want to add create db, delete, and batch insert APIs to the model layer of operator-registry and a new set of operator registry commands to utilize those new APIs:

`operator-registry create`
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These aren't the actual commands we are going to implement though right? operator-registry does not exist as a top level command based on #89


#### Add

To achieve this we need to pull down images from a registry using podman, extract the bundle files from the container's filesystem and insert the bundle into the database. For each channel defined in the bundle's `package.yaml`:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably support more than just podman here, probably through an environment variable (docker)? We can default to podman though.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Along these lines, it's reasonable to just use containerd. Then users don't require additional tooling.

(we still may want options for shelling out for certain environments, but I think containerd gives the best ux out of the door)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we want to have a common user experience to the operator-sdk in this case. I do know that the sdk uses environment variables and wraps their build commands (for example) but under the hood they are using podman/buildah/docker cli: https://github.com/operator-framework/operator-sdk/blob/master/cmd/operator-sdk/build/cmd.go#L62

If the sdk is going to call these commands as functions, should we attempt to also have the same experience there? We could even just default to containerd if we wanted to, but from the perspective of a user trying to wrangle all these tools together does it make more sense that they all have the same defaults?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reminds me a lot of the Interface Segregation Principle. We don't require everything that SDK does, so why take on the burdens of requiring podman? I don't think the UX of this tool will differ since we're already abstracting over the operation.


### Implementation details

#### Add
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this section is making some assumptions about what the workflow is that may not be obvious to the reader. Can you explicitly define what happens internally when you call add? For example, today when we call initialize it reads the yaml files into memory, reads them into a set of data structures, and then validates that the set is internally consistent. Now we have some other constraints that involve more than just reading that stuff into memory, validating, and then performing an insert:

  1. We need to download the images that were specified

  2. We need to do something about checking whether adding the new bundle is internally consistent with the rest of the data. Does that happen via an insert and failing due to changes in the schema itself? Do we pull the bundles that are relevant to building the graph at runtime and perform the same checks that already exist by adding the new bundle to that map? How does this work?

  3. What schema changes (if any) are required for this?


1. If the channel points to a csv that is not in this bundle.

In this case, IGNORE this channel.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you be more specific about input and output here? What do you mean by ignore the channel? As in, ignore the update path for the new bundle in this channel?

Can you outline the general strategy around how the package.yaml file will be used to handle updates before going into each edge case?


- The csv is already in the database. Cannot insert.

4. The bundle is an updated version of an operator that is in the database.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this imply that version + package name == operator bundle? Can you call that out explicitly?


Cons: ordering of images may affect the state of the db?

2. We can preprocess the images to minimize collisions or optimize for a given objective
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you go into more detail here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideas for heuristics:

  • order based on semver versions of bundles
  • lexicographic order (may work for bundles that put versions in the name but don't keep the version field aligned)
  • timestamp labels

But all of these have a problem, which is that they all require unpacking all of the bundles locally at once for processing.

I lean towards doing (1) and addressing the other concerns with the separate "graph metadata" we discussed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like we can do all of (1) (2) and (3) by updating the database schema and storing those values as well. Or is that exactly what you are describing with your last sentence?


## Motivation

An index image is defined as a set of operator bundle images that are released independently and optimized in a way that can be productized by operator authors and pipeline developers. The intent of the index image is to aggregate these images that are out of scope of this enhancement. As an operator author, I want to be able to modify an existing index so I don't have to build it from scratch each time.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Being nitpicky: an index image is really defined as container image the serves the grpc api. I'm concerned someone reading this will thing that "list of operator bundle images" == "index image"

The intent of the index image is to aggregate these images that are out of scope of this enhancement.

Can we just say to aggregate these [bundle images](/link/to/bundle/enhancement)?

As an operator author, I want to be able to modify an existing index so I don't have to build it from scratch each time.

I think this should either be rewritten to fit in the paragraph, or be separated and called out as a user story.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that this section doesn't adequately explain why these artifacts need to be mutable, or explain that, in todays world, they're immutable. Could you add something to that effect?


## Proposal

This implementation makes the assumption that a separate process is built that generates container images that contain individual operator bundles for each version of an operator.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can omit this


This implementation makes the assumption that a separate process is built that generates container images that contain individual operator bundles for each version of an operator.

To start, let's define what the operator-registry does today. It:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

being nitpicky again - there are multiple tools involved here, it might be worth calling that out.


#### Add

To achieve this we need to pull down images from a registry using podman, extract the bundle files from the container's filesystem and insert the bundle into the database. For each channel defined in the bundle's `package.yaml`:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Along these lines, it's reasonable to just use containerd. Then users don't require additional tooling.

(we still may want options for shelling out for certain environments, but I think containerd gives the best ux out of the door)


Pros: simple to implement

Cons: ordering of images may affect the state of the db?
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a question - this is true given the above description of channel handling


In this case, IGNORE this channel.

2. The bundle is attached to an operator that is not in the database.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wording could be a bit clearer.

Are you saying "the image reference (quay.io/...), contains a csv such that csv.metadata.name is not a key in the bundle table"? (We don't need to be that specific here, but we should call out what the uniqueness is.)


2. The bundle is attached to an operator that is not in the database.

In this case, we can simply add this bundle to the database.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did I miss the section that describes the schema changes that allow adding bundle references to the db?


In this case, we can simply add this bundle to the database.

3. The bundle is attached to an operator in the database. If the channel points to a csv that is in this bundle:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be "for each channel in the package.yaml in the bundle, if the channel points to ..."?


3. The bundle is attached to an operator in the database. If the channel points to a csv that is in this bundle:

1. This channel is not in the database. Insert the bundle for this new channel into the database.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And insert the channel as well?


1. This channel is not in the database. Insert the bundle for this new channel into the database.

2. This channel is in the database. SELECT all csv's of that channel from the database. By looking at the replaces and skips fields of the bundle's csv, we can know where this new csv fits in the update graph. If:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually think this whole section can be reduced to the loading steps similar to what we already do:

  1. Add the bundle to the database
  2. Add the package data:
    1. If the package is not there, create it.
    2. For each channel
      1. if the channel is not there, create it
      2. if the channel is there
        1. if the new head "replaces" the current head
          1. update the channel pointer and add the new head, replacing the old head.
        2. else, delete the whole channel. Walk through the entire channel and delete the channel entries.
          1. add the new head of the channel as a channel entry as specified in package.yaml
          2. add all of the channel entries by walking back through the "replaces"

This is nice because:

  • we already have functions defined that do most of these steps, they might just need some refactring
  • we don't have to worry about "correctly" perturbing the channel in the right way
  • this generalized to batch processing easily, because you can add all of the bundles and then take the latest package data as a final step to shake out the channels
  • we have the option of optimizing more in the future

@stale
Copy link
Copy Markdown

stale Bot commented Feb 26, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale Bot added the wontfix label Feb 26, 2020
@openshift-ci-robot openshift-ci-robot added triage/unresolved Indicates an issue that can not or will not be resolved. and removed wontfix labels Feb 27, 2020
@stale
Copy link
Copy Markdown

stale Bot commented Apr 26, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@njhale
Copy link
Copy Markdown
Member

njhale commented Jun 26, 2020

IIRC, parts of this ended up being absorbed into other enhancements.

@njhale njhale closed this Jun 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Denotes a PR that changes 100-499 lines, ignoring generated files. triage/unresolved Indicates an issue that can not or will not be resolved.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants