Skip to content
This repository has been archived by the owner on Aug 12, 2024. It is now read-only.

Add package for handling bundle formats #396

Merged
merged 17 commits into from
Jun 27, 2022
Merged

Add package for handling bundle formats #396

merged 17 commits into from
Jun 27, 2022

Conversation

ryantking
Copy link

@ryantking ryantking commented May 24, 2022

This adds package github.com/operator-framework/rukpak/pkg/bundle, which is a public API for working with and converting between bundle formats. Support is limited for the registry+v1 and plain+v0 formats and converting from the former to the latter.

@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label May 24, 2022
Copy link
Contributor

@timflannagan timflannagan left a comment

Choose a reason for hiding this comment

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

I took a glance at these changes and they seem relatively reasonable to me. I'm a fan of using the options pattern here to help improve interacting with this library.

I have a couple of quick questions:

  • Can we create a tracking issue for modularizing this library?
  • Does it make sense to have a standalone commit for moving the convert library from the internal directory to the pkg directory?

I think my only concern right now is support guarantees with exported functions in a pkg/ directory that clients depend on while we continue to iterate on this project. Maybe it's sufficient in the short term to have a nested README that adds a warning that the exported functions/behaviors are subject to change? Thoughts?

Copy link
Member

@joelanford joelanford left a comment

Choose a reason for hiding this comment

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

Nice! This is looking much cleaner than before.

I think the next step (could be in a follow-up) would be to have functions that can convert:

  • fs.FS => RegistryV1
  • Plain => fs.FS

That way, it would be simple to chain fs.FS => RegistryV1 => Plain => fs.FS

@joelanford
Copy link
Member

I think my only concern right now is support guarantees with exported functions in a pkg/ directory that clients depend on while we continue to iterate on this project.

As long as we stay at v0, we're good to make breaking changes on minor version bumps of this repo.

@timflannagan
Copy link
Contributor

That way, it would be simple to chain fs.FS => RegistryV1 => Plain => fs.FS

Yeah, this seems super reasonable to me. Does the registry code around FBCs also have an intermediate representation layer too?

@openshift-ci openshift-ci bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 1, 2022
@openshift-ci openshift-ci bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 21, 2022
@ryantking ryantking marked this pull request as ready for review June 22, 2022 18:25
@ryantking ryantking requested a review from a team as a code owner June 22, 2022 18:26
@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jun 22, 2022
Copy link
Member

@exdx exdx left a comment

Choose a reason for hiding this comment

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

This is a very cool PR, I like the use of generics. I had some high-level feedback.

pkg/bundle/fs.go Show resolved Hide resolved
pkg/bundle/fs.go Show resolved Hide resolved
pkg/bundle/fs.go Outdated Show resolved Hide resolved
pkg/bundle/plain/v0/bundle.go Outdated Show resolved Hide resolved
}

func (b Bundle) generateName(base string, o interface{}) string {
const maxNameLength = 63
Copy link
Member

Choose a reason for hiding this comment

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

nit: we enforce that the length of a rukpak Bundle type is maximum 40 characters long (see https://github.com/operator-framework/rukpak/blob/main/manifests/apis/crds/patches/bundle_validation.yaml#L1). Would it make sense to have a similar limit here?

Copy link
Author

Choose a reason for hiding this comment

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

Pinging @joelanford and @timflannagan to weigh on this one.

pkg/bundle/plain/v0/bundle.go Outdated Show resolved Hide resolved
pkg/bundle/fs.go Show resolved Hide resolved
pkg/bundle/fs.go Show resolved Hide resolved
pkg/bundle/fs.go Outdated Show resolved Hide resolved
pkg/bundle/fs.go Outdated Show resolved Hide resolved
pkg/bundle/fs_test.go Show resolved Hide resolved
pkg/bundle/objectfile.go Show resolved Hide resolved
pkg/bundle/plain/v0/bundle.go Show resolved Hide resolved
pkg/bundle/plain/v0/bundle.go Outdated Show resolved Hide resolved
Copy link
Contributor

@tylerslaton tylerslaton left a comment

Choose a reason for hiding this comment

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

Nice! This looks good to me. Great job, Ryan. 🚀

pkg/bundle/fs.go Show resolved Hide resolved
pkg/bundle/fs_test.go Show resolved Hide resolved
pkg/bundle/plain/v0/bundle.go Show resolved Hide resolved
@ryantking ryantking changed the title Refactor convert package to public API Add package for handling bundle formats Jun 24, 2022
@ryantking ryantking changed the base branch from main to bundle-convert-package June 27, 2022 14:30
@timflannagan timflannagan merged commit c2680c5 into operator-framework:bundle-convert-package Jun 27, 2022
@ryantking ryantking deleted the feature/public-convert-lib branch June 27, 2022 17:38
Comment on lines +26 to +27
// TODO(ryantking): Should we support any other file system abstractions beyond `fs.FS`?
// `fs.FS` doesn't support any write operations. They can modify the objects in an `ObjectFile`, but that won't change
Copy link
Member

Choose a reason for hiding this comment

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

IMO, fs.FS is sufficient. We can use https://pkg.go.dev/testing/fstest#MapFS as a writable in-memory FS implementation, and if we want a writable disk implementation, then we can just use os.* functions to create the necessary files/directories and then use os.DirFS to read it.

Comment on lines +59 to +67
// WithManifestDir returns an option for creating new bundle filesystems.
//
// This option specifies which directories can contain manifests. If this opion is unset then the filesystem will search
// in all directories for manifests.
func WithManifestDirs(dirs ...string) func(*FS) {
return func(fsys *FS) {
fsys.manifestDirs = append(fsys.manifestDirs, dirs...)
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Is this too bundle format specific? A helm chart bundle format wouldn't have a manifests directory at all. How would that type of bundle work with this package?

Comment on lines +121 to +123
if filepath.Ext(name) != ".yaml" || filepath.Ext(name) == ".yml" {
return false
}
Copy link
Member

Choose a reason for hiding this comment

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

Is there a bug here with != and ==? Also, what about json files?

Comment on lines +84 to +86
// TODO(ryantking): Does srcBundle.CSV().GetName() give us package name
// per @joelanford's install namespace detection suggestion?
b.installNamespace = fmt.Sprintf("%s-system", csv.GetName())
Copy link
Member

Choose a reason for hiding this comment

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

No, csv.GetName() will return the CSV name (typically something like foo.v0.1.0). We want this to be the package name (typically something like foo).

The package name can be discovered from a registry+v1 bundle's metadata/annotations.yaml file.

return Bundle{bundleFS}
}

return Bundle{bundle.New(fsys, bundle.WithManifestDirs("manifests"))}
Copy link
Member

Choose a reason for hiding this comment

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

Technically the manifests directory for a registry+v1 bundle is defined in a property in the metadata/annotations.yaml file. I don't think I've ever seen a bundle image where that value is anything other than /manifests, so I think this is probably fine.

But just an FYI, that there may eventually be a bug reported against this functionality for not respecting the manifests dir defined in the annotations file.

Comment on lines +33 to +34
// embed.FS is only walkable from the root directory so this function accepts a prefix to filter out unwanted files.
// This looks like it could be a go bug if its not explicitly called out.
Copy link
Member

Choose a reason for hiding this comment

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

Can you use https://pkg.go.dev/io/fs#Sub here? It returns an fs that is a subdirectory of the root FS.

Comment on lines +124 to +126
if len(fsys.manifestDirs) == 0 {
return true
}
Copy link
Member

Choose a reason for hiding this comment

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

In the case of a theoretical helm chart bundle, I assume there would be no manifest dirs, which would mean every file is a manifest file? Should this block actually return false?

Comment on lines +127 to +131
for _, dir := range fsys.manifestDirs {
if strings.HasPrefix(name, dir) {
return true
}
}
Copy link
Member

Choose a reason for hiding this comment

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

This seems like something that should be left to the bundle specification. For explicitness and clarity, we said that plain manifest bundles:

  • must have a manifests directory in the root of the bundle
  • must not have any subdirectories in the manifests directory (i.e. the manifests directory must be a flat list of manifest files.

However seems like it would parse manifest files in subdirectories of a manifests dir. I think this gets back to my comment that perhaps the generic bundle code should not have any concept of manifests or kubernetes objects?

How much would it blow up this PR if we said that we wouldn't parse k8s objects at all in this generic bundle.FS layer? Would there be anything valuable left?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants