// Get retrieves the manifest with digest `dgst`. func (r *repository) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) { if err := r.checkPendingErrors(ctx); err != nil { return nil, err } if _, err := r.getImageStreamImage(dgst); err != nil { context.GetLogger(r.ctx).Errorf("error retrieving ImageStreamImage %s/%s@%s: %v", r.namespace, r.name, dgst.String(), err) return nil, err } image, err := r.getImage(dgst) if err != nil { context.GetLogger(r.ctx).Errorf("error retrieving image %s: %v", dgst.String(), err) return nil, err } ref := imageapi.DockerImageReference{Namespace: r.namespace, Name: r.name, Registry: r.registryAddr} if managed := image.Annotations[imageapi.ManagedByOpenShiftAnnotation]; managed == "true" { // Repository without a registry part is refers to repository containing locally managed images. // Such an entry is retrieved, checked and set by blobDescriptorService operating only on local blobs. ref.Registry = "" } else { // Repository with a registry points to remote repository. This is used by pullthrough middleware. ref = ref.DockerClientDefaults().AsRepository() } manifest, err := r.manifestFromImageWithCachedLayers(image, ref.Exact()) return manifest, err }
// Get retrieves the manifest with digest `dgst`. func (r *repository) Get(dgst digest.Digest) (*schema1.SignedManifest, error) { if _, err := r.getImageStreamImage(dgst); err != nil { context.GetLogger(r.ctx).Errorf("Error retrieving ImageStreamImage %s/%s@%s: %v", r.namespace, r.name, dgst.String(), err) return nil, err } image, err := r.getImage(dgst) if err != nil { context.GetLogger(r.ctx).Errorf("Error retrieving image %s: %v", dgst.String(), err) return nil, err } ref := imageapi.DockerImageReference{Namespace: r.namespace, Name: r.name, Registry: r.registryAddr} return r.manifestFromImageWithCachedLayers(image, ref.DockerClientDefaults().Exact()) }
// pullthroughGetByTag attempts to load the given image manifest from the remote server defined by ref, using cacheName to store any cached layers. func (r *repository) pullthroughGetByTag(image *imageapi.Image, ref imageapi.DockerImageReference, cacheName string, options ...distribution.ManifestServiceOption) (*schema1.SignedManifest, error) { defaultRef := ref.DockerClientDefaults() retriever := r.importContext() repo, err := retriever.Repository(r.ctx, defaultRef.RegistryURL(), defaultRef.RepositoryName(), false) if err != nil { context.GetLogger(r.ctx).Errorf("Error getting remote repository for image %q: %v", image.DockerImageReference, err) return nil, err } // get a manifest context manifests, err := repo.Manifests(r.ctx) if err != nil { context.GetLogger(r.ctx).Errorf("Error getting manifests for image %q: %v", image.DockerImageReference, err) return nil, err } // fetch this by image if len(ref.ID) > 0 { dgst, err := digest.ParseDigest(ref.ID) if err != nil { context.GetLogger(r.ctx).Errorf("Error getting manifests for image %q: %v", image.DockerImageReference, err) return nil, err } manifest, err := manifests.Get(dgst) if err != nil { context.GetLogger(r.ctx).Errorf("Error getting manifest from remote server for image %q: %v", image.DockerImageReference, err) return nil, err } r.rememberLayers(manifest, cacheName) return manifest, nil } // fetch this by tag manifest, err := manifests.GetByTag(ref.Tag, options...) if err != nil { context.GetLogger(r.ctx).Errorf("Error getting manifest from remote server for image %q: %v", image.DockerImageReference, err) return nil, err } r.rememberLayers(manifest, cacheName) return manifest, nil }
// Get retrieves the manifest with digest `dgst`. func (r *repository) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) { if err := r.checkPendingErrors(ctx); err != nil { return nil, err } if _, err := r.getImageStreamImage(dgst); err != nil { context.GetLogger(r.ctx).Errorf("error retrieving ImageStreamImage %s/%s@%s: %v", r.namespace, r.name, dgst.String(), err) return nil, err } image, err := r.getImage(dgst) if err != nil { context.GetLogger(r.ctx).Errorf("error retrieving image %s: %v", dgst.String(), err) return nil, err } ref := imageapi.DockerImageReference{Namespace: r.namespace, Name: r.name, Registry: r.registryAddr} manifest, err := r.manifestFromImageWithCachedLayers(image, ref.DockerClientDefaults().Exact()) return manifest, err }
// importImages updates the passed ImageStreamImport object and sets Status for each image based on whether the import // succeeded or failed. Cache is updated with any loaded images. Limiter is optional and controls how fast images are updated. func (i *ImageStreamImporter) importImages(ctx gocontext.Context, retriever RepositoryRetriever, isi *api.ImageStreamImport, limiter flowcontrol.RateLimiter) { tags := make(map[manifestKey][]int) ids := make(map[manifestKey][]int) repositories := make(map[repositoryKey]*importRepository) cache := i.digestToRepositoryCache[ctx] isi.Status.Images = make([]api.ImageImportStatus, len(isi.Spec.Images)) for i := range isi.Spec.Images { spec := &isi.Spec.Images[i] from := spec.From if from.Kind != "DockerImage" { continue } // TODO: This should be removed in 1.6 // See for more info: https://github.com/openshift/origin/pull/11774#issuecomment-258905994 var ( err error ref api.DockerImageReference ) if from.Name != "*" { ref, err = api.ParseDockerImageReference(from.Name) if err != nil { isi.Status.Images[i].Status = invalidStatus("", field.Invalid(field.NewPath("from", "name"), from.Name, fmt.Sprintf("invalid name: %v", err))) continue } } else { ref = api.DockerImageReference{Name: from.Name} } defaultRef := ref.DockerClientDefaults() repoName := defaultRef.RepositoryName() registryURL := defaultRef.RegistryURL() key := repositoryKey{url: *registryURL, name: repoName} repo, ok := repositories[key] if !ok { repo = &importRepository{ Ref: ref, Registry: &key.url, Name: key.name, Insecure: spec.ImportPolicy.Insecure, } repositories[key] = repo } if len(defaultRef.ID) > 0 { id := manifestKey{repositoryKey: key} id.value = defaultRef.ID ids[id] = append(ids[id], i) if len(ids[id]) == 1 { repo.Digests = append(repo.Digests, importDigest{ Name: defaultRef.ID, Image: cache[id], }) } } else { tag := manifestKey{repositoryKey: key} tag.value = defaultRef.Tag tags[tag] = append(tags[tag], i) if len(tags[tag]) == 1 { repo.Tags = append(repo.Tags, importTag{ Name: defaultRef.Tag, Image: cache[tag], }) } } } // for each repository we found, import all tags and digests for key, repo := range repositories { i.importRepositoryFromDocker(ctx, retriever, repo, limiter) for _, tag := range repo.Tags { j := manifestKey{repositoryKey: key} j.value = tag.Name if tag.Image != nil { cache[j] = tag.Image } for _, index := range tags[j] { if tag.Err != nil { setImageImportStatus(isi, index, tag.Name, tag.Err) continue } copied := *tag.Image image := &isi.Status.Images[index] ref := repo.Ref ref.Tag, ref.ID = tag.Name, copied.Name copied.DockerImageReference = ref.MostSpecific().Exact() image.Tag = tag.Name image.Image = &copied image.Status.Status = unversioned.StatusSuccess } } for _, digest := range repo.Digests { j := manifestKey{repositoryKey: key} j.value = digest.Name if digest.Image != nil { cache[j] = digest.Image } for _, index := range ids[j] { if digest.Err != nil { setImageImportStatus(isi, index, "", digest.Err) continue } image := &isi.Status.Images[index] copied := *digest.Image ref := repo.Ref ref.Tag, ref.ID = "", copied.Name copied.DockerImageReference = ref.MostSpecific().Exact() image.Image = &copied image.Status.Status = unversioned.StatusSuccess } } } }
// importFromRepository imports the repository named on the ImageStreamImport, if any, importing up to maximumTags, and reporting // status on each image that is attempted to be imported. If the repository cannot be found or tags cannot be retrieved, the repository // status field is set. func (i *ImageStreamImporter) importFromRepository(ctx gocontext.Context, retriever RepositoryRetriever, isi *api.ImageStreamImport, maximumTags int, limiter flowcontrol.RateLimiter) { if isi.Spec.Repository == nil { return } cache := i.digestToRepositoryCache[ctx] isi.Status.Repository = &api.RepositoryImportStatus{} status := isi.Status.Repository spec := isi.Spec.Repository from := spec.From if from.Kind != "DockerImage" { return } // TODO: This should be removed in 1.6 // See for more info: https://github.com/openshift/origin/pull/11774#issuecomment-258905994 var ( err error ref api.DockerImageReference ) if from.Name != "*" { ref, err = api.ParseDockerImageReference(from.Name) if err != nil { status.Status = invalidStatus("", field.Invalid(field.NewPath("from", "name"), from.Name, fmt.Sprintf("invalid name: %v", err))) return } } else { ref = api.DockerImageReference{Name: from.Name} } defaultRef := ref.DockerClientDefaults() repoName := defaultRef.RepositoryName() registryURL := defaultRef.RegistryURL() key := repositoryKey{url: *registryURL, name: repoName} repo := &importRepository{ Ref: ref, Registry: &key.url, Name: key.name, Insecure: spec.ImportPolicy.Insecure, MaximumTags: maximumTags, } i.importRepositoryFromDocker(ctx, retriever, repo, limiter) if repo.Err != nil { status.Status = imageImportStatus(repo.Err, "", "repository") return } additional := []string{} tagKey := manifestKey{repositoryKey: key} for _, s := range repo.AdditionalTags { tagKey.value = s if image, ok := cache[tagKey]; ok { repo.Tags = append(repo.Tags, importTag{ Name: s, Image: image, }) } else { additional = append(additional, s) } } status.AdditionalTags = additional failures := 0 status.Status.Status = unversioned.StatusSuccess status.Images = make([]api.ImageImportStatus, len(repo.Tags)) for i, tag := range repo.Tags { status.Images[i].Tag = tag.Name if tag.Err != nil { failures++ status.Images[i].Status = imageImportStatus(tag.Err, "", "repository") continue } status.Images[i].Status.Status = unversioned.StatusSuccess copied := *tag.Image ref.Tag, ref.ID = tag.Name, copied.Name copied.DockerImageReference = ref.MostSpecific().Exact() status.Images[i].Image = &copied } if failures > 0 { status.Status.Status = unversioned.StatusFailure status.Status.Reason = unversioned.StatusReason("ImportFailed") switch failures { case 1: status.Status.Message = "one of the images from this repository failed to import" default: status.Status.Message = fmt.Sprintf("%d of the images from this repository failed to import", failures) } } }