Skip to content

Commit

Permalink
Add image pruning support
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy Goldstein committed Apr 29, 2015
1 parent 36cc1f9 commit 7a9aa6a
Show file tree
Hide file tree
Showing 15 changed files with 1,588 additions and 32 deletions.
14 changes: 13 additions & 1 deletion pkg/api/graph/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

type Node struct {
concrete.Node
graph.Node
UniqueName
}

Expand All @@ -23,6 +23,10 @@ type uniqueNamer interface {
UniqueName() string
}

type NodeFinder interface {
Find(name UniqueName) graph.Node
}

// UniqueNodeInitializer is a graph that allows nodes with a unique name to be added without duplication.
// If the node is newly added, true will be returned.
type UniqueNodeInitializer interface {
Expand All @@ -44,6 +48,7 @@ type MutableUniqueGraph interface {
graph.Mutable
MutableDirectedEdge
UniqueNodeInitializer
NodeFinder
}

type Edge struct {
Expand Down Expand Up @@ -294,6 +299,13 @@ func (g uniqueNamedGraph) FindOrCreate(name UniqueName, fn NodeInitializerFunc)
return node, false
}

func (g uniqueNamedGraph) Find(name UniqueName) graph.Node {
if node, ok := g.names[name]; ok {
return node
}
return nil
}

type typedGraph struct{}

type stringer interface {
Expand Down
3 changes: 2 additions & 1 deletion pkg/api/graph/graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ func TestGraph(t *testing.T) {
}
bc++
case *image.ImageStream:
if g.Kind(node) != ImageStreamGraphKind {
// TODO resolve this check for 2 kinds, since both have the same object type
if g.Kind(node) != ImageStreamGraphKind && g.Kind(node) != ImageStreamTagGraphKind {
t.Fatalf("unexpected kind: %v", g.Kind(node))
}
ir++
Expand Down
171 changes: 166 additions & 5 deletions pkg/api/graph/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@ import (

const (
UnknownGraphKind = iota
ImageStreamGraphKind
ImageStreamTagGraphKind
DockerRepositoryGraphKind
BuildConfigGraphKind
DeploymentConfigGraphKind
SourceRepositoryGraphKind
ServiceGraphKind
ImageGraphKind
PodGraphKind
ImageStreamGraphKind
ReplicationControllerGraphKind
ImageLayerGraphKind
BuildGraphKind
)
const (
UnknownGraphEdgeKind = iota
Expand All @@ -36,6 +42,9 @@ const (
BuildOutputGraphEdgeKind
UsedInDeploymentGraphEdgeKind
ExposedThroughServiceGraphEdgeKind
ReferencedImageGraphEdgeKind
WeakReferencedImageGraphEdgeKind
ReferencedImageLayerGraphEdgeKind
)

type ServiceNode struct {
Expand Down Expand Up @@ -119,7 +128,7 @@ func (n ImageStreamTagNode) String() string {
}

func (*ImageStreamTagNode) Kind() int {
return ImageStreamGraphKind
return ImageStreamTagGraphKind
}

type DockerImageRepositoryNode struct {
Expand Down Expand Up @@ -159,6 +168,50 @@ func (SourceRepositoryNode) Kind() int {
return SourceRepositoryGraphKind
}

type ImageNode struct {
Node
Image *image.Image
}

func (n ImageNode) Object() interface{} {
return n.Image
}

func (n ImageNode) String() string {
return fmt.Sprintf("<image %s>", n.Image.Name)
}

func (*ImageNode) Kind() int {
return ImageGraphKind
}

func Image(g MutableUniqueGraph, img *image.Image) graph.Node {
return EnsureUnique(g,
UniqueName(fmt.Sprintf("%d|%s", ImageGraphKind, img.Name)),
func(node Node) graph.Node {
return &ImageNode{node, img}
},
)
}

func FindImage(g MutableUniqueGraph, imageName string) graph.Node {
return g.Find(UniqueName(fmt.Sprintf("%d|%s", ImageGraphKind, imageName)))
}

type PodNode struct {
Node
Pod *kapi.Pod
}

func Pod(g MutableUniqueGraph, pod *kapi.Pod) graph.Node {
return EnsureUnique(g,
UniqueName(fmt.Sprintf("%d|%s/%s", PodGraphKind, pod.Namespace, pod.Name)),
func(node Node) graph.Node {
return &PodNode{node, pod}
},
)
}

// Service adds the provided service to the graph if it does not already exist. It does not
// link the service to covered nodes (that is a separate method).
func Service(g MutableUniqueGraph, svc *kapi.Service) graph.Node {
Expand Down Expand Up @@ -218,13 +271,13 @@ func SourceRepository(g MutableUniqueGraph, source build.BuildSource) (graph.Nod
), true
}

// ImageStreamTag adds a graph node for the specific tag in an Image Repository if it
// ImageStreamTag adds a graph node for the specific tag in an Image Stream if it
// does not already exist.
func ImageStreamTag(g MutableUniqueGraph, namespace, name, tag string) graph.Node {
if len(tag) == 0 {
tag = image.DefaultImageTag
}
uname := UniqueName(fmt.Sprintf("%d|%s/%s:%s", ImageStreamGraphKind, namespace, name, tag))
uname := UniqueName(fmt.Sprintf("%d|%s/%s:%s", ImageStreamTagGraphKind, namespace, name, tag))
return EnsureUnique(g,
uname,
func(node Node) graph.Node {
Expand Down Expand Up @@ -270,7 +323,7 @@ func BuildConfig(g MutableUniqueGraph, config *build.BuildConfig) graph.Node {
g.AddEdge(in, node, BuildInputGraphEdgeKind)
}

from := buildutil.GetImageStreamForStrategy(config)
from := buildutil.GetImageStreamForStrategy(config.Parameters.Strategy)
if from != nil {
for _, trigger := range config.Triggers {
if trigger.ImageChange != nil {
Expand Down Expand Up @@ -437,3 +490,111 @@ func defaultNamespace(value, defaultValue string) string {
}
return value
}

type ImageStreamNode struct {
Node
*image.ImageStream
}

func (n ImageStreamNode) Object() interface{} {
return n.ImageStream
}

func (n ImageStreamNode) String() string {
return fmt.Sprintf("<image stream %s/%s>", n.Namespace, n.Name)
}

func (*ImageStreamNode) Kind() int {
return ImageStreamGraphKind
}

// ImageStream adds a graph node for the Image Stream if it does not already exist.
func ImageStream(g MutableUniqueGraph, stream *image.ImageStream) graph.Node {
return EnsureUnique(g,
UniqueName(fmt.Sprintf("%d|%s/%s", ImageStreamGraphKind, stream.Namespace, stream.Name)),
func(node Node) graph.Node {
return &ImageStreamNode{node, stream}
},
)
}

type ReplicationControllerNode struct {
Node
*kapi.ReplicationController
}

func (n ReplicationControllerNode) Object() interface{} {
return n.ReplicationController
}

func (n ReplicationControllerNode) String() string {
return fmt.Sprintf("<replication controller %s/%s>", n.Namespace, n.Name)
}

func (*ReplicationControllerNode) Kind() int {
return ReplicationControllerGraphKind
}

// ReplicationController adds a graph node for the ReplicationController if it does not already exist.
func ReplicationController(g MutableUniqueGraph, rc *kapi.ReplicationController) graph.Node {
return EnsureUnique(g,
UniqueName(fmt.Sprintf("%d|%s/%s", ReplicationControllerGraphKind, rc.Namespace, rc.Name)),
func(node Node) graph.Node {
return &ReplicationControllerNode{node, rc}
},
)
}

type ImageLayerNode struct {
Node
Layer string
}

func (n ImageLayerNode) Object() interface{} {
return n.Layer
}

func (n ImageLayerNode) String() string {
return fmt.Sprintf("<image layer %s>", n.Layer)
}

func (*ImageLayerNode) Kind() int {
return ImageLayerGraphKind
}

// ImageLayer adds a graph node for the layer if it does not already exist.
func ImageLayer(g MutableUniqueGraph, layer string) graph.Node {
return EnsureUnique(g,
UniqueName(fmt.Sprintf("%d|%s", ImageLayerGraphKind, layer)),
func(node Node) graph.Node {
return &ImageLayerNode{node, layer}
},
)
}

type BuildNode struct {
Node
Build *build.Build
}

func (n BuildNode) Object() interface{} {
return n.Build
}

func (n BuildNode) String() string {
return fmt.Sprintf("<build %s/%s>", n.Build.Namespace, n.Build.Name)
}

func (*BuildNode) Kind() int {
return BuildGraphKind
}

// Build adds a graph node for the build if it does not already exist.
func Build(g MutableUniqueGraph, build *build.Build) graph.Node {
return EnsureUnique(g,
UniqueName(fmt.Sprintf("%d|%s/%s", BuildGraphKind, build.Namespace, build.Name)),
func(node Node) graph.Node {
return &BuildNode{node, build}
},
)
}
2 changes: 1 addition & 1 deletion pkg/build/controller/image_change_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageStream) erro
// TODO: this is inefficient
for _, bc := range c.BuildConfigStore.List() {
config := bc.(*buildapi.BuildConfig)
from := buildutil.GetImageStreamForStrategy(config)
from := buildutil.GetImageStreamForStrategy(config.Parameters.Strategy)
if from == nil || from.Kind != "ImageStreamTag" {
continue
}
Expand Down
12 changes: 6 additions & 6 deletions pkg/build/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ func GetBuildPodName(build *buildapi.Build) string {
}

// GetImageStreamForStrategy returns the ImageStream[Tag/Image] ObjectReference associated
// with the BuildStrategy of a BuildConfig.
func GetImageStreamForStrategy(config *buildapi.BuildConfig) *kapi.ObjectReference {
switch config.Parameters.Strategy.Type {
// with the BuildStrategy.
func GetImageStreamForStrategy(strategy buildapi.BuildStrategy) *kapi.ObjectReference {
switch strategy.Type {
case buildapi.STIBuildStrategyType:
return config.Parameters.Strategy.STIStrategy.From
return strategy.STIStrategy.From
case buildapi.DockerBuildStrategyType:
return config.Parameters.Strategy.DockerStrategy.From
return strategy.DockerStrategy.From
case buildapi.CustomBuildStrategyType:
return config.Parameters.Strategy.CustomStrategy.From
return strategy.CustomStrategy.From
default:
return nil

Expand Down
11 changes: 8 additions & 3 deletions pkg/client/fake_imagestreams.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ func (c *FakeImageStreams) Get(name string) (*imageapi.ImageStream, error) {
return obj.(*imageapi.ImageStream), err
}

func (c *FakeImageStreams) Create(repo *imageapi.ImageStream) (*imageapi.ImageStream, error) {
func (c *FakeImageStreams) Create(stream *imageapi.ImageStream) (*imageapi.ImageStream, error) {
obj, err := c.Fake.Invokes(FakeAction{Action: "create-imagestream"}, &imageapi.ImageStream{})
return obj.(*imageapi.ImageStream), err
}

func (c *FakeImageStreams) Update(repo *imageapi.ImageStream) (*imageapi.ImageStream, error) {
obj, err := c.Fake.Invokes(FakeAction{Action: "update-imagestream"}, &imageapi.ImageStream{})
func (c *FakeImageStreams) Update(stream *imageapi.ImageStream) (*imageapi.ImageStream, error) {
obj, err := c.Fake.Invokes(FakeAction{Action: "update-imagestream", Value: stream}, stream)
return obj.(*imageapi.ImageStream), err
}

Expand All @@ -47,3 +47,8 @@ func (c *FakeImageStreams) Watch(label labels.Selector, field fields.Selector, r
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "watch-imagestreams"})
return nil, nil
}

func (c *FakeImageStreams) UpdateStatus(stream *imageapi.ImageStream) (result *imageapi.ImageStream, err error) {
obj, err := c.Fake.Invokes(FakeAction{Action: "update-status-imagestream", Value: stream}, stream)
return obj.(*imageapi.ImageStream), err
}
8 changes: 8 additions & 0 deletions pkg/client/imagestreams.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type ImageStreamInterface interface {
Update(stream *imageapi.ImageStream) (*imageapi.ImageStream, error)
Delete(name string) error
Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
UpdateStatus(stream *imageapi.ImageStream) (*imageapi.ImageStream, error)
}

// ImageStreamNamespaceGetter exposes methods to get ImageStreams by Namespace
Expand Down Expand Up @@ -100,3 +101,10 @@ func (c *imageStreams) Watch(label labels.Selector, field fields.Selector, resou
FieldsSelectorParam(field).
Watch()
}

// UpdateStatus updates the image stream's status. Returns the server's representation of the image stream, and an error, if it occurs.
func (c *imageStreams) UpdateStatus(stream *imageapi.ImageStream) (result *imageapi.ImageStream, err error) {
result = &imageapi.ImageStream{}
err = c.r.Put().Namespace(c.ns).Resource("imageStreams").Name(stream.Name).SubResource("status").Body(stream).Do().Into(result)
return
}
2 changes: 2 additions & 0 deletions pkg/cmd/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"io"

eximageprune "github.com/openshift/origin/pkg/cmd/experimental/imageprune"
"github.com/spf13/cobra"

"github.com/openshift/origin/pkg/cmd/cli/cmd"
Expand Down Expand Up @@ -47,6 +48,7 @@ func NewCommandAdmin(name, fullName string, out io.Writer) *cobra.Command {
cmds.AddCommand(exipfailover.NewCmdIPFailoverConfig(f, fullName, "ipfailover", out))
cmds.AddCommand(exrouter.NewCmdRouter(f, fullName, "router", out))
cmds.AddCommand(exregistry.NewCmdRegistry(f, fullName, "registry", out))
cmds.AddCommand(eximageprune.NewCmdPruneImages(f, fullName, "prune-images", out))
cmds.AddCommand(buildchain.NewCmdBuildChain(f, fullName, "build-chain"))
cmds.AddCommand(cmd.NewCmdConfig(fullName, "config"))

Expand Down
Loading

0 comments on commit 7a9aa6a

Please sign in to comment.