// PullImage pulls docker image func (c *DockerClient) PullImage(name string) error { image := imagename.NewFromString(name) // e.g. s3:bucket-name/image-name if image.Storage == imagename.StorageS3 { if isOld, warning := imagename.WarnIfOldS3ImageName(name); isOld { c.log.Warn(warning) } return c.s3storage.Pull(name) } var ( pipeReader, pipeWriter = io.Pipe() fdOut, isTerminalOut = term.GetFdInfo(c.log.Out) out = c.log.Out errch = make(chan error, 1) ) if !isTerminalOut { out = c.log.Writer() } opts := docker.PullImageOptions{ Repository: image.NameWithRegistry(), Registry: image.Registry, Tag: image.GetTag(), OutputStream: pipeWriter, RawJSONStream: true, } c.log.Infof("| Pull image %s", image) c.log.Debugf("Pull image %s with options: %# v", image, opts) go func() { errch <- jsonmessage.DisplayJSONMessagesStream(pipeReader, out, fdOut, isTerminalOut) }() auth, err := dockerclient.GetAuthForRegistry(c.auth, image) if err != nil { return fmt.Errorf("Failed to authenticate registry %s, error: %s", image.Registry, err) } if err := c.client.PullImage(opts, auth); err != nil { return err } pipeWriter.Close() return <-errch }
// TagImage adds tag to the image func (c *DockerClient) TagImage(imageID, imageName string) error { img := imagename.NewFromString(imageName) if isOld, warning := imagename.WarnIfOldS3ImageName(imageName); isOld { c.log.Warn(warning) } c.log.Infof("| Tag %.12s -> %s", imageID, img) opts := docker.TagImageOptions{ Repo: img.NameWithRegistry(), Tag: img.GetTag(), Force: true, } c.log.Debugf("Tag image %s with options: %# v", imageID, opts) return c.client.TagImage(imageID, opts) }
// 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()) }
// pushImageInner pushes the image is the inner straightforward push without retries func (c *DockerClient) pushImageInner(imageName string) (digest string, err error) { img := imagename.NewFromString(imageName) // Use direct S3 image pusher instead if img.Storage == imagename.StorageS3 { if isOld, warning := imagename.WarnIfOldS3ImageName(imageName); isOld { c.log.Warn(warning) } return c.s3storage.Push(imageName) } var ( buf bytes.Buffer pipeReader, pipeWriter = io.Pipe() outStream = io.MultiWriter(pipeWriter, &buf) fdOut, isTerminalOut = term.GetFdInfo(c.log.Out) out = c.log.Out opts = docker.PushImageOptions{ Name: img.NameWithRegistry(), Tag: img.GetTag(), Registry: img.Registry, OutputStream: outStream, RawJSONStream: true, } errch = make(chan error, 1) ) if !isTerminalOut { out = c.log.Writer() } c.log.Infof("| Push %s", img) c.log.Debugf("Push with options: %# v", opts) // TODO: DisplayJSONMessagesStream may fail by client.PushImage run without errors go func() { errch <- jsonmessage.DisplayJSONMessagesStream(pipeReader, out, fdOut, isTerminalOut) }() auth, err := dockerclient.GetAuthForRegistry(c.auth, img) if err != nil { return "", fmt.Errorf("Failed to authenticate registry %s, error: %s", img.Registry, err) } if err := c.client.PushImage(opts, auth); err != nil { return "", err } pipeWriter.Close() if err := <-errch; err != nil { return "", fmt.Errorf("Failed to process json stream, error %s", err) } // It is the best way to have pushed image digest so far matches := captureDigest.FindStringSubmatch(buf.String()) if len(matches) > 0 { digest = matches[1] } return digest, nil }