... | ... |
@@ -13819,8 +13819,6 @@ _openshift_ex_diagnostics() |
13819 | 13819 |
flags+=("--context=") |
13820 | 13820 |
flags+=("--diaglevel=") |
13821 | 13821 |
two_word_flags+=("-l") |
13822 |
- flags+=("--diagnostics=") |
|
13823 |
- two_word_flags+=("-d") |
|
13824 | 13822 |
flags+=("--host") |
13825 | 13823 |
flags+=("--images=") |
13826 | 13824 |
flags+=("--latest-images") |
... | ... |
@@ -27,7 +27,7 @@ This command validates that a configuration file intended to be used for a node |
27 | 27 |
valiateNodeConfigExample = ` // Validate node configuration file |
28 | 28 |
$ %s openshift.local.config/master/node-config.yaml` |
29 | 29 |
|
30 |
- validateNodeConfigDeprecationMessage = `This command is deprecated and will be removed. Use 'openshift ex diagnostics NodeConfigCheck --node-config=<path/to/config.yaml' instead.` |
|
30 |
+ validateNodeConfigDeprecationMessage = `This command is deprecated and will be removed. Use 'openshift ex diagnostics NodeConfigCheck --node-config=path/to/config.yaml' instead.` |
|
31 | 31 |
) |
32 | 32 |
|
33 | 33 |
type ValidateNodeConfigOptions struct { |
... | ... |
@@ -29,7 +29,7 @@ func (o DiagnosticsOptions) buildClientDiagnostics(rawConfig *clientcmdapi.Confi |
29 | 29 |
} |
30 | 30 |
|
31 | 31 |
diagnostics := []types.Diagnostic{} |
32 |
- requestedDiagnostics := intersection(sets.NewString(o.RequestedDiagnostics...), available).List() |
|
32 |
+ requestedDiagnostics := available.Intersection(sets.NewString(o.RequestedDiagnostics...)).List() |
|
33 | 33 |
for _, diagnosticName := range requestedDiagnostics { |
34 | 34 |
switch diagnosticName { |
35 | 35 |
case clientdiags.ConfigContextsName: |
... | ... |
@@ -26,7 +26,7 @@ var ( |
26 | 26 |
// buildClusterDiagnostics builds cluster Diagnostic objects if a cluster-admin client can be extracted from the rawConfig passed in. |
27 | 27 |
// Returns the Diagnostics built, "ok" bool for whether to proceed or abort, and an error if any was encountered during the building of diagnostics.) { |
28 | 28 |
func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Config) ([]types.Diagnostic, bool, error) { |
29 |
- requestedDiagnostics := intersection(sets.NewString(o.RequestedDiagnostics...), availableClusterDiagnostics).List() |
|
29 |
+ requestedDiagnostics := availableClusterDiagnostics.Intersection(sets.NewString(o.RequestedDiagnostics...)).List() |
|
30 | 30 |
if len(requestedDiagnostics) == 0 { // no diagnostics to run here |
31 | 31 |
return nil, true, nil // don't waste time on discovery |
32 | 32 |
} |
... | ... |
@@ -77,8 +77,8 @@ you will receive an error if they are not found. For example: |
77 | 77 |
* If a client config file is not found, client and cluster diagnostics |
78 | 78 |
are skipped. |
79 | 79 |
|
80 |
-Diagnostics may be individually run with --diagnostics. The available |
|
81 |
-diagnostic names are: |
|
80 |
+Diagnostics may be individually run by passing diagnostic name as arguments. |
|
81 |
+The available diagnostic names are: |
|
82 | 82 |
%[2]s |
83 | 83 |
|
84 | 84 |
NOTE: This is a beta version of diagnostics and may still evolve in a |
... | ... |
@@ -96,9 +96,11 @@ func NewCommandDiagnostics(name string, fullName string, out io.Writer) *cobra.C |
96 | 96 |
cmd := &cobra.Command{ |
97 | 97 |
Use: name, |
98 | 98 |
Short: "This utility helps you troubleshoot and diagnose.", |
99 |
- Long: fmt.Sprintf(longDescription, fullName, strings.Join(availableDiagnostics().List(), ",")), |
|
99 |
+ Long: fmt.Sprintf(longDescription, fullName, strings.Join(availableDiagnostics().List(), " ")), |
|
100 | 100 |
Run: func(c *cobra.Command, args []string) { |
101 |
- kcmdutil.CheckErr(o.Complete()) |
|
101 |
+ kcmdutil.CheckErr(o.Complete(args)) |
|
102 |
+ |
|
103 |
+ kcmdutil.CheckErr(o.Validate()) |
|
102 | 104 |
|
103 | 105 |
failed, err, warnCount, errorCount := o.RunDiagnostics() |
104 | 106 |
o.Logger.Summary(warnCount, errorCount) |
... | ... |
@@ -125,45 +127,48 @@ func NewCommandDiagnostics(name string, fullName string, out io.Writer) *cobra.C |
125 | 125 |
cmd.Flags().BoolVar(&o.PreventModification, options.FlagPreventModificationName, false, "May be set to prevent diagnostics making any changes via the API") |
126 | 126 |
flagtypes.GLog(cmd.Flags()) |
127 | 127 |
options.BindLoggerOptionFlags(cmd.Flags(), o.LogOptions, options.RecommendedLoggerOptionFlags()) |
128 |
- options.BindDiagnosticFlag(cmd.Flags(), &o.RequestedDiagnostics, options.NewRecommendedDiagnosticFlag()) |
|
129 | 128 |
|
130 | 129 |
return cmd |
131 | 130 |
} |
132 | 131 |
|
133 | 132 |
// Complete fills in DiagnosticsOptions needed if the command is actually invoked. |
134 |
-func (o *DiagnosticsOptions) Complete() error { |
|
133 |
+func (o *DiagnosticsOptions) Complete(args []string) error { |
|
135 | 134 |
var err error |
136 | 135 |
o.Logger, err = o.LogOptions.NewLogger() |
137 | 136 |
if err != nil { |
138 | 137 |
return err |
139 | 138 |
} |
140 | 139 |
|
141 |
- return nil |
|
142 |
-} |
|
140 |
+ // If not given master/client config file locations, check if the defaults exist |
|
141 |
+ // and adjust the options accordingly: |
|
142 |
+ if len(o.MasterConfigLocation) == 0 { |
|
143 |
+ if _, err := os.Stat(StandardMasterConfigPath); !os.IsNotExist(err) { |
|
144 |
+ o.MasterConfigLocation = StandardMasterConfigPath |
|
145 |
+ } |
|
146 |
+ } |
|
147 |
+ if len(o.NodeConfigLocation) == 0 { |
|
148 |
+ if _, err := os.Stat(StandardNodeConfigPath); !os.IsNotExist(err) { |
|
149 |
+ o.NodeConfigLocation = StandardNodeConfigPath |
|
150 |
+ } |
|
151 |
+ } |
|
143 | 152 |
|
144 |
-func availableDiagnostics() sets.String { |
|
145 |
- available := sets.NewString() |
|
146 |
- available.Insert(availableClientDiagnostics.List()...) |
|
147 |
- available.Insert(availableClusterDiagnostics.List()...) |
|
148 |
- available.Insert(availableHostDiagnostics.List()...) |
|
149 |
- return available |
|
153 |
+ o.RequestedDiagnostics = append(o.RequestedDiagnostics, args...) |
|
154 |
+ if len(o.RequestedDiagnostics) == 0 { |
|
155 |
+ o.RequestedDiagnostics = availableDiagnostics().List() |
|
156 |
+ } |
|
157 |
+ |
|
158 |
+ return nil |
|
150 | 159 |
} |
151 | 160 |
|
152 |
-// RunDiagnostics builds diagnostics based on the options and executes them, returning a summary. |
|
153 |
-func (o DiagnosticsOptions) RunDiagnostics() (bool, error, int, int) { |
|
154 |
- failed := false |
|
155 |
- warnings := []error{} |
|
156 |
- errors := []error{} |
|
157 |
- diagnostics := []types.Diagnostic{} |
|
161 |
+func (o *DiagnosticsOptions) Validate() error { |
|
158 | 162 |
available := availableDiagnostics() |
159 |
- if len(o.RequestedDiagnostics) == 0 { |
|
160 |
- o.RequestedDiagnostics = available.List() |
|
161 |
- } else if common := intersection(sets.NewString(o.RequestedDiagnostics...), available); len(common) == 0 { |
|
163 |
+ |
|
164 |
+ if common := available.Intersection(sets.NewString(o.RequestedDiagnostics...)); len(common) == 0 { |
|
162 | 165 |
o.Logger.Error("CED3012", log.EvalTemplate("CED3012", "None of the requested diagnostics are available:\n {{.requested}}\nPlease try from the following:\n {{.available}}", |
163 | 166 |
log.Hash{"requested": o.RequestedDiagnostics, "available": available.List()})) |
164 |
- return false, fmt.Errorf("No requested diagnostics available"), 0, 1 |
|
167 |
+ return fmt.Errorf("No requested diagnostics are available: requested=%s available=%s", strings.Join(o.RequestedDiagnostics, " "), strings.Join(available.List(), " ")) |
|
168 |
+ |
|
165 | 169 |
} else if len(common) < len(o.RequestedDiagnostics) { |
166 |
- errors = append(errors, fmt.Errorf("Not all requested diagnostics are available")) |
|
167 | 170 |
o.Logger.Error("CED3013", log.EvalTemplate("CED3013", ` |
168 | 171 |
Of the requested diagnostics: |
169 | 172 |
{{.requested}} |
... | ... |
@@ -172,21 +177,31 @@ only these are available: |
172 | 172 |
The list of all possible is: |
173 | 173 |
{{.available}} |
174 | 174 |
`, log.Hash{"requested": o.RequestedDiagnostics, "common": common.List(), "available": available.List()})) |
175 |
- } |
|
176 | 175 |
|
177 |
- // If not given master/client config file locations, check if the defaults exist |
|
178 |
- // and adjust the options accordingly: |
|
179 |
- if len(o.MasterConfigLocation) == 0 { |
|
180 |
- if _, err := os.Stat(StandardMasterConfigPath); !os.IsNotExist(err) { |
|
181 |
- o.MasterConfigLocation = StandardMasterConfigPath |
|
182 |
- } |
|
183 |
- } |
|
184 |
- if len(o.NodeConfigLocation) == 0 { |
|
185 |
- if _, err := os.Stat(StandardNodeConfigPath); !os.IsNotExist(err) { |
|
186 |
- o.NodeConfigLocation = StandardNodeConfigPath |
|
187 |
- } |
|
176 |
+ return fmt.Errorf("Not all requested diagnostics are available: missing=%s requested=%s available=%s", |
|
177 |
+ strings.Join(sets.NewString(o.RequestedDiagnostics...).Difference(available).List(), " "), |
|
178 |
+ strings.Join(o.RequestedDiagnostics, " "), |
|
179 |
+ strings.Join(available.List(), " ")) |
|
188 | 180 |
} |
189 | 181 |
|
182 |
+ return nil |
|
183 |
+} |
|
184 |
+ |
|
185 |
+func availableDiagnostics() sets.String { |
|
186 |
+ available := sets.NewString() |
|
187 |
+ available.Insert(availableClientDiagnostics.List()...) |
|
188 |
+ available.Insert(availableClusterDiagnostics.List()...) |
|
189 |
+ available.Insert(availableHostDiagnostics.List()...) |
|
190 |
+ return available |
|
191 |
+} |
|
192 |
+ |
|
193 |
+// RunDiagnostics builds diagnostics based on the options and executes them, returning a summary. |
|
194 |
+func (o DiagnosticsOptions) RunDiagnostics() (bool, error, int, int) { |
|
195 |
+ failed := false |
|
196 |
+ warnings := []error{} |
|
197 |
+ errors := []error{} |
|
198 |
+ diagnostics := []types.Diagnostic{} |
|
199 |
+ |
|
190 | 200 |
func() { // don't trust discovery/build of diagnostics; wrap panic nicely in case of developer error |
191 | 201 |
defer func() { |
192 | 202 |
if r := recover(); r != nil { |
... | ... |
@@ -283,14 +298,3 @@ func (o DiagnosticsOptions) Run(diagnostics []types.Diagnostic) (bool, error, in |
283 | 283 |
} |
284 | 284 |
return errorCount > 0, nil, warnCount, errorCount |
285 | 285 |
} |
286 |
- |
|
287 |
-// TODO move upstream |
|
288 |
-func intersection(s1 sets.String, s2 sets.String) sets.String { |
|
289 |
- result := sets.NewString() |
|
290 |
- for key := range s1 { |
|
291 |
- if s2.Has(key) { |
|
292 |
- result.Insert(key) |
|
293 |
- } |
|
294 |
- } |
|
295 |
- return result |
|
296 |
-} |
... | ... |
@@ -19,7 +19,7 @@ var ( |
19 | 19 |
// buildHostDiagnostics builds host Diagnostic objects based on the host environment. |
20 | 20 |
// Returns the Diagnostics built, "ok" bool for whether to proceed or abort, and an error if any was encountered during the building of diagnostics.) { |
21 | 21 |
func (o DiagnosticsOptions) buildHostDiagnostics() ([]types.Diagnostic, bool, error) { |
22 |
- requestedDiagnostics := intersection(sets.NewString(o.RequestedDiagnostics...), availableHostDiagnostics).List() |
|
22 |
+ requestedDiagnostics := availableHostDiagnostics.Intersection(sets.NewString(o.RequestedDiagnostics...)).List() |
|
23 | 23 |
if len(requestedDiagnostics) == 0 { // no diagnostics to run here |
24 | 24 |
return nil, true, nil // don't waste time on discovery |
25 | 25 |
} |
... | ... |
@@ -22,13 +22,3 @@ func RecommendedLoggerOptionFlags() LoggerOptionFlags { |
22 | 22 |
func BindLoggerOptionFlags(cmdFlags *pflag.FlagSet, loggerOptions *log.LoggerOptions, flags LoggerOptionFlags) { |
23 | 23 |
flags.Level.BindIntFlag(cmdFlags, &loggerOptions.Level) |
24 | 24 |
} |
25 |
- |
|
26 |
-// NewRecommendedDiagnosticFlag provides default overrideable Diagnostic flag specifications to be bound to options. |
|
27 |
-func NewRecommendedDiagnosticFlag() FlagInfo { |
|
28 |
- return FlagInfo{FlagDiagnosticsName, "d", "", `Comma-separated list of diagnostic names to run, e.g. "AnalyzeLogs"`} |
|
29 |
-} |
|
30 |
- |
|
31 |
-// BindLoggerOptionFlags binds a flag on a diagnostics command per the flagInfo. |
|
32 |
-func BindDiagnosticFlag(cmdFlags *pflag.FlagSet, diagnostics *[]string, flagInfo FlagInfo) { |
|
33 |
- flagInfo.BindListFlag(cmdFlags, diagnostics) |
|
34 |
-} |
... | ... |
@@ -48,7 +48,6 @@ const ( |
48 | 48 |
FlagMasterConfigName = "master-config" |
49 | 49 |
FlagNodeConfigName = "node-config" |
50 | 50 |
FlagClusterContextName = "cluster-context" |
51 |
- FlagDiagnosticsName = "diagnostics" |
|
52 | 51 |
FlagLevelName = "diaglevel" |
53 | 52 |
FlagIsHostName = "host" |
54 | 53 |
FlagImageTemplateName = "images" |
... | ... |
@@ -53,7 +53,7 @@ func NewCommandPodDiagnostics(name string, out io.Writer) *cobra.Command { |
53 | 53 |
Short: "Within a pod, run pod diagnostics", |
54 | 54 |
Long: fmt.Sprintf(longPodDiagDescription), |
55 | 55 |
Run: func(c *cobra.Command, args []string) { |
56 |
- kcmdutil.CheckErr(o.Complete()) |
|
56 |
+ kcmdutil.CheckErr(o.Complete(args)) |
|
57 | 57 |
|
58 | 58 |
failed, err, warnCount, errorCount := o.BuildAndRunDiagnostics() |
59 | 59 |
o.Logger.Summary(warnCount, errorCount) |
... | ... |
@@ -68,19 +68,23 @@ func NewCommandPodDiagnostics(name string, out io.Writer) *cobra.Command { |
68 | 68 |
cmd.SetOutput(out) // for output re: usage / help |
69 | 69 |
|
70 | 70 |
options.BindLoggerOptionFlags(cmd.Flags(), o.LogOptions, options.RecommendedLoggerOptionFlags()) |
71 |
- options.BindDiagnosticFlag(cmd.Flags(), &o.RequestedDiagnostics, options.NewRecommendedDiagnosticFlag()) |
|
72 | 71 |
|
73 | 72 |
return cmd |
74 | 73 |
} |
75 | 74 |
|
76 | 75 |
// Complete fills in PodDiagnosticsOptions needed if the command is actually invoked. |
77 |
-func (o *PodDiagnosticsOptions) Complete() error { |
|
76 |
+func (o *PodDiagnosticsOptions) Complete(args []string) error { |
|
78 | 77 |
var err error |
79 | 78 |
o.Logger, err = o.LogOptions.NewLogger() |
80 | 79 |
if err != nil { |
81 | 80 |
return err |
82 | 81 |
} |
83 | 82 |
|
83 |
+ o.RequestedDiagnostics = append(o.RequestedDiagnostics, args...) |
|
84 |
+ if len(o.RequestedDiagnostics) == 0 { |
|
85 |
+ o.RequestedDiagnostics = availablePodDiagnostics.List() |
|
86 |
+ } |
|
87 |
+ |
|
84 | 88 |
return nil |
85 | 89 |
} |
86 | 90 |
|
... | ... |
@@ -196,7 +200,7 @@ func determineRequestedDiagnostics(available []string, requested []string, logge |
196 | 196 |
diagnostics := []string{} |
197 | 197 |
if len(requested) == 0 { // not specified, use the available list |
198 | 198 |
diagnostics = available |
199 |
- } else if diagnostics = intersection(sets.NewString(requested...), sets.NewString(available...)).List(); len(diagnostics) == 0 { |
|
199 |
+ } else if diagnostics = sets.NewString(requested...).Intersection(sets.NewString(available...)).List(); len(diagnostics) == 0 { |
|
200 | 200 |
logger.Error("CED6001", log.EvalTemplate("CED6001", "None of the requested diagnostics are available:\n {{.requested}}\nPlease try from the following:\n {{.available}}", |
201 | 201 |
log.Hash{"requested": requested, "available": available})) |
202 | 202 |
return fmt.Errorf("No requested diagnostics available"), diagnostics |
... | ... |
@@ -9,7 +9,7 @@ source "${OS_ROOT}/hack/util.sh" |
9 | 9 |
source "${OS_ROOT}/hack/cmd_util.sh" |
10 | 10 |
os::log::install_errexit |
11 | 11 |
|
12 |
-# Cleanup cluster resources created by this test |
|
12 |
+#Cleanup cluster resources created by this test |
|
13 | 13 |
( |
14 | 14 |
set +e |
15 | 15 |
oc delete project/example project/ui-test-project project/recreated-project |
... | ... |
@@ -300,3 +300,8 @@ os::cmd::expect_success_and_not_text "oc get clusterrolebindings/cluster-admins |
300 | 300 |
os::cmd::expect_success_and_not_text "oc get rolebindings/cluster-admin --output-version=v1 --template='{{.subjects}}' -n default" 'cascaded-group' |
301 | 301 |
os::cmd::expect_success_and_not_text "oc get scc/restricted --output-version=v1 --template='{{.groups}}'" 'cascaded-group' |
302 | 302 |
echo "user-group-cascade: ok" |
303 |
+ |
|
304 |
+ |
|
305 |
+os::cmd::expect_failure_and_text 'openshift ex diagnostics FakeDiagnostic AlsoMissing' 'No requested diagnostics are available: requested=FakeDiagnostic AlsoMissing' |
|
306 |
+os::cmd::expect_failure_and_text 'openshift ex diagnostics AnalyzeLogs AlsoMissing' 'Not all requested diagnostics are available: missing=AlsoMissing requested=AnalyzeLogs AlsoMissing available=' |
|
307 |
+echo "diagnostics: ok" |