func (l *dcLoader) AddToGraph(g osgraph.Graph) error { for i := range l.items { deploygraph.EnsureDeploymentConfigNode(g, &l.items[i]) } return nil }
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) } } }
// addDeploymentConfigsToGraph adds deployment configs to the graph. // // Edges are added to the graph from each deployment config to the images // specified by its pod spec's list of containers, as long as the image is // managed by OpenShift. func addDeploymentConfigsToGraph(g graph.Graph, dcs *deployapi.DeploymentConfigList) { for i := range dcs.Items { dc := &dcs.Items[i] glog.V(4).Infof("Examining DeploymentConfig %s/%s", dc.Namespace, dc.Name) dcNode := deploygraph.EnsureDeploymentConfigNode(g, dc) addPodSpecToGraph(g, &dc.Template.ControllerTemplate.Template.Spec, dcNode) } }
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 }
func loadDeploymentConfigs(g osgraph.Graph, graphLock sync.Mutex, namespace string, kclient kclient.Interface, client client.Interface) error { dcs, err := client.DeploymentConfigs(namespace).List(labels.Everything(), fields.Everything()) if err != nil { return err } graphLock.Lock() defer graphLock.Unlock() for i := range dcs.Items { deploygraph.EnsureDeploymentConfigNode(g, &dcs.Items[i]) } return nil }
// 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 }) }
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) } } }
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()) } } } }
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) } } } } } }
// 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 }) }