func tagReferenceToTagEvent(stream *api.ImageStream, tagRef api.TagReference, tagOrID string) (*api.TagEvent, error) { switch tagRef.From.Kind { case "DockerImage": return &api.TagEvent{ Created: unversioned.Now(), DockerImageReference: tagRef.From.Name, }, nil case "ImageStreamImage": ref, err := api.DockerImageReferenceForStream(stream) if err != nil { return nil, err } resolvedIDs := api.ResolveImageID(stream, tagOrID) switch len(resolvedIDs) { case 1: ref.ID = resolvedIDs.List()[0] return &api.TagEvent{ Created: unversioned.Now(), DockerImageReference: ref.String(), Image: ref.ID, }, nil case 0: return nil, fmt.Errorf("no images match the prefix %q", tagOrID) default: return nil, fmt.Errorf("multiple images match the prefix %q: %s", tagOrID, strings.Join(resolvedIDs.List(), ", ")) } case "ImageStreamTag": return api.LatestTaggedImage(stream, tagOrID), nil default: return nil, fmt.Errorf("invalid from.kind %q: it must be ImageStreamImage or ImageStreamTag", tagRef.From.Kind) } }
// resolveImageStreamReference looks up the ImageStream[Tag/Image] and converts it to a // docker pull spec that can be used in an Image field. func (g *BuildGenerator) resolveImageStreamReference(ctx kapi.Context, from kapi.ObjectReference, defaultNamespace string) (string, error) { var namespace string if len(from.Namespace) != 0 { namespace = from.Namespace } else { namespace = defaultNamespace } glog.V(4).Infof("Resolving ImageStreamReference %s of Kind %s in namespace %s", from.Name, from.Kind, namespace) switch from.Kind { case "ImageStream": // NOTE: The 'ImageStream' reference should be used only for the 'output' image is, err := g.Client.GetImageStream(kapi.WithNamespace(ctx, namespace), from.Name) if err != nil { glog.V(2).Infof("Error getting ImageStream %s/%s: %v", namespace, from.Name, err) return "", err } image, err := imageapi.DockerImageReferenceForStream(is) if err != nil { glog.V(2).Infof("Error resolving Docker image reference for %s/%s: %v", namespace, from.Name, err) return "", err } return image.String(), nil case "ImageStreamImage": imageStreamImage, err := g.Client.GetImageStreamImage(kapi.WithNamespace(ctx, namespace), from.Name) if err != nil { glog.V(2).Infof("Error ImageStreamReference %s in namespace %s: %v", from.Name, namespace, err) if errors.IsNotFound(err) { return "", err } return "", fatalError{err} } image := imageStreamImage.Image glog.V(4).Infof("Resolved ImageStreamReference %s to image %s with reference %s in namespace %s", from.Name, image.Name, image.DockerImageReference, namespace) return image.DockerImageReference, nil case "ImageStreamTag": imageStreamTag, err := g.Client.GetImageStreamTag(kapi.WithNamespace(ctx, namespace), from.Name) if err != nil { glog.V(2).Infof("Error resolving ImageStreamTag reference %s in namespace %s: %v", from.Name, namespace, err) if errors.IsNotFound(err) { return "", err } return "", fatalError{err} } image := imageStreamTag.Image glog.V(4).Infof("Resolved ImageStreamTag %s to image %s with reference %s in namespace %s", from.Name, image.Name, image.DockerImageReference, namespace) return image.DockerImageReference, nil case "DockerImage": return from.Name, nil default: return "", fatalError{fmt.Errorf("Unknown From Kind %s", from.Kind)} } }
// pruneImages invokes imagePruneFunc with each image that is prunable, along // with the image streams that reference the image. After imagePruneFunc is // invoked, the image node is removed from the graph, so that layers eligible // for pruning may later be identified. func pruneImages(g graph.Graph, imageNodes []*graph.ImageNode, pruneImage ImagePruneFunc, pruneStream ImageStreamPruneFunc, pruneManifest ManifestPruneFunc) { for _, imageNode := range imageNodes { glog.V(4).Infof("Examining image %q", imageNode.Image.Name) if !imageIsPrunable(g, imageNode) { glog.V(4).Infof("Image has strong references - not pruning") continue } glog.V(4).Infof("Image has only weak references - pruning") if err := pruneImage(imageNode.Image); err != nil { util.HandleError(fmt.Errorf("error pruning image %q: %v", imageNode.Image.Name, err)) } for _, n := range g.Predecessors(imageNode) { if streamNode, ok := n.(*graph.ImageStreamNode); ok { stream := streamNode.ImageStream repoName := fmt.Sprintf("%s/%s", stream.Namespace, stream.Name) glog.V(4).Infof("Pruning image from stream %s", repoName) updatedStream, err := pruneStream(stream, imageNode.Image) if err != nil { util.HandleError(fmt.Errorf("error pruning image from stream: %v", err)) continue } streamNode.ImageStream = updatedStream ref, err := imageapi.DockerImageReferenceForStream(stream) if err != nil { util.HandleError(fmt.Errorf("error constructing DockerImageReference for %q: %v", repoName, err)) continue } glog.V(4).Infof("Invoking pruneManifest for registry %q, repo %q, image %q", ref.Registry, repoName, imageNode.Image.Name) if err := pruneManifest(ref.Registry, repoName, imageNode.Image.Name); err != nil { util.HandleError(fmt.Errorf("error pruning manifest for registry %q, repo %q, image %q: %v", ref.Registry, repoName, imageNode.Image.Name, err)) } } } // remove pruned image node from graph, for layer pruning later g.RemoveNode(imageNode) } }
// resolveImageStreamDockerRepository looks up the ImageStream[Tag/Image] and converts it to a // the docker repository reference with no tag information func (g *BuildGenerator) resolveImageStreamDockerRepository(ctx kapi.Context, from kapi.ObjectReference, defaultNamespace string) (string, error) { namespace := defaultNamespace if len(from.Namespace) > 0 { namespace = from.Namespace } glog.V(4).Infof("Resolving ImageStreamReference %s of Kind %s in namespace %s", from.Name, from.Kind, namespace) switch from.Kind { case "ImageStreamImage": imageStreamImage, err := g.Client.GetImageStreamImage(kapi.WithNamespace(ctx, namespace), from.Name) if err != nil { glog.V(2).Infof("Error ImageStreamReference %s in namespace %s: %v", from.Name, namespace, err) if errors.IsNotFound(err) { return "", err } return "", err } image := imageStreamImage.Image glog.V(4).Infof("Resolved ImageStreamReference %s to image %s with reference %s in namespace %s", from.Name, image.Name, image.DockerImageReference, namespace) return image.DockerImageReference, nil case "ImageStreamTag": name := strings.Split(from.Name, ":")[0] is, err := g.Client.GetImageStream(kapi.WithNamespace(ctx, namespace), name) if err != nil { glog.V(2).Infof("Error getting ImageStream %s/%s: %v", namespace, name, err) if errors.IsNotFound(err) { return "", err } return "", err } image, err := imageapi.DockerImageReferenceForStream(is) if err != nil { glog.V(2).Infof("Error resolving Docker image reference for %s/%s: %v", namespace, name, err) return "", err } glog.V(4).Infof("Resolved ImageStreamTag %s/%s to repository %s", namespace, from.Name, image) return image.String(), nil case "DockerImage": return from.Name, nil default: return "", fmt.Errorf("Unknown From Kind %s", from.Kind) } }
// pruneLayers creates a mapping of registryURLs to // server.DeleteLayersRequest objects, invoking layerPruneFunc for each // registryURL and request. func pruneLayers(g graph.Graph, layerNodes []*graph.ImageLayerNode, pruneLayer LayerPruneFunc, pruneBlob BlobPruneFunc) { for _, layerNode := range layerNodes { glog.V(4).Infof("Examining layer %q", layerNode.Layer) if !layerIsPrunable(g, layerNode) { glog.V(4).Infof("Layer %q has image references - not pruning", layerNode.Layer) continue } registries := util.NewStringSet() // get streams that reference layer streamNodes := streamLayerReferences(g, layerNode) for _, streamNode := range streamNodes { stream := streamNode.ImageStream streamName := fmt.Sprintf("%s/%s", stream.Namespace, stream.Name) glog.V(4).Infof("Layer has an ImageStream predecessor: %s", streamName) ref, err := imageapi.DockerImageReferenceForStream(stream) if err != nil { util.HandleError(fmt.Errorf("error constructing DockerImageReference for %q: %v", streamName, err)) continue } if !registries.Has(ref.Registry) { registries.Insert(ref.Registry) glog.V(4).Infof("Invoking pruneBlob with registry=%q, blob=%q", ref.Registry, layerNode.Layer) if err := pruneBlob(ref.Registry, layerNode.Layer); err != nil { util.HandleError(fmt.Errorf("error invoking pruneBlob: %v", err)) } } repoName := fmt.Sprintf("%s/%s", ref.Namespace, ref.Name) glog.V(4).Infof("Invoking pruneLayer with registry=%q, repo=%q, layer=%q", ref.Registry, repoName, layerNode.Layer) if err := pruneLayer(ref.Registry, repoName, layerNode.Layer); err != nil { util.HandleError(fmt.Errorf("error invoking pruneLayer: %v", err)) } } } }