Fix unhelpful error message for oci-archive scheme (#705)

* Improve error message

Signed-off-by: Dan Luhring <dan+github@luhrings.com>

* Return error from stereoscope immediately

Signed-off-by: Dan Luhring <dan+github@luhrings.com>

* Bump version of stereoscope

Signed-off-by: Dan Luhring <dan+github@luhrings.com>

* Conditionally retry image retrieval

Signed-off-by: Dan Luhring <dan+github@luhrings.com>

* Update error message for source construction failure

Signed-off-by: Dan Luhring <dan+github@luhrings.com>

* Update stereoscope

Signed-off-by: Dan Luhring <dan+github@luhrings.com>

* Retry image pull without predetermined image source

Signed-off-by: Dan Luhring <dan+github@luhrings.com>

* Add comment to image pull source determination

Signed-off-by: Dan Luhring <dan+github@luhrings.com>
This commit is contained in:
Dan Luhring
2021-12-22 18:53:23 +00:00
committed by GitHub
parent 474ed682bc
commit 7de5e1288f
4 changed files with 55 additions and 16 deletions
+51 -12
View File
@@ -51,7 +51,7 @@ func New(userInput string, registryOptions *image.RegistryOptions, exclusions []
case DirectoryScheme:
source, cleanupFn, err = generateDirectorySource(fs, location)
case ImageScheme:
source, cleanupFn, err = generateImageSource(location, userInput, imageSource, registryOptions)
source, cleanupFn, err = generateImageSource(userInput, location, imageSource, registryOptions)
default:
err = fmt.Errorf("unable to process input for scanning: '%s'", userInput)
}
@@ -63,17 +63,8 @@ func New(userInput string, registryOptions *image.RegistryOptions, exclusions []
return source, cleanupFn, err
}
func generateImageSource(location, userInput string, imageSource image.Source, registryOptions *image.RegistryOptions) (*Source, func(), error) {
img, err := stereoscope.GetImageFromSource(location, imageSource, registryOptions)
if err != nil {
log.Debugf("error parsing location: %s after detecting scheme; pulling image: %s", location, userInput)
// we may have been to aggressive reading the source hint
// try the input as supplied by the user if our initial parse failed
img, err = stereoscope.GetImageFromSource(userInput, imageSource, registryOptions)
}
cleanup := stereoscope.Cleanup
func generateImageSource(userInput, location string, imageSource image.Source, registryOptions *image.RegistryOptions) (*Source, func(), error) {
img, cleanup, err := getImageWithRetryStrategy(userInput, location, imageSource, registryOptions)
if err != nil || img == nil {
return &Source{}, cleanup, fmt.Errorf("could not fetch image '%s': %w", location, err)
}
@@ -86,6 +77,54 @@ func generateImageSource(location, userInput string, imageSource image.Source, r
return &s, cleanup, nil
}
func parseScheme(userInput string) string {
parts := strings.SplitN(userInput, ":", 2)
if len(parts) < 2 {
return ""
}
return parts[0]
}
func getImageWithRetryStrategy(userInput, location string, imageSource image.Source, registryOptions *image.RegistryOptions) (*image.Image, func(), error) {
img, err := stereoscope.GetImageFromSource(location, imageSource, registryOptions)
if err == nil {
// Success on the first try!
return img, stereoscope.Cleanup, nil
}
scheme := parseScheme(userInput)
if !(scheme == "docker" || scheme == "registry") {
// Image retrieval failed, and we shouldn't retry it. It's most likely that the
// user _did_ intend the parsed scheme, but there was a legitimate failure with
// using the scheme to load the image. Alert the user to this failure, so they
// can fix the problem.
return nil, nil, err
}
// Maybe the user wanted "docker" or "registry" to refer to an _image name_
// (e.g. "docker:latest"), not a scheme. We'll retry image retrieval with this
// alternative interpretation, in an attempt to avoid unnecessary user friction.
log.Warnf(
"scheme %q specified, but it coincides with a common image name; re-examining user input %q"+
" without scheme parsing because image retrieval using scheme parsing was unsuccessful: %v",
scheme,
userInput,
err,
)
// We need to determine the image source again, such that this determination
// doesn't take scheme parsing into account.
imageSource = image.DetermineImagePullSource(userInput)
img, err = stereoscope.GetImageFromSource(userInput, imageSource, registryOptions)
if err != nil {
return nil, nil, err
}
return img, stereoscope.Cleanup, nil
}
func generateDirectorySource(fs afero.Fs, location string) (*Source, func(), error) {
fileMeta, err := fs.Stat(location)
if err != nil {