Skip to content

Commit 73597be

Browse files
committed
Add suggestions in oc status
1 parent 8f61adf commit 73597be

File tree

13 files changed

+179
-89
lines changed

13 files changed

+179
-89
lines changed

contrib/completions/bash/oc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,8 @@ _oc_status()
609609

610610
flags+=("--output=")
611611
two_word_flags+=("-o")
612+
flags+=("--verbose")
613+
flags+=("-v")
612614
flags+=("--alsologtostderr")
613615
flags+=("--api-version=")
614616
flags+=("--boot-id-file=")

contrib/completions/bash/openshift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5336,6 +5336,8 @@ _openshift_cli_status()
53365336

53375337
flags+=("--output=")
53385338
two_word_flags+=("-o")
5339+
flags+=("--verbose")
5340+
flags+=("-v")
53395341
flags+=("--alsologtostderr")
53405342
flags+=("--api-version=")
53415343
flags+=("--boot-id-file=")

docs/generated/oc_by_example_content.adoc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,8 +959,14 @@ Show an overview of the current project
959959
960960
[options="nowrap"]
961961
----
962-
# Show an overview of the current project
962+
# See an overview of the current project.
963963
$ oc status
964+
965+
# Export the overview of the current project in an svg file.
966+
$ oc status -o dot | dot -T svg -o project.svg
967+
968+
# See an overview of the current project including details for any identified issues.
969+
$ oc status -v
964970
----
965971
====
966972

pkg/api/graph/interfaces.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package graph
22

33
import (
4+
"fmt"
5+
46
"github.com/gonum/graph"
57
)
68

@@ -15,8 +17,12 @@ type Marker struct {
1517
Severity Severity
1618
// Key is a short string to identify this message
1719
Key string
20+
1821
// Message is a human-readable string that describes what is interesting
1922
Message string
23+
// Suggestion is a human-readable string that holds advice for resolving this
24+
// marker.
25+
Suggestion Suggestion
2026
}
2127

2228
// Severity indicates how important this problem is.
@@ -97,3 +103,9 @@ func (m ByKey) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
97103
func (m ByKey) Less(i, j int) bool {
98104
return m[i].Key < m[j].Key
99105
}
106+
107+
type Suggestion string
108+
109+
func (s Suggestion) String() string {
110+
return fmt.Sprintf("try: %s", string(s))
111+
}

pkg/build/graph/analysis/bc.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ import (
1515
)
1616

1717
const (
18-
MissingRequiredRegistryWarning = "MissingRequiredRegistry"
19-
MissingImageStreamWarning = "MissingImageStream"
20-
CyclicBuildConfigWarning = "CyclicBuildConfig"
18+
MissingRequiredRegistryErr = "MissingRequiredRegistry"
19+
MissingImageStreamErr = "MissingImageStream"
20+
CyclicBuildConfigWarning = "CyclicBuildConfig"
2121
)
2222

2323
// FindUnpushableBuildConfigs checks all build configs that will output to an IST backed by an ImageStream and checks to make sure their builds can push.
@@ -35,8 +35,8 @@ bc:
3535
Node: bcNode,
3636
RelatedNodes: []graph.Node{istNode},
3737

38-
Severity: osgraph.WarningSeverity,
39-
Key: MissingImageStreamWarning,
38+
Severity: osgraph.ErrorSeverity,
39+
Key: MissingImageStreamErr,
4040
Message: fmt.Sprintf("%s is pushing to %s that is using %s, but that image stream does not exist.",
4141
bcNode.(*buildgraph.BuildConfigNode).ResourceString(), istNode.(*imagegraph.ImageStreamTagNode).ResourceString(), imageStreamNode.ResourceString()),
4242
})
@@ -49,8 +49,8 @@ bc:
4949
Node: bcNode,
5050
RelatedNodes: []graph.Node{istNode},
5151

52-
Severity: osgraph.WarningSeverity,
53-
Key: MissingRequiredRegistryWarning,
52+
Severity: osgraph.ErrorSeverity,
53+
Key: MissingRequiredRegistryErr,
5454
Message: fmt.Sprintf("%s is pushing to %s that is using %s, but the administrator has not configured the integrated Docker registry. (oadm registry)",
5555
bcNode.(*buildgraph.BuildConfigNode).ResourceString(), istNode.(*imagegraph.ImageStreamTagNode).ResourceString(), imageStreamNode.ResourceString()),
5656
})

pkg/build/graph/analysis/bc_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func TestUnpushableBuild(t *testing.T) {
2424
t.Fatalf("expected %v, got %v", e, a)
2525
}
2626

27-
if got, expected := markers[0].Key, MissingRequiredRegistryWarning; got != expected {
27+
if got, expected := markers[0].Key, MissingRequiredRegistryErr; got != expected {
2828
t.Fatalf("expected marker key %q, got %q", expected, got)
2929
}
3030

@@ -53,7 +53,7 @@ func TestUnpushableBuild(t *testing.T) {
5353
t.Fatalf("expected %v, got %v", e, a)
5454
}
5555

56-
if got, expected := markers[0].Key, MissingImageStreamWarning; got != expected {
56+
if got, expected := markers[0].Key, MissingImageStreamErr; got != expected {
5757
t.Fatalf("expected marker key %q, got %q", expected, got)
5858
}
5959
}

pkg/cmd/cli/cmd/status.go

Lines changed: 77 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package cmd
22

33
import (
4+
"errors"
45
"fmt"
56
"io"
6-
"strings"
77

88
"github.com/gonum/graph/encoding/dot"
99
"github.com/spf13/cobra"
@@ -14,9 +14,10 @@ import (
1414
"github.com/openshift/origin/pkg/cmd/util/clientcmd"
1515
)
1616

17-
const (
18-
StatusRecommendedName = "status"
17+
// StatusRecommendedName is the recommended command name.
18+
const StatusRecommendedName = "status"
1919

20+
const (
2021
statusLong = `
2122
Show a high level overview of the current project
2223
@@ -28,36 +29,59 @@ oc describe deploymentConfig, oc describe service).
2829
You can specify an output format of "-o dot" to have this command output the generated status
2930
graph in DOT format that is suitable for use by the "dot" command.`
3031

31-
statusExample = ` # Show an overview of the current project
32-
$ %[1]s`
32+
statusExample = ` # See an overview of the current project.
33+
$ %[1]s
34+
35+
# Export the overview of the current project in an svg file.
36+
$ %[1]s -o dot | dot -T svg -o project.svg
37+
38+
# See an overview of the current project including details for any identified issues.
39+
$ %[1]s -v`
3340
)
3441

35-
// NewCmdStatus implements the OpenShift cli status command
42+
// StatusOptions contains all the necessary options for the Openshift cli status command.
43+
type StatusOptions struct {
44+
namespace string
45+
outputFormat string
46+
describer *describe.ProjectStatusDescriber
47+
out io.Writer
48+
verbose bool
49+
}
50+
51+
// NewCmdStatus implements the OpenShift cli status command.
3652
func NewCmdStatus(name, fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
37-
outputFormat := ""
53+
opts := &StatusOptions{}
3854

3955
cmd := &cobra.Command{
40-
Use: "status",
56+
Use: fmt.Sprintf("%s [-o dot | -v ]", StatusRecommendedName),
4157
Short: "Show an overview of the current project",
4258
Long: statusLong,
4359
Example: fmt.Sprintf(statusExample, fullName),
4460
Run: func(cmd *cobra.Command, args []string) {
45-
if strings.ToLower(outputFormat) == "dot" {
46-
cmdutil.CheckErr(RunGraph(f, out))
47-
return
61+
err := opts.Complete(f, cmd, args, out)
62+
cmdutil.CheckErr(err)
63+
64+
if err := opts.Validate(); err != nil {
65+
cmdutil.CheckErr(cmdutil.UsageError(cmd, err.Error()))
4866
}
4967

50-
cmdutil.CheckErr(RunStatus(f, out))
68+
err = opts.RunStatus()
69+
cmdutil.CheckErr(err)
5170
},
5271
}
5372

54-
cmd.Flags().StringVarP(&outputFormat, "output", "o", outputFormat, "Output format. One of: dot.")
73+
cmd.Flags().StringVarP(&opts.outputFormat, "output", "o", opts.outputFormat, "Output format. One of: dot.")
74+
cmd.Flags().BoolVarP(&opts.verbose, "verbose", "v", opts.verbose, "See details for resolving issues.")
5575

5676
return cmd
5777
}
5878

59-
// RunStatus contains all the necessary functionality for the OpenShift cli status command
60-
func RunStatus(f *clientcmd.Factory, out io.Writer) error {
79+
// Complete completes the options for the Openshift cli status command.
80+
func (o *StatusOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string, out io.Writer) error {
81+
if len(args) > 0 {
82+
return cmdutil.UsageError(cmd, "no arguments should be provided")
83+
}
84+
6185
client, kclient, err := f.Clients()
6286
if err != nil {
6387
return err
@@ -72,45 +96,53 @@ func RunStatus(f *clientcmd.Factory, out io.Writer) error {
7296
if err != nil {
7397
return err
7498
}
99+
o.namespace = namespace
75100

76-
describer := &describe.ProjectStatusDescriber{K: kclient, C: client, Server: config.Host}
77-
s, err := describer.Describe(namespace, "")
78-
if err != nil {
79-
return err
80-
}
101+
o.describer = &describe.ProjectStatusDescriber{K: kclient, C: client, Server: config.Host, Suggest: o.verbose}
102+
103+
o.out = out
81104

82-
fmt.Fprintf(out, s)
83105
return nil
84106
}
85107

86-
// RunGraph contains all the necessary functionality for the OpenShift cli graph command
87-
func RunGraph(f *clientcmd.Factory, out io.Writer) error {
88-
client, kclient, err := f.Clients()
89-
if err != nil {
90-
return err
108+
// Validate validates the options for the Openshift cli status command.
109+
func (o StatusOptions) Validate() error {
110+
if len(o.outputFormat) != 0 && o.outputFormat != "dot" {
111+
return fmt.Errorf("invalid output format provided: %s", o.outputFormat)
91112
}
92-
93-
config, err := f.OpenShiftClientConfig.ClientConfig()
94-
if err != nil {
95-
return err
96-
}
97-
98-
namespace, _, err := f.DefaultNamespace()
99-
if err != nil {
100-
return err
101-
}
102-
103-
describer := &describe.ProjectStatusDescriber{K: kclient, C: client, Server: config.Host}
104-
g, _, err := describer.MakeGraph(namespace)
105-
if err != nil {
106-
return err
113+
if len(o.outputFormat) > 0 && o.verbose {
114+
return errors.New("cannot provide suggestions when output format is dot")
107115
}
116+
return nil
117+
}
108118

109-
data, err := dot.Marshal(g, namespace, "", " ", false)
110-
if err != nil {
111-
return err
119+
// RunStatus contains all the necessary functionality for the OpenShift cli status command.
120+
func (o StatusOptions) RunStatus() error {
121+
var (
122+
s string
123+
err error
124+
)
125+
126+
switch o.outputFormat {
127+
case "":
128+
s, err = o.describer.Describe(o.namespace, "")
129+
if err != nil {
130+
return err
131+
}
132+
case "dot":
133+
g, _, err := o.describer.MakeGraph(o.namespace)
134+
if err != nil {
135+
return err
136+
}
137+
data, err := dot.Marshal(g, o.namespace, "", " ", false)
138+
if err != nil {
139+
return err
140+
}
141+
s = string(data)
142+
default:
143+
return fmt.Errorf("invalid output format provided: %s", o.outputFormat)
112144
}
113145

114-
fmt.Fprintf(out, "%s", string(data))
146+
fmt.Fprintf(o.out, s)
115147
return nil
116148
}

pkg/cmd/cli/describe/projectstatus.go

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ const ForbiddenListWarning = "Forbidden"
4848

4949
// ProjectStatusDescriber generates extended information about a Project
5050
type ProjectStatusDescriber struct {
51-
K kclient.Interface
52-
C client.Interface
53-
Server string
51+
K kclient.Interface
52+
C client.Interface
53+
Server string
54+
Suggest bool
5455
}
5556

5657
func (d *ProjectStatusDescriber) MakeGraph(namespace string) (osgraph.Graph, sets.String, error) {
@@ -210,32 +211,66 @@ func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error
210211

211212
sort.Stable(osgraph.ByKey(allMarkers))
212213
sort.Stable(osgraph.ByNodeID(allMarkers))
213-
if errorMarkers := allMarkers.BySeverity(osgraph.ErrorSeverity); len(errorMarkers) > 0 {
214+
215+
errorMarkers := allMarkers.BySeverity(osgraph.ErrorSeverity)
216+
if len(errorMarkers) > 0 {
214217
fmt.Fprintln(out, "Errors:")
215218
for _, marker := range errorMarkers {
216219
fmt.Fprintln(out, indent+"* "+marker.Message)
220+
if len(marker.Suggestion) > 0 && d.Suggest {
221+
fmt.Fprintln(out, indent+" "+marker.Suggestion.String())
222+
}
217223
}
218224
}
219-
if warningMarkers := allMarkers.BySeverity(osgraph.WarningSeverity); len(warningMarkers) > 0 {
220-
fmt.Fprintln(out, "Warnings:")
225+
226+
warningMarkers := allMarkers.BySeverity(osgraph.WarningSeverity)
227+
if len(warningMarkers) > 0 {
228+
if d.Suggest {
229+
fmt.Fprintln(out, "Warnings:")
230+
}
221231
for _, marker := range warningMarkers {
222-
fmt.Fprintln(out, indent+"* "+marker.Message)
232+
if d.Suggest {
233+
fmt.Fprintln(out, indent+"* "+marker.Message)
234+
if len(marker.Suggestion) > 0 {
235+
fmt.Fprintln(out, indent+" "+marker.Suggestion.String())
236+
}
237+
}
223238
}
224239
}
225-
if infoMarkers := allMarkers.BySeverity(osgraph.InfoSeverity); len(infoMarkers) > 0 {
226-
fmt.Fprintln(out, "Info:")
227-
for _, marker := range infoMarkers {
228-
fmt.Fprintln(out, indent+"* "+marker.Message)
229-
}
240+
241+
// We print errors by default and warnings if -v is used. If we get none,
242+
// this would be an extra new line.
243+
if len(errorMarkers) != 0 || (d.Suggest && len(warningMarkers) != 0) {
244+
fmt.Fprintln(out)
230245
}
231246

232-
fmt.Fprintln(out)
247+
errors, warnings := "", ""
248+
if len(errorMarkers) == 1 {
249+
errors = "1 error"
250+
} else if len(errorMarkers) > 1 {
251+
errors = fmt.Sprintf("%d errors", len(errorMarkers))
252+
}
253+
if len(warningMarkers) == 1 {
254+
warnings = "1 warning"
255+
} else if len(warningMarkers) > 1 {
256+
warnings = fmt.Sprintf("%d warnings", len(warningMarkers))
257+
}
258+
259+
switch {
260+
case !d.Suggest && len(errorMarkers) > 0 && len(warningMarkers) > 0:
261+
fmt.Fprintf(out, "%s and %s identified, use 'oc status -v' to see details.\n", errors, warnings)
233262

234-
if (len(services) == 0) && (len(standaloneDCs) == 0) && (len(standaloneImages) == 0) {
263+
case !d.Suggest && len(errorMarkers) > 0:
264+
fmt.Fprintf(out, "%s identified, use 'oc status -v' to see details.\n", errors)
265+
266+
case !d.Suggest && len(warningMarkers) > 0:
267+
fmt.Fprintf(out, "%s identified, use 'oc status -v' to see details.\n", warnings)
268+
269+
case (len(services) == 0) && (len(standaloneDCs) == 0) && (len(standaloneImages) == 0):
235270
fmt.Fprintln(out, "You have no services, deployment configs, or build configs.")
236271
fmt.Fprintln(out, "Run 'oc new-app' to create an application.")
237272

238-
} else {
273+
default:
239274
fmt.Fprintln(out, "To see more, use 'oc describe <resource>/<name>'.")
240275
fmt.Fprintln(out, "You can use 'oc get all' to see a list of other objects.")
241276
}

0 commit comments

Comments
 (0)