diff --git a/pkg/oc/admin/diagnostics/client.go b/pkg/oc/admin/diagnostics/client.go index 922713de3608..b1c571313e05 100644 --- a/pkg/oc/admin/diagnostics/client.go +++ b/pkg/oc/admin/diagnostics/client.go @@ -7,14 +7,14 @@ import ( clientcmdapi "k8s.io/client-go/tools/clientcmd/api" clientdiags "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/client" - networkdiags "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/network" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/client/pod" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" ) // availableClientDiagnostics returns definitions of client diagnostics that can be executed // during a single run of diagnostics. Add more diagnostics to the list as they are defined. func availableClientDiagnostics() types.DiagnosticList { - return types.DiagnosticList{clientdiags.ConfigContext{}, &clientdiags.DiagnosticPod{}, &networkdiags.NetworkDiagnostic{}} + return types.DiagnosticList{clientdiags.ConfigContext{}, &pod.DiagnosticPod{}} } // buildClientDiagnostics builds client Diagnostic objects based on the rawConfig passed in. @@ -22,9 +22,8 @@ func availableClientDiagnostics() types.DiagnosticList { func (o DiagnosticsOptions) buildClientDiagnostics(rawConfig *clientcmdapi.Config) ([]types.Diagnostic, error) { available := availableClientDiagnostics().Names() - networkClient, err := o.Factory.OpenshiftInternalNetworkClient() kubeClient, clientErr := o.Factory.ClientSet() - if clientErr != nil || err != nil { + if clientErr != nil { o.Logger().Notice("CED0001", "Could not configure a client, so client diagnostics are limited to testing configuration and connection") available = sets.NewString(clientdiags.ConfigContextsName) } @@ -45,24 +44,14 @@ func (o DiagnosticsOptions) buildClientDiagnostics(rawConfig *clientcmdapi.Confi diagnostics = append(diagnostics, diagnostic) } } - case clientdiags.DiagnosticPodName: - dp := o.ParameterizedDiagnostics[diagnosticName].(*clientdiags.DiagnosticPod) + case pod.DiagnosticPodName: + dp := o.ParameterizedDiagnostics[diagnosticName].(*pod.DiagnosticPod) dp.KubeClient = kubeClient dp.Namespace = rawConfig.Contexts[rawConfig.CurrentContext].Namespace dp.Level = o.LogOptions.Level dp.Factory = o.Factory dp.PreventModification = dp.PreventModification || o.PreventModification diagnostics = append(diagnostics, dp) - case networkdiags.NetworkDiagnosticName: - nd := o.ParameterizedDiagnostics[diagnosticName].(*networkdiags.NetworkDiagnostic) - nd.KubeClient = kubeClient - nd.NetNamespacesClient = networkClient.Network() - nd.ClusterNetworkClient = networkClient.Network() - nd.ClientFlags = o.ClientFlags - nd.Level = o.LogOptions.Level - nd.Factory = o.Factory - nd.PreventModification = o.PreventModification - diagnostics = append(diagnostics, nd) default: return nil, fmt.Errorf("unknown diagnostic: %v", diagnosticName) } diff --git a/pkg/oc/admin/diagnostics/cluster.go b/pkg/oc/admin/diagnostics/cluster.go index 8ded7eaf40f9..eb4bd8340bc2 100644 --- a/pkg/oc/admin/diagnostics/cluster.go +++ b/pkg/oc/admin/diagnostics/cluster.go @@ -14,10 +14,12 @@ import ( appsclient "github.com/openshift/origin/pkg/apps/generated/internalclientset" oauthorizationclient "github.com/openshift/origin/pkg/authorization/generated/internalclientset" imageclient "github.com/openshift/origin/pkg/image/generated/internalclientset" + networkclient "github.com/openshift/origin/pkg/network/generated/internalclientset" oauthclient "github.com/openshift/origin/pkg/oauth/generated/internalclientset" clustdiags "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster" agldiags "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/aggregated_logging" appcreate "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/app_create" + networkdiags "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" osclientcmd "github.com/openshift/origin/pkg/oc/cli/util/clientcmd" projectclient "github.com/openshift/origin/pkg/project/generated/internalclientset" @@ -41,6 +43,7 @@ func availableClusterDiagnostics() types.DiagnosticList { &clustdiags.NodeDefinitions{}, &clustdiags.RouteCertificateValidation{}, &clustdiags.ServiceExternalIPs{}, + &networkdiags.NetworkDiagnostic{}, } } @@ -54,14 +57,14 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf var kclusterClient kclientset.Interface - config, kclusterClient, serverUrl, err := o.findClusterClients(rawConfig) + config, kclusterClient, rawAdminConfig, err := o.findClusterClients(rawConfig) + if err != nil { + return nil, err + } if config == nil { o.Logger().Notice("CED1002", "Could not configure a client with cluster-admin permissions for the current server, so cluster diagnostics will be skipped") return nil, nil } - if err != nil { - return nil, err - } imageClient, err := imageclient.NewForConfig(config) if err != nil { return nil, err @@ -90,6 +93,10 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf if err != nil { return nil, err } + networkClient, err := networkclient.NewForConfig(config) + if err != nil { + return nil, err + } diagnostics := []types.Diagnostic{} for _, diagnosticName := range requestedDiagnostics { @@ -111,6 +118,7 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf case clustdiags.NodeDefinitionsName: d = &clustdiags.NodeDefinitions{KubeClient: kclusterClient} case clustdiags.MasterNodeName: + serverUrl := rawAdminConfig.Clusters[rawAdminConfig.Contexts[rawAdminConfig.CurrentContext].Cluster].Server d = &clustdiags.MasterNode{KubeClient: kclusterClient, ServerUrl: serverUrl, MasterConfigFile: o.MasterConfigLocation} case clustdiags.ClusterRegistryName: d = &clustdiags.ClusterRegistry{KubeClient: kclusterClient, ImageStreamClient: imageClient.Image(), PreventModification: o.PreventModification} @@ -126,6 +134,17 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf d = &clustdiags.ServiceExternalIPs{MasterConfigFile: o.MasterConfigLocation, KclusterClient: kclusterClient} case clustdiags.RouteCertificateValidationName: d = &clustdiags.RouteCertificateValidation{SARClient: kclusterClient.Authorization(), RESTConfig: config} + case networkdiags.NetworkDiagnosticName: + nd := o.ParameterizedDiagnostics[diagnosticName].(*networkdiags.NetworkDiagnostic) + nd.KubeClient = kclusterClient + nd.NetNamespacesClient = networkClient.Network() + nd.ClusterNetworkClient = networkClient.Network() + nd.ClientFlags = o.ClientFlags + nd.Level = o.LogOptions.Level + nd.Factory = o.Factory + nd.RawConfig = rawAdminConfig + nd.PreventModification = o.PreventModification + d = nd default: return nil, fmt.Errorf("unknown diagnostic: %v", diagnosticName) } @@ -135,84 +154,96 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf } // attempts to find which context in the config might be a cluster-admin for the server in the current context. -// returns config for the context chosen, kclusterClient for same, serverUrl of same, and any fatal error -func (o DiagnosticsOptions) findClusterClients(rawConfig *clientcmdapi.Config) (*rest.Config, kclientset.Interface, string, error) { +// returns openshift client config for the context chosen, kclusterClient and raw config of same, and any fatal error +func (o DiagnosticsOptions) findClusterClients(rawConfig *clientcmdapi.Config) (*rest.Config, kclientset.Interface, *clientcmdapi.Config, error) { if o.ClientClusterContext != "" { // user has specified cluster context to use context, exists := rawConfig.Contexts[o.ClientClusterContext] if !exists { configErr := fmt.Errorf("Specified '%s' as cluster-admin context, but it was not found in your client configuration.", o.ClientClusterContext) o.Logger().Error("CED1003", configErr.Error()) - return nil, nil, "", configErr + return nil, nil, nil, configErr } - config, kube, serverUrl, err := o.makeClusterClients(rawConfig, o.ClientClusterContext, context) - if err != nil || config == nil { - return nil, nil, "", err - } - return config, kube, serverUrl, nil + return o.makeClusterClients(rawConfig, o.ClientClusterContext, context) } currentContext, exists := rawConfig.Contexts[rawConfig.CurrentContext] if !exists { // config specified cluster admin context that doesn't exist; complain and quit configErr := fmt.Errorf("Current context '%s' not found in client configuration; will not attempt cluster diagnostics.", rawConfig.CurrentContext) o.Logger().Error("CED1004", configErr.Error()) - return nil, nil, "", configErr + return nil, nil, nil, configErr } + // check if current context is already cluster admin - config, kube, serverUrl, err := o.makeClusterClients(rawConfig, rawConfig.CurrentContext, currentContext) + config, kube, rawAdminConfig, err := o.makeClusterClients(rawConfig, rawConfig.CurrentContext, currentContext) if err == nil && config != nil { - return config, kube, serverUrl, nil + return config, kube, rawAdminConfig, nil } + // otherwise, for convenience, search for a context with the same server but with the system:admin user for name, context := range rawConfig.Contexts { if context.Cluster == currentContext.Cluster && name != rawConfig.CurrentContext && strings.HasPrefix(context.AuthInfo, "system:admin/") { - config, kube, serverUrl, err := o.makeClusterClients(rawConfig, name, context) + config, kube, rawAdminConfig, err := o.makeClusterClients(rawConfig, name, context) if err != nil || config == nil { break // don't try more than one such context, they'll probably fail the same } - return config, kube, serverUrl, nil + return config, kube, rawAdminConfig, nil } } - return nil, nil, "", nil + return nil, nil, nil, nil } // makes the client from the specified context and determines whether it is a cluster-admin. -func (o DiagnosticsOptions) makeClusterClients(rawConfig *clientcmdapi.Config, contextName string, context *clientcmdapi.Context) (*rest.Config, kclientset.Interface, string, error) { +func (o DiagnosticsOptions) makeClusterClients(rawConfig *clientcmdapi.Config, contextName string, context *clientcmdapi.Context) (*rest.Config, kclientset.Interface, *clientcmdapi.Config, error) { overrides := &clientcmd.ConfigOverrides{Context: *context} clientConfig := clientcmd.NewDefaultClientConfig(*rawConfig, overrides) - serverUrl := rawConfig.Clusters[context.Cluster].Server factory := osclientcmd.NewFactory(clientConfig) + + // create a config for making openshift clients config, err := factory.ClientConfig() if err != nil { - o.Logger().Debug("CED1006", fmt.Sprintf("Error creating client for context '%s':\n%v", contextName, err)) - return nil, nil, "", nil + o.Logger().Debug("CED1006", fmt.Sprintf("Error creating client config for context '%s':\n%v", contextName, err)) + return nil, nil, nil, nil } + + // create a kube client + kubeClient, err := factory.ClientSet() + if err != nil { + o.Logger().Debug("CED1006", fmt.Sprintf("Error creating kube client for context '%s':\n%v", contextName, err)) + return nil, nil, nil, nil + } + o.Logger().Debug("CED1005", fmt.Sprintf("Checking if context is cluster-admin: '%s'", contextName)) - if kubeClient, err := factory.ClientSet(); err != nil { - o.Logger().Debug("CED1006", fmt.Sprintf("Error creating client for context '%s':\n%v", contextName, err)) - return nil, nil, "", nil - } else { - subjectAccessReview := &authorization.SelfSubjectAccessReview{ - Spec: authorization.SelfSubjectAccessReviewSpec{ - ResourceAttributes: &authorization.ResourceAttributes{ - // if you can do everything, you're the cluster admin. - Verb: "*", - Group: "*", - Resource: "*", - }, + subjectAccessReview := &authorization.SelfSubjectAccessReview{ + Spec: authorization.SelfSubjectAccessReviewSpec{ + ResourceAttributes: &authorization.ResourceAttributes{ + // if you can do everything, you're the cluster admin. + Verb: "*", + Group: "*", + Resource: "*", }, - } - if resp, err := kubeClient.Authorization().SelfSubjectAccessReviews().Create(subjectAccessReview); err != nil { - if regexp.MustCompile(`User "[\w:]+" cannot create \w+ at the cluster scope`).MatchString(err.Error()) { - o.Logger().Debug("CED1007", fmt.Sprintf("Context '%s' does not have cluster-admin access:\n%v", contextName, err)) - return nil, nil, "", nil - } else { - o.Logger().Error("CED1008", fmt.Sprintf("Unknown error testing cluster-admin access for context '%s':\n%v", contextName, err)) - return nil, nil, "", err - } - } else if resp.Status.Allowed { - o.Logger().Info("CED1009", fmt.Sprintf("Using context for cluster-admin access: '%s'", contextName)) - return config, kubeClient, serverUrl, nil - } + }, + } + resp, err := kubeClient.Authorization().SelfSubjectAccessReviews().Create(subjectAccessReview) + if err != nil && regexp.MustCompile(`User "[\w:]+" cannot create \w+ at the cluster scope`).MatchString(err.Error()) { + o.Logger().Debug("CED1007", fmt.Sprintf("Context '%s' does not have cluster-admin access:\n%v", contextName, err)) + return nil, nil, nil, nil + } + if err != nil { + o.Logger().Error("CED1008", fmt.Sprintf("Unknown error testing cluster-admin access for context '%s':\n%v", contextName, err)) + return nil, nil, nil, err + } + if !resp.Status.Allowed { + o.Logger().Debug("CED1010", fmt.Sprintf("Context does not have cluster-admin access: '%s'", contextName)) + return nil, nil, nil, nil + } + + o.Logger().Info("CED1009", fmt.Sprintf("Using context for cluster-admin access: '%s'", contextName)) + adminConfig := rawConfig.DeepCopy() + adminConfig.CurrentContext = contextName + if err := clientcmdapi.MinifyConfig(adminConfig); err != nil { + return nil, nil, nil, err + } + if err := clientcmdapi.FlattenConfig(adminConfig); err != nil { + return nil, nil, nil, err } - o.Logger().Debug("CED1010", fmt.Sprintf("Context does not have cluster-admin access: '%s'", contextName)) - return nil, nil, "", nil + return config, kubeClient, adminConfig, nil } diff --git a/pkg/oc/admin/diagnostics/diagnostics.go b/pkg/oc/admin/diagnostics/diagnostics.go index 0672cd95ecb0..af7272334648 100644 --- a/pkg/oc/admin/diagnostics/diagnostics.go +++ b/pkg/oc/admin/diagnostics/diagnostics.go @@ -13,13 +13,12 @@ import ( kutilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" - kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "github.com/openshift/origin/pkg/client/config" "github.com/openshift/origin/pkg/cmd/flagtypes" - clientdiag "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/client" + poddiag "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod" + networkpoddiag "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" - networkdiag "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/network" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" "github.com/openshift/origin/pkg/oc/admin/diagnostics/options" "github.com/openshift/origin/pkg/oc/admin/diagnostics/util" @@ -120,7 +119,7 @@ func NewCmdDiagnostics(name string, fullName string, out io.Writer) *cobra.Comma Use: name, Short: "Diagnose common cluster problems", Long: fmt.Sprintf(longDescription, fullName), - Run: commandRunFunc(o), + Run: util.CommandRunFunc(o), } cmd.SetOutput(out) // for output re: usage / help o.bindCommonFlags(cmd.Flags()) @@ -135,8 +134,8 @@ func NewCmdDiagnostics(name string, fullName string, out io.Writer) *cobra.Comma } // add hidden in-pod subcommands cmd.AddCommand( - NewCommandPodDiagnostics(clientdiag.InPodDiagnosticRecommendedName, out), - NewCommandNetworkPodDiagnostics(networkdiag.InPodNetworkCheckRecommendedName, out), + poddiag.NewCommandPodDiagnostics(poddiag.InPodDiagnosticRecommendedName, out), + networkpoddiag.NewCommandNetworkPodDiagnostics(networkpoddiag.InPodNetworkCheckRecommendedName, out), ) return cmd @@ -154,7 +153,7 @@ func NewCmdDiagnosticsAll(name string, fullName string, out io.Writer, available Use: name, Short: "Diagnose common cluster problems", Long: fmt.Sprintf(longDescriptionAll, fullName), - Run: commandRunFunc(o), + Run: util.CommandRunFunc(o), } cmd.SetOutput(out) // for output re: usage / help o.bindCommonFlags(cmd.Flags()) @@ -176,7 +175,7 @@ func NewCmdDiagnosticsIndividual(name string, fullName string, out io.Writer, di Use: name, Short: diagnostic.Description(), Long: fmt.Sprintf(longDescriptionIndividual, diagnostic.Name(), diagnostic.Description()), - Run: commandRunFunc(o), + Run: util.CommandRunFunc(o), Aliases: []string{diagnostic.Name()}, } cmd.SetOutput(out) // for output re: usage / help @@ -194,27 +193,6 @@ func NewCmdDiagnosticsIndividual(name string, fullName string, out io.Writer, di return cmd } -type optionsRunner interface { - Logger() *log.Logger - Complete(*cobra.Command, []string) error - RunDiagnostics() error -} - -// returns a shared function that runs when one of these Commands actually executes -func commandRunFunc(o optionsRunner) func(c *cobra.Command, args []string) { - return func(c *cobra.Command, args []string) { - kcmdutil.CheckErr(o.Complete(c, args)) - - if err := o.RunDiagnostics(); err != nil { - o.Logger().Error("CED3001", fmt.Sprintf("Encountered fatal error while building diagnostics: %s", err.Error())) - } - o.Logger().Summary() - if o.Logger().ErrorsSeen() { - os.Exit(1) - } - } -} - // returns the logger built according to options (must be Complete()ed) func (o *DiagnosticsOptions) Logger() *log.Logger { return o.logger diff --git a/pkg/oc/admin/diagnostics/diagnostics/pod/auth.go b/pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod/auth.go similarity index 99% rename from pkg/oc/admin/diagnostics/diagnostics/pod/auth.go rename to pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod/auth.go index 17cd353a2931..84e8910b3d52 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/pod/auth.go +++ b/pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod/auth.go @@ -1,4 +1,4 @@ -package pod +package in_pod import ( "crypto/tls" diff --git a/pkg/oc/admin/diagnostics/pod.go b/pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod/cmd.go similarity index 91% rename from pkg/oc/admin/diagnostics/pod.go rename to pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod/cmd.go index 954172eb8129..fcb9fb337760 100644 --- a/pkg/oc/admin/diagnostics/pod.go +++ b/pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod/cmd.go @@ -1,4 +1,4 @@ -package diagnostics +package in_pod import ( "fmt" @@ -11,7 +11,6 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" - poddiag "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/pod" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" "github.com/openshift/origin/pkg/oc/admin/diagnostics/options" "github.com/openshift/origin/pkg/oc/admin/diagnostics/util" @@ -34,6 +33,8 @@ func (o *PodDiagnosticsOptions) Logger() *log.Logger { } const ( + InPodDiagnosticRecommendedName = "inpod-poddiagnostic" + // Standard locations for the secrets mounted in pods StandardMasterCaPath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" StandardTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token" @@ -55,7 +56,7 @@ func NewCommandPodDiagnostics(name string, out io.Writer) *cobra.Command { Use: name, Short: "Within a pod, run pod diagnostics", Long: fmt.Sprintf(longPodDiagDescription), - Run: commandRunFunc(o), + Run: util.CommandRunFunc(o), Hidden: true, } cmd.SetOutput(out) // for output re: usage / help @@ -106,7 +107,7 @@ func (o PodDiagnosticsOptions) RunDiagnostics() error { var ( // availablePodDiagnostics contains the names of host diagnostics that can be executed // during a single run of diagnostics. Add more diagnostics to the list as they are defined. - availablePodDiagnostics = sets.NewString(poddiag.PodCheckDnsName, poddiag.PodCheckAuthName) + availablePodDiagnostics = sets.NewString(PodCheckDnsName, PodCheckAuthName) ) // buildPodDiagnostics builds host Diagnostic objects based on the host environment. @@ -122,11 +123,11 @@ func (o PodDiagnosticsOptions) buildPodDiagnostics() ([]types.Diagnostic, error) for _, diagnosticName := range requestedDiagnostics { switch diagnosticName { - case poddiag.PodCheckDnsName: - diagnostics = append(diagnostics, poddiag.PodCheckDns{}) + case PodCheckDnsName: + diagnostics = append(diagnostics, PodCheckDns{}) - case poddiag.PodCheckAuthName: - diagnostics = append(diagnostics, poddiag.PodCheckAuth{ + case PodCheckAuthName: + diagnostics = append(diagnostics, PodCheckAuth{ MasterCaPath: StandardMasterCaPath, TokenPath: StandardTokenPath, MasterUrl: StandardMasterUrl, diff --git a/pkg/oc/admin/diagnostics/diagnostics/pod/dns.go b/pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod/dns.go similarity index 99% rename from pkg/oc/admin/diagnostics/diagnostics/pod/dns.go rename to pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod/dns.go index 0f1adb28b3d1..7f6b0f724802 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/pod/dns.go +++ b/pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod/dns.go @@ -1,4 +1,4 @@ -package pod +package in_pod import ( "fmt" diff --git a/pkg/oc/admin/diagnostics/diagnostics/pod/util.go b/pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod/util.go similarity index 99% rename from pkg/oc/admin/diagnostics/diagnostics/pod/util.go rename to pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod/util.go index 71b2e2c67a7f..d68ff8a1e326 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/pod/util.go +++ b/pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod/util.go @@ -1,4 +1,4 @@ -package pod +package in_pod import ( "fmt" diff --git a/pkg/oc/admin/diagnostics/diagnostics/client/run_diagnostics_pod.go b/pkg/oc/admin/diagnostics/diagnostics/client/pod/run_diagnostics_pod.go similarity index 95% rename from pkg/oc/admin/diagnostics/diagnostics/client/run_diagnostics_pod.go rename to pkg/oc/admin/diagnostics/diagnostics/client/pod/run_diagnostics_pod.go index fdf788c8ac8e..11e3a6503221 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/client/run_diagnostics_pod.go +++ b/pkg/oc/admin/diagnostics/diagnostics/client/pod/run_diagnostics_pod.go @@ -1,4 +1,4 @@ -package client +package pod import ( "bufio" @@ -15,15 +15,15 @@ import ( kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "github.com/openshift/origin/pkg/cmd/util/variable" + poddiag "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/client/pod/in_pod" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" osclientcmd "github.com/openshift/origin/pkg/oc/cli/util/clientcmd" ) const ( - InPodDiagnosticRecommendedName = "inpod-poddiagnostic" - DiagnosticPodName = "DiagnosticPod" - ImageTemplateParam = "images" - LatestImageParam = "latest-images" + DiagnosticPodName = "DiagnosticPod" + ImageTemplateParam = "images" + LatestImageParam = "latest-images" ) // DiagnosticPod is a diagnostic that runs a diagnostic pod and relays the results. @@ -88,7 +88,7 @@ func (d *DiagnosticPod) runDiagnosticPod(r types.DiagnosticResult) { { Name: "pod-diagnostics", Image: imageName, - Command: []string{"oc", "adm", "diagnostics", InPodDiagnosticRecommendedName, "-l", strconv.Itoa(loglevel)}, + Command: []string{"oc", "adm", "diagnostics", poddiag.InPodDiagnosticRecommendedName, "-l", strconv.Itoa(loglevel)}, }, }, }, diff --git a/pkg/oc/admin/diagnostics/network_pod.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/cmd.go similarity index 84% rename from pkg/oc/admin/diagnostics/network_pod.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/cmd.go index e2b11c1ca257..556abe57ba40 100644 --- a/pkg/oc/admin/diagnostics/network_pod.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/cmd.go @@ -1,4 +1,4 @@ -package diagnostics +package in_pod import ( "fmt" @@ -12,13 +12,16 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" - networkdiag "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" "github.com/openshift/origin/pkg/oc/admin/diagnostics/options" "github.com/openshift/origin/pkg/oc/admin/diagnostics/util" osclientcmd "github.com/openshift/origin/pkg/oc/cli/util/clientcmd" ) +const ( + InPodNetworkCheckRecommendedName = "inpod-networkcheck" +) + // NetworkPodDiagnosticsOptions holds values received from environment variables // for the command to operate. type NetworkPodDiagnosticsOptions struct { @@ -38,7 +41,7 @@ log the results so that the calling diagnostic can report them. var ( // availableNetworkPodDiagnostics contains the names of network diagnostics that can be executed // during a single run of diagnostics. Add more diagnostics to the list as they are defined. - availableNetworkPodDiagnostics = sets.NewString(networkdiag.CheckNodeNetworkName, networkdiag.CheckPodNetworkName, networkdiag.CheckExternalNetworkName, networkdiag.CheckServiceNetworkName, networkdiag.CollectNetworkInfoName) + availableNetworkPodDiagnostics = sets.NewString(CheckNodeNetworkName, CheckPodNetworkName, CheckExternalNetworkName, CheckServiceNetworkName, CollectNetworkInfoName) ) // NewCommandNetworkPodDiagnostics is the command for running network diagnostics. @@ -52,7 +55,7 @@ func NewCommandNetworkPodDiagnostics(name string, out io.Writer) *cobra.Command Use: name, Short: "Within a privileged pod, run network diagnostics", Long: fmt.Sprintf(longNetworkPodDiagDescription), - Run: commandRunFunc(o), + Run: util.CommandRunFunc(o), Hidden: true, } cmd.SetOutput(out) // for output re: usage / help @@ -128,30 +131,30 @@ func (o NetworkPodDiagnosticsOptions) buildNetworkPodDiagnostics() ([]types.Diag for _, diagnosticName := range requestedDiagnostics { switch diagnosticName { - case networkdiag.CheckNodeNetworkName: - diagnostics = append(diagnostics, networkdiag.CheckNodeNetwork{ + case CheckNodeNetworkName: + diagnostics = append(diagnostics, CheckNodeNetwork{ KubeClient: kubeClient, }) - case networkdiag.CheckPodNetworkName: - diagnostics = append(diagnostics, networkdiag.CheckPodNetwork{ + case CheckPodNetworkName: + diagnostics = append(diagnostics, CheckPodNetwork{ KubeClient: kubeClient, NetNamespacesClient: networkClient.Network(), ClusterNetworkClient: networkClient.Network(), }) - case networkdiag.CheckExternalNetworkName: - diagnostics = append(diagnostics, networkdiag.CheckExternalNetwork{}) + case CheckExternalNetworkName: + diagnostics = append(diagnostics, CheckExternalNetwork{}) - case networkdiag.CheckServiceNetworkName: - diagnostics = append(diagnostics, networkdiag.CheckServiceNetwork{ + case CheckServiceNetworkName: + diagnostics = append(diagnostics, CheckServiceNetwork{ KubeClient: kubeClient, NetNamespacesClient: networkClient.Network(), ClusterNetworkClient: networkClient.Network(), }) - case networkdiag.CollectNetworkInfoName: - diagnostics = append(diagnostics, networkdiag.CollectNetworkInfo{ + case CollectNetworkInfoName: + diagnostics = append(diagnostics, CollectNetworkInfo{ KubeClient: kubeClient, }) diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/collect.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/collect.go similarity index 97% rename from pkg/oc/admin/diagnostics/diagnostics/networkpod/collect.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/collect.go index 521e52c8f07c..b83cf9714f5a 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/networkpod/collect.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/collect.go @@ -1,4 +1,4 @@ -package network +package in_pod import ( "errors" @@ -7,7 +7,7 @@ import ( kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod/util" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" ) diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/external.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/external.go similarity index 99% rename from pkg/oc/admin/diagnostics/diagnostics/networkpod/external.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/external.go index d7ea0db41602..f517d6889301 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/networkpod/external.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/external.go @@ -1,4 +1,4 @@ -package network +package in_pod import ( "fmt" diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/node.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/node.go similarity index 98% rename from pkg/oc/admin/diagnostics/diagnostics/networkpod/node.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/node.go index 560d679f233c..0d3fcff6db49 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/networkpod/node.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/node.go @@ -1,4 +1,4 @@ -package network +package in_pod import ( "errors" @@ -10,7 +10,7 @@ import ( kcontainer "k8s.io/kubernetes/pkg/kubelet/container" kexec "k8s.io/utils/exec" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod/util" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" ) diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/pod.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/pod.go similarity index 99% rename from pkg/oc/admin/diagnostics/diagnostics/networkpod/pod.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/pod.go index f4e88969d065..4a22b1bdc780 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/networkpod/pod.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/pod.go @@ -1,4 +1,4 @@ -package network +package in_pod import ( "errors" @@ -13,7 +13,7 @@ import ( "github.com/openshift/origin/pkg/network" networktypedclient "github.com/openshift/origin/pkg/network/generated/internalclientset/typed/network/internalversion" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod/util" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" ) diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/service.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/service.go similarity index 99% rename from pkg/oc/admin/diagnostics/diagnostics/networkpod/service.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/service.go index 33e37ad768c9..bb73af7d5958 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/networkpod/service.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/service.go @@ -1,4 +1,4 @@ -package network +package in_pod import ( "errors" @@ -13,7 +13,7 @@ import ( "github.com/openshift/origin/pkg/network" networktypedclient "github.com/openshift/origin/pkg/network/generated/internalclientset/typed/network/internalversion" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod/util" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" ) diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/util/log.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util/log.go similarity index 100% rename from pkg/oc/admin/diagnostics/diagnostics/networkpod/util/log.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util/log.go diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/util/util.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util/util.go similarity index 100% rename from pkg/oc/admin/diagnostics/diagnostics/networkpod/util/util.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util/util.go diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/util/util_test.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util/util_test.go similarity index 100% rename from pkg/oc/admin/diagnostics/diagnostics/networkpod/util/util_test.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util/util_test.go diff --git a/pkg/oc/admin/diagnostics/diagnostics/network/objects.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/objects.go similarity index 99% rename from pkg/oc/admin/diagnostics/diagnostics/network/objects.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/objects.go index a4eea8cb3ee0..cd70e802d8c6 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/network/objects.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/objects.go @@ -10,7 +10,7 @@ import ( kclientcmd "k8s.io/client-go/tools/clientcmd" kapi "k8s.io/kubernetes/pkg/apis/core" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod/util" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util" ) const ( diff --git a/pkg/oc/admin/diagnostics/diagnostics/network/results.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/results.go similarity index 99% rename from pkg/oc/admin/diagnostics/diagnostics/network/results.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/results.go index 363306c59c99..45419ea028d7 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/network/results.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/results.go @@ -17,7 +17,7 @@ import ( kerrs "k8s.io/apimachinery/pkg/util/errors" kapi "k8s.io/kubernetes/pkg/apis/core" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod/util" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util" ) func (d *NetworkDiagnostic) CollectNetworkPodLogs() error { diff --git a/pkg/oc/admin/diagnostics/diagnostics/network/run_pod.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/run_pod.go similarity index 93% rename from pkg/oc/admin/diagnostics/diagnostics/network/run_pod.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/run_pod.go index 902c9896fafe..034a20485306 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/network/run_pod.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/run_pod.go @@ -16,24 +16,25 @@ import ( kvalidation "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/storage/names" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" kapi "k8s.io/kubernetes/pkg/apis/core" kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" networktypedclient "github.com/openshift/origin/pkg/network/generated/internalclientset/typed/network/internalversion" + networkpoddiag "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod/util" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" osclientcmd "github.com/openshift/origin/pkg/oc/cli/util/clientcmd" ) const ( - InPodNetworkCheckRecommendedName = "inpod-networkcheck" - NetworkDiagnosticName = "NetworkCheck" - FlagNetworkDiagLogDir = "logdir" - FlagNetworkDiagPodImage = "pod-image" - FlagNetworkDiagTestPodImage = "test-pod-image" - FlagNetworkDiagTestPodProtocol = "test-pod-protocol" - FlagNetworkDiagTestPodPort = "test-pod-port" + NetworkDiagnosticName = "NetworkCheck" + FlagNetworkDiagLogDir = "logdir" + FlagNetworkDiagPodImage = "pod-image" + FlagNetworkDiagTestPodImage = "test-pod-image" + FlagNetworkDiagTestPodProtocol = "test-pod-protocol" + FlagNetworkDiagTestPodPort = "test-pod-port" ) // NetworkDiagnostic is a diagnostic that runs a network diagnostic pod and relays the results. @@ -44,6 +45,7 @@ type NetworkDiagnostic struct { ClientFlags *flag.FlagSet Level int Factory *osclientcmd.Factory + RawConfig *clientcmdapi.Config PreventModification bool LogDir string PodImage string @@ -112,8 +114,6 @@ func (d *NetworkDiagnostic) CanRun() (bool, error) { return false, errors.New("must have kube client") } else if d.NetNamespacesClient == nil || d.ClusterNetworkClient == nil { return false, errors.New("must have openshift client") - } else if _, err := d.getKubeConfig(); err != nil { - return false, err } return true, nil } @@ -182,7 +182,7 @@ func (d *NetworkDiagnostic) runNetworkDiagnostic() { // In Collection phase, results from each node are moved to the user machine where the CLI cmd is executed. // TEST Phase: Run network diagnostic pod on all valid nodes in parallel - command := fmt.Sprintf("oc adm diagnostics %s -l %d", InPodNetworkCheckRecommendedName, loglevel) + command := fmt.Sprintf("oc adm diagnostics %s -l %d", networkpoddiag.InPodNetworkCheckRecommendedName, loglevel) if err := d.runNetworkPod(command); err != nil { d.res.Error("DNet2006", err, err.Error()) return diff --git a/pkg/oc/admin/diagnostics/diagnostics/network/setup.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/setup.go similarity index 91% rename from pkg/oc/admin/diagnostics/diagnostics/network/setup.go rename to pkg/oc/admin/diagnostics/diagnostics/cluster/network/setup.go index 7231ad4ecac4..9670d4accfc5 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/network/setup.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/network/setup.go @@ -2,25 +2,28 @@ package network // Set up test environment needed for network diagnostics import ( + "bytes" "fmt" - "io/ioutil" "strings" "time" kerrs "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" kerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/storage/names" kclientcmd "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/clientcmd/api/latest" kapi "k8s.io/kubernetes/pkg/apis/core" + cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/printers" - "github.com/openshift/origin/pkg/client/config" "github.com/openshift/origin/pkg/network" networkapi "github.com/openshift/origin/pkg/network/apis/network" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod/util" - diagutil "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/util" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util" ) func (d *NetworkDiagnostic) TestSetup() error { @@ -273,20 +276,23 @@ func (d *NetworkDiagnostic) makeNamespaceGlobal(nsName string) error { }) } +// turn a raw config object into its string representation (kubeconfig) func (d *NetworkDiagnostic) getKubeConfig() ([]byte, error) { - // KubeConfig path search order: - // 1. User given config path - // 2. Default admin config paths - // 3. Default openshift client config search paths - paths := []string{} - paths = append(paths, d.ClientFlags.Lookup(config.OpenShiftConfigFlagName).Value.String()) - paths = append(paths, diagutil.AdminKubeConfigPaths...) - paths = append(paths, config.NewOpenShiftClientConfigLoadingRules().Precedence...) + var b bytes.Buffer - for _, path := range paths { - if configData, err := ioutil.ReadFile(path); err == nil { - return configData, nil - } + // there does not seem to be a simple DefaultPrinter to invoke; create one + options := &printers.PrintOptions{ + OutputFormatType: "yaml", + AllowMissingKeys: true, + } + printer, err := cmdutil.PrinterForOptions(meta.NewDefaultRESTMapper(nil, nil), latest.Scheme, nil, []runtime.Decoder{latest.Codec}, options) + if err != nil { + return nil, fmt.Errorf("from PrinterForOptions: %#v", err) + } + printer = printers.NewVersionedPrinter(printer, latest.Scheme, latest.ExternalVersion) + + if err := printer.PrintObj(d.RawConfig, &b); err != nil { + return nil, fmt.Errorf("from PrintObj: %#v", err) } - return nil, fmt.Errorf("Unable to find kube config") + return b.Bytes(), nil } diff --git a/pkg/oc/admin/diagnostics/diagnostics/log/text.go b/pkg/oc/admin/diagnostics/diagnostics/log/text.go index 959bc75218be..4038dd48037e 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/log/text.go +++ b/pkg/oc/admin/diagnostics/diagnostics/log/text.go @@ -3,11 +3,10 @@ package log import ( "fmt" "io" - "os" "strings" ct "github.com/daviddengcn/go-colortext" - "github.com/docker/docker/pkg/term" + "github.com/openshift/origin/pkg/cmd/util/term" ) type textLogger struct { @@ -19,19 +18,13 @@ type textLogger struct { func newTextLogger(out io.Writer) *textLogger { logger := &textLogger{out: out, lastNewline: true} - if IsTerminal(out) { + if term.IsTerminalWriter(out) { // only want color sequences to humans, not redirected output (logs, "less", etc.) logger.ttyOutput = true } return logger } -// cribbed a la "github.com/openshift/origin/pkg/cmd/util" -func IsTerminal(w io.Writer) bool { - file, ok := w.(*os.File) - return ok && term.IsTerminal(file.Fd()) -} - func (t *textLogger) Write(entry Entry) { if t.ttyOutput { ct.ChangeColor(entry.Level.Color, entry.Level.Bright, ct.None, false) diff --git a/pkg/oc/admin/diagnostics/util/util.go b/pkg/oc/admin/diagnostics/util/util.go index 27a980dea986..4d4e9df8cacf 100644 --- a/pkg/oc/admin/diagnostics/util/util.go +++ b/pkg/oc/admin/diagnostics/util/util.go @@ -2,9 +2,12 @@ package util import ( "fmt" + "github.com/spf13/cobra" + "os" "runtime/debug" "k8s.io/apimachinery/pkg/util/sets" + kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" @@ -66,3 +69,24 @@ func RunDiagnostics(logger *log.Logger, diagnostics []types.Diagnostic) error { } return nil } + +type OptionsRunner interface { + Logger() *log.Logger + Complete(*cobra.Command, []string) error + RunDiagnostics() error +} + +// returns a shared function that runs when one of these Commands actually executes +func CommandRunFunc(o OptionsRunner) func(c *cobra.Command, args []string) { + return func(c *cobra.Command, args []string) { + kcmdutil.CheckErr(o.Complete(c, args)) + + if err := o.RunDiagnostics(); err != nil { + o.Logger().Error("CED3001", fmt.Sprintf("Encountered fatal error while building diagnostics: %s", err.Error())) + } + o.Logger().Summary() + if o.Logger().ErrorsSeen() { + os.Exit(1) + } + } +}