mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	on projectatomic-based docker, we get "docker.io/library/busybox:latest" when someone uses an unqualified name like "busybox". Though when we inspect, the RepoTag will still say "docker.io/busybox:latest", So we have reparse the tag, normalize it and try again. Please see the additional test case. Signed-off-by: Andy Goldstein <andy.goldstein@gmail.com>
		
			
				
	
	
		
			173 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2014 The Kubernetes Authors.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package libdocker
 | 
						|
 | 
						|
import (
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
 | 
						|
	dockerref "github.com/docker/distribution/reference"
 | 
						|
	dockertypes "github.com/docker/docker/api/types"
 | 
						|
	"github.com/golang/glog"
 | 
						|
	godigest "github.com/opencontainers/go-digest"
 | 
						|
)
 | 
						|
 | 
						|
// ParseDockerTimestamp parses the timestamp returned by Interface from string to time.Time
 | 
						|
func ParseDockerTimestamp(s string) (time.Time, error) {
 | 
						|
	// Timestamp returned by Docker is in time.RFC3339Nano format.
 | 
						|
	return time.Parse(time.RFC3339Nano, s)
 | 
						|
}
 | 
						|
 | 
						|
// matchImageTagOrSHA checks if the given image specifier is a valid image ref,
 | 
						|
// and that it matches the given image. It should fail on things like image IDs
 | 
						|
// (config digests) and other digest-only references, but succeed on image names
 | 
						|
// (`foo`), tag references (`foo:bar`), and manifest digest references
 | 
						|
// (`foo@sha256:xyz`).
 | 
						|
func matchImageTagOrSHA(inspected dockertypes.ImageInspect, image string) bool {
 | 
						|
	// The image string follows the grammar specified here
 | 
						|
	// https://github.com/docker/distribution/blob/master/reference/reference.go#L4
 | 
						|
	named, err := dockerref.ParseNormalizedNamed(image)
 | 
						|
	if err != nil {
 | 
						|
		glog.V(4).Infof("couldn't parse image reference %q: %v", image, err)
 | 
						|
		return false
 | 
						|
	}
 | 
						|
	_, isTagged := named.(dockerref.Tagged)
 | 
						|
	digest, isDigested := named.(dockerref.Digested)
 | 
						|
	if !isTagged && !isDigested {
 | 
						|
		// No Tag or SHA specified, so just return what we have
 | 
						|
		return true
 | 
						|
	}
 | 
						|
 | 
						|
	if isTagged {
 | 
						|
		// Check the RepoTags for a match.
 | 
						|
		for _, tag := range inspected.RepoTags {
 | 
						|
			// An image name (without the tag/digest) can be [hostname '/'] component ['/' component]*
 | 
						|
			// Because either the RepoTag or the name *may* contain the
 | 
						|
			// hostname or not, we only check for the suffix match.
 | 
						|
			if strings.HasSuffix(image, tag) || strings.HasSuffix(tag, image) {
 | 
						|
				return true
 | 
						|
			} else {
 | 
						|
				// TODO: We need to remove this hack when project atomic based
 | 
						|
				// docker distro(s) like centos/fedora/rhel image fix problems on
 | 
						|
				// their end.
 | 
						|
				// Say the tag is "docker.io/busybox:latest"
 | 
						|
				// and the image is "docker.io/library/busybox:latest"
 | 
						|
				t, err := dockerref.ParseNormalizedNamed(tag)
 | 
						|
				if err != nil {
 | 
						|
					continue
 | 
						|
				}
 | 
						|
				// the parsed/normalized tag will look like
 | 
						|
				// reference.taggedReference {
 | 
						|
				// 	 namedRepository: reference.repository {
 | 
						|
				// 	   domain: "docker.io",
 | 
						|
				// 	   path: "library/busybox"
 | 
						|
				//	},
 | 
						|
				// 	tag: "latest"
 | 
						|
				// }
 | 
						|
				// If it does not have tags then we bail out
 | 
						|
				t2, ok := t.(dockerref.Tagged)
 | 
						|
				if !ok {
 | 
						|
					continue
 | 
						|
				}
 | 
						|
				// normalized tag would look like "docker.io/library/busybox:latest"
 | 
						|
				// note the library get added in the string
 | 
						|
				normalizedTag := t2.String()
 | 
						|
				if normalizedTag == "" {
 | 
						|
					continue
 | 
						|
				}
 | 
						|
				if strings.HasSuffix(image, normalizedTag) || strings.HasSuffix(normalizedTag, image) {
 | 
						|
					return true
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if isDigested {
 | 
						|
		for _, repoDigest := range inspected.RepoDigests {
 | 
						|
			named, err := dockerref.ParseNormalizedNamed(repoDigest)
 | 
						|
			if err != nil {
 | 
						|
				glog.V(4).Infof("couldn't parse image RepoDigest reference %q: %v", repoDigest, err)
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			if d, isDigested := named.(dockerref.Digested); isDigested {
 | 
						|
				if digest.Digest().Algorithm().String() == d.Digest().Algorithm().String() &&
 | 
						|
					digest.Digest().Hex() == d.Digest().Hex() {
 | 
						|
					return true
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// process the ID as a digest
 | 
						|
		id, err := godigest.Parse(inspected.ID)
 | 
						|
		if err != nil {
 | 
						|
			glog.V(4).Infof("couldn't parse image ID reference %q: %v", id, err)
 | 
						|
			return false
 | 
						|
		}
 | 
						|
		if digest.Digest().Algorithm().String() == id.Algorithm().String() && digest.Digest().Hex() == id.Hex() {
 | 
						|
			return true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	glog.V(4).Infof("Inspected image (%q) does not match %s", inspected.ID, image)
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// matchImageIDOnly checks that the given image specifier is a digest-only
 | 
						|
// reference, and that it matches the given image.
 | 
						|
func matchImageIDOnly(inspected dockertypes.ImageInspect, image string) bool {
 | 
						|
	// If the image ref is literally equal to the inspected image's ID,
 | 
						|
	// just return true here (this might be the case for Docker 1.9,
 | 
						|
	// where we won't have a digest for the ID)
 | 
						|
	if inspected.ID == image {
 | 
						|
		return true
 | 
						|
	}
 | 
						|
 | 
						|
	// Otherwise, we should try actual parsing to be more correct
 | 
						|
	ref, err := dockerref.Parse(image)
 | 
						|
	if err != nil {
 | 
						|
		glog.V(4).Infof("couldn't parse image reference %q: %v", image, err)
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	digest, isDigested := ref.(dockerref.Digested)
 | 
						|
	if !isDigested {
 | 
						|
		glog.V(4).Infof("the image reference %q was not a digest reference", image)
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	id, err := godigest.Parse(inspected.ID)
 | 
						|
	if err != nil {
 | 
						|
		glog.V(4).Infof("couldn't parse image ID reference %q: %v", id, err)
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	if digest.Digest().Algorithm().String() == id.Algorithm().String() && digest.Digest().Hex() == id.Hex() {
 | 
						|
		return true
 | 
						|
	}
 | 
						|
 | 
						|
	glog.V(4).Infof("The reference %s does not directly refer to the given image's ID (%q)", image, inspected.ID)
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// isImageNotFoundError returns whether the err is caused by image not found in docker
 | 
						|
// TODO: Use native error tester once ImageNotFoundError is supported in docker-engine client(eg. ImageRemove())
 | 
						|
func isImageNotFoundError(err error) bool {
 | 
						|
	if err != nil {
 | 
						|
		return strings.Contains(err.Error(), "No such image:")
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 |