Skip to content
This repository was archived by the owner on Mar 3, 2025. It is now read-only.

Conversation

@joelanford
Copy link
Member

See:

I've structured this PR with a series of commits:

  1. Copy containers_image.go directly from operator-controller
  2. Modify it to use catalogd types
  3. The majority of the actual changes necessary to integrate into catalogd and pass tests.

Signed-off-by: Joe Lanford [email protected]

Signed-off-by: Joe Lanford [email protected]

@joelanford joelanford requested a review from a team as a code owner September 13, 2024 13:57
@codecov
Copy link

codecov bot commented Sep 13, 2024

Codecov Report

Attention: Patch coverage is 58.22222% with 94 lines in your changes missing coverage. Please review.

Project coverage is 38.04%. Comparing base (dbdce9b) to head (7b41ed3).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
internal/source/containers_image.go 62.43% 46 Missing and 31 partials ⚠️
cmd/manager/main.go 0.00% 11 Missing ⚠️
...rnal/controllers/core/clustercatalog_controller.go 0.00% 3 Missing ⚠️
internal/storage/localdir.go 25.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #399      +/-   ##
==========================================
+ Coverage   35.55%   38.04%   +2.48%     
==========================================
  Files          17       15       -2     
  Lines         734      786      +52     
==========================================
+ Hits          261      299      +38     
  Misses        443      443              
- Partials       30       44      +14     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Comment on lines -13 to -15
- op: add
path: /spec/template/spec/containers/1/args/-
value: "--ca-certs-dir=/var/certs"
Copy link
Member Author

Choose a reason for hiding this comment

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

Moved this to config/components/ca/patches/manager_deployment_cacerts.yaml (1) and changed the mount directory to /var/ca-certs (2). Why?

  1. I figured the setup of the CA was a better place to put the volume mount for that CA
  2. containers/image library complained about the original /var/certs containing the catalogd server crt/key, so this change puts just the CA in the /var/ca-certs directory separately.

Comment on lines +10 to +11
func NewUnrecoverable(err error) Unrecoverable {
return Unrecoverable{err}
Copy link
Member Author

Choose a reason for hiding this comment

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

Aligned this function with the similar change in operator-controller. There's no need for this to return a pointer. Returning a pointer here means that errors.As requires a double pointer, which is error prone.

Comment on lines 149 to 145
if cleanupErr := os.RemoveAll(unpackPath); cleanupErr != nil {
err = errors.Join(err, cleanupErr)
}
_, isDigestBased := imgRef.(reference.Canonical)
return nil, wrapUnrecoverable(fmt.Errorf("error unpacking image: %w", err), isDigestBased)
Copy link
Member Author

Choose a reason for hiding this comment

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

This is something we may want to transfer back over to operator-controller.

return err
}

func applyLayerFilter(srcPath string) archive.Filter {
Copy link
Member Author

Choose a reason for hiding this comment

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

If/when we consolidate catalogd and operator-controller, it seems like we'll want this filter function to be configurable.

For now, this is updated from operator-controller's implementation to account for catalogd's ability to unpack just the relevant FBC root directory.

Comment on lines +299 to +324
cleanName := path.Clean(strings.TrimPrefix(h.Name, "/"))
relPath, err := filepath.Rel(cleanSrcPath, cleanName)
if err != nil {
return false, fmt.Errorf("error getting relative path: %w", err)
}
return relPath != ".." && !strings.HasPrefix(relPath, "../"), nil
Copy link
Member Author

Choose a reason for hiding this comment

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

I changed the implementation that catalogd had been using because I re-read it and couldn't convince myself if would work in unexpected, but still valid, scenarios.

I added a bunch of unit tests for this function to convince myself that this implementation is solid.

assert.Contains(t, buf.String(), "found image in filesystem cache")
assert.Equal(t, tt.catalog.Status.ResolvedSource.Image.LastUnpacked, rs.ResolvedSource.Image.LastUnpacked)
assert.Contains(t, buf.String(), "image already unpacked")
assert.Equal(t, rs.ResolvedSource.Image.LastUnpacked.Time, unpackDirStat.ModTime())
Copy link
Member Author

Choose a reason for hiding this comment

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

Instead of reading status, we now expect the mod time of the directory to match.

Comment on lines +402 to +403
assert.NotEqual(t, rs.ResolvedSource.Image.LastUnpacked.Time, oldDigestModTime)
assert.NoDirExists(t, oldDigestDir)
Copy link
Member Author

Choose a reason for hiding this comment

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

Instead of reading status, we now expect the new unpack time to be different than the mod time of the old digest.

We also expect the old digest dir to no longer exist.

assert.Error(t, err)
var unrecov *catalogderrors.Unrecoverable
isUnrecov := errors.As(err, &unrecov)
isUnrecov := errors.As(err, &catalogderrors.Unrecoverable{})
Copy link
Member Author

Choose a reason for hiding this comment

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

Changing this to remove the double-pointer thing.

StateUnpacked State = "Unpacked"
)

type unpacker struct {
Copy link
Member Author

Choose a reason for hiding this comment

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

No need for all of this extra abstraction since we no longer have alternate source types.


var unrecov *catalogderrors.Unrecoverable
if errors.As(reconcileErr, &unrecov) {
if errors.As(reconcileErr, &catalogderrors.Unrecoverable{}) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Changing this to remove the double-pointer thing.

@joelanford
Copy link
Member Author

joelanford commented Sep 13, 2024

/hold

I want to update the e2e in a similar way that I did in operator-controller, where the image registry uses an untrusted cert and we mount an extra /etc/containers/registries.conf to allow an untrusted connection (and therefore verify that configuration is honored)

@openshift-ci openshift-ci bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Sep 13, 2024
Copy link
Member

@m1kola m1kola left a comment

Choose a reason for hiding this comment

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

Still need to review few more files. Will try to come back to this on Monday.

Going forward - can we please split large PRs into smaller ones as much as possible? For example build tag changes seem to be fairly independent here. It is easier to review small changes and smaller commits make code archaeology less challenging.

Comment on lines +51 to +56
//////////////////////////////////////////////////////
//
// Resolve a canonical reference for the image.
//
//////////////////////////////////////////////////////
Copy link
Member

Choose a reason for hiding this comment

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

Nit: I'm a fan of comments like this. Most of these sections look like they deserve own function.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll take a look to see if these can be function-ified. Only thing that comes to mind is if those functions would end up having to accept a bunch of parameters and return a bunch of values (and if so, maybe that wouldn't be much better?)

But good callout. I'll take a look.

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated! I made functions for:

  • resolving the named and canonical refs
  • loading the signature policy

There isn't really a lot more to squeeze out of this IMO. At this point, it's basically a series of steps with pretty straightforward error handling and basically no nesting, conditionals, or loops.

@everettraven asked for comments and structure along these lines when I was putting operator-controller's PR together because containers/image is a bit less ergonomic than google/go-containerregistry (I agree). So these comments are included to help explain what is actually going on.

I'm happy to reformat if there are other suggestions on style, but I do think the grouping and walkthrough-style narrative is helpful for the uninitiated.

-X "$(VERSION_PKG).gitTreeState=$(GIT_TREE_STATE)" \
-X "$(VERSION_PKG).commitDate=$(GIT_COMMIT_DATE)"
export GO_BUILD_GCFLAGS := all=-trimpath=${PWD}
export GO_BUILD_TAGS := containers_image_openpgp
Copy link
Member Author

Choose a reason for hiding this comment

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

@m1kola To answer your question about build tags: containers/image needs this build tag in order to build without requiring a third-party library that requires CGO.

I'm not sure it would make sense to split that into a separate PR.

Copy link
Member

Choose a reason for hiding this comment

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

@joelanford I was thinking it was possible, for example, to introduce the plumbing for the build tags and add the actual tag in this PR. But that was just an example.

In general just asking (everyone) to be conscious about the PR sizes.

Comment on lines +330 to +397
func setReadOnlyRecursive(root string) error {
if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}

fi, err := d.Info()
if err != nil {
return err
}

if err := func() error {
switch typ := fi.Mode().Type(); typ {
case os.ModeSymlink:
// do not follow symlinks
// 1. if they resolve to other locations in the root, we'll find them anyway
// 2. if they resolve to other locations outside the root, we don't want to change their permissions
return nil
case os.ModeDir:
return os.Chmod(path, 0500)
case 0: // regular file
return os.Chmod(path, 0400)
default:
return fmt.Errorf("refusing to change ownership of file %q with type %v", path, typ.String())
}
}(); err != nil {
return err
}
return nil
}); err != nil {
return fmt.Errorf("error making catalog cache read-only: %w", err)
}
return nil
}

func deleteRecursive(root string) error {
if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if !d.IsDir() {
return nil
}
if err := os.Chmod(path, 0700); err != nil {
return err
}
return nil
}); err != nil {
return fmt.Errorf("error making catalog cache writable for deletion: %w", err)
}
return os.RemoveAll(root)
}
Copy link
Member Author

@joelanford joelanford Sep 13, 2024

Choose a reason for hiding this comment

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

Probably makes sense to port these back over to operator-controller and use them there as well.

@joelanford joelanford force-pushed the containers-image branch 4 times, most recently from 23a6eff to 9878970 Compare September 14, 2024 18:10
@joelanford joelanford removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Sep 14, 2024
m1kola
m1kola previously approved these changes Sep 16, 2024
Copy link
Member

@m1kola m1kola left a comment

Choose a reason for hiding this comment

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

Just noticed one place where we duplicate if. Other than that - looks good.

I spent a lot of time staring at internal/source/containers_image.go. I think I understand what is going on there and didn't manage to spot any issues. But it might be good to have another pair of eyes on it.

-X "$(VERSION_PKG).gitTreeState=$(GIT_TREE_STATE)" \
-X "$(VERSION_PKG).commitDate=$(GIT_COMMIT_DATE)"
export GO_BUILD_GCFLAGS := all=-trimpath=${PWD}
export GO_BUILD_TAGS := containers_image_openpgp
Copy link
Member

Choose a reason for hiding this comment

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

@joelanford I was thinking it was possible, for example, to introduce the plumbing for the build tags and add the actual tag in this PR. But that was just an example.

In general just asking (everyone) to be conscious about the PR sizes.

Copy link
Member

@m1kola m1kola left a comment

Choose a reason for hiding this comment

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

Re-approving after unused error check removed.

@joelanford joelanford added this pull request to the merge queue Sep 16, 2024
Merged via the queue into operator-framework:main with commit ffdb9c3 Sep 16, 2024
@joelanford joelanford deleted the containers-image branch September 16, 2024 14:25
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.

2 participants