// Describe returns the description of a project func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error) { g, err := d.MakeGraph(namespace) if err != nil { return "", err } project, err := d.C.Projects().Get(namespace) if err != nil { return "", err } coveredNodes := graphview.IntSet{} services, coveredByServices := graphview.AllServiceGroups(g, coveredNodes) coveredNodes.Insert(coveredByServices.List()...) standaloneDCs, coveredByDCs := graphview.AllDeploymentConfigPipelines(g, coveredNodes) coveredNodes.Insert(coveredByDCs.List()...) standaloneBCs, coveredByBCs := graphview.AllImagePipelinesFromBuildConfig(g, coveredNodes) coveredNodes.Insert(coveredByBCs.List()...) return tabbedString(func(out *tabwriter.Writer) error { indent := " " fmt.Fprintf(out, "In project %s\n", projectapi.DisplayNameAndNameForProject(project)) for _, service := range services { fmt.Fprintln(out) printLines(out, indent, 0, describeServiceInServiceGroup(service)...) for _, dcPipeline := range service.DeploymentConfigPipelines { printLines(out, indent, 1, describeDeploymentInServiceGroup(dcPipeline)...) } } for _, standaloneDC := range standaloneDCs { fmt.Fprintln(out) printLines(out, indent, 0, describeDeploymentInServiceGroup(standaloneDC)...) } for _, standaloneBC := range standaloneBCs { fmt.Fprintln(out) printLines(out, indent, 0, describeStandaloneBuildGroup(standaloneBC, namespace)...) printLines(out, indent, 1, describeAdditionalBuildDetail(standaloneBC.Build, true)...) } if (len(services) == 0) && (len(standaloneDCs) == 0) && (len(standaloneBCs) == 0) { fmt.Fprintln(out) fmt.Fprintln(out, "You have no services, deployment configs, or build configs.") fmt.Fprintln(out, "Run 'oc new-app' to create an application.") } else { fmt.Fprintln(out) fmt.Fprintln(out, "To see more, use 'oc describe service <name>' or 'oc describe dc <name>'.") fmt.Fprintln(out, "You can use 'oc get all' to see a list of other objects.") } return nil }) }
// 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 }
// Describe returns the description of a project func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error) { var f formatter = namespacedFormatter{} g, forbiddenResources, err := d.MakeGraph(namespace) if err != nil { return "", err } allNamespaces := namespace == kapi.NamespaceAll var project *projectapi.Project if !allNamespaces { p, err := d.C.Projects().Get(namespace) if err != nil { return "", err } project = p f = namespacedFormatter{currentNamespace: namespace} } coveredNodes := graphview.IntSet{} services, coveredByServices := graphview.AllServiceGroups(g, coveredNodes) coveredNodes.Insert(coveredByServices.List()...) standaloneDCs, coveredByDCs := graphview.AllDeploymentConfigPipelines(g, coveredNodes) coveredNodes.Insert(coveredByDCs.List()...) standaloneRCs, coveredByRCs := graphview.AllReplicationControllers(g, coveredNodes) coveredNodes.Insert(coveredByRCs.List()...) standaloneImages, coveredByImages := graphview.AllImagePipelinesFromBuildConfig(g, coveredNodes) coveredNodes.Insert(coveredByImages.List()...) standalonePods, coveredByPods := graphview.AllPods(g, coveredNodes) coveredNodes.Insert(coveredByPods.List()...) return tabbedString(func(out *tabwriter.Writer) error { indent := " " if allNamespaces { fmt.Fprintf(out, describeAllProjectsOnServer(f, d.Server)) } else { fmt.Fprintf(out, describeProjectAndServer(f, project, d.Server)) } for _, service := range services { if !service.Service.Found() { continue } local := namespacedFormatter{currentNamespace: service.Service.Namespace} var exposes []string for _, routeNode := range service.ExposingRoutes { exposes = append(exposes, describeRouteInServiceGroup(local, routeNode)...) } sort.Sort(exposedRoutes(exposes)) fmt.Fprintln(out) printLines(out, "", 0, describeServiceInServiceGroup(f, service, exposes...)...) for _, dcPipeline := range service.DeploymentConfigPipelines { printLines(out, indent, 1, describeDeploymentInServiceGroup(local, dcPipeline)...) } rcNode: for _, rcNode := range service.FulfillingRCs { for _, coveredDC := range service.FulfillingDCs { if deployedges.BelongsToDeploymentConfig(coveredDC.DeploymentConfig, rcNode.ReplicationController) { continue rcNode } } printLines(out, indent, 1, describeRCInServiceGroup(local, rcNode)...) } pod: for _, podNode := range service.FulfillingPods { // skip pods that have been displayed in a roll-up of RCs and DCs (by implicit usage of RCs) for _, coveredRC := range service.FulfillingRCs { if g.Edge(podNode, coveredRC) != nil { continue pod } } printLines(out, indent, 1, describePodInServiceGroup(local, podNode)...) } } for _, standaloneDC := range standaloneDCs { fmt.Fprintln(out) printLines(out, indent, 0, describeDeploymentInServiceGroup(f, standaloneDC)...) } for _, standaloneImage := range standaloneImages { fmt.Fprintln(out) lines := describeStandaloneBuildGroup(f, standaloneImage, namespace) lines = append(lines, describeAdditionalBuildDetail(standaloneImage.Build, standaloneImage.LastSuccessfulBuild, standaloneImage.LastUnsuccessfulBuild, standaloneImage.ActiveBuilds, standaloneImage.DestinationResolved, true)...) printLines(out, indent, 0, lines...) } for _, standaloneRC := range standaloneRCs { fmt.Fprintln(out) printLines(out, indent, 0, describeRCInServiceGroup(f, standaloneRC.RC)...) } monopods, err := filterBoringPods(standalonePods) if err != nil { return err } for _, monopod := range monopods { fmt.Fprintln(out) printLines(out, indent, 0, describeMonopod(f, monopod.Pod)...) } allMarkers := osgraph.Markers{} allMarkers = append(allMarkers, createForbiddenMarkers(forbiddenResources)...) for _, scanner := range getMarkerScanners(d.LogsCommandName, d.SecurityPolicyCommandFormat, d.SetProbeCommandName) { allMarkers = append(allMarkers, scanner(g, f)...) } // TODO: Provide an option to chase these hidden markers. allMarkers = allMarkers.FilterByNamespace(namespace) fmt.Fprintln(out) sort.Stable(osgraph.ByKey(allMarkers)) sort.Stable(osgraph.ByNodeID(allMarkers)) errorMarkers := allMarkers.BySeverity(osgraph.ErrorSeverity) errorSuggestions := 0 if len(errorMarkers) > 0 { fmt.Fprintln(out, "Errors:") for _, marker := range errorMarkers { fmt.Fprintln(out, indent+"* "+marker.Message) if len(marker.Suggestion) > 0 { errorSuggestions++ if d.Suggest { switch s := marker.Suggestion.String(); { case strings.Contains(s, "\n"): fmt.Fprintln(out) for _, line := range strings.Split(s, "\n") { fmt.Fprintln(out, indent+" "+line) } case len(s) > 0: fmt.Fprintln(out, indent+" try: "+s) } } } } } warningMarkers := allMarkers.BySeverity(osgraph.WarningSeverity) if len(warningMarkers) > 0 { if d.Suggest { fmt.Fprintln(out, "Warnings:") } for _, marker := range warningMarkers { if d.Suggest { fmt.Fprintln(out, indent+"* "+marker.Message) switch s := marker.Suggestion.String(); { case strings.Contains(s, "\n"): fmt.Fprintln(out) for _, line := range strings.Split(s, "\n") { fmt.Fprintln(out, indent+" "+line) } case len(s) > 0: fmt.Fprintln(out, indent+" try: "+s) } } } } // We print errors by default and warnings if -v is used. If we get none, // this would be an extra new line. if len(errorMarkers) != 0 || (d.Suggest && len(warningMarkers) != 0) { fmt.Fprintln(out) } errors, warnings := "", "" if len(errorMarkers) == 1 { errors = "1 error" } else if len(errorMarkers) > 1 { errors = fmt.Sprintf("%d errors", len(errorMarkers)) } if len(warningMarkers) == 1 { warnings = "1 warning" } else if len(warningMarkers) > 1 { warnings = fmt.Sprintf("%d warnings", len(warningMarkers)) } switch { case !d.Suggest && len(errorMarkers) > 0 && len(warningMarkers) > 0: fmt.Fprintf(out, "%s and %s identified, use 'oc status -v' to see details.\n", errors, warnings) case !d.Suggest && len(errorMarkers) > 0 && errorSuggestions > 0: fmt.Fprintf(out, "%s identified, use 'oc status -v' to see details.\n", errors) case !d.Suggest && len(warningMarkers) > 0: fmt.Fprintf(out, "%s identified, use 'oc status -v' to see details.\n", warnings) case (len(services) == 0) && (len(standaloneDCs) == 0) && (len(standaloneImages) == 0): fmt.Fprintln(out, "You have no services, deployment configs, or build configs.") fmt.Fprintln(out, "Run 'oc new-app' to create an application.") default: fmt.Fprintln(out, "View details with 'oc describe <resource>/<name>' or list everything with 'oc get all'.") } return nil }) }
// Describe returns the description of a project func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error) { g, err := d.MakeGraph(namespace) if err != nil { return "", err } project, err := d.C.Projects().Get(namespace) if err != nil { return "", err } coveredNodes := graphview.IntSet{} services, coveredByServices := graphview.AllServiceGroups(g, coveredNodes) coveredNodes.Insert(coveredByServices.List()...) standaloneDCs, coveredByDCs := graphview.AllDeploymentConfigPipelines(g, coveredNodes) coveredNodes.Insert(coveredByDCs.List()...) standaloneRCs, coveredByRCs := graphview.AllReplicationControllers(g, coveredNodes) coveredNodes.Insert(coveredByRCs.List()...) standaloneImages, coveredByImages := graphview.AllImagePipelinesFromBuildConfig(g, coveredNodes) coveredNodes.Insert(coveredByImages.List()...) return tabbedString(func(out *tabwriter.Writer) error { indent := " " fmt.Fprintf(out, "In project %s\n", projectapi.DisplayNameAndNameForProject(project)) for _, service := range services { fmt.Fprintln(out) printLines(out, indent, 0, describeServiceInServiceGroup(service)...) for _, dcPipeline := range service.DeploymentConfigPipelines { printLines(out, indent, 1, describeDeploymentInServiceGroup(dcPipeline)...) } rcNode: for _, rcNode := range service.FulfillingRCs { for _, coveredDC := range service.FulfillingDCs { if deployedges.BelongsToDeploymentConfig(coveredDC.DeploymentConfig, rcNode.ReplicationController) { continue rcNode } } printLines(out, indent, 1, describeRCInServiceGroup(rcNode)...) } pod: for _, podNode := range service.FulfillingPods { // skip pods that have been displayed in a roll-up of RCs and DCs (by implicit usage of RCs) for _, coveredRC := range service.FulfillingRCs { if g.Edge(podNode, coveredRC) != nil { continue pod } } printLines(out, indent, 1, describePodInServiceGroup(podNode)...) } } for _, standaloneDC := range standaloneDCs { fmt.Fprintln(out) printLines(out, indent, 0, describeDeploymentInServiceGroup(standaloneDC)...) } for _, standaloneImage := range standaloneImages { fmt.Fprintln(out) printLines(out, indent, 0, describeStandaloneBuildGroup(standaloneImage, namespace)...) printLines(out, indent, 1, describeAdditionalBuildDetail(standaloneImage.Build, standaloneImage.LastSuccessfulBuild, standaloneImage.LastUnsuccessfulBuild, standaloneImage.ActiveBuilds, standaloneImage.DestinationResolved, true)...) } for _, standaloneRC := range standaloneRCs { fmt.Fprintln(out) printLines(out, indent, 0, describeRCInServiceGroup(standaloneRC.RC)...) } // always output warnings fmt.Fprintln(out) allMarkers := osgraph.Markers{} for _, scanner := range getMarkerScanners() { allMarkers = append(allMarkers, scanner(g)...) } sort.Stable(osgraph.ByKey(allMarkers)) sort.Stable(osgraph.ByNodeID(allMarkers)) if errorMarkers := allMarkers.BySeverity(osgraph.ErrorSeverity); len(errorMarkers) > 0 { fmt.Fprintln(out, "Errors:") for _, marker := range errorMarkers { fmt.Fprintln(out, indent+marker.Message) } } if warningMarkers := allMarkers.BySeverity(osgraph.WarningSeverity); len(warningMarkers) > 0 { fmt.Fprintln(out, "Warnings:") for _, marker := range warningMarkers { fmt.Fprintln(out, indent+marker.Message) } } if (len(services) == 0) && (len(standaloneDCs) == 0) && (len(standaloneImages) == 0) { fmt.Fprintln(out, "You have no services, deployment configs, or build configs.") fmt.Fprintln(out, "Run 'oc new-app' to create an application.") } else { fmt.Fprintln(out, "To see more, use 'oc describe service <name>' or 'oc describe dc <name>'.") fmt.Fprintln(out, "You can use 'oc get all' to see a list of other objects.") } return nil }) }
// Describe returns the description of a project func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error) { g, err := d.MakeGraph(namespace) if err != nil { return "", err } project, err := d.C.Projects().Get(namespace) if err != nil { return "", err } coveredNodes := graphview.IntSet{} services, coveredByServices := graphview.AllServiceGroups(g, coveredNodes) coveredNodes.Insert(coveredByServices.List()...) standaloneDCs, coveredByDCs := graphview.AllDeploymentConfigPipelines(g, coveredNodes) coveredNodes.Insert(coveredByDCs.List()...) standaloneRCs, coveredByRCs := graphview.AllReplicationControllers(g, coveredNodes) coveredNodes.Insert(coveredByRCs.List()...) standaloneImages, coveredByImages := graphview.AllImagePipelinesFromBuildConfig(g, coveredNodes) coveredNodes.Insert(coveredByImages.List()...) return tabbedString(func(out *tabwriter.Writer) error { indent := " " fmt.Fprintf(out, "In project %s\n", projectapi.DisplayNameAndNameForProject(project)) for _, service := range services { fmt.Fprintln(out) printLines(out, indent, 0, describeServiceInServiceGroup(service)...) for _, dcPipeline := range service.DeploymentConfigPipelines { printLines(out, indent, 1, describeDeploymentInServiceGroup(dcPipeline)...) } rcNode: for _, rcNode := range service.FulfillingRCs { for _, coveredDC := range service.FulfillingDCs { if deployedges.BelongsToDeploymentConfig(coveredDC.DeploymentConfig, rcNode.ReplicationController) { continue rcNode } } printLines(out, indent, 1, describeRCInServiceGroup(rcNode)...) } pod: for _, podNode := range service.FulfillingPods { // skip pods that have been displayed in a roll-up of RCs and DCs (by implicit usage of RCs) for _, coveredRC := range service.FulfillingRCs { if g.EdgeBetween(podNode, coveredRC) != nil { continue pod } } printLines(out, indent, 1, describePodInServiceGroup(podNode)...) } } for _, standaloneDC := range standaloneDCs { fmt.Fprintln(out) printLines(out, indent, 0, describeDeploymentInServiceGroup(standaloneDC)...) } for _, standaloneImage := range standaloneImages { fmt.Fprintln(out) printLines(out, indent, 0, describeStandaloneBuildGroup(standaloneImage, namespace)...) printLines(out, indent, 1, describeAdditionalBuildDetail(standaloneImage.Build, standaloneImage.LastSuccessfulBuild, standaloneImage.LastUnsuccessfulBuild, standaloneImage.ActiveBuilds, standaloneImage.DestinationResolved, true)...) } for _, standaloneRC := range standaloneRCs { fmt.Fprintln(out) printLines(out, indent, 0, describeRCInServiceGroup(standaloneRC.RC)...) } if (len(services) == 0) && (len(standaloneDCs) == 0) && (len(standaloneImages) == 0) { fmt.Fprintln(out) fmt.Fprintln(out, "You have no services, deployment configs, or build configs.") fmt.Fprintln(out, "Run 'oc new-app' to create an application.") } else { fmt.Fprintln(out) if hasUnresolvedImageStreamTag(g) { fmt.Fprintln(out, "Warning: Some of your builds are pointing to image streams, but the administrator has not configured the integrated Docker registry (oadm registry).") } if lines, _ := describeBadPodSpecs(out, g); len(lines) > 0 { fmt.Fprintln(out, strings.Join(lines, "\n")) } fmt.Fprintln(out, "To see more, use 'oc describe service <name>' or 'oc describe dc <name>'.") fmt.Fprintln(out, "You can use 'oc get all' to see a list of other objects.") } return nil }) }
// Describe returns the description of a project func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error) { g, forbiddenResources, err := d.MakeGraph(namespace) if err != nil { return "", err } project, err := d.C.Projects().Get(namespace) if err != nil { return "", err } coveredNodes := graphview.IntSet{} services, coveredByServices := graphview.AllServiceGroups(g, coveredNodes) coveredNodes.Insert(coveredByServices.List()...) standaloneDCs, coveredByDCs := graphview.AllDeploymentConfigPipelines(g, coveredNodes) coveredNodes.Insert(coveredByDCs.List()...) standaloneRCs, coveredByRCs := graphview.AllReplicationControllers(g, coveredNodes) coveredNodes.Insert(coveredByRCs.List()...) standaloneImages, coveredByImages := graphview.AllImagePipelinesFromBuildConfig(g, coveredNodes) coveredNodes.Insert(coveredByImages.List()...) return tabbedString(func(out *tabwriter.Writer) error { indent := " " fmt.Fprintf(out, describeProjectAndServer(project, d.Server)) for _, service := range services { if !service.Service.Found() { continue } fmt.Fprintln(out) printLines(out, indent, 0, describeServiceInServiceGroup(service)...) for _, dcPipeline := range service.DeploymentConfigPipelines { printLines(out, indent, 1, describeDeploymentInServiceGroup(dcPipeline)...) } rcNode: for _, rcNode := range service.FulfillingRCs { for _, coveredDC := range service.FulfillingDCs { if deployedges.BelongsToDeploymentConfig(coveredDC.DeploymentConfig, rcNode.ReplicationController) { continue rcNode } } printLines(out, indent, 1, describeRCInServiceGroup(rcNode)...) } pod: for _, podNode := range service.FulfillingPods { // skip pods that have been displayed in a roll-up of RCs and DCs (by implicit usage of RCs) for _, coveredRC := range service.FulfillingRCs { if g.Edge(podNode, coveredRC) != nil { continue pod } } printLines(out, indent, 1, describePodInServiceGroup(podNode)...) } for _, routeNode := range service.ExposingRoutes { printLines(out, indent, 1, describeRouteInServiceGroup(routeNode)...) } } for _, standaloneDC := range standaloneDCs { fmt.Fprintln(out) printLines(out, indent, 0, describeDeploymentInServiceGroup(standaloneDC)...) } for _, standaloneImage := range standaloneImages { fmt.Fprintln(out) lines := describeStandaloneBuildGroup(standaloneImage, namespace) lines = append(lines, describeAdditionalBuildDetail(standaloneImage.Build, standaloneImage.LastSuccessfulBuild, standaloneImage.LastUnsuccessfulBuild, standaloneImage.ActiveBuilds, standaloneImage.DestinationResolved, true)...) printLines(out, indent, 0, lines...) } for _, standaloneRC := range standaloneRCs { fmt.Fprintln(out) printLines(out, indent, 0, describeRCInServiceGroup(standaloneRC.RC)...) } allMarkers := osgraph.Markers{} allMarkers = append(allMarkers, createForbiddenMarkers(forbiddenResources)...) for _, scanner := range getMarkerScanners() { allMarkers = append(allMarkers, scanner(g)...) } fmt.Fprintln(out) sort.Stable(osgraph.ByKey(allMarkers)) sort.Stable(osgraph.ByNodeID(allMarkers)) errorMarkers := allMarkers.BySeverity(osgraph.ErrorSeverity) errorSuggestions := 0 if len(errorMarkers) > 0 { fmt.Fprintln(out, "Errors:") for _, marker := range errorMarkers { fmt.Fprintln(out, indent+"* "+marker.Message) if len(marker.Suggestion) > 0 { errorSuggestions++ if d.Suggest { fmt.Fprintln(out, indent+" "+marker.Suggestion.String()) } } } } warningMarkers := allMarkers.BySeverity(osgraph.WarningSeverity) if len(warningMarkers) > 0 { if d.Suggest { fmt.Fprintln(out, "Warnings:") } for _, marker := range warningMarkers { if d.Suggest { fmt.Fprintln(out, indent+"* "+marker.Message) if len(marker.Suggestion) > 0 { fmt.Fprintln(out, indent+" "+marker.Suggestion.String()) } } } } // We print errors by default and warnings if -v is used. If we get none, // this would be an extra new line. if len(errorMarkers) != 0 || (d.Suggest && len(warningMarkers) != 0) { fmt.Fprintln(out) } errors, warnings := "", "" if len(errorMarkers) == 1 { errors = "1 error" } else if len(errorMarkers) > 1 { errors = fmt.Sprintf("%d errors", len(errorMarkers)) } if len(warningMarkers) == 1 { warnings = "1 warning" } else if len(warningMarkers) > 1 { warnings = fmt.Sprintf("%d warnings", len(warningMarkers)) } switch { case !d.Suggest && len(errorMarkers) > 0 && len(warningMarkers) > 0: fmt.Fprintf(out, "%s and %s identified, use 'oc status -v' to see details.\n", errors, warnings) case !d.Suggest && len(errorMarkers) > 0 && errorSuggestions > 0: fmt.Fprintf(out, "%s identified, use 'oc status -v' to see details.\n", errors) case !d.Suggest && len(warningMarkers) > 0: fmt.Fprintf(out, "%s identified, use 'oc status -v' to see details.\n", warnings) case (len(services) == 0) && (len(standaloneDCs) == 0) && (len(standaloneImages) == 0): fmt.Fprintln(out, "You have no services, deployment configs, or build configs.") fmt.Fprintln(out, "Run 'oc new-app' to create an application.") default: fmt.Fprintln(out, "View details with 'oc describe <resource>/<name>' or list everything with 'oc get all'.") } return nil }) }
// Describe returns the description of a project func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error) { g, err := d.MakeGraph(namespace) if err != nil { return "", err } project, err := d.C.Projects().Get(namespace) if err != nil { return "", err } coveredNodes := graphview.IntSet{} services, coveredByServices := graphview.AllServiceGroups(g, coveredNodes) coveredNodes.Insert(coveredByServices.List()...) standaloneDCs, coveredByDCs := graphview.AllDeploymentConfigPipelines(g, coveredNodes) coveredNodes.Insert(coveredByDCs.List()...) standaloneImages, coveredByImages := graphview.AllImagePipelinesFromBuildConfig(g, coveredNodes) coveredNodes.Insert(coveredByImages.List()...) return tabbedString(func(out *tabwriter.Writer) error { indent := " " fmt.Fprintf(out, "In project %s\n", projectapi.DisplayNameAndNameForProject(project)) for _, service := range services { fmt.Fprintln(out) printLines(out, indent, 0, describeServiceInServiceGroup(service)...) for _, dcPipeline := range service.DeploymentConfigPipelines { printLines(out, indent, 1, describeDeploymentInServiceGroup(dcPipeline)...) } } for _, standaloneDC := range standaloneDCs { fmt.Fprintln(out) printLines(out, indent, 0, describeDeploymentInServiceGroup(standaloneDC)...) } for _, standaloneImage := range standaloneImages { fmt.Fprintln(out) printLines(out, indent, 0, describeStandaloneBuildGroup(standaloneImage, namespace)...) printLines(out, indent, 1, describeAdditionalBuildDetail(standaloneImage.Build, standaloneImage.LastSuccessfulBuild, standaloneImage.LastUnsuccessfulBuild, standaloneImage.ActiveBuilds, standaloneImage.DestinationResolved, true)...) } if (len(services) == 0) && (len(standaloneDCs) == 0) && (len(standaloneImages) == 0) { fmt.Fprintln(out) fmt.Fprintln(out, "You have no services, deployment configs, or build configs.") fmt.Fprintln(out, "Run 'oc new-app' to create an application.") } else { fmt.Fprintln(out) if hasUnresolvedImageStreamTag(g) { fmt.Fprintln(out, "Warning: Some of your builds are pointing to image streams, but the administrator has not configured the integrated Docker registry (oadm registry).") } fmt.Fprintln(out, "To see more, use 'oc describe service <name>' or 'oc describe dc <name>'.") fmt.Fprintln(out, "You can use 'oc get all' to see a list of other objects.") } return nil }) }