// importTag import single tag from given ImageStream. Returns retrieved image (for later reuse), // a flag saying if we should retry imports and an error if one occurs. func (c *ImportController) importTag(stream *api.ImageStream, tag string, ref api.DockerImageReference, dockerImage *dockerregistry.Image, client dockerregistry.Client, insecure bool) (*dockerregistry.Image, bool, error) { glog.V(5).Infof("Importing tag %s from %s/%s...", tag, stream.Namespace, stream.Name) if dockerImage == nil { // TODO insecure applies to the stream's spec.dockerImageRepository, not necessarily to an external one! conn, err := client.Connect(ref.Registry, insecure) if err != nil { // retry-able error no. 3 return nil, true, err } if len(ref.ID) > 0 { dockerImage, err = conn.ImageByID(ref.Namespace, ref.Name, ref.ID) } else { dockerImage, err = conn.ImageByTag(ref.Namespace, ref.Name, ref.Tag) } switch { case dockerregistry.IsRepositoryNotFound(err), dockerregistry.IsRegistryNotFound(err), dockerregistry.IsImageNotFound(err), dockerregistry.IsTagNotFound(err): return nil, false, err case err != nil: // retry-able error no. 4 return nil, true, err } } var image api.DockerImage if err := kapi.Scheme.Convert(&dockerImage.Image, &image); err != nil { return nil, false, fmt.Errorf("could not convert image: %#v", err) } // prefer to pull by ID always if dockerImage.PullByID { // if the registry indicates the image is pullable by ID, clear the tag ref.Tag = "" ref.ID = dockerImage.ID } mapping := &api.ImageStreamMapping{ ObjectMeta: kapi.ObjectMeta{ Name: stream.Name, Namespace: stream.Namespace, }, Tag: tag, Image: api.Image{ ObjectMeta: kapi.ObjectMeta{ Name: dockerImage.ID, }, DockerImageReference: ref.String(), DockerImageMetadata: image, }, } if err := c.mappings.ImageStreamMappings(stream.Namespace).Create(mapping); err != nil { // retry-able no. 5 return nil, true, err } return dockerImage, false, nil }
// getTags returns tags from default upstream image repository and explicitly defined. // Returns a map of tags to be imported and an error if one occurs. // Tags explicitly defined will overwrite those from default upstream image repository. func getTags(stream *api.ImageStream, client dockerregistry.Client, insecure bool) (map[string]api.DockerImageReference, error) { imports := make(map[string]api.DockerImageReference) references := sets.NewString() // read explicitly defined tags for tagName, specTag := range stream.Spec.Tags { if specTag.From == nil { continue } if specTag.From.Kind != "DockerImage" || specTag.Reference { references.Insert(tagName) continue } ref, err := api.ParseDockerImageReference(specTag.From.Name) if err != nil { glog.V(2).Infof("error parsing DockerImage %s: %v", specTag.From.Name, err) continue } imports[tagName] = ref.DockerClientDefaults() } if len(stream.Spec.DockerImageRepository) == 0 { return imports, nil } // read tags from default upstream image repository streamRef, err := api.ParseDockerImageReference(stream.Spec.DockerImageRepository) if err != nil { util.HandleError(fmt.Errorf("invalid docker image repository, cannot import data: %v", err)) return imports, nil } conn, err := client.Connect(streamRef.Registry, insecure) if err != nil { // retry-able error no. 1 return imports, err } tags, err := conn.ImageTags(streamRef.Namespace, streamRef.Name) switch { case dockerregistry.IsRepositoryNotFound(err), dockerregistry.IsRegistryNotFound(err): return imports, nil case err != nil: // retry-able error no. 2 return imports, err } for tag, image := range tags { if _, ok := imports[tag]; ok || references.Has(tag) { continue } idTagPresent := false // this for loop is for backwards compatibility with v1 repo, where // there was no image id returned with tags, like v2 does right now. for t2, i2 := range tags { if i2 == image && t2 == image { idTagPresent = true break } } ref := streamRef if idTagPresent { ref.Tag = image } else { ref.Tag = tag } ref.ID = image imports[tag] = ref } return imports, nil }