Example #1
0
func TestDCRCSpecNode(t *testing.T) {
	g := osgraph.New()

	dc := &deployapi.DeploymentConfig{}
	dc.Namespace = "ns"
	dc.Name = "foo"

	dcNode := EnsureDeploymentConfigNode(g, dc)

	if len(g.NodeList()) != 2 {
		t.Errorf("expected 2 nodes, got %v", g.NodeList())
	}

	if len(g.EdgeList()) != 1 {
		t.Errorf("expected 2 edge, got %v", g.EdgeList())
	}

	edge := g.EdgeList()[0]
	if !g.EdgeKinds(edge).Has(osgraph.ContainsEdgeKind) {
		t.Errorf("expected %v, got %v", osgraph.ContainsEdgeKind, g.EdgeKinds(edge))
	}
	if edge.Head().ID() != dcNode.ID() {
		t.Errorf("expected %v, got %v", dcNode.ID(), edge.Head())
	}
}
Example #2
0
func TestPodSpecNode(t *testing.T) {
	g := osgraph.New()

	pod := &kapi.Pod{}
	pod.Namespace = "ns"
	pod.Name = "foo"
	pod.Spec.NodeName = "any-host"

	podNode := EnsurePodNode(g, pod)

	if len(g.Nodes()) != 2 {
		t.Errorf("expected 2 nodes, got %v", g.Nodes())
	}

	if len(g.Edges()) != 1 {
		t.Errorf("expected 1 edge, got %v", g.Edges())
	}

	edge := g.Edges()[0]
	if !g.EdgeKinds(edge).Has(osgraph.ContainsEdgeKind) {
		t.Errorf("expected %v, got %v", osgraph.ContainsEdgeKind, g.EdgeKinds(edge))
	}
	if edge.From().ID() != podNode.ID() {
		t.Errorf("expected %v, got %v", podNode.ID(), edge.From())
	}
}
Example #3
0
// MakeGraph will create the graph of all build configurations and the image streams
// they point to via image change triggers in the provided namespace(s)
func (d *ChainDescriber) MakeGraph() (osgraph.Graph, error) {
	g := osgraph.New()

	loaders := []GraphLoader{}
	for namespace := range d.namespaces {
		glog.V(4).Infof("Loading build configurations from %q", namespace)
		loaders = append(loaders, &bcLoader{namespace: namespace, lister: d.c})
	}
	loadingFuncs := []func() error{}
	for _, loader := range loaders {
		loadingFuncs = append(loadingFuncs, loader.Load)
	}

	if errs := parallel.Run(loadingFuncs...); len(errs) > 0 {
		return g, utilerrors.NewAggregate(errs)
	}

	for _, loader := range loaders {
		loader.AddToGraph(g)
	}

	buildedges.AddAllInputOutputEdges(g)

	return g, nil
}
Example #4
0
func TestHPADCEdges(t *testing.T) {
	hpa := &autoscaling.HorizontalPodAutoscaler{}
	hpa.Namespace = "test-ns"
	hpa.Name = "test-hpa"
	hpa.Spec = autoscaling.HorizontalPodAutoscalerSpec{
		ScaleTargetRef: autoscaling.CrossVersionObjectReference{
			Name: "test-dc",
			Kind: "DeploymentConfig",
		},
	}

	dc := &deployapi.DeploymentConfig{}
	dc.Name = "test-dc"
	dc.Namespace = "test-ns"

	g := osgraph.New()
	hpaNode := kubegraph.EnsureHorizontalPodAutoscalerNode(g, hpa)
	dcNode := deploygraph.EnsureDeploymentConfigNode(g, dc)

	AddHPAScaleRefEdges(g)

	if edge := g.Edge(hpaNode, dcNode); edge == nil {
		t.Fatalf("edge between HPA and DC missing")
	} else {
		if !g.EdgeKinds(edge).Has(ScalingEdgeKind) {
			t.Errorf("expected edge to have kind %v, got %v", ScalingEdgeKind, edge)
		}
	}
}
Example #5
0
/*
NewImageRegistryPruner creates a new ImageRegistryPruner.

Images younger than keepYoungerThan and images referenced by image streams
and/or pods younger than keepYoungerThan are preserved. All other images are
candidates for pruning. For example, if keepYoungerThan is 60m, and an
ImageStream is only 59 minutes old, none of the images it references are
eligible for pruning.

keepTagRevisions is the number of revisions per tag in an image stream's
status.tags that are preserved and ineligible for pruning. Any revision older
than keepTagRevisions is eligible for pruning.

images, streams, pods, rcs, bcs, builds, and dcs are the resources used to run
the pruning algorithm. These should be the full list for each type from the
cluster; otherwise, the pruning algorithm might result in incorrect
calculations and premature pruning.

The ImagePruner performs the following logic: remove any image containing the
annotation openshift.io/image.managed=true that was created at least *n*
minutes ago and is *not* currently referenced by:

- any pod created less than *n* minutes ago
- any image stream created less than *n* minutes ago
- any running pods
- any pending pods
- any replication controllers
- any deployment configs
- any build configs
- any builds
- the n most recent tag revisions in an image stream's status.tags

When removing an image, remove all references to the image from all
ImageStreams having a reference to the image in `status.tags`.

Also automatically remove any image layer that is no longer referenced by any
images.
*/
func NewImageRegistryPruner(options ImageRegistryPrunerOptions) ImageRegistryPruner {
	g := graph.New()

	glog.V(1).Infof("Creating image pruner with keepYoungerThan=%v, keepTagRevisions=%d", options.KeepYoungerThan, options.KeepTagRevisions)

	algorithm := pruneAlgorithm{
		keepYoungerThan:  options.KeepYoungerThan,
		keepTagRevisions: options.KeepTagRevisions,
	}

	addImagesToGraph(g, options.Images, algorithm)
	addImageStreamsToGraph(g, options.Streams, algorithm)
	addPodsToGraph(g, options.Pods, algorithm)
	addReplicationControllersToGraph(g, options.RCs)
	addBuildConfigsToGraph(g, options.BCs)
	addBuildsToGraph(g, options.Builds)
	addDeploymentConfigsToGraph(g, options.DCs)

	var rp registryPinger
	if options.DryRun {
		rp = &dryRunRegistryPinger{}
	} else {
		rp = &defaultRegistryPinger{options.RegistryClient}
	}

	return &imageRegistryPruner{
		g:              g,
		algorithm:      algorithm,
		registryPinger: rp,
		registryClient: options.RegistryClient,
		registryURL:    options.RegistryURL,
	}
}
Example #6
0
// imagesTop generates Image information from a graph and returns this as a list
// of imageInfo array.
func (o TopImagesOptions) imagesTop() []Info {
	g := graph.New()
	addImagesToGraph(g, o.Images)
	addImageStreamsToGraph(g, o.Streams)
	addPodsToGraph(g, o.Pods)
	markParentsInGraph(g)

	infos := []Info{}
	imageNodes := getImageNodes(g.Nodes())
	for _, in := range imageNodes {
		image := in.Image
		istags := getImageStreamTags(g, in)
		parents := getImageParents(g, in)
		usage := getImageUsage(g, in)
		metadata := len(image.DockerImageManifest) != 0 && len(image.DockerImageLayers) != 0
		storage := getStorage(image)
		infos = append(infos, imageInfo{
			Image:           image.Name,
			ImageStreamTags: istags,
			Parents:         parents,
			Usage:           usage,
			Metadata:        metadata,
			Storage:         storage,
		})
	}

	return infos
}
Example #7
0
func TestHPARCEdges(t *testing.T) {
	hpa := &autoscaling.HorizontalPodAutoscaler{}
	hpa.Namespace = "test-ns"
	hpa.Name = "test-hpa"
	hpa.Spec = autoscaling.HorizontalPodAutoscalerSpec{
		ScaleTargetRef: autoscaling.CrossVersionObjectReference{
			Name: "test-rc",
			Kind: "ReplicationController",
		},
	}

	rc := &kapi.ReplicationController{}
	rc.Name = "test-rc"
	rc.Namespace = "test-ns"

	g := osgraph.New()
	hpaNode := kubegraph.EnsureHorizontalPodAutoscalerNode(g, hpa)
	rcNode := kubegraph.EnsureReplicationControllerNode(g, rc)

	AddHPAScaleRefEdges(g)

	if edge := g.Edge(hpaNode, rcNode); edge == nil {
		t.Fatalf("edge between HPA and RC missing")
	} else {
		if !g.EdgeKinds(edge).Has(ScalingEdgeKind) {
			t.Errorf("expected edge to have kind %v, got %v", ScalingEdgeKind, edge)
		}
	}
}
Example #8
0
func (d *ProjectStatusDescriber) MakeGraph(namespace string) (osgraph.Graph, sets.String, error) {
	g := osgraph.New()

	loaders := []GraphLoader{
		&serviceLoader{namespace: namespace, lister: d.K},
		&serviceAccountLoader{namespace: namespace, lister: d.K},
		&secretLoader{namespace: namespace, lister: d.K},
		&rcLoader{namespace: namespace, lister: d.K},
		&podLoader{namespace: namespace, lister: d.K},
		// TODO check swagger for feature enablement and selectively add bcLoader and buildLoader
		// then remove errors.TolerateNotFoundError method.
		&bcLoader{namespace: namespace, lister: d.C},
		&buildLoader{namespace: namespace, lister: d.C},
		&isLoader{namespace: namespace, lister: d.C},
		&dcLoader{namespace: namespace, lister: d.C},
		&routeLoader{namespace: namespace, lister: d.C},
	}
	loadingFuncs := []func() error{}
	for _, loader := range loaders {
		loadingFuncs = append(loadingFuncs, loader.Load)
	}

	forbiddenResources := sets.String{}
	if errs := parallel.Run(loadingFuncs...); len(errs) > 0 {
		actualErrors := []error{}
		for _, err := range errs {
			if kapierrors.IsForbidden(err) {
				forbiddenErr := err.(*kapierrors.StatusError)
				if (forbiddenErr.Status().Details != nil) && (len(forbiddenErr.Status().Details.Kind) > 0) {
					forbiddenResources.Insert(forbiddenErr.Status().Details.Kind)
				}
				continue
			}
			actualErrors = append(actualErrors, err)
		}

		if len(actualErrors) > 0 {
			return g, forbiddenResources, utilerrors.NewAggregate(actualErrors)
		}
	}

	for _, loader := range loaders {
		loader.AddToGraph(g)
	}

	kubeedges.AddAllExposedPodTemplateSpecEdges(g)
	kubeedges.AddAllExposedPodEdges(g)
	kubeedges.AddAllManagedByRCPodEdges(g)
	kubeedges.AddAllRequestedServiceAccountEdges(g)
	kubeedges.AddAllMountableSecretEdges(g)
	kubeedges.AddAllMountedSecretEdges(g)
	buildedges.AddAllInputOutputEdges(g)
	buildedges.AddAllBuildEdges(g)
	deployedges.AddAllTriggerEdges(g)
	deployedges.AddAllDeploymentEdges(g)
	imageedges.AddAllImageStreamRefEdges(g)
	routeedges.AddAllRouteEdges(g)

	return g, forbiddenResources, nil
}
Example #9
0
func (d *ProjectStatusDescriber) MakeGraph(namespace string) (osgraph.Graph, error) {
	g := osgraph.New()

	svcs, err := d.K.Services(namespace).List(labels.Everything())
	if err != nil {
		return g, err
	}

	iss, err := d.C.ImageStreams(namespace).List(labels.Everything(), fields.Everything())
	if err != nil {
		return g, err
	}

	bcs, err := d.C.BuildConfigs(namespace).List(labels.Everything(), fields.Everything())
	if err != nil {
		return g, err
	}

	dcs, err := d.C.DeploymentConfigs(namespace).List(labels.Everything(), fields.Everything())
	if err != nil {
		return g, err
	}

	builds := &buildapi.BuildList{}
	if len(bcs.Items) > 0 {
		if b, err := d.C.Builds(namespace).List(labels.Everything(), fields.Everything()); err == nil {
			builds = b
		}
	}

	rcs, err := d.K.ReplicationControllers(namespace).List(labels.Everything())
	if err != nil {
		rcs = &kapi.ReplicationControllerList{}
	}

	for i := range iss.Items {
		imagegraph.EnsureImageStreamNode(g, &iss.Items[i])
		imagegraph.EnsureAllImageStreamTagNodes(g, &iss.Items[i])
	}
	for i := range bcs.Items {
		build := buildgraph.EnsureBuildConfigNode(g, &bcs.Items[i])
		buildedges.AddInputOutputEdges(g, build)
		buildedges.JoinBuilds(build, builds.Items)
	}
	for i := range dcs.Items {
		deploy := deploygraph.EnsureDeploymentConfigNode(g, &dcs.Items[i])
		deployedges.AddTriggerEdges(g, deploy)
		deployedges.JoinDeployments(deploy, rcs.Items)
	}
	for i := range svcs.Items {
		service := kubegraph.EnsureServiceNode(g, &svcs.Items[i])
		kubeedges.AddExposedPodTemplateSpecEdges(g, service)
	}

	imageedges.AddAllImageStreamRefEdges(g)

	return g, nil
}
Example #10
0
func TestReplicationControllerSpecNode(t *testing.T) {
	g := osgraph.New()

	rc := &kapi.ReplicationController{}
	rc.Namespace = "ns"
	rc.Name = "foo"
	rc.Spec.Template = &kapi.PodTemplateSpec{}

	rcNode := EnsureReplicationControllerNode(g, rc)

	if len(g.Nodes()) != 4 {
		t.Errorf("expected 4 nodes, got %v", g.Nodes())
	}

	if len(g.Edges()) != 3 {
		t.Errorf("expected 3 edge, got %v", g.Edges())
	}

	rcEdges := g.OutboundEdges(rcNode)
	if len(rcEdges) != 1 {
		t.Fatalf("expected 1 edge, got %v for \n%v", rcEdges, g)
	}
	if !g.EdgeKinds(rcEdges[0]).Has(osgraph.ContainsEdgeKind) {
		t.Errorf("expected %v, got %v", osgraph.ContainsEdgeKind, rcEdges[0])
	}

	uncastRCSpec := rcEdges[0].To()
	rcSpec, ok := uncastRCSpec.(*ReplicationControllerSpecNode)
	if !ok {
		t.Fatalf("expected rcSpec, got %v", uncastRCSpec)
	}
	rcSpecEdges := g.OutboundEdges(rcSpec)
	if len(rcSpecEdges) != 1 {
		t.Fatalf("expected 1 edge, got %v", rcSpecEdges)
	}
	if !g.EdgeKinds(rcSpecEdges[0]).Has(osgraph.ContainsEdgeKind) {
		t.Errorf("expected %v, got %v", osgraph.ContainsEdgeKind, rcSpecEdges[0])
	}

	uncastPTSpec := rcSpecEdges[0].To()
	ptSpec, ok := uncastPTSpec.(*PodTemplateSpecNode)
	if !ok {
		t.Fatalf("expected ptspec, got %v", uncastPTSpec)
	}
	ptSpecEdges := g.OutboundEdges(ptSpec)
	if len(ptSpecEdges) != 1 {
		t.Fatalf("expected 1 edge, got %v", ptSpecEdges)
	}
	if !g.EdgeKinds(ptSpecEdges[0]).Has(osgraph.ContainsEdgeKind) {
		t.Errorf("expected %v, got %v", osgraph.ContainsEdgeKind, ptSpecEdges[0])
	}

}
Example #11
0
// NewPruner creates a Pruner.
//
// Images younger than keepYoungerThan and images referenced by image streams
// and/or pods younger than keepYoungerThan are preserved. All other images are
// candidates for pruning. For example, if keepYoungerThan is 60m, and an
// ImageStream is only 59 minutes old, none of the images it references are
// eligible for pruning.
//
// keepTagRevisions is the number of revisions per tag in an image stream's
// status.tags that are preserved and ineligible for pruning. Any revision older
// than keepTagRevisions is eligible for pruning.
//
// pruneOverSizeLimit is a boolean flag speyfing that all images exceeding limits
// defined in their namespace will be considered for pruning. Important to note is
// the fact that this flag does not work in any combination with the keep* flags.
//
// images, streams, pods, rcs, bcs, builds, and dcs are the resources used to run
// the pruning algorithm. These should be the full list for each type from the
// cluster; otherwise, the pruning algorithm might result in incorrect
// calculations and premature pruning.
//
// The ImageDeleter performs the following logic:
//
// remove any image that was created at least *n* minutes ago and is *not*
// currently referenced by:
//
// - any pod created less than *n* minutes ago
// - any image stream created less than *n* minutes ago
// - any running pods
// - any pending pods
// - any replication controllers
// - any deployment configs
// - any build configs
// - any builds
// - the n most recent tag revisions in an image stream's status.tags
//
// including only images with the annotation openshift.io/image.managed=true
// unless allImages is true.
//
// When removing an image, remove all references to the image from all
// ImageStreams having a reference to the image in `status.tags`.
//
// Also automatically remove any image layer that is no longer referenced by any
// images.
func NewPruner(options PrunerOptions) Pruner {
	keepTagRevisions := "<nil>"
	if options.KeepTagRevisions != nil {
		keepTagRevisions = fmt.Sprintf("%d", *options.KeepTagRevisions)
	}
	pruneOverSizeLimit := "<nil>"
	if options.PruneOverSizeLimit != nil {
		pruneOverSizeLimit = fmt.Sprintf("%v", *options.PruneOverSizeLimit)
	}
	glog.V(1).Infof("Creating image pruner with keepYoungerThan=%v, keepTagRevisions=%s, pruneOverSizeLimit=%s, allImages=%t",
		options.KeepYoungerThan, keepTagRevisions, pruneOverSizeLimit, options.AllImages)

	algorithm := pruneAlgorithm{}
	if options.KeepYoungerThan != nil {
		algorithm.keepYoungerThan = *options.KeepYoungerThan
	}
	if options.KeepTagRevisions != nil {
		algorithm.keepTagRevisions = *options.KeepTagRevisions
	}
	if options.PruneOverSizeLimit != nil {
		algorithm.pruneOverSizeLimit = *options.PruneOverSizeLimit
	}
	if options.AllImages != nil {
		algorithm.allImages = *options.AllImages
	}
	algorithm.namespace = options.Namespace

	g := graph.New()
	addImagesToGraph(g, options.Images, algorithm)
	addImageStreamsToGraph(g, options.Streams, options.LimitRanges, algorithm)
	addPodsToGraph(g, options.Pods, algorithm)
	addReplicationControllersToGraph(g, options.RCs)
	addBuildConfigsToGraph(g, options.BCs)
	addBuildsToGraph(g, options.Builds)
	addDeploymentConfigsToGraph(g, options.DCs)

	var rp registryPinger
	if options.DryRun {
		rp = &dryRunRegistryPinger{}
	} else {
		rp = &defaultRegistryPinger{options.RegistryClient}
	}

	return &pruner{
		g:              g,
		algorithm:      algorithm,
		registryPinger: rp,
		registryClient: options.RegistryClient,
		registryURL:    options.RegistryURL,
	}
}
Example #12
0
func TestNamespaceEdgeMatching(t *testing.T) {
	g := osgraph.New()

	fn := func(namespace string, g osgraph.Interface) {
		pod := &kapi.Pod{}
		pod.Namespace = namespace
		pod.Name = "the-pod"
		pod.Labels = map[string]string{"a": "1"}
		kubegraph.EnsurePodNode(g, pod)

		rc := &kapi.ReplicationController{}
		rc.Namespace = namespace
		rc.Name = "the-rc"
		rc.Spec.Selector = map[string]string{"a": "1"}
		kubegraph.EnsureReplicationControllerNode(g, rc)

		p := &kapps.PetSet{}
		p.Namespace = namespace
		p.Name = "the-petset"
		p.Spec.Selector = &unversioned.LabelSelector{
			MatchLabels: map[string]string{"a": "1"},
		}
		kubegraph.EnsurePetSetNode(g, p)

		svc := &kapi.Service{}
		svc.Namespace = namespace
		svc.Name = "the-svc"
		svc.Spec.Selector = map[string]string{"a": "1"}
		kubegraph.EnsureServiceNode(g, svc)
	}

	fn("ns", g)
	fn("other", g)
	AddAllExposedPodEdges(g)
	AddAllExposedPodTemplateSpecEdges(g)
	AddAllManagedByControllerPodEdges(g)

	for _, edge := range g.Edges() {
		nsTo, err := namespaceFor(edge.To())
		if err != nil {
			t.Fatal(err)
		}
		nsFrom, err := namespaceFor(edge.From())
		if err != nil {
			t.Fatal(err)
		}
		if nsFrom != nsTo {
			t.Errorf("edge %#v crosses namespace: %s %s", edge, nsFrom, nsTo)
		}
	}
}
Example #13
0
func TestDCPodTemplateSpecNode(t *testing.T) {
	g := osgraph.New()

	dc := &deployapi.DeploymentConfig{}
	dc.Namespace = "ns"
	dc.Name = "foo"
	dc.Spec.Template = test.OkPodTemplate()

	_ = EnsureDeploymentConfigNode(g, dc)

	edges := g.Edges()
	if len(edges) != 2 {
		t.Errorf("expected 2 edges, got %d", len(edges))
		return
	}
	for i := range edges {
		if !g.EdgeKinds(edges[i]).Has(osgraph.ContainsEdgeKind) {
			t.Errorf("expected %v, got %v", osgraph.ContainsEdgeKind, g.EdgeKinds(edges[i]))
			return
		}
	}

	nodes := g.Nodes()
	if len(nodes) != 3 {
		t.Errorf("expected 3 nodes, got %d", len(nodes))
		return
	}
	sorted, err := topo.Sort(g)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
		return
	}
	// Just to be sure
	if len(sorted) != 3 {
		t.Errorf("expected 3 nodes, got %d", len(sorted))
		return
	}
	if _, ok := sorted[0].(*DeploymentConfigNode); !ok {
		t.Errorf("expected first node to be a DeploymentConfigNode")
		return
	}
	if _, ok := sorted[1].(*kubetypes.PodTemplateSpecNode); !ok {
		t.Errorf("expected second node to be a PodTemplateSpecNode")
		return
	}
	if _, ok := sorted[2].(*kubetypes.PodSpecNode); !ok {
		t.Errorf("expected third node to be a PodSpecNode")
	}
}
Example #14
0
// Describe returns the description of the latest deployments for a config
func (d *LatestDeploymentsDescriber) Describe(namespace, name string) (string, error) {
	var f formatter

	config, err := d.client.getDeploymentConfig(namespace, name)
	if err != nil {
		return "", err
	}

	var deployments []kapi.ReplicationController
	if d.count == -1 || d.count > 1 {
		list, err := d.client.listDeployments(namespace, labels.Everything())
		if err != nil && !kerrors.IsNotFound(err) {
			return "", err
		}
		deployments = list.Items
	} else {
		deploymentName := deployutil.LatestDeploymentNameForConfig(config)
		deployment, err := d.client.getDeployment(config.Namespace, deploymentName)
		if err != nil && !kerrors.IsNotFound(err) {
			return "", err
		}
		if deployment != nil {
			deployments = []kapi.ReplicationController{*deployment}
		}
	}

	g := graph.New()
	dcNode := deploygraph.EnsureDeploymentConfigNode(g, config)
	for i := range deployments {
		kubegraph.EnsureReplicationControllerNode(g, &deployments[i])
	}
	deployedges.AddTriggerEdges(g, dcNode)
	deployedges.AddDeploymentEdges(g, dcNode)
	activeDeployment, inactiveDeployments := deployedges.RelevantDeployments(g, dcNode)

	return tabbedString(func(out *tabwriter.Writer) error {
		descriptions := describeDeployments(f, dcNode, activeDeployment, inactiveDeployments, d.count)
		for i, description := range descriptions {
			descriptions[i] = fmt.Sprintf("%v %v", name, description)
		}
		printLines(out, "", 0, descriptions...)
		return nil
	})
}
Example #15
0
func TestSecretEdges(t *testing.T) {
	sa := &kapi.ServiceAccount{}
	sa.Namespace = "ns"
	sa.Name = "shultz"
	sa.Secrets = []kapi.ObjectReference{{Name: "i-know-nothing"}, {Name: "missing"}}

	secret1 := &kapi.Secret{}
	secret1.Namespace = "ns"
	secret1.Name = "i-know-nothing"

	pod := &kapi.Pod{}
	pod.Namespace = "ns"
	pod.Name = "the-pod"
	pod.Spec.Volumes = []kapi.Volume{{Name: "rose", VolumeSource: kapi.VolumeSource{Secret: &kapi.SecretVolumeSource{SecretName: "i-know-nothing"}}}}

	g := osgraph.New()
	saNode := kubegraph.EnsureServiceAccountNode(g, sa)
	secretNode := kubegraph.EnsureSecretNode(g, secret1)
	podNode := kubegraph.EnsurePodNode(g, pod)

	AddAllMountableSecretEdges(g)
	AddAllMountedSecretEdges(g)

	if edge := g.Edge(saNode, secretNode); edge == nil {
		t.Errorf("edge missing")
	} else {
		if !g.EdgeKinds(edge).Has(MountableSecretEdgeKind) {
			t.Errorf("expected %v, got %v", MountableSecretEdgeKind, edge)
		}
	}

	podSpecNodes := g.SuccessorNodesByNodeAndEdgeKind(podNode, kubegraph.PodSpecNodeKind, osgraph.ContainsEdgeKind)
	if len(podSpecNodes) != 1 {
		t.Fatalf("wrong number of podspecs: %v", podSpecNodes)
	}

	if edge := g.Edge(podSpecNodes[0], secretNode); edge == nil {
		t.Errorf("edge missing")
	} else {
		if !g.EdgeKinds(edge).Has(MountedSecretEdgeKind) {
			t.Errorf("expected %v, got %v", MountedSecretEdgeKind, edge)
		}
	}
}
Example #16
0
// imageStreamsTop generates ImageStream information from a graph and
// returns this as a list of imageStreamInfo array.
func (o TopImageStreamsOptions) imageStreamsTop() []Info {
	g := graph.New()
	addImagesToGraph(g, o.Images)
	addImageStreamsToGraph(g, o.Streams)

	infos := []Info{}
	streamNodes := getImageStreamNodes(g.Nodes())
	for _, sn := range streamNodes {
		storage, images, layers := getImageStreamSize(g, sn)
		infos = append(infos, imageStreamInfo{
			ImageStream: fmt.Sprintf("%s/%s", sn.ImageStream.Namespace, sn.ImageStream.Name),
			Storage:     storage,
			Images:      images,
			Layers:      layers,
		})
	}

	return infos
}
Example #17
0
func (d *ProjectStatusDescriber) MakeGraph(namespace string) (osgraph.Graph, error) {
	g := osgraph.New()

	loaders := []GraphLoader{
		&serviceLoader{namespace: namespace, lister: d.K},
		&serviceAccountLoader{namespace: namespace, lister: d.K},
		&secretLoader{namespace: namespace, lister: d.K},
		&rcLoader{namespace: namespace, lister: d.K},
		&podLoader{namespace: namespace, lister: d.K},
		&bcLoader{namespace: namespace, lister: d.C},
		&buildLoader{namespace: namespace, lister: d.C},
		&isLoader{namespace: namespace, lister: d.C},
		&dcLoader{namespace: namespace, lister: d.C},
	}
	loadingFuncs := []func() error{}
	for _, loader := range loaders {
		loadingFuncs = append(loadingFuncs, loader.Load)
	}

	if errs := parallel.Run(loadingFuncs...); len(errs) > 0 {
		return g, utilerrors.NewAggregate(errs)
	}

	for _, loader := range loaders {
		loader.AddToGraph(g)
	}

	kubeedges.AddAllExposedPodTemplateSpecEdges(g)
	kubeedges.AddAllExposedPodEdges(g)
	kubeedges.AddAllManagedByRCPodEdges(g)
	kubeedges.AddAllRequestedServiceAccountEdges(g)
	kubeedges.AddAllMountableSecretEdges(g)
	kubeedges.AddAllMountedSecretEdges(g)
	buildedges.AddAllInputOutputEdges(g)
	buildedges.AddAllBuildEdges(g)
	deployedges.AddAllTriggerEdges(g)
	deployedges.AddAllDeploymentEdges(g)
	imageedges.AddAllImageStreamRefEdges(g)

	return g, nil
}
Example #18
0
// DescendentNodesByNodeKind starts at the root navigates down the root.  Every edge is checked against the edgeChecker
// to determine whether or not to follow it.  The nodes at the tail end of every chased edge are then checked against the
// the targetNodeKind.  Matches are added to the return and every checked node then has its edges checked: lather, rinse, repeat
func DescendentNodesByNodeKind(g osgraph.Graph, visitedNodes graphview.IntSet, node graph.Node, targetNodeKind string, edgeChecker osgraph.EdgeFunc) []graph.Node {
	if visitedNodes.Has(node.ID()) {
		return []graph.Node{}
	}
	visitedNodes.Insert(node.ID())

	ret := []graph.Node{}
	for _, successor := range g.From(node) {
		edge := g.Edge(node, successor)

		if edgeChecker(osgraph.New(), node, successor, g.EdgeKinds(edge)) {
			if g.Kind(successor) == targetNodeKind {
				ret = append(ret, successor)
			}

			ret = append(ret, DescendentNodesByNodeKind(g, visitedNodes, successor, targetNodeKind, edgeChecker)...)
		}
	}

	return ret
}
Example #19
0
func (d *ProjectStatusDescriber) MakeGraph(namespace string) (osgraph.Graph, error) {
	g := osgraph.New()

	loadingFuncs := []GraphLoadingFunc{loadServices, loadBuildConfigs, loadImageStreams, loadDeploymentConfigs, loadBuilds, loadReplicationControllers}

	listingWaitGroup := sync.WaitGroup{}
	graphLock := sync.Mutex{}
	errorChannel := make(chan error, len(loadingFuncs))

	for _, loadingFunc := range loadingFuncs {
		listingWaitGroup.Add(1)
		go func(loadingFunc GraphLoadingFunc) {
			defer listingWaitGroup.Done()
			if err := loadingFunc(g, graphLock, namespace, d.K, d.C); err != nil {
				errorChannel <- err
			}
		}(loadingFunc)
	}
	listingWaitGroup.Wait()
	close(errorChannel)

	// if we had an error.  Aggregate them and return them
	errlist := []error{}
	for err := range errorChannel {
		errlist = append(errlist, err)
	}
	if len(errlist) > 0 {
		return g, utilerrors.NewAggregate(errlist)
	}

	kubeedges.AddAllExposedPodTemplateSpecEdges(g)
	buildedges.AddAllInputOutputEdges(g)
	buildedges.AddAllBuildEdges(g)
	deployedges.AddAllTriggerEdges(g)
	deployedges.AddAllDeploymentEdges(g)

	imageedges.AddAllImageStreamRefEdges(g)

	return g, nil
}
Example #20
0
// Describe returns the description of the latest deployments for a config
func (d *LatestDeploymentsDescriber) Describe(namespace, name string) (string, error) {
	config, err := d.client.getDeploymentConfig(namespace, name)
	if err != nil {
		return "", err
	}

	var deployments []kapi.ReplicationController
	if d.count == -1 || d.count > 1 {
		list, err := d.client.listDeployments(namespace, labels.Everything())
		if err != nil && !kerrors.IsNotFound(err) {
			return "", err
		}
		deployments = list.Items
	} else {
		deploymentName := deployutil.LatestDeploymentNameForConfig(config)
		deployment, err := d.client.getDeployment(config.Namespace, deploymentName)
		if err != nil && !kerrors.IsNotFound(err) {
			return "", err
		}
		if deployment != nil {
			deployments = []kapi.ReplicationController{*deployment}
		}
	}

	g := graph.New()
	deploy := graph.DeploymentConfig(g, config)
	if len(deployments) > 0 {
		graph.JoinDeployments(deploy.(*graph.DeploymentConfigNode), deployments)
	}

	return tabbedString(func(out *tabwriter.Writer) error {
		node := deploy.(*graph.DeploymentConfigNode)
		descriptions := describeDeployments(node, d.count)
		for i, description := range descriptions {
			descriptions[i] = fmt.Sprintf("%v %v", name, description)
		}
		printLines(out, "", 0, descriptions...)
		return nil
	})
}
Example #21
0
func TestNamespaceEdgeMatching(t *testing.T) {
	g := osgraph.New()

	fn := func(namespace string, g osgraph.Interface) {
		bc := &api.BuildConfig{}
		bc.Namespace = namespace
		bc.Name = "the-bc"
		nodes.EnsureBuildConfigNode(g, bc)

		b := &api.Build{}
		b.Namespace = namespace
		b.Name = "the-build"
		b.Labels = map[string]string{api.BuildConfigLabel: "the-bc"}
		b.Annotations = map[string]string{api.BuildConfigAnnotation: "the-bc"}
		nodes.EnsureBuildNode(g, b)
	}

	fn("ns", g)
	fn("other", g)
	AddAllBuildEdges(g)

	if len(g.Edges()) != 2 {
		t.Fatal(g)
	}
	for _, edge := range g.Edges() {
		nsTo, err := namespaceFor(edge.To())
		if err != nil {
			t.Fatal(err)
		}
		nsFrom, err := namespaceFor(edge.From())
		if err != nil {
			t.Fatal(err)
		}
		if nsFrom != nsTo {
			t.Errorf("edge %#v crosses namespace: %s %s", edge, nsFrom, nsTo)
		}
	}
}
func BuildGraph(path string) (osgraph.Graph, []runtime.Object, error) {
	g := osgraph.New()
	objs := []runtime.Object{}

	abspath, err := filepath.Abs(path)
	if err != nil {
		return g, objs, err
	}

	mapper := latest.RESTMapper
	typer := kapi.Scheme
	clientMapper := resource.ClientMapperFunc(func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
		return nil, nil
	})

	r := resource.NewBuilder(mapper, typer, clientMapper).
		FilenameParam(abspath).
		Flatten().
		Do()

	if r.Err() != nil {
		return g, objs, r.Err()
	}

	infos, err := r.Infos()
	if err != nil {
		return g, objs, err
	}
	for _, info := range infos {
		objs = append(objs, info.Object)

		if err := EnsureNode(g, info.Object); err != nil {
			return g, objs, err
		}
	}

	return g, objs, nil
}
func BuildGraph(path string) (osgraph.Graph, []runtime.Object, error) {
	g := osgraph.New()
	objs := []runtime.Object{}

	abspath, err := filepath.Abs(path)
	if err != nil {
		return g, objs, err
	}

	mapper := registered.RESTMapper()
	typer := kapi.Scheme
	clientMapper := resource.ClientMapperFunc(func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
		return nil, nil
	})

	r := resource.NewBuilder(mapper, typer, clientMapper, kapi.Codecs.UniversalDecoder()).
		FilenameParam(false, &resource.FilenameOptions{Recursive: false, Filenames: []string{abspath}}).
		Flatten().
		Do()

	if r.Err() != nil {
		return g, objs, r.Err()
	}

	infos, err := r.Infos()
	if err != nil {
		return g, objs, err
	}
	for _, info := range infos {
		objs = append(objs, info.Object)

		if err := EnsureNode(g, info.Object); err != nil {
			return g, objs, err
		}
	}

	return g, objs, nil
}
Example #24
0
func TestNamespaceEdgeMatching(t *testing.T) {
	g := osgraph.New()

	fn := func(namespace string, g osgraph.Interface) {
		dc := &api.DeploymentConfig{}
		dc.Namespace = namespace
		dc.Name = "the-dc"
		dc.Spec.Selector = map[string]string{"a": "1"}
		nodes.EnsureDeploymentConfigNode(g, dc)

		rc := &kapi.ReplicationController{}
		rc.Namespace = namespace
		rc.Name = "the-rc"
		rc.Annotations = map[string]string{api.DeploymentConfigAnnotation: "the-dc"}
		kubegraph.EnsureReplicationControllerNode(g, rc)
	}

	fn("ns", g)
	fn("other", g)
	AddAllDeploymentEdges(g)

	if len(g.Edges()) != 4 {
		t.Fatal(g)
	}
	for _, edge := range g.Edges() {
		nsTo, err := namespaceFor(edge.To())
		if err != nil {
			t.Fatal(err)
		}
		nsFrom, err := namespaceFor(edge.From())
		if err != nil {
			t.Fatal(err)
		}
		if nsFrom != nsTo {
			t.Errorf("edge %#v crosses namespace: %s %s", edge, nsFrom, nsTo)
		}
	}
}
Example #25
0
/*
NewImagePruner creates a new ImagePruner.

Images younger than keepYoungerThan and images referenced by image streams
and/or pods younger than keepYoungerThan are preserved. All other images are
candidates for pruning. For example, if keepYoungerThan is 60m, and an
ImageStream is only 59 minutes old, none of the images it references are
eligible for pruning.

tagRevisionsToKeep is the number of revisions per tag in an image stream's
status.tags that are preserved and ineligible for pruning. Any revision older
than tagRevisionsToKeep is eligible for pruning.

images, streams, pods, rcs, bcs, builds, and dcs are the resources used to run
the pruning algorithm. These should be the full list for each type from the
cluster; otherwise, the pruning algorithm might result in incorrect
calculations and premature pruning.

The ImagePruner performs the following logic: remove any image contaning the
annotation openshift.io/image.managed=true that was created at least *n*
minutes ago and is *not* currently referenced by:

- any pod created less than *n* minutes ago
- any image stream created less than *n* minutes ago
- any running pods
- any pending pods
- any replication controllers
- any deployment configs
- any build configs
- any builds
- the n most recent tag revisions in an image stream's status.tags

When removing an image, remove all references to the image from all
ImageStreams having a reference to the image in `status.tags`.

Also automatically remove any image layer that is no longer referenced by any
images.
*/
func NewImagePruner(keepYoungerThan time.Duration, tagRevisionsToKeep int, images *imageapi.ImageList, streams *imageapi.ImageStreamList, pods *kapi.PodList, rcs *kapi.ReplicationControllerList, bcs *buildapi.BuildConfigList, builds *buildapi.BuildList, dcs *deployapi.DeploymentConfigList) ImagePruner {
	g := graph.New()

	glog.V(1).Infof("Creating image pruner with keepYoungerThan=%v, tagRevisionsToKeep=%d", keepYoungerThan, tagRevisionsToKeep)

	algorithm := pruneAlgorithm{
		keepYoungerThan:    keepYoungerThan,
		tagRevisionsToKeep: tagRevisionsToKeep,
	}

	addImagesToGraph(g, images, algorithm)
	addImageStreamsToGraph(g, streams, algorithm)
	addPodsToGraph(g, pods, algorithm)
	addReplicationControllersToGraph(g, rcs)
	addBuildConfigsToGraph(g, bcs)
	addBuildsToGraph(g, builds)
	addDeploymentConfigsToGraph(g, dcs)

	return &imagePruner{
		g:         g,
		algorithm: algorithm,
	}
}
Example #26
0
func TestGraph(t *testing.T) {
	g := osgraph.New()
	now := time.Now()
	builds := []buildapi.Build{
		{
			ObjectMeta: kapi.ObjectMeta{
				Name:              "build1-1-abc",
				Labels:            map[string]string{buildapi.BuildConfigLabel: "build1"},
				CreationTimestamp: util.NewTime(now.Add(-10 * time.Second)),
			},
			Status: buildapi.BuildStatusFailed,
		},
		{
			ObjectMeta: kapi.ObjectMeta{
				Name:              "build1-2-abc",
				Labels:            map[string]string{buildapi.BuildConfigLabel: "build1"},
				CreationTimestamp: util.NewTime(now.Add(-5 * time.Second)),
			},
			Status: buildapi.BuildStatusComplete,
		},
		{
			ObjectMeta: kapi.ObjectMeta{
				Name:              "build1-3-abc",
				Labels:            map[string]string{buildapi.BuildConfigLabel: "build1"},
				CreationTimestamp: util.NewTime(now.Add(-15 * time.Second)),
			},
			Status: buildapi.BuildStatusPending,
		},
	}

	bc1Node := buildgraph.EnsureBuildConfigNode(g, &buildapi.BuildConfig{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "build1"},
		Triggers: []buildapi.BuildTriggerPolicy{
			{
				ImageChange: &buildapi.ImageChangeTrigger{},
			},
		},
		Parameters: buildapi.BuildParameters{
			Strategy: buildapi.BuildStrategy{
				Type: buildapi.SourceBuildStrategyType,
				SourceStrategy: &buildapi.SourceBuildStrategy{
					From: kapi.ObjectReference{Kind: "ImageStreamTag", Name: "test:base-image"},
				},
			},
			Output: buildapi.BuildOutput{
				To:  &kapi.ObjectReference{Name: "other"},
				Tag: "tag1",
			},
		},
	})
	buildedges.JoinBuilds(bc1Node, builds)
	bcTestNode := buildgraph.EnsureBuildConfigNode(g, &buildapi.BuildConfig{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "test"},
		Parameters: buildapi.BuildParameters{
			Output: buildapi.BuildOutput{
				To:  &kapi.ObjectReference{Name: "other"},
				Tag: "base-image",
			},
		},
	})
	buildgraph.EnsureBuildConfigNode(g, &buildapi.BuildConfig{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "build2"},
		Parameters: buildapi.BuildParameters{
			Output: buildapi.BuildOutput{
				DockerImageReference: "mycustom/repo/image",
				Tag:                  "tag2",
			},
		},
	})
	kubegraph.EnsureServiceNode(g, &kapi.Service{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "svc-is-ignored"},
		Spec: kapi.ServiceSpec{
			Selector: nil,
		},
	})
	kubegraph.EnsureServiceNode(g, &kapi.Service{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "svc1"},
		Spec: kapi.ServiceSpec{
			Selector: map[string]string{
				"deploymentconfig": "deploy1",
			},
		},
	})
	kubegraph.EnsureServiceNode(g, &kapi.Service{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "svc2"},
		Spec: kapi.ServiceSpec{
			Selector: map[string]string{
				"deploymentconfig": "deploy1",
				"env":              "prod",
			},
		},
	})
	deploygraph.EnsureDeploymentConfigNode(g, &deployapi.DeploymentConfig{
		ObjectMeta: kapi.ObjectMeta{Namespace: "other", Name: "deploy1"},
		Triggers: []deployapi.DeploymentTriggerPolicy{
			{
				ImageChangeParams: &deployapi.DeploymentTriggerImageChangeParams{
					From:           kapi.ObjectReference{Namespace: "default", Name: "other"},
					ContainerNames: []string{"1", "2"},
					Tag:            "tag1",
				},
			},
		},
		Template: deployapi.DeploymentTemplate{
			ControllerTemplate: kapi.ReplicationControllerSpec{
				Template: &kapi.PodTemplateSpec{
					ObjectMeta: kapi.ObjectMeta{
						Labels: map[string]string{
							"deploymentconfig": "deploy1",
							"env":              "prod",
						},
					},
					Spec: kapi.PodSpec{
						Containers: []kapi.Container{
							{
								Name:  "1",
								Image: "mycustom/repo/image",
							},
							{
								Name:  "2",
								Image: "mycustom/repo/image2",
							},
							{
								Name:  "3",
								Image: "mycustom/repo/image3",
							},
						},
					},
				},
			},
		},
	})
	deploygraph.EnsureDeploymentConfigNode(g, &deployapi.DeploymentConfig{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "deploy2"},
		Template: deployapi.DeploymentTemplate{
			ControllerTemplate: kapi.ReplicationControllerSpec{
				Template: &kapi.PodTemplateSpec{
					ObjectMeta: kapi.ObjectMeta{
						Labels: map[string]string{
							"deploymentconfig": "deploy2",
							"env":              "dev",
						},
					},
					Spec: kapi.PodSpec{
						Containers: []kapi.Container{
							{
								Name:  "1",
								Image: "someother/image:v1",
							},
						},
					},
				},
			},
		},
	})

	kubeedges.AddAllExposedPodTemplateSpecEdges(g)
	buildedges.AddAllInputOutputEdges(g)
	deployedges.AddAllTriggerEdges(g)

	t.Log(g)

	ir, dc, bc, other := 0, 0, 0, 0
	for _, node := range g.NodeList() {
		switch g.Object(node).(type) {
		case *deployapi.DeploymentConfig:
			if g.Kind(node) != deploygraph.DeploymentConfigNodeKind {
				t.Fatalf("unexpected kind: %v", g.Kind(node))
			}
			dc++
		case *buildapi.BuildConfig:
			if g.Kind(node) != buildgraph.BuildConfigNodeKind {
				t.Fatalf("unexpected kind: %v", g.Kind(node))
			}
			bc++
		case *imageapi.ImageStream:
			// TODO resolve this check for 2 kinds, since both have the same object type
			if g.Kind(node) != imagegraph.ImageStreamNodeKind && g.Kind(node) != imagegraph.ImageStreamTagNodeKind {
				t.Fatalf("unexpected kind: %v", g.Kind(node))
			}
			ir++
		default:
			other++
		}
	}

	if dc != 2 || bc != 3 || ir != 3 || other != 12 {
		t.Errorf("unexpected nodes: %d %d %d %d", dc, bc, ir, other)
	}
	for _, edge := range g.EdgeList() {
		if g.EdgeKind(edge) == osgraph.UnknownEdgeKind {
			t.Errorf("edge reported unknown kind: %#v", edge)
		}
	}

	// imagestreamtag default/other:base-image
	istID := 0
	for _, node := range g.NodeList() {
		if g.Name(node) == "<imagestreamtag default/other:base-image>" {
			istID = node.ID()
			break
		}
	}

	edge := g.EdgeBetween(concrete.Node(bcTestNode.ID()), concrete.Node(istID))
	if edge == nil {
		t.Fatalf("failed to find edge between %d and %d", bcTestNode.ID(), istID)
	}
	if len(g.SubgraphWithNodes([]graph.Node{edge.Head(), edge.Tail()}, osgraph.ExistingDirectEdge).EdgeList()) != 1 {
		t.Fatalf("expected one edge")
	}
	if len(g.SubgraphWithNodes([]graph.Node{edge.Tail(), edge.Head()}, osgraph.ExistingDirectEdge).EdgeList()) != 1 {
		t.Fatalf("expected one edge")
	}

	if e := g.EdgeBetween(concrete.Node(bcTestNode.ID()), concrete.Node(istID)); e == nil {
		t.Errorf("expected edge for %d-%d", bcTestNode.ID(), istID)
	}
	if e := g.EdgeBetween(concrete.Node(istID), concrete.Node(bcTestNode.ID())); e == nil {
		t.Errorf("expected edge for %d-%d", bcTestNode.ID(), istID)
	}

	pipelines, covered := DeploymentPipelines(g)
	if len(pipelines) != 2 {
		t.Fatalf("unexpected pipelines: %#v", pipelines)
	}
	if len(covered) != 7 {
		t.Fatalf("unexpected covered nodes: %#v", covered)
	}
	for from, images := range pipelines {
		t.Logf("from %s", from.Name)
		for _, path := range images {
			t.Logf("  %v", path)
		}
	}

	serviceGroups := ServiceAndDeploymentGroups(g)
	if len(serviceGroups) != 5 {
		t.Errorf("unexpected service groups: %#v", serviceGroups)
	}
	if len(serviceGroups[3].Builds) != 1 {
		t.Fatalf("unexpected final group: %#v", serviceGroups[2])
	}
	for _, group := range serviceGroups {
		dcs := len(group.Deployments)
		svcs := len(group.Services)
		for _, svc := range group.Services {
			t.Logf("service %s", svc.Service.Name)
		}
		indent := ""
		if svcs > 0 {
			indent = "  "
		}
		for _, deployment := range group.Deployments {
			t.Logf("%sdeployment %s", indent, deployment.Deployment.Name)
			for _, image := range deployment.Images {
				t.Logf("%s  image %s", indent, image.Image.ImageSpec())
				if image.Build != nil {
					if image.Build.LastSuccessfulBuild != nil {
						t.Logf("%s    built at %s", indent, image.Build.LastSuccessfulBuild.CreationTimestamp)
					} else if image.Build.LastUnsuccessfulBuild != nil {
						t.Logf("%s    build %s at %s", indent, image.Build.LastUnsuccessfulBuild.Status, image.Build.LastSuccessfulBuild.CreationTimestamp)
					}
					for _, b := range image.Build.ActiveBuilds {
						t.Logf("%s    build %s %s", indent, b.Name, b.Status)
					}
				}
			}
		}
		if dcs != 0 || svcs != 0 {
			continue
		}
		for _, build := range group.Builds {
			if build.Image != nil {
				if build.Build != nil {
					t.Logf("%s <- build %s (%d)", build.Image.ImageSpec(), build.Build.Name, build.Image.ID())
				} else {
					t.Logf("%s (%d)", build.Image.ImageSpec(), build.Image.ID())
				}
			} else {
				t.Logf("build %s (%d)", build.Build.Name, build.Build.ID())
				t.Errorf("expected build %d to have an image edge", build.Build.ID())
			}
		}
	}
}
Example #27
0
// Describe returns the description of a project
func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error) {
	project, err := d.C.Projects().Get(namespace)
	if err != nil {
		return "", err
	}

	svcs, err := d.K.Services(namespace).List(labels.Everything())
	if err != nil {
		return "", err
	}

	bcs, err := d.C.BuildConfigs(namespace).List(labels.Everything(), fields.Everything())
	if err != nil {
		return "", err
	}

	dcs, err := d.C.DeploymentConfigs(namespace).List(labels.Everything(), fields.Everything())
	if err != nil {
		return "", err
	}

	builds := &buildapi.BuildList{}
	if len(bcs.Items) > 0 {
		if b, err := d.C.Builds(namespace).List(labels.Everything(), fields.Everything()); err == nil {
			builds = b
		}
	}

	rcs, err := d.K.ReplicationControllers(namespace).List(labels.Everything())
	if err != nil {
		rcs = &kapi.ReplicationControllerList{}
	}

	g := graph.New()
	for i := range bcs.Items {
		build := buildgraph.EnsureBuildConfigNode(g, &bcs.Items[i])
		buildedges.AddInputOutputEdges(g, build)
		buildedges.JoinBuilds(build, builds.Items)
	}
	for i := range dcs.Items {
		deploy := deploygraph.EnsureDeploymentConfigNode(g, &dcs.Items[i])
		deployedges.AddTriggerEdges(g, deploy)
		deployedges.JoinDeployments(deploy, rcs.Items)
	}
	for i := range svcs.Items {
		service := kubegraph.EnsureServiceNode(g, &svcs.Items[i])
		kubeedges.AddExposedPodTemplateSpecEdges(g, service)
	}
	groups := graphveneers.ServiceAndDeploymentGroups(g)

	return tabbedString(func(out *tabwriter.Writer) error {
		indent := "  "
		fmt.Fprintf(out, "In project %s\n", projectapi.DisplayNameAndNameForProject(project))

		for _, group := range groups {
			if len(group.Builds) != 0 {
				for _, build := range group.Builds {
					fmt.Fprintln(out)
					printLines(out, indent, 0, describeStandaloneBuildGroup(build, namespace)...)
					printLines(out, indent, 1, describeAdditionalBuildDetail(build.Build, true)...)
				}
				continue
			}
			if len(group.Services) == 0 {
				for _, deploy := range group.Deployments {
					fmt.Fprintln(out)
					printLines(out, indent, 0, describeDeploymentInServiceGroup(deploy)...)
				}
				continue
			}
			fmt.Fprintln(out)
			for _, svc := range group.Services {
				printLines(out, indent, 0, describeServiceInServiceGroup(svc)...)
			}
			for _, deploy := range group.Deployments {
				printLines(out, indent, 1, describeDeploymentInServiceGroup(deploy)...)
			}
		}

		if len(groups) == 0 {
			fmt.Fprintln(out, "\nYou have no Services, DeploymentConfigs, or BuildConfigs. 'oc new-app' can be used to create applications from scratch from existing Docker images and templates.")
		} else {
			fmt.Fprintln(out, "\nTo see more information about a Service or DeploymentConfig, use 'oc describe service <name>' or 'oc describe dc <name>'.")
			fmt.Fprintln(out, "You can use 'oc get all' to see lists of each of the types described above.")
		}

		return nil
	})
}
func TestGraph(t *testing.T) {
	g := osgraph.New()
	now := time.Now()
	builds := []buildapi.Build{
		{
			ObjectMeta: kapi.ObjectMeta{
				Name:              "build1-1-abc",
				Labels:            map[string]string{buildapi.BuildConfigLabel: "build1"},
				CreationTimestamp: util.NewTime(now.Add(-10 * time.Second)),
			},
			Status: buildapi.BuildStatus{
				Phase: buildapi.BuildPhaseFailed,
			},
		},
		{
			ObjectMeta: kapi.ObjectMeta{
				Name:              "build1-2-abc",
				Labels:            map[string]string{buildapi.BuildConfigLabel: "build1"},
				CreationTimestamp: util.NewTime(now.Add(-5 * time.Second)),
			},
			Status: buildapi.BuildStatus{
				Phase: buildapi.BuildPhaseComplete,
			},
		},
		{
			ObjectMeta: kapi.ObjectMeta{
				Name:              "build1-3-abc",
				Labels:            map[string]string{buildapi.BuildConfigLabel: "build1"},
				CreationTimestamp: util.NewTime(now.Add(-15 * time.Second)),
			},
			Status: buildapi.BuildStatus{
				Phase: buildapi.BuildPhasePending,
			},
		},
	}
	for i := range builds {
		buildgraph.EnsureBuildNode(g, &builds[i])
	}

	buildgraph.EnsureBuildConfigNode(g, &buildapi.BuildConfig{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "build1"},
		Spec: buildapi.BuildConfigSpec{
			Triggers: []buildapi.BuildTriggerPolicy{
				{
					ImageChange: &buildapi.ImageChangeTrigger{},
				},
			},
			BuildSpec: buildapi.BuildSpec{
				Strategy: buildapi.BuildStrategy{
					Type: buildapi.SourceBuildStrategyType,
					SourceStrategy: &buildapi.SourceBuildStrategy{
						From: kapi.ObjectReference{Kind: "ImageStreamTag", Name: "test:base-image"},
					},
				},
				Output: buildapi.BuildOutput{
					To: &kapi.ObjectReference{Kind: "ImageStreamTag", Name: "other:tag1"},
				},
			},
		},
	})
	bcTestNode := buildgraph.EnsureBuildConfigNode(g, &buildapi.BuildConfig{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "test"},
		Spec: buildapi.BuildConfigSpec{
			BuildSpec: buildapi.BuildSpec{
				Output: buildapi.BuildOutput{
					To: &kapi.ObjectReference{Kind: "ImageStreamTag", Name: "other:base-image"},
				},
			},
		},
	})
	buildgraph.EnsureBuildConfigNode(g, &buildapi.BuildConfig{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "build2"},
		Spec: buildapi.BuildConfigSpec{
			BuildSpec: buildapi.BuildSpec{
				Output: buildapi.BuildOutput{
					To: &kapi.ObjectReference{Kind: "DockerImage", Name: "mycustom/repo/image:tag2"},
				},
			},
		},
	})
	kubegraph.EnsureServiceNode(g, &kapi.Service{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "svc-is-ignored"},
		Spec: kapi.ServiceSpec{
			Selector: nil,
		},
	})
	kubegraph.EnsureServiceNode(g, &kapi.Service{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "svc1"},
		Spec: kapi.ServiceSpec{
			Selector: map[string]string{
				"deploymentconfig": "deploy1",
			},
		},
	})
	kubegraph.EnsureServiceNode(g, &kapi.Service{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "svc2"},
		Spec: kapi.ServiceSpec{
			Selector: map[string]string{
				"deploymentconfig": "deploy1",
				"env":              "prod",
			},
		},
	})
	deploygraph.EnsureDeploymentConfigNode(g, &deployapi.DeploymentConfig{
		ObjectMeta: kapi.ObjectMeta{Namespace: "other", Name: "deploy1"},
		Triggers: []deployapi.DeploymentTriggerPolicy{
			{
				ImageChangeParams: &deployapi.DeploymentTriggerImageChangeParams{
					From:           kapi.ObjectReference{Namespace: "default", Name: "other"},
					ContainerNames: []string{"1", "2"},
					Tag:            "tag1",
				},
			},
		},
		Template: deployapi.DeploymentTemplate{
			ControllerTemplate: kapi.ReplicationControllerSpec{
				Template: &kapi.PodTemplateSpec{
					ObjectMeta: kapi.ObjectMeta{
						Labels: map[string]string{
							"deploymentconfig": "deploy1",
							"env":              "prod",
						},
					},
					Spec: kapi.PodSpec{
						Containers: []kapi.Container{
							{
								Name:  "1",
								Image: "mycustom/repo/image",
							},
							{
								Name:  "2",
								Image: "mycustom/repo/image2",
							},
							{
								Name:  "3",
								Image: "mycustom/repo/image3",
							},
						},
					},
				},
			},
		},
	})
	deploygraph.EnsureDeploymentConfigNode(g, &deployapi.DeploymentConfig{
		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "deploy2"},
		Template: deployapi.DeploymentTemplate{
			ControllerTemplate: kapi.ReplicationControllerSpec{
				Template: &kapi.PodTemplateSpec{
					ObjectMeta: kapi.ObjectMeta{
						Labels: map[string]string{
							"deploymentconfig": "deploy2",
							"env":              "dev",
						},
					},
					Spec: kapi.PodSpec{
						Containers: []kapi.Container{
							{
								Name:  "1",
								Image: "someother/image:v1",
							},
						},
					},
				},
			},
		},
	})

	kubeedges.AddAllExposedPodTemplateSpecEdges(g)
	buildedges.AddAllInputOutputEdges(g)
	buildedges.AddAllBuildEdges(g)
	deployedges.AddAllTriggerEdges(g)
	deployedges.AddAllDeploymentEdges(g)

	t.Log(g)

	for _, edge := range g.Edges() {
		if g.EdgeKinds(edge).Has(osgraph.UnknownEdgeKind) {
			t.Errorf("edge reported unknown kind: %#v", edge)
		}
	}

	// imagestreamtag default/other:base-image
	istID := 0
	for _, node := range g.Nodes() {
		if g.Name(node) == "ImageStreamTag|default/other:base-image" {
			istID = node.ID()
			break
		}
	}

	edge := g.Edge(concrete.Node(bcTestNode.ID()), concrete.Node(istID))
	if edge == nil {
		t.Fatalf("failed to find edge between %d and %d", bcTestNode.ID(), istID)
	}
	if len(g.SubgraphWithNodes([]graph.Node{edge.From(), edge.To()}, osgraph.ExistingDirectEdge).Edges()) != 1 {
		t.Fatalf("expected one edge")
	}
	if len(g.SubgraphWithNodes([]graph.Node{edge.To(), edge.From()}, osgraph.ExistingDirectEdge).Edges()) != 1 {
		t.Fatalf("expected one edge")
	}

	if e := g.Edge(concrete.Node(bcTestNode.ID()), concrete.Node(istID)); e == nil {
		t.Errorf("expected edge for %d-%d", bcTestNode.ID(), istID)
	}

	coveredNodes := IntSet{}

	serviceGroups, coveredByServiceGroups := AllServiceGroups(g, coveredNodes)
	coveredNodes.Insert(coveredByServiceGroups.List()...)

	bareDCPipelines, coveredByDCs := AllDeploymentConfigPipelines(g, coveredNodes)
	coveredNodes.Insert(coveredByDCs.List()...)

	if len(bareDCPipelines) != 1 {
		t.Fatalf("unexpected pipelines: %#v", bareDCPipelines)
	}
	if len(coveredNodes) != 10 {
		t.Fatalf("unexpected covered nodes: %#v", coveredNodes)
	}

	for _, bareDCPipeline := range bareDCPipelines {
		t.Logf("from %s", bareDCPipeline.Deployment.Name)
		for _, path := range bareDCPipeline.Images {
			t.Logf("  %v", path)
		}
	}

	if len(serviceGroups) != 3 {
		t.Errorf("unexpected service groups: %#v", serviceGroups)
	}
	for _, serviceGroup := range serviceGroups {
		t.Logf("service %s", serviceGroup.Service.Name)
		indent := "  "

		for _, deployment := range serviceGroup.DeploymentConfigPipelines {
			t.Logf("%sdeployment %s", indent, deployment.Deployment.Name)
			for _, image := range deployment.Images {
				t.Logf("%s  image %s", indent, image.Image.ImageSpec())
				if image.Build != nil {
					if image.LastSuccessfulBuild != nil {
						t.Logf("%s    built at %s", indent, image.LastSuccessfulBuild.Build.CreationTimestamp)
					} else if image.LastUnsuccessfulBuild != nil {
						t.Logf("%s    build %s at %s", indent, image.LastUnsuccessfulBuild.Build.Status, image.LastUnsuccessfulBuild.Build.CreationTimestamp)
					}
					for _, b := range image.ActiveBuilds {
						t.Logf("%s    build %s %s", indent, b.Build.Name, b.Build.Status)
					}
				}
			}
		}
	}
}