Browse code

accept diagnostics as args

deads2k authored on 2016/01/13 22:51:39
Showing 10 changed files
... ...
@@ -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"