예제 #1
0
// RegistryListTags returns the list of images instances obtained from all tags existing in the registry
func RegistryListTags(image *imagename.ImageName, auth *docker.AuthConfigurations) (images []*imagename.ImageName, err error) {
	var (
		name     = image.Name
		registry = image.Registry
	)

	regAuth, err := GetAuthForRegistry(auth, image)
	if err != nil {
		return nil, fmt.Errorf("Failed to get auth token for registry: %s, make sure you are properly logged in using `docker login` or have AWS credentials set in case of using ECR", image)
	}

	// XXX: AWS ECR Registry API v2 does not support listing tags
	// wo we just return a single image tag if it exists and no wildcards used
	if image.IsECR() {
		log.Debugf("ECR detected %s", registry)
		if !image.IsStrict() {
			return nil, fmt.Errorf("Amazon ECR does not support tags listing, therefore image wildcards are not supported, sorry: %s", image)
		}
		if exists, err := ecrImageExists(image, regAuth); err != nil {
			return nil, err
		} else if exists {
			log.Debugf("ECR image %s found in the registry", image)
			images = append(images, image)
		}
		return
	}

	if registry == "" {
		registry = "registry-1.docker.io"
		if !strings.Contains(name, "/") {
			name = "library/" + name
		}
	}

	var (
		tg  = tags{}
		url = fmt.Sprintf("https://%s/v2/%s/tags/list?page_size=9999&page=1", registry, name)
	)

	log.Debugf("Listing image tags from the remote registry %s", url)

	if err := registryGet(url, regAuth, &tg); err != nil {
		return nil, err
	}

	log.Debugf("Got %d tags from the remote registry for image %s", len(tg.Tags), image)

	for _, t := range tg.Tags {
		candidate := imagename.New(image.NameWithRegistry(), t)
		if image.Contains(candidate) || image.Tag == candidate.Tag {
			images = append(images, candidate)
		}
	}

	return
}
예제 #2
0
// GetAuthForRegistry extracts desired docker.AuthConfiguration object from the
// list of docker.AuthConfigurations by registry hostname
func GetAuthForRegistry(auth *docker.AuthConfigurations, image *imagename.ImageName) (result docker.AuthConfiguration, err error) {

	registry := image.Registry

	// The default registry is "index.docker.io"
	if registry == "" || registry == "registry-1.docker.io" {
		registry = "index.docker.io"
	}
	// Optionally override auth took via aws-sdk (through ENV vars)
	if image.IsECR() {
		if awsRegAuth, err := GetECRAuth(registry, image.GetECRRegion()); err != nil && err != credentials.ErrNoValidProvidersFoundInChain {
			return result, err
		} else if awsRegAuth.Username != "" {
			return awsRegAuth, nil
		}
	}

	if auth == nil {
		return
	}

	if result, ok := auth.Configs[registry]; ok {
		return result, nil
	}
	if result, ok := auth.Configs["https://"+registry]; ok {
		return result, nil
	}
	if result, ok := auth.Configs["https://"+registry+"/v1/"]; ok {
		return result, nil
	}
	// not sure /v2/ is needed, but just in case
	if result, ok := auth.Configs["https://"+registry+"/v2/"]; ok {
		return result, nil
	}
	if result, ok := auth.Configs["*"]; ok {
		return result, nil
	}
	return
}
예제 #3
0
// PullDockerImage pulls an image and streams to a logger respecting terminal features
func PullDockerImage(client *docker.Client, image *imagename.ImageName, auth *docker.AuthConfigurations) (*docker.Image, error) {
	if image.Storage == imagename.StorageS3 {
		s3storage := s3.New(client, os.TempDir())
		if err := s3storage.Pull(image.String()); err != nil {
			return nil, err
		}
	} else {
		pipeReader, pipeWriter := io.Pipe()

		pullOpts := docker.PullImageOptions{
			Repository:    image.NameWithRegistry(),
			Registry:      image.Registry,
			Tag:           image.Tag,
			OutputStream:  pipeWriter,
			RawJSONStream: true,
		}

		repoAuth, err := dockerclient.GetAuthForRegistry(auth, image)
		if err != nil {
			return nil, fmt.Errorf("Failed to authenticate registry %s, error: %s", image.Registry, err)
		}

		errch := make(chan error, 1)

		go func() {
			err := client.PullImage(pullOpts, repoAuth)

			if err := pipeWriter.Close(); err != nil {
				log.Errorf("Failed to close pull image stream for %s, error: %s", image, err)
			}

			errch <- err
		}()

		def := log.StandardLogger()
		fd, isTerminal := term.GetFdInfo(def.Out)
		out := def.Out

		if !isTerminal {
			out = def.Writer()
		}

		if err := jsonmessage.DisplayJSONMessagesStream(pipeReader, out, fd, isTerminal); err != nil {
			return nil, fmt.Errorf("Failed to process json stream for image: %s, error: %s", image, err)
		}

		if err := <-errch; err != nil {
			return nil, fmt.Errorf("Failed to pull image %s, error: %s", image, err)
		}
	}

	img, err := client.InspectImage(image.String())
	if err != nil {
		return nil, fmt.Errorf("Failed to inspect image %s after pull, error: %s", image, err)
	}

	return img, nil
}
예제 #4
0
// lookupImage looks up for the image by name and returns *docker.Image object (result of the inspect)
// `Pull` config option defines whether we want to update the latest version of the image from the remote registry
// See build.Config struct for more details about other build config options.
//
// If `Pull` is false, it tries to lookup locally by exact matching, e.g. if the image is already
// pulled with that exact name given (no fuzzy semver matching)
//
// Then the function fetches the list of all pulled images and tries to match one of them by the given name.
//
// If `Pull` is set to true or if it cannot find the image locally, it then fetches all image
// tags from the remote registry and finds the best match for the given image name.
//
// If it cannot find the image either locally or in the remote registry, it returns `nil`
//
// In case the given image has sha256 tag, it looks for it locally and pulls if it's not found.
// No semver matching is done for sha256 tagged images.
//
// See also TestBuild_LookupImage_* test cases in build_test.go
func (b *Build) lookupImage(name string) (img *docker.Image, err error) {
	var (
		candidate, remoteCandidate *imagename.ImageName

		imgName = imagename.NewFromString(name)
		pull    = false
		hub     = b.cfg.Pull
		isSha   = imgName.TagIsSha()
	)

	// If hub is true, then there is no sense to inspect the local image
	if !hub || isSha {
		if isOld, warning := imagename.WarnIfOldS3ImageName(name); isOld {
			log.Warn(warning)
		}
		// Try to inspect image as is, without version resolution
		if img, err := b.client.InspectImage(imgName.String()); err != nil || img != nil {
			return img, err
		}
	}

	if isSha {
		// If we are still here and image not found locally, we want to pull it
		candidate = imgName
		hub = false
		pull = true
	}

	if !isSha && !hub {
		// List local images
		var localImages = []*imagename.ImageName{}
		if localImages, err = b.client.ListImages(); err != nil {
			return nil, err
		}
		// Resolve local candidate
		candidate = imgName.ResolveVersion(localImages, true)
	}

	// In case we want to include external images as well, pulling list of available
	// images from the remote registry
	if hub || candidate == nil {
		log.Debugf("Getting list of tags for %s from the registry", imgName)

		var remoteImages []*imagename.ImageName

		if remoteImages, err = b.client.ListImageTags(imgName.String()); err != nil {
			err = fmt.Errorf("Failed to list tags of image %s from the remote registry, error: %s", imgName, err)
			return
		}

		// Since we found the remote image, we want to pull it
		if remoteCandidate = imgName.ResolveVersion(remoteImages, false); remoteCandidate != nil {
			pull = true
			candidate = remoteCandidate

			// If we've found needed image on s3 it should be pulled in the same name style as lookuped image
			candidate.IsOldS3Name = imgName.IsOldS3Name
		}
	}

	// If not candidate found, it's an error
	if candidate == nil {
		err = fmt.Errorf("Image not found: %s (also checked in the remote registry)", imgName)
		return
	}

	if !isSha && imgName.GetTag() != candidate.GetTag() {
		if remoteCandidate != nil {
			log.Infof("Resolve %s --> %s (found remotely)", imgName, candidate.GetTag())
		} else {
			log.Infof("Resolve %s --> %s", imgName, candidate.GetTag())
		}
	}

	if pull {
		if err = b.client.PullImage(candidate.String()); err != nil {
			return
		}
	}

	return b.client.InspectImage(candidate.String())
}