Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prune image configs of manifest V2 schema 2 #10835

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 13 additions & 14 deletions pkg/cmd/admin/prune/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,21 +233,21 @@ func (o PruneImagesOptions) Run() error {

imageDeleter := &describingImageDeleter{w: w}
imageStreamDeleter := &describingImageStreamDeleter{w: w}
layerDeleter := &describingLayerDeleter{w: w}
layerLinkDeleter := &describingLayerLinkDeleter{w: w}
blobDeleter := &describingBlobDeleter{w: w}
manifestDeleter := &describingManifestDeleter{w: w}

if o.Confirm {
imageDeleter.delegate = prune.NewImageDeleter(o.Client.Images())
imageStreamDeleter.delegate = prune.NewImageStreamDeleter(o.Client)
layerDeleter.delegate = prune.NewLayerDeleter()
layerLinkDeleter.delegate = prune.NewLayerLinkDeleter()
blobDeleter.delegate = prune.NewBlobDeleter()
manifestDeleter.delegate = prune.NewManifestDeleter()
} else {
fmt.Fprintln(os.Stderr, "Dry run enabled - no modifications will be made. Add --confirm to remove images")
}

return o.Pruner.Prune(imageDeleter, imageStreamDeleter, layerDeleter, blobDeleter, manifestDeleter)
return o.Pruner.Prune(imageDeleter, imageStreamDeleter, layerLinkDeleter, blobDeleter, manifestDeleter)
}

// describingImageStreamDeleter prints information about each image stream update.
Expand Down Expand Up @@ -312,33 +312,32 @@ func (p *describingImageDeleter) DeleteImage(image *imageapi.Image) error {
return err
}

// describingLayerDeleter prints information about each repo layer link being
// deleted. If a delegate exists, its DeleteLayer function is invoked prior to
// returning.
type describingLayerDeleter struct {
// describingLayerLinkDeleter prints information about each repo layer link being deleted. If a delegate
// exists, its DeleteLayerLink function is invoked prior to returning.
type describingLayerLinkDeleter struct {
w io.Writer
delegate prune.LayerDeleter
delegate prune.LayerLinkDeleter
headerPrinted bool
}

var _ prune.LayerDeleter = &describingLayerDeleter{}
var _ prune.LayerLinkDeleter = &describingLayerLinkDeleter{}

func (p *describingLayerDeleter) DeleteLayer(registryClient *http.Client, registryURL, repo, layer string) error {
func (p *describingLayerLinkDeleter) DeleteLayerLink(registryClient *http.Client, registryURL, repo, name string) error {
if !p.headerPrinted {
p.headerPrinted = true
fmt.Fprintln(p.w, "\nDeleting registry repository layer links ...")
fmt.Fprintln(p.w, "REPO\tLAYER")
fmt.Fprintln(p.w, "REPO\tLAYER LINK")
}

fmt.Fprintf(p.w, "%s\t%s\n", repo, layer)
fmt.Fprintf(p.w, "%s\t%s\n", repo, name)

if p.delegate == nil {
return nil
}

err := p.delegate.DeleteLayer(registryClient, registryURL, repo, layer)
err := p.delegate.DeleteLayerLink(registryClient, registryURL, repo, name)
if err != nil {
fmt.Fprintf(os.Stderr, "error deleting repository %s layer link %s from the registry: %v\n", repo, layer, err)
fmt.Fprintf(os.Stderr, "error deleting repository %s layer link %s from the registry: %v\n", repo, name, err)
}

return err
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/admin/top/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func addImagesToGraph(g graph.Graph, images *imageapi.ImageList) {
// schema v2 does not have that problem.
for i := len(image.DockerImageLayers) - 1; i >= 0; i-- {
layer := image.DockerImageLayers[i]
layerNode := imagegraph.EnsureImageLayerNode(g, layer.Name)
layerNode := imagegraph.EnsureImageComponentLayerNode(g, layer.Name)
edgeKind := ImageLayerEdgeKind
if !topLayerAdded && layer.Name != digest.DigestSha256EmptyTar && layer.Name != digestSHA256GzippedEmptyTar {
edgeKind = ImageTopLayerEdgeKind
Expand Down Expand Up @@ -138,7 +138,7 @@ func markParentsInGraph(g graph.Graph) {
for _, in := range imageNodes {
// find image's top layer, should be just one
for _, e := range g.OutboundEdges(in, ImageTopLayerEdgeKind) {
layerNode, _ := e.To().(*imagegraph.ImageLayerNode)
layerNode, _ := e.To().(*imagegraph.ImageComponentNode)
// find image's containing this layer but not being their top layer
for _, ed := range g.InboundEdges(layerNode, ImageLayerEdgeKind) {
childNode, _ := ed.From().(*imagegraph.ImageNode)
Expand Down
34 changes: 29 additions & 5 deletions pkg/image/graph/nodes/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,36 @@ func FindOrCreateSyntheticImageStreamNode(g osgraph.MutableUniqueGraph, is *imag
).(*ImageStreamNode)
}

// EnsureImageLayerNode adds a graph node for the layer if it does not already exist.
func EnsureImageLayerNode(g osgraph.MutableUniqueGraph, layer string) graph.Node {
return osgraph.EnsureUnique(g,
ImageLayerNodeName(layer),
func ensureImageComponentNode(g osgraph.MutableUniqueGraph, name string, t ImageComponentType) graph.Node {
node := osgraph.EnsureUnique(g,
ImageComponentNodeName(name),
func(node osgraph.Node) graph.Node {
return &ImageLayerNode{node, layer}
return &ImageComponentNode{
Node: node,
Component: name,
Type: t,
}
},
)

// If at least one image referers to the blob as its config, treat it as a config even if it is a layer of
// some other image.
if t == ImageComponentTypeConfig {
cn := node.(*ImageComponentNode)
if cn.Type != ImageComponentTypeConfig {
cn.Type = ImageComponentTypeConfig
}
}

return node
}

// EnsureImageComponentConfigNode adds a graph node for the image config if it does not already exist.
func EnsureImageComponentConfigNode(g osgraph.MutableUniqueGraph, name string) graph.Node {
return ensureImageComponentNode(g, name, ImageComponentTypeConfig)
}

// EnsureImageComponentLayerNode adds a graph node for the image layer if it does not already exist.
func EnsureImageComponentLayerNode(g osgraph.MutableUniqueGraph, name string) graph.Node {
return ensureImageComponentNode(g, name, ImageComponentTypeLayer)
}
38 changes: 27 additions & 11 deletions pkg/image/graph/nodes/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ import (
imageapi "github.com/openshift/origin/pkg/image/api"
)

type ImageComponentType string

const (
ImageComponentNodeKind = "ImageComponent"

ImageComponentTypeConfig ImageComponentType = `Config`
ImageComponentTypeLayer ImageComponentType = `Layer`
)

var (
ImageStreamNodeKind = reflect.TypeOf(imageapi.ImageStream{}).Name()
ImageNodeKind = reflect.TypeOf(imageapi.Image{}).Name()
Expand All @@ -16,7 +25,6 @@ var (

// non-api types
DockerRepositoryNodeKind = reflect.TypeOf(imageapi.DockerImageReference{}).Name()
ImageLayerNodeKind = "ImageLayer"
)

func ImageStreamNodeName(o *imageapi.ImageStream) osgraph.UniqueName {
Expand Down Expand Up @@ -185,23 +193,31 @@ func (*ImageNode) Kind() string {
return ImageNodeKind
}

func ImageLayerNodeName(layer string) osgraph.UniqueName {
return osgraph.UniqueName(fmt.Sprintf("%s|%s", ImageLayerNodeKind, layer))
func ImageComponentNodeName(name string) osgraph.UniqueName {
return osgraph.UniqueName(fmt.Sprintf("%s|%s", ImageComponentNodeKind, name))
}

type ImageLayerNode struct {
// ImageComponentNode represents either an image layer or image config. All the components are treated the
// same. A particular component (identified by a hash) can be of just one type.
type ImageComponentNode struct {
osgraph.Node
Layer string
Component string
// An additional information describing the type of the component.
Type ImageComponentType
}

func (n ImageComponentNode) Object() interface{} {
return n.Component
}

func (n ImageLayerNode) Object() interface{} {
return n.Layer
func (n ImageComponentNode) String() string {
return string(ImageComponentNodeName(n.Component))
}

func (n ImageLayerNode) String() string {
return string(ImageLayerNodeName(n.Layer))
func (n *ImageComponentNode) Describe() string {
return fmt.Sprintf("Image%s|%s", n.Type, n.Component)
}

func (*ImageLayerNode) Kind() string {
return ImageLayerNodeKind
func (*ImageComponentNode) Kind() string {
return ImageComponentNodeKind
}
Loading