feature: Add proper error reporting for `inspect`
It would be very nice if skopeo would have proper error reporting interface. Especially on
skopeo inspect "docker:/..."
where its not clear where the image does not exist or there was an authentication error.
Its not clear how to deal with errors with skopeo in general and for tooling this is a problem.
I see the following errors on all skopeo commands:
- exit code X: Authorization Error
on inspect:
- exit code Y: -> manifest unknow or image not existing (currently its somehow
exit 2but its nowhere documented?)
Thanks for reaching out. Please be more specific in what you mean by “proper”.
Are you talking about exit codes only? And, if relevant, what conditions?
(Ultimately, there’s very little that can fit into an 8-bit field. At some point, it would be easier to write a Go program a receive full Go types directly … to the extent those make any promises about reported error types, which is also somewhat limited.)
The current exit status 2 is documented in skopeo(1). But note the caveat there; there is no way to reliably distinguish an authentication failure from a missing image, in general. Some things just aren’t possible.
Ah ok, jeah I mean only exit code: so you say the container registry API does not have a destinction in http response status codes between notfound and auth error? Strange? especially for the transport docker://
It does have that distinction, but there have been registries which replied with “not found” to requests to read something the user (anonymous or authenticated) does not have the right to to access — I guess with the idea that even disclosing the existence of that name is disclosing private information.
Ah, ok. Its just hard to know what maps to 2? Possibly anything? Also server error? Or only failures of Unauthorized/Notfound etc for that Inspect operations?
It just leads to code like this, but maybe there is no better way?
func checkIfExists(skopeo *skopeo.Context, dest string) (exists bool, err error) {
log.Info("Checking if image already exists.")
cmd := []string{"inspect"}
cmd = append(cmd, dest)
exists = true
// When repository does not exist yet ->
// we get exit code 1, an we need to handle it somehow.
// The workaround below is really ugly and prone to break!
resp, e := skopeo.GetCombinedWithEC(
func(cmdError *exec.CmdError) error {
if cmdError != nil && cmdError.ExitCode() == 2 {
exists = false
return nil
}
return cmdError
},
cmd...)
if e != nil {
if strings.Contains(resp, "invalid status code from registry 403") ||
strings.Contains(resp, "requested access to the resource is denied") {
// we have 403 which is ok, the registry does not yet exist.
exists = false
}
return true, errors.AddContext(
e,
"could not check if image '%s' exists:\nstdout/err:\n%s",
dest,
resp,
)
}
return exists, nil
}
I’d expect the behavior to be stable for a given server (and server’s software version?). But writing a tool reliably working for any registry on the internet is difficult.
(To be explicit, nothing in Skopeo promises to continue to use the exact text invalid status code from registry 403 in error messages, and we did change error texts in the past.)
@mtrmac : Jeah thats correct, its a dumb workaround =). I now understand that its kind of difficult to make it work in all cases. The tool is great though!
As an example of the difficulty of doing something useful here, recently I have noticed:
% skopeo inspect docker://quay.io/libpod/alpine:nonexistenttag
FATA[0001] Error parsing image name "docker://quay.io/libpod/alpine:nonexistenttag": reading manifest nonexistenttag in quay.io/libpod/alpine: manifest unknown
% skopeo inspect docker://quay.io/libpod/nonexistentrepo
FATA[0001] Error parsing image name "docker://quay.io/libpod/nonexistentrepo": reading manifest latest in quay.io/libpod/nonexistentrepo: unauthorized: access to the requested resource is not authorized
A friendly reminder that this issue had no activity for 30 days.