예제 #1
0
// layerIsPrunable returns true if the layer is not referenced by any images.
func layerIsPrunable(g graph.Graph, layerNode *graph.ImageLayerNode) bool {
	for _, predecessor := range g.Predecessors(layerNode) {
		glog.V(4).Infof("Examining layer predecessor %#v", predecessor)
		if g.Kind(predecessor) == graph.ImageGraphKind {
			glog.V(4).Infof("Layer has an image predecessor")
			return false
		}
	}

	return true
}
예제 #2
0
// streamLayerReferences returns a list of ImageStreamNodes that reference a
// given ImageLayeNode.
func streamLayerReferences(g graph.Graph, layerNode *graph.ImageLayerNode) []*graph.ImageStreamNode {
	ret := []*graph.ImageStreamNode{}

	for _, predecessor := range g.Predecessors(layerNode) {
		if g.Kind(predecessor) != graph.ImageStreamGraphKind {
			continue
		}

		ret = append(ret, predecessor.(*graph.ImageStreamNode))
	}

	return ret
}
예제 #3
0
// imageIsPrunable returns true iff the image node only has weak references
// from its predecessors to it. A weak reference to an image is a reference
// from an image stream to an image where the image is not the current image
// for a tag and the image stream is at least as old as the minimum pruning
// age.
func imageIsPrunable(g graph.Graph, imageNode *graph.ImageNode) bool {
	onlyWeakReferences := true

	for _, n := range g.Predecessors(imageNode) {
		glog.V(4).Infof("Examining predecessor %#v", n)
		if !edgeKind(g, n, imageNode, graph.WeakReferencedImageGraphEdgeKind) {
			glog.V(4).Infof("Strong reference detected")
			onlyWeakReferences = false
			break
		}
	}

	return onlyWeakReferences

}
예제 #4
0
// pruneStreams removes references from all image streams' status.tags entries
// to prunable images, invoking streamPruner.PruneImageStream for each updated
// stream.
func pruneStreams(g graph.Graph, imageNodes []*imagegraph.ImageNode, streamPruner ImageStreamPruner) []error {
	errs := []error{}

	glog.V(4).Infof("Removing pruned image references from streams")
	for _, imageNode := range imageNodes {
		for _, n := range g.Predecessors(imageNode) {
			streamNode, ok := n.(*imagegraph.ImageStreamNode)
			if !ok {
				continue
			}

			stream := streamNode.ImageStream
			updatedTags := util.NewStringSet()

			glog.V(4).Infof("Checking if ImageStream %s/%s has references to image %s in status.tags", stream.Namespace, stream.Name, imageNode.Image.Name)

			for tag, history := range stream.Status.Tags {
				glog.V(4).Infof("Checking tag %q", tag)

				newHistory := imageapi.TagEventList{}

				for i, tagEvent := range history.Items {
					glog.V(4).Infof("Checking tag event %d with image %q", i, tagEvent.Image)

					if tagEvent.Image != imageNode.Image.Name {
						glog.V(4).Infof("Tag event doesn't match deleted image - keeping")
						newHistory.Items = append(newHistory.Items, tagEvent)
					} else {
						glog.V(4).Infof("Tag event matches deleted image - removing reference")
						updatedTags.Insert(tag)
					}
				}
				stream.Status.Tags[tag] = newHistory
			}

			updatedStream, err := streamPruner.PruneImageStream(stream, imageNode.Image, updatedTags.List())
			if err != nil {
				errs = append(errs, fmt.Errorf("error pruning image from stream: %v", err))
				continue
			}

			streamNode.ImageStream = updatedStream
		}
	}
	glog.V(4).Infof("Done removing pruned image references from streams")
	return errs
}
예제 #5
0
// 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)
	}
}
예제 #6
0
// pruneManifests invokes manifestPruner.PruneManifest for each repository
// manifest to be deleted from the registry.
func pruneManifests(g graph.Graph, registryClient *http.Client, registryURL string, imageNodes []*imagegraph.ImageNode, manifestPruner ManifestPruner) []error {
	errs := []error{}

	for _, imageNode := range imageNodes {
		for _, n := range g.Predecessors(imageNode) {
			streamNode, ok := n.(*imagegraph.ImageStreamNode)
			if !ok {
				continue
			}

			stream := streamNode.ImageStream
			repoName := fmt.Sprintf("%s/%s", stream.Namespace, stream.Name)

			glog.V(4).Infof("Pruning manifest for registry %q, repo %q, image %q", registryURL, repoName, imageNode.Image.Name)
			if err := manifestPruner.PruneManifest(registryClient, registryURL, repoName, imageNode.Image.Name); err != nil {
				errs = append(errs, fmt.Errorf("error pruning manifest for registry %q, repo %q, image %q: %v", registryURL, repoName, imageNode.Image.Name, err))
			}
		}
	}

	return errs
}