Skip to content

Conversation

@erikh
Copy link
Contributor

@erikh erikh commented Feb 6, 2017

This patch augments the interfaces' close methods with an error return which is
only actually useful in one or two spots for now. However, it can be utilized
later as things fill in.

Fixes #82

Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

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

Thanks!

skopeo should be similarly updated to handle the errors.

I am still not sold on this being truly worthwhile (all this only to report a failure in daemonImageSource when we fail to remove a temporary file which will be very likely cleaned up by systemd-tmpfiles in the worst case?), but if we are doing this, let’s actually do it right.

var err error
if !d.committed {
logrus.Debugf("docker-daemon: Closing tar stream to abort loading")
err = errors.New("Aborting upload, daemonImageDestination closed without a previous .Commit()")
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is not an error in .Close(); if the caller decides to abort without a .Commit(), and the upload is successfully aborted, .Close() should indicate success.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is still outstanding.

Reference() ImageReference
// Close removes resources associated with an initialized ImageDestination, if any.
Close()
Close() error
Copy link
Collaborator

Choose a reason for hiding this comment

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

The caller in copy.Image should be updated to handle the error.

Reference() ImageReference
// Close removes resources associated with an initialized UnparsedImage, if any.
Close()
Close() error
Copy link
Collaborator

Choose a reason for hiding this comment

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

The callers in copy.Image (both for UnparseImage and Image) should be updated to handle the error.

And perhaps doc.go as well?

@mtrmac
Copy link
Collaborator

mtrmac commented Feb 6, 2017

To link the two, this fixes #82.

@erikh
Copy link
Contributor Author

erikh commented Feb 6, 2017

Will make adjustments, and file a PR on skopeo in the next few days.

@erikh erikh force-pushed the close-with-error branch 2 times, most recently from 484c771 to 2682f2f Compare February 9, 2017 02:58
@erikh
Copy link
Contributor Author

erikh commented Feb 9, 2017

Ok I updated this to handle close errors, I also changed the return convention (read the comments at the inner-top of copy.Image) to use output variables. All is explained in comments, but if this feels too cumbersome for the benefits we can talk about alternatives.

// source image admissibility.
func Image(policyContext *signature.PolicyContext, destRef, srcRef types.ImageReference, options *Options) (retErr error) {
// XXX this function uses an output parameter for the error return value.
// Setting this and returning is the ideal way to return an error.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Looking at https://golang.org/ref/spec#Return_statements , even with a named return value it would be perfectly fine to just return somerrorvalue AFAICS.

(Also, doesn’t XXX mean “this is bad”? Perhaps just NOTE: or something like that.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. I typically use it to say "WARNING" or something of the like: "pay attention" basically.

copy/copy.go Outdated
defer dest.Close()
defer func() {
if err := dest.Close(); err != nil {
retErr = errors.Wrapf(retErr, "dest: %v", err)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should only happen if retErr == nil; the original value of retErr was the primary cause we are failing; that dest.Close() has failed may be completely unrelated, or it may be a side effect of the original retErr failure.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok sure, I was just thinking that maybe it'd be nice to have all the error context in the event of a copy failure.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh, sorry, I wasn’t paying enough attention to notice that this preserves both. Let me check…

Copy link
Collaborator

Choose a reason for hiding this comment

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

… something like this would be nice if we can make that human-readable. See how the other errors.Wrapf calls in here try to tell the user what is going on. I am not sure that this is workable here:

errors.Wrapf(retErr, "Error closing destination: %v, after primary failure", err)

is bordering on incomprehensible, especially if err were long / created by several errors.Wrapf calls. (We can make the underlying data type situation better by using something like aggregateErr from openshift-copies.go, but that is probably even worse for readability.)

If we can’t make that human-readable, I think preserving a non-nil retErr is more important than the failure from .Close.

@runcom ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I get the concern.

What if I did something like this:

errors.Wrapf(retErr, "(destination error %v) ", err)

That way each indepednent error would be wrapped by parens. I could also add newlines.

I think the errors will be valuable context in the face of other, higher level errors.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That’s certainly better than my attempt.

The code as is (making daemonImageSource.Close fail using an invalid path):

$ sudo ./x docker-daemon:busybox:latest dir:d
FATA[0000] Error copying: source: remove makethisfail//var/tmp/docker-daemon-tar266436759: no such file or directory: Error writing blob: open d/dir-put-blob135662858: no such file or directory 

quite misleading about the cause/effect relationships

“primary error” wording:

FATA[0000] Error copying: Error closing source: remove makethisfail//var/tmp/docker-daemon-tar088311212: no such file or directory, after primary failure: Error writing blob: open d/dir-put-blob812853531: no such file or directory 

Still focusing on the wrong thing (closing failure)

With the parentheses:

FATA[0000] Error copying: (source error remove makethisfail//var/tmp/docker-daemon-tar460112488: no such file or directory): Error writing blob: open d/dir-put-blob983238823: no such file or directory 

Certainly better. Good enough?

Newlines are attractive (they would even allow us to build a bulleted list :) ) but risky, the caller is fairly likely not expecting them.

At this point I am really not sure, I’ll let @runcom weigh in.

copy/copy.go Outdated
if unparsedImage != nil {
unparsedImage.Close()
if err := unparsedImage.Close(); err != nil {
retErr = errors.Wrapf(retErr, "unparsed: %v", err)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here

copy/copy.go Outdated
defer src.Close()
defer func() {
if err := src.Close(); err != nil {
retErr = errors.Wrapf(retErr, "source: %v", err)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here

var err error
if !d.committed {
logrus.Debugf("docker-daemon: Closing tar stream to abort loading")
err = errors.New("Aborting upload, daemonImageDestination closed without a previous .Commit()")
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is still outstanding.

copy/copy.go Outdated
if err != nil {
return errors.Wrapf(err, "Error initializing destination %s", transports.ImageName(destRef))
retErr = errors.Wrapf(err, "Error initializing destination %s", transports.ImageName(destRef))
return
Copy link
Contributor

Choose a reason for hiding this comment

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

This change is not necessary. return X will set retErr = x implicitly.

@erikh
Copy link
Contributor Author

erikh commented Feb 20, 2017

PTAL

changes:

  • using parens for inner errors now
  • retErr code was adjusted based on return semantics.

@erikh
Copy link
Contributor Author

erikh commented Feb 21, 2017

#240 is blocking this.

@mtrmac
Copy link
Collaborator

mtrmac commented Feb 21, 2017

LGTM pending tests. (Shouldn't test-skopeo work even after the API change? If not, the way we deal with API interdependencies is usually to

  • Temporarily modify the corresponding skopeo PR to vendor from the proposed branch, show that that passes tests
  • Then merge the containers/image PR, ignoring the test failure
  • Update the skopeo PR to vendor from the updated containers/image master again, and merge it.

Approved with PullApprove

@mtrmac
Copy link
Collaborator

mtrmac commented Feb 21, 2017

👍

@erikh
Copy link
Contributor Author

erikh commented Feb 25, 2017

rebased

@runcom
Copy link
Member

runcom commented Feb 25, 2017

@erikh sorry needs one last rebase before I merge this

This allows us to provide in the image interfaces a method of providing
an error at close time. This is only currently used in a few situations.

Signed-off-by: Erik Hollensbe <github@hollensbe.org>
@erikh
Copy link
Contributor Author

erikh commented Feb 25, 2017 via email

@runcom
Copy link
Member

runcom commented Feb 25, 2017

👍

Approved with PullApprove

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Close() should be Close() error

4 participants