From 241fd4fbabc4804ebecdad45a4d996a07a5cdf75 Mon Sep 17 00:00:00 2001 From: Luke Meyer Date: Tue, 26 Sep 2017 21:20:49 -0400 Subject: [PATCH 1/2] diagnostics: enable per-diagnostic parameters Adds the ability to specify parameters for individual diagnostics on the command line (without proliferating flags). Addresses https://github.com/openshift/origin/issues/14640 --- contrib/completions/bash/oc | 1242 ++++++++++++++++- contrib/completions/zsh/oc | 1242 ++++++++++++++++- docs/man/man1/.files_generated_oc | 38 + .../oc-adm-diagnostics-aggregatedlogging.1 | 3 + docs/man/man1/oc-adm-diagnostics-all.1 | 3 + .../man/man1/oc-adm-diagnostics-analyzelogs.1 | 3 + .../man1/oc-adm-diagnostics-clusterregistry.1 | 3 + .../oc-adm-diagnostics-clusterrolebindings.1 | 3 + .../man1/oc-adm-diagnostics-clusterroles.1 | 3 + .../man1/oc-adm-diagnostics-clusterrouter.1 | 3 + .../man1/oc-adm-diagnostics-configcontexts.1 | 3 + .../man1/oc-adm-diagnostics-diagnosticpod.1 | 3 + .../man1/oc-adm-diagnostics-etcdwritevolume.1 | 3 + .../oc-adm-diagnostics-masterconfigcheck.1 | 3 + docs/man/man1/oc-adm-diagnostics-masternode.1 | 3 + .../man1/oc-adm-diagnostics-metricsapiproxy.1 | 3 + .../man1/oc-adm-diagnostics-networkcheck.1 | 3 + .../man1/oc-adm-diagnostics-nodeconfigcheck.1 | 3 + .../man1/oc-adm-diagnostics-nodedefinitions.1 | 3 + ...m-diagnostics-routecertificatevalidation.1 | 3 + .../oc-adm-diagnostics-serviceexternalips.1 | 3 + docs/man/man1/oc-adm-diagnostics-unitstatus.1 | 3 + .../oc-ex-diagnostics-aggregatedlogging.1 | 3 + docs/man/man1/oc-ex-diagnostics-all.1 | 3 + docs/man/man1/oc-ex-diagnostics-analyzelogs.1 | 3 + .../man1/oc-ex-diagnostics-clusterregistry.1 | 3 + .../oc-ex-diagnostics-clusterrolebindings.1 | 3 + .../man/man1/oc-ex-diagnostics-clusterroles.1 | 3 + .../man1/oc-ex-diagnostics-clusterrouter.1 | 3 + .../man1/oc-ex-diagnostics-configcontexts.1 | 3 + .../man1/oc-ex-diagnostics-diagnosticpod.1 | 3 + .../man1/oc-ex-diagnostics-etcdwritevolume.1 | 3 + .../oc-ex-diagnostics-masterconfigcheck.1 | 3 + docs/man/man1/oc-ex-diagnostics-masternode.1 | 3 + .../man1/oc-ex-diagnostics-metricsapiproxy.1 | 3 + .../man/man1/oc-ex-diagnostics-networkcheck.1 | 3 + .../man1/oc-ex-diagnostics-nodeconfigcheck.1 | 3 + .../man1/oc-ex-diagnostics-nodedefinitions.1 | 3 + ...x-diagnostics-routecertificatevalidation.1 | 3 + .../oc-ex-diagnostics-serviceexternalips.1 | 3 + docs/man/man1/oc-ex-diagnostics-unitstatus.1 | 3 + pkg/oc/admin/diagnostics/client.go | 52 +- pkg/oc/admin/diagnostics/cluster.go | 34 +- pkg/oc/admin/diagnostics/config.go | 7 +- pkg/oc/admin/diagnostics/diagnostics.go | 391 +++--- .../diagnostics/client/config_contexts.go | 7 + .../diagnostics/client/run_diagnostics_pod.go | 19 +- .../cluster/aggregated_logging/diagnostic.go | 23 +- .../diagnostics/cluster/master_node.go | 4 + .../diagnostics/cluster/metrics.go | 4 + .../diagnostics/cluster/node_definitions.go | 6 +- .../diagnostics/cluster/registry.go | 4 + .../diagnostics/cluster/rolebindings.go | 4 + .../diagnostics/diagnostics/cluster/roles.go | 4 + .../diagnostics/cluster/route_validation.go | 4 + .../diagnostics/diagnostics/cluster/router.go | 6 +- .../diagnostics/cluster/service_externalip.go | 28 +- .../diagnostics/host/check_master_config.go | 30 +- .../diagnostics/host/check_node_config.go | 6 + .../diagnostics/{cluster => host}/etcd.go | 102 +- .../diagnostics/diagnostics/host/util.go | 16 +- .../diagnostics/network/run_pod.go | 46 +- .../diagnostics/networkpod/collect.go | 4 + .../diagnostics/networkpod/external.go | 4 + .../diagnostics/networkpod/node.go | 4 + .../diagnostics/diagnostics/networkpod/pod.go | 4 + .../diagnostics/networkpod/service.go | 4 + .../admin/diagnostics/diagnostics/pod/auth.go | 4 + .../admin/diagnostics/diagnostics/pod/dns.go | 4 + .../diagnostics/systemd/analyze_logs.go | 4 + .../diagnostics/systemd/unit_status.go | 6 + .../diagnostics/types/diagnostic.go | 54 + pkg/oc/admin/diagnostics/etcd.go | 91 -- pkg/oc/admin/diagnostics/host.go | 45 +- pkg/oc/admin/diagnostics/options/flaginfo.go | 8 - test/cmd/diagnostics.sh | 26 +- 76 files changed, 3283 insertions(+), 412 deletions(-) create mode 100644 docs/man/man1/oc-adm-diagnostics-aggregatedlogging.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-all.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-analyzelogs.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-clusterregistry.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-clusterrolebindings.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-clusterroles.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-clusterrouter.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-configcontexts.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-diagnosticpod.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-etcdwritevolume.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-masterconfigcheck.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-masternode.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-metricsapiproxy.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-networkcheck.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-nodeconfigcheck.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-nodedefinitions.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-routecertificatevalidation.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-serviceexternalips.1 create mode 100644 docs/man/man1/oc-adm-diagnostics-unitstatus.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-aggregatedlogging.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-all.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-analyzelogs.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-clusterregistry.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-clusterrolebindings.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-clusterroles.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-clusterrouter.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-configcontexts.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-diagnosticpod.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-etcdwritevolume.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-masterconfigcheck.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-masternode.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-metricsapiproxy.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-networkcheck.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-nodeconfigcheck.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-nodedefinitions.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-routecertificatevalidation.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-serviceexternalips.1 create mode 100644 docs/man/man1/oc-ex-diagnostics-unitstatus.1 rename pkg/oc/admin/diagnostics/diagnostics/{cluster => host}/etcd.go (55%) delete mode 100644 pkg/oc/admin/diagnostics/etcd.go diff --git a/contrib/completions/bash/oc b/contrib/completions/bash/oc index 87c26d80a009..0c43c136f413 100644 --- a/contrib/completions/bash/oc +++ b/contrib/completions/bash/oc @@ -2388,10 +2388,1238 @@ _oc_adm_create-provider-selection-template() noun_aliases=() } +_oc_adm_diagnostics_aggregatedlogging() +{ + last_command="oc_adm_diagnostics_aggregatedlogging" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_all() +{ + last_command="oc_adm_diagnostics_all" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--diagnosticpod-images=") + local_nonpersistent_flags+=("--diagnosticpod-images=") + flags+=("--diagnosticpod-latest-images") + local_nonpersistent_flags+=("--diagnosticpod-latest-images") + flags+=("--etcdwritevolume-duration=") + local_nonpersistent_flags+=("--etcdwritevolume-duration=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--networkcheck-logdir=") + local_nonpersistent_flags+=("--networkcheck-logdir=") + flags+=("--networkcheck-pod-image=") + local_nonpersistent_flags+=("--networkcheck-pod-image=") + flags+=("--networkcheck-test-pod-image=") + local_nonpersistent_flags+=("--networkcheck-test-pod-image=") + flags+=("--networkcheck-test-pod-port=") + local_nonpersistent_flags+=("--networkcheck-test-pod-port=") + flags+=("--networkcheck-test-pod-protocol=") + local_nonpersistent_flags+=("--networkcheck-test-pod-protocol=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_analyzelogs() +{ + last_command="oc_adm_diagnostics_analyzelogs" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_clusterregistry() +{ + last_command="oc_adm_diagnostics_clusterregistry" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_clusterrolebindings() +{ + last_command="oc_adm_diagnostics_clusterrolebindings" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_clusterroles() +{ + last_command="oc_adm_diagnostics_clusterroles" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_clusterrouter() +{ + last_command="oc_adm_diagnostics_clusterrouter" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_configcontexts() +{ + last_command="oc_adm_diagnostics_configcontexts" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_diagnosticpod() +{ + last_command="oc_adm_diagnostics_diagnosticpod" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--images=") + local_nonpersistent_flags+=("--images=") + flags+=("--latest-images") + local_nonpersistent_flags+=("--latest-images") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_etcdwritevolume() +{ + last_command="oc_adm_diagnostics_etcdwritevolume" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--duration=") + local_nonpersistent_flags+=("--duration=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_masterconfigcheck() +{ + last_command="oc_adm_diagnostics_masterconfigcheck" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_masternode() +{ + last_command="oc_adm_diagnostics_masternode" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_metricsapiproxy() +{ + last_command="oc_adm_diagnostics_metricsapiproxy" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_networkcheck() +{ + last_command="oc_adm_diagnostics_networkcheck" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--logdir=") + local_nonpersistent_flags+=("--logdir=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--pod-image=") + local_nonpersistent_flags+=("--pod-image=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--test-pod-image=") + local_nonpersistent_flags+=("--test-pod-image=") + flags+=("--test-pod-port=") + local_nonpersistent_flags+=("--test-pod-port=") + flags+=("--test-pod-protocol=") + local_nonpersistent_flags+=("--test-pod-protocol=") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_nodeconfigcheck() +{ + last_command="oc_adm_diagnostics_nodeconfigcheck" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_nodedefinitions() +{ + last_command="oc_adm_diagnostics_nodedefinitions" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_routecertificatevalidation() +{ + last_command="oc_adm_diagnostics_routecertificatevalidation" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_serviceexternalips() +{ + last_command="oc_adm_diagnostics_serviceexternalips" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_unitstatus() +{ + last_command="oc_adm_diagnostics_unitstatus" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _oc_adm_diagnostics() { last_command="oc_adm_diagnostics" commands=() + commands+=("aggregatedlogging") + commands+=("all") + commands+=("analyzelogs") + commands+=("clusterregistry") + commands+=("clusterrolebindings") + commands+=("clusterroles") + commands+=("clusterrouter") + commands+=("configcontexts") + commands+=("diagnosticpod") + commands+=("etcdwritevolume") + commands+=("masterconfigcheck") + commands+=("masternode") + commands+=("metricsapiproxy") + commands+=("networkcheck") + commands+=("nodeconfigcheck") + commands+=("nodedefinitions") + commands+=("routecertificatevalidation") + commands+=("serviceexternalips") + commands+=("unitstatus") flags=() two_word_flags=() @@ -2412,26 +3640,12 @@ _oc_adm_diagnostics() local_nonpersistent_flags+=("--diaglevel=") flags+=("--host") local_nonpersistent_flags+=("--host") - flags+=("--images=") - local_nonpersistent_flags+=("--images=") - flags+=("--latest-images") - local_nonpersistent_flags+=("--latest-images") flags+=("--loglevel=") local_nonpersistent_flags+=("--loglevel=") flags+=("--logspec=") local_nonpersistent_flags+=("--logspec=") flags+=("--master-config=") local_nonpersistent_flags+=("--master-config=") - flags+=("--network-logdir=") - local_nonpersistent_flags+=("--network-logdir=") - flags+=("--network-pod-image=") - local_nonpersistent_flags+=("--network-pod-image=") - flags+=("--network-test-pod-image=") - local_nonpersistent_flags+=("--network-test-pod-image=") - flags+=("--network-test-pod-port=") - local_nonpersistent_flags+=("--network-test-pod-port=") - flags+=("--network-test-pod-protocol=") - local_nonpersistent_flags+=("--network-test-pod-protocol=") flags+=("--node-config=") local_nonpersistent_flags+=("--node-config=") flags+=("--prevent-modification") diff --git a/contrib/completions/zsh/oc b/contrib/completions/zsh/oc index f67366b97b09..5e50fa24f82b 100644 --- a/contrib/completions/zsh/oc +++ b/contrib/completions/zsh/oc @@ -2530,10 +2530,1238 @@ _oc_adm_create-provider-selection-template() noun_aliases=() } +_oc_adm_diagnostics_aggregatedlogging() +{ + last_command="oc_adm_diagnostics_aggregatedlogging" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_all() +{ + last_command="oc_adm_diagnostics_all" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--diagnosticpod-images=") + local_nonpersistent_flags+=("--diagnosticpod-images=") + flags+=("--diagnosticpod-latest-images") + local_nonpersistent_flags+=("--diagnosticpod-latest-images") + flags+=("--etcdwritevolume-duration=") + local_nonpersistent_flags+=("--etcdwritevolume-duration=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--networkcheck-logdir=") + local_nonpersistent_flags+=("--networkcheck-logdir=") + flags+=("--networkcheck-pod-image=") + local_nonpersistent_flags+=("--networkcheck-pod-image=") + flags+=("--networkcheck-test-pod-image=") + local_nonpersistent_flags+=("--networkcheck-test-pod-image=") + flags+=("--networkcheck-test-pod-port=") + local_nonpersistent_flags+=("--networkcheck-test-pod-port=") + flags+=("--networkcheck-test-pod-protocol=") + local_nonpersistent_flags+=("--networkcheck-test-pod-protocol=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_analyzelogs() +{ + last_command="oc_adm_diagnostics_analyzelogs" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_clusterregistry() +{ + last_command="oc_adm_diagnostics_clusterregistry" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_clusterrolebindings() +{ + last_command="oc_adm_diagnostics_clusterrolebindings" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_clusterroles() +{ + last_command="oc_adm_diagnostics_clusterroles" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_clusterrouter() +{ + last_command="oc_adm_diagnostics_clusterrouter" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_configcontexts() +{ + last_command="oc_adm_diagnostics_configcontexts" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_diagnosticpod() +{ + last_command="oc_adm_diagnostics_diagnosticpod" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--images=") + local_nonpersistent_flags+=("--images=") + flags+=("--latest-images") + local_nonpersistent_flags+=("--latest-images") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_etcdwritevolume() +{ + last_command="oc_adm_diagnostics_etcdwritevolume" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--duration=") + local_nonpersistent_flags+=("--duration=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_masterconfigcheck() +{ + last_command="oc_adm_diagnostics_masterconfigcheck" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_masternode() +{ + last_command="oc_adm_diagnostics_masternode" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_metricsapiproxy() +{ + last_command="oc_adm_diagnostics_metricsapiproxy" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_networkcheck() +{ + last_command="oc_adm_diagnostics_networkcheck" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--logdir=") + local_nonpersistent_flags+=("--logdir=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--pod-image=") + local_nonpersistent_flags+=("--pod-image=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--test-pod-image=") + local_nonpersistent_flags+=("--test-pod-image=") + flags+=("--test-pod-port=") + local_nonpersistent_flags+=("--test-pod-port=") + flags+=("--test-pod-protocol=") + local_nonpersistent_flags+=("--test-pod-protocol=") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_nodeconfigcheck() +{ + last_command="oc_adm_diagnostics_nodeconfigcheck" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_nodedefinitions() +{ + last_command="oc_adm_diagnostics_nodedefinitions" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_routecertificatevalidation() +{ + last_command="oc_adm_diagnostics_routecertificatevalidation" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_serviceexternalips() +{ + last_command="oc_adm_diagnostics_serviceexternalips" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--cluster-context=") + local_nonpersistent_flags+=("--cluster-context=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + local_nonpersistent_flags+=("--config=") + flags+=("--context=") + local_nonpersistent_flags+=("--context=") + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--prevent-modification") + local_nonpersistent_flags+=("--prevent-modification") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_oc_adm_diagnostics_unitstatus() +{ + last_command="oc_adm_diagnostics_unitstatus" + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--diaglevel=") + two_word_flags+=("-l") + local_nonpersistent_flags+=("--diaglevel=") + flags+=("--host") + local_nonpersistent_flags+=("--host") + flags+=("--loglevel=") + local_nonpersistent_flags+=("--loglevel=") + flags+=("--logspec=") + local_nonpersistent_flags+=("--logspec=") + flags+=("--master-config=") + local_nonpersistent_flags+=("--master-config=") + flags+=("--node-config=") + local_nonpersistent_flags+=("--node-config=") + flags+=("--v=") + local_nonpersistent_flags+=("--v=") + flags+=("--vmodule=") + local_nonpersistent_flags+=("--vmodule=") + flags+=("--as=") + flags+=("--as-group=") + flags+=("--cache-dir=") + flags+=("--certificate-authority=") + flags_with_completion+=("--certificate-authority") + flags_completion+=("_filedir") + flags+=("--client-certificate=") + flags_with_completion+=("--client-certificate") + flags_completion+=("_filedir") + flags+=("--client-key=") + flags_with_completion+=("--client-key") + flags_completion+=("_filedir") + flags+=("--cluster=") + flags+=("--config=") + flags_with_completion+=("--config") + flags_completion+=("_filedir") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--log-flush-frequency=") + flags+=("--match-server-version") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--request-timeout=") + flags+=("--server=") + flags+=("--token=") + flags+=("--user=") + flags+=("--version") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _oc_adm_diagnostics() { last_command="oc_adm_diagnostics" commands=() + commands+=("aggregatedlogging") + commands+=("all") + commands+=("analyzelogs") + commands+=("clusterregistry") + commands+=("clusterrolebindings") + commands+=("clusterroles") + commands+=("clusterrouter") + commands+=("configcontexts") + commands+=("diagnosticpod") + commands+=("etcdwritevolume") + commands+=("masterconfigcheck") + commands+=("masternode") + commands+=("metricsapiproxy") + commands+=("networkcheck") + commands+=("nodeconfigcheck") + commands+=("nodedefinitions") + commands+=("routecertificatevalidation") + commands+=("serviceexternalips") + commands+=("unitstatus") flags=() two_word_flags=() @@ -2554,26 +3782,12 @@ _oc_adm_diagnostics() local_nonpersistent_flags+=("--diaglevel=") flags+=("--host") local_nonpersistent_flags+=("--host") - flags+=("--images=") - local_nonpersistent_flags+=("--images=") - flags+=("--latest-images") - local_nonpersistent_flags+=("--latest-images") flags+=("--loglevel=") local_nonpersistent_flags+=("--loglevel=") flags+=("--logspec=") local_nonpersistent_flags+=("--logspec=") flags+=("--master-config=") local_nonpersistent_flags+=("--master-config=") - flags+=("--network-logdir=") - local_nonpersistent_flags+=("--network-logdir=") - flags+=("--network-pod-image=") - local_nonpersistent_flags+=("--network-pod-image=") - flags+=("--network-test-pod-image=") - local_nonpersistent_flags+=("--network-test-pod-image=") - flags+=("--network-test-pod-port=") - local_nonpersistent_flags+=("--network-test-pod-port=") - flags+=("--network-test-pod-protocol=") - local_nonpersistent_flags+=("--network-test-pod-protocol=") flags+=("--node-config=") local_nonpersistent_flags+=("--node-config=") flags+=("--prevent-modification") diff --git a/docs/man/man1/.files_generated_oc b/docs/man/man1/.files_generated_oc index dbea9fbcabcb..4b8f511abdfc 100644 --- a/docs/man/man1/.files_generated_oc +++ b/docs/man/man1/.files_generated_oc @@ -37,6 +37,25 @@ oc-adm-create-node-config.1 oc-adm-create-provider-selection-template.1 oc-adm-create-server-cert.1 oc-adm-create-signer-cert.1 +oc-adm-diagnostics-aggregatedlogging.1 +oc-adm-diagnostics-all.1 +oc-adm-diagnostics-analyzelogs.1 +oc-adm-diagnostics-clusterregistry.1 +oc-adm-diagnostics-clusterrolebindings.1 +oc-adm-diagnostics-clusterroles.1 +oc-adm-diagnostics-clusterrouter.1 +oc-adm-diagnostics-configcontexts.1 +oc-adm-diagnostics-diagnosticpod.1 +oc-adm-diagnostics-etcdwritevolume.1 +oc-adm-diagnostics-masterconfigcheck.1 +oc-adm-diagnostics-masternode.1 +oc-adm-diagnostics-metricsapiproxy.1 +oc-adm-diagnostics-networkcheck.1 +oc-adm-diagnostics-nodeconfigcheck.1 +oc-adm-diagnostics-nodedefinitions.1 +oc-adm-diagnostics-routecertificatevalidation.1 +oc-adm-diagnostics-serviceexternalips.1 +oc-adm-diagnostics-unitstatus.1 oc-adm-diagnostics.1 oc-adm-drain.1 oc-adm-groups-add-users.1 @@ -171,6 +190,25 @@ oc-env.1 oc-ex-build-chain.1 oc-ex-config-patch.1 oc-ex-config.1 +oc-ex-diagnostics-aggregatedlogging.1 +oc-ex-diagnostics-all.1 +oc-ex-diagnostics-analyzelogs.1 +oc-ex-diagnostics-clusterregistry.1 +oc-ex-diagnostics-clusterrolebindings.1 +oc-ex-diagnostics-clusterroles.1 +oc-ex-diagnostics-clusterrouter.1 +oc-ex-diagnostics-configcontexts.1 +oc-ex-diagnostics-diagnosticpod.1 +oc-ex-diagnostics-etcdwritevolume.1 +oc-ex-diagnostics-masterconfigcheck.1 +oc-ex-diagnostics-masternode.1 +oc-ex-diagnostics-metricsapiproxy.1 +oc-ex-diagnostics-networkcheck.1 +oc-ex-diagnostics-nodeconfigcheck.1 +oc-ex-diagnostics-nodedefinitions.1 +oc-ex-diagnostics-routecertificatevalidation.1 +oc-ex-diagnostics-serviceexternalips.1 +oc-ex-diagnostics-unitstatus.1 oc-ex-diagnostics.1 oc-ex-dockergc.1 oc-ex-ipfailover.1 diff --git a/docs/man/man1/oc-adm-diagnostics-aggregatedlogging.1 b/docs/man/man1/oc-adm-diagnostics-aggregatedlogging.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-aggregatedlogging.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-all.1 b/docs/man/man1/oc-adm-diagnostics-all.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-all.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-analyzelogs.1 b/docs/man/man1/oc-adm-diagnostics-analyzelogs.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-analyzelogs.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-clusterregistry.1 b/docs/man/man1/oc-adm-diagnostics-clusterregistry.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-clusterregistry.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-clusterrolebindings.1 b/docs/man/man1/oc-adm-diagnostics-clusterrolebindings.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-clusterrolebindings.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-clusterroles.1 b/docs/man/man1/oc-adm-diagnostics-clusterroles.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-clusterroles.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-clusterrouter.1 b/docs/man/man1/oc-adm-diagnostics-clusterrouter.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-clusterrouter.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-configcontexts.1 b/docs/man/man1/oc-adm-diagnostics-configcontexts.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-configcontexts.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-diagnosticpod.1 b/docs/man/man1/oc-adm-diagnostics-diagnosticpod.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-diagnosticpod.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-etcdwritevolume.1 b/docs/man/man1/oc-adm-diagnostics-etcdwritevolume.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-etcdwritevolume.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-masterconfigcheck.1 b/docs/man/man1/oc-adm-diagnostics-masterconfigcheck.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-masterconfigcheck.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-masternode.1 b/docs/man/man1/oc-adm-diagnostics-masternode.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-masternode.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-metricsapiproxy.1 b/docs/man/man1/oc-adm-diagnostics-metricsapiproxy.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-metricsapiproxy.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-networkcheck.1 b/docs/man/man1/oc-adm-diagnostics-networkcheck.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-networkcheck.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-nodeconfigcheck.1 b/docs/man/man1/oc-adm-diagnostics-nodeconfigcheck.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-nodeconfigcheck.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-nodedefinitions.1 b/docs/man/man1/oc-adm-diagnostics-nodedefinitions.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-nodedefinitions.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-routecertificatevalidation.1 b/docs/man/man1/oc-adm-diagnostics-routecertificatevalidation.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-routecertificatevalidation.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-serviceexternalips.1 b/docs/man/man1/oc-adm-diagnostics-serviceexternalips.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-serviceexternalips.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-adm-diagnostics-unitstatus.1 b/docs/man/man1/oc-adm-diagnostics-unitstatus.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-adm-diagnostics-unitstatus.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-aggregatedlogging.1 b/docs/man/man1/oc-ex-diagnostics-aggregatedlogging.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-aggregatedlogging.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-all.1 b/docs/man/man1/oc-ex-diagnostics-all.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-all.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-analyzelogs.1 b/docs/man/man1/oc-ex-diagnostics-analyzelogs.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-analyzelogs.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-clusterregistry.1 b/docs/man/man1/oc-ex-diagnostics-clusterregistry.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-clusterregistry.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-clusterrolebindings.1 b/docs/man/man1/oc-ex-diagnostics-clusterrolebindings.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-clusterrolebindings.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-clusterroles.1 b/docs/man/man1/oc-ex-diagnostics-clusterroles.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-clusterroles.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-clusterrouter.1 b/docs/man/man1/oc-ex-diagnostics-clusterrouter.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-clusterrouter.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-configcontexts.1 b/docs/man/man1/oc-ex-diagnostics-configcontexts.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-configcontexts.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-diagnosticpod.1 b/docs/man/man1/oc-ex-diagnostics-diagnosticpod.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-diagnosticpod.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-etcdwritevolume.1 b/docs/man/man1/oc-ex-diagnostics-etcdwritevolume.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-etcdwritevolume.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-masterconfigcheck.1 b/docs/man/man1/oc-ex-diagnostics-masterconfigcheck.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-masterconfigcheck.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-masternode.1 b/docs/man/man1/oc-ex-diagnostics-masternode.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-masternode.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-metricsapiproxy.1 b/docs/man/man1/oc-ex-diagnostics-metricsapiproxy.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-metricsapiproxy.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-networkcheck.1 b/docs/man/man1/oc-ex-diagnostics-networkcheck.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-networkcheck.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-nodeconfigcheck.1 b/docs/man/man1/oc-ex-diagnostics-nodeconfigcheck.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-nodeconfigcheck.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-nodedefinitions.1 b/docs/man/man1/oc-ex-diagnostics-nodedefinitions.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-nodedefinitions.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-routecertificatevalidation.1 b/docs/man/man1/oc-ex-diagnostics-routecertificatevalidation.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-routecertificatevalidation.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-serviceexternalips.1 b/docs/man/man1/oc-ex-diagnostics-serviceexternalips.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-serviceexternalips.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/docs/man/man1/oc-ex-diagnostics-unitstatus.1 b/docs/man/man1/oc-ex-diagnostics-unitstatus.1 new file mode 100644 index 000000000000..b6fd7a0f9896 --- /dev/null +++ b/docs/man/man1/oc-ex-diagnostics-unitstatus.1 @@ -0,0 +1,3 @@ +This file is autogenerated, but we've stopped checking such files into the +repository to reduce the need for rebases. Please run hack/generate-docs.sh to +populate this file. diff --git a/pkg/oc/admin/diagnostics/client.go b/pkg/oc/admin/diagnostics/client.go index d497f3b21163..6c477edc81c7 100644 --- a/pkg/oc/admin/diagnostics/client.go +++ b/pkg/oc/admin/diagnostics/client.go @@ -11,16 +11,16 @@ import ( "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" ) -var ( - // availableClientDiagnostics contains the names of client diagnostics that can be executed - // during a single run of diagnostics. Add more diagnostics to the list as they are defined. - availableClientDiagnostics = sets.NewString(clientdiags.ConfigContextsName, clientdiags.DiagnosticPodName, networkdiags.NetworkDiagnosticName) -) +// 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{}} +} // buildClientDiagnostics builds client Diagnostic objects based on the rawConfig passed in. // Returns the Diagnostics built, "ok" bool for whether to proceed or abort, and an error if any was encountered during the building of diagnostics.) { func (o DiagnosticsOptions) buildClientDiagnostics(rawConfig *clientcmdapi.Config) ([]types.Diagnostic, bool, error) { - available := availableClientDiagnostics + available := availableClientDiagnostics().Names() networkClient, err := o.Factory.OpenshiftInternalNetworkClient() kubeClient, clientErr := o.Factory.ClientSet() @@ -30,7 +30,7 @@ func (o DiagnosticsOptions) buildClientDiagnostics(rawConfig *clientcmdapi.Confi } diagnostics := []types.Diagnostic{} - requestedDiagnostics := available.Intersection(sets.NewString(o.RequestedDiagnostics...)).List() + requestedDiagnostics := available.Intersection(sets.NewString(o.RequestedDiagnostics.List()...)).List() for _, diagnosticName := range requestedDiagnostics { switch diagnosticName { case clientdiags.ConfigContextsName: @@ -46,29 +46,23 @@ func (o DiagnosticsOptions) buildClientDiagnostics(rawConfig *clientcmdapi.Confi } } case clientdiags.DiagnosticPodName: - diagnostics = append(diagnostics, &clientdiags.DiagnosticPod{ - KubeClient: kubeClient, - Namespace: rawConfig.Contexts[rawConfig.CurrentContext].Namespace, - Level: o.LogOptions.Level, - Factory: o.Factory, - PreventModification: o.PreventModification, - ImageTemplate: o.ImageTemplate, - }) + dp := o.ParameterizedDiagnostics[diagnosticName].(*clientdiags.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: - diagnostics = append(diagnostics, &networkdiags.NetworkDiagnostic{ - KubeClient: kubeClient, - NetNamespacesClient: networkClient.Network(), - ClusterNetworkClient: networkClient.Network(), - ClientFlags: o.ClientFlags, - Level: o.LogOptions.Level, - Factory: o.Factory, - PreventModification: o.PreventModification, - LogDir: o.NetworkOptions.LogDir, - PodImage: o.NetworkOptions.PodImage, - TestPodImage: o.NetworkOptions.TestPodImage, - TestPodProtocol: o.NetworkOptions.TestPodProtocol, - TestPodPort: o.NetworkOptions.TestPodPort, - }) + 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, false, fmt.Errorf("unknown diagnostic: %v", diagnosticName) } diff --git a/pkg/oc/admin/diagnostics/cluster.go b/pkg/oc/admin/diagnostics/cluster.go index fcc673e731b2..87c9c3a4ba38 100644 --- a/pkg/oc/admin/diagnostics/cluster.go +++ b/pkg/oc/admin/diagnostics/cluster.go @@ -25,27 +25,27 @@ import ( "k8s.io/kubernetes/pkg/apis/authorization" ) -var ( - // availableClusterDiagnostics contains the names of cluster diagnostics that can be executed - // during a single run of diagnostics. Add more diagnostics to the list as they are defined. - availableClusterDiagnostics = sets.NewString( - agldiags.AggregatedLoggingName, - clustdiags.ClusterRegistryName, - clustdiags.ClusterRouterName, - clustdiags.ClusterRolesName, - clustdiags.ClusterRoleBindingsName, - clustdiags.MasterNodeName, - clustdiags.MetricsApiProxyName, - clustdiags.NodeDefinitionsName, - clustdiags.RouteCertificateValidationName, - clustdiags.ServiceExternalIPsName, - ) -) +// availableClusterDiagnostics contains the names of cluster diagnostics that can be executed +// during a single run of diagnostics. Add more diagnostics to the list as they are defined. +func availableClusterDiagnostics() types.DiagnosticList { + return types.DiagnosticList{ + &agldiags.AggregatedLogging{}, + &clustdiags.ClusterRegistry{}, + &clustdiags.ClusterRouter{}, + &clustdiags.ClusterRoles{}, + &clustdiags.ClusterRoleBindings{}, + &clustdiags.MasterNode{}, + &clustdiags.MetricsApiProxy{}, + &clustdiags.NodeDefinitions{}, + &clustdiags.RouteCertificateValidation{}, + &clustdiags.ServiceExternalIPs{}, + } +} // buildClusterDiagnostics builds cluster Diagnostic objects if a cluster-admin client can be extracted from the rawConfig passed in. // Returns the Diagnostics built, "ok" bool for whether to proceed or abort, and an error if any was encountered during the building of diagnostics.) { func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Config) ([]types.Diagnostic, bool, error) { - requestedDiagnostics := availableClusterDiagnostics.Intersection(sets.NewString(o.RequestedDiagnostics...)).List() + requestedDiagnostics := availableClusterDiagnostics().Names().Intersection(sets.NewString(o.RequestedDiagnostics.List()...)).List() if len(requestedDiagnostics) == 0 { // no diagnostics to run here return nil, true, nil // don't waste time on discovery } diff --git a/pkg/oc/admin/diagnostics/config.go b/pkg/oc/admin/diagnostics/config.go index 94f890695477..6c2d614711cf 100644 --- a/pkg/oc/admin/diagnostics/config.go +++ b/pkg/oc/admin/diagnostics/config.go @@ -11,14 +11,17 @@ import ( ) // determine if we even have a client config -func (o DiagnosticsOptions) detectClientConfig() (bool, []types.DiagnosticError, []types.DiagnosticError) { +func (o DiagnosticsOptions) detectClientConfig() (bool, bool, []types.DiagnosticError, []types.DiagnosticError) { + if o.ClientFlags == nil { + return false, false, []types.DiagnosticError{}, []types.DiagnosticError{} + } diagnostic := &clientdiagnostics.ConfigLoading{ConfFlagName: config.OpenShiftConfigFlagName, ClientFlags: o.ClientFlags} o.Logger.Notice("CED2011", "Determining if client configuration exists for client/cluster diagnostics") result := diagnostic.Check() for _, entry := range result.Logs() { o.Logger.LogEntry(entry) } - return diagnostic.SuccessfulLoad(), result.Warnings(), result.Errors() + return true, diagnostic.SuccessfulLoad(), result.Warnings(), result.Errors() } // use the base factory to return a raw config (not specific to a context) diff --git a/pkg/oc/admin/diagnostics/diagnostics.go b/pkg/oc/admin/diagnostics/diagnostics.go index 7445b7866b65..50dc2445f314 100644 --- a/pkg/oc/admin/diagnostics/diagnostics.go +++ b/pkg/oc/admin/diagnostics/diagnostics.go @@ -4,7 +4,6 @@ import ( "fmt" "io" "os" - "path/filepath" "runtime/debug" "strings" @@ -13,16 +12,12 @@ import ( kutilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" - kvalidation "k8s.io/apimachinery/pkg/util/validation" - kapi "k8s.io/kubernetes/pkg/apis/core" "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" - "github.com/openshift/origin/pkg/cmd/util/variable" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" - netutil "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod/util" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" "github.com/openshift/origin/pkg/oc/admin/diagnostics/options" osclientcmd "github.com/openshift/origin/pkg/oc/cli/util/clientcmd" @@ -31,17 +26,18 @@ import ( // DiagnosticsOptions holds values received from command line flags as well as // other objects generated for the command to operate. type DiagnosticsOptions struct { - // list of diagnostic names to limit what is run - RequestedDiagnostics []string + // list of diagnostic name(s) to run + RequestedDiagnostics sets.String + // flag bindings for any diagnostics that require them + ParameterizedDiagnostics types.ParameterizedDiagnosticMap + + // list available diagnostics and exit + ListAll bool // specify locations of host config files MasterConfigLocation string NodeConfigLocation string - // specify context name to be used for cluster-admin access - ClientClusterContext string // indicate this is an openshift host despite lack of other indicators IsHost bool - // specify the image template to use for DiagnosticPod - ImageTemplate variable.ImageTemplate // When true, prevent diagnostics from changing API state (e.g. creating something) PreventModification bool // We need a factory for creating clients. Creating a factory @@ -49,31 +45,18 @@ type DiagnosticsOptions struct { // The command creates these and binds only the flags we want. ClientFlags *flag.FlagSet Factory *osclientcmd.Factory + // specify context name to be used for cluster-admin access + ClientClusterContext string // LogOptions determine globally what the user wants to see and how. LogOptions *log.LoggerOptions // The Logger is built with the options and should be used for all diagnostic output. Logger *log.Logger - // Options specific to network diagnostics - NetworkOptions *NetworkDiagnosticsOptions -} - -// NetworkDiagnosticsOptions holds additional values received from command line flags that -// are specify to network diagnostics. -type NetworkDiagnosticsOptions struct { - // Path to store network diagnostic results in case of errors - LogDir string - // Image to use for network diagnostic pod - PodImage string - // Image to use for network diagnostic test pod - TestPodImage string - // Protocol used to connect network diagnostic test pod - TestPodProtocol string - // Serving port on the network diagnostic test pod - TestPodPort int } const ( - DiagnosticsRecommendedName = "diagnostics" + // Command name + DiagnosticsRecommendedName = "diagnostics" + AllDiagnosticsRecommendedName = "all" // Standard locations for the host config files OpenShift uses. StandardMasterConfigPath string = "/etc/origin/master/master-config.yaml" @@ -82,93 +65,237 @@ const ( var ( longDescription = templates.LongDesc(` - This utility helps troubleshoot and diagnose known problems. It runs - diagnostics using a client and/or the state of a running master / - node host. + This utility helps troubleshoot and diagnose known problems for an OpenShift cluster + and/or local host. The base command runs a standard set of diagnostics: %[1]s - If run without flags, it will check for standard config files for - client, master, and node, and if found, use them for diagnostics. - You may also specify config files explicitly with flags, in which case - you will receive an error if they are not found. For example: + Available diagnostics vary based on client config and local OpenShift host config. + Config files in standard locations for client, master, and node are used, or + you may specify config files explicitly with flags. For example: %[1]s --master-config=/etc/origin/master/master-config.yaml - * If master/node config files are not found and the --host flag is not - present, host diagnostics are skipped. - * If the client has cluster-admin access, this access enables cluster - diagnostics to run which regular users cannot. - * If a client config file is not found, client and cluster diagnostics - are skipped. + * Explicitly specifying a config file raises an error if it is not found. + * A client config with cluster-admin access is required for most cluster diagnostics. + * Diagnostics that require a config file are skipped if it is not found. + * The standard set also skips diagnostics considered too heavyweight. - Diagnostics may be individually run by passing diagnostic name as arguments. + An individual diagnostic may be run as a subcommand which may have flags + for specifying options specific to that diagnostic. - %[1]s + Finally, the "all" subcommand runs all available diagnostics (including heavyweight + ones skipped in the standard set) and provides all individual diagnostic flags. + `) + longDescriptionAll = templates.LongDesc(` + This utility helps troubleshoot and diagnose known problems for an OpenShift cluster + and/or local host. This subcommand exists to run all available diagnostics: - The available diagnostic names are: %[2]s.`) + %[1]s + + Available diagnostics vary based on client config and local OpenShift host config. + All flags from the base command work similarly here, but all possible flags for + individual diagnostics are also available. + `) + longDescriptionIndividual = templates.LongDesc(` + Runs the %s diagnostic. + + %s + `) ) // NewCmdDiagnostics is the base command for running any diagnostics. func NewCmdDiagnostics(name string, fullName string, out io.Writer) *cobra.Command { + available := availableDiagnostics() + o := &DiagnosticsOptions{ + RequestedDiagnostics: available.Names().Difference(defaultSkipDiagnostics()), + ParameterizedDiagnostics: types.NewParameterizedDiagnosticMap(available...), + LogOptions: &log.LoggerOptions{Out: out}, + } + + cmd := &cobra.Command{ + Use: name, + Short: "Diagnose common cluster problems", + Long: fmt.Sprintf(longDescription, fullName), + Run: func(c *cobra.Command, args []string) { + kcmdutil.CheckErr(o.Complete(c, args)) + + failed, err, warnCount, errorCount := o.RunDiagnostics() + o.Logger.Summary(warnCount, errorCount) + + kcmdutil.CheckErr(err) + if failed { + os.Exit(1) + } + + }, + } + cmd.SetOutput(out) // for output re: usage / help + o.bindCommonFlags(cmd.Flags()) + o.bindClientFlags(cmd.Flags()) + o.bindHostFlags(cmd.Flags()) + + // add "all" subcommand + cmd.AddCommand(NewCmdDiagnosticsAll(AllDiagnosticsRecommendedName, fullName+" "+AllDiagnosticsRecommendedName, out, available)) + // add individual diagnostic subcommands + for _, diag := range available { + cmd.AddCommand(NewCmdDiagnosticsIndividual(strings.ToLower(diag.Name()), fullName+" "+strings.ToLower(diag.Name()), out, diag)) + } + + return cmd +} + +// NewCmdDiagnosticsAll is the command for running ALL diagnostics and providing all flags. +func NewCmdDiagnosticsAll(name string, fullName string, out io.Writer, available types.DiagnosticList) *cobra.Command { o := &DiagnosticsOptions{ - RequestedDiagnostics: []string{}, - LogOptions: &log.LoggerOptions{Out: out}, - ImageTemplate: variable.NewDefaultImageTemplate(), - NetworkOptions: &NetworkDiagnosticsOptions{}, + RequestedDiagnostics: available.Names(), + ParameterizedDiagnostics: types.NewParameterizedDiagnosticMap(available...), + LogOptions: &log.LoggerOptions{Out: out}, } cmd := &cobra.Command{ Use: name, Short: "Diagnose common cluster problems", - Long: fmt.Sprintf(longDescription, fullName, strings.Join(availableDiagnostics().List(), ", ")), + Long: fmt.Sprintf(longDescriptionAll, fullName), Run: func(c *cobra.Command, args []string) { - kcmdutil.CheckErr(o.Complete(args)) + kcmdutil.CheckErr(o.Complete(c, args)) - kcmdutil.CheckErr(o.Validate()) + failed, err, warnCount, errorCount := o.RunDiagnostics() + o.Logger.Summary(warnCount, errorCount) + + kcmdutil.CheckErr(err) + if failed { + os.Exit(1) + } + + }, + } + cmd.SetOutput(out) // for output re: usage / help + o.bindCommonFlags(cmd.Flags()) + o.bindClientFlags(cmd.Flags()) + o.bindHostFlags(cmd.Flags()) + o.bindRequestedIndividualFlags(cmd.Flags()) + return cmd +} + +// NewCmdDiagnosticsIndividual is a generic subcommand providing a single diagnostic and its flags. +func NewCmdDiagnosticsIndividual(name string, fullName string, out io.Writer, diagnostic types.Diagnostic) *cobra.Command { + o := &DiagnosticsOptions{ + RequestedDiagnostics: sets.NewString(diagnostic.Name()), + ParameterizedDiagnostics: types.NewParameterizedDiagnosticMap(diagnostic), + LogOptions: &log.LoggerOptions{Out: out}, + } + + cmd := &cobra.Command{ + Use: name, + Short: diagnostic.Description(), + Long: fmt.Sprintf(longDescriptionIndividual, diagnostic.Name(), diagnostic.Description()), + Run: func(c *cobra.Command, args []string) { + kcmdutil.CheckErr(o.Complete(c, args)) failed, err, warnCount, errorCount := o.RunDiagnostics() o.Logger.Summary(warnCount, errorCount) kcmdutil.CheckErr(err) if failed { - os.Exit(255) + os.Exit(1) } }, + Aliases: []string{diagnostic.Name()}, } cmd.SetOutput(out) // for output re: usage / help + o.bindCommonFlags(cmd.Flags()) + needClient, needHost := diagnostic.Requirements() + if pd, ok := diagnostic.(types.ParameterizedDiagnostic); ok { + bindIndividualFlags(pd, "", cmd.Flags()) + } + if needClient { + o.bindClientFlags(cmd.Flags()) + } + if needHost { + o.bindHostFlags(cmd.Flags()) + } + return cmd +} +// gather a list of all diagnostics that are available to be invoked by the main command +func availableDiagnostics() types.DiagnosticList { + available := availableClientDiagnostics() + available = append(available, availableClusterDiagnostics()...) + available = append(available, availableHostDiagnostics()...) + return available +} + +// gather a list of diagnostic names to skip when running the main command +func defaultSkipDiagnostics() sets.String { + toSkip := sets.NewString() + toSkip.Insert(defaultSkipHostDiagnostics.List()...) + return toSkip +} + +// bind flags that are available on all user-facing commands +func (o *DiagnosticsOptions) bindCommonFlags(flags *flag.FlagSet) { + flagtypes.GLog(flags) + options.BindLoggerOptionFlags(flags, o.LogOptions, options.RecommendedLoggerOptionFlags()) +} + +// bind flags that are necessary for setting up an API client +func (o *DiagnosticsOptions) bindClientFlags(flags *flag.FlagSet) { o.ClientFlags = flag.NewFlagSet("client", flag.ContinueOnError) // hide the extensive set of client flags o.Factory = osclientcmd.New(o.ClientFlags) // that would otherwise be added to this command - cmd.Flags().AddFlag(o.ClientFlags.Lookup(config.OpenShiftConfigFlagName)) - cmd.Flags().AddFlag(o.ClientFlags.Lookup("context")) // TODO: find k8s constant - cmd.Flags().StringVar(&o.ClientClusterContext, options.FlagClusterContextName, "", "Client context to use for cluster administrator") - cmd.Flags().StringVar(&o.MasterConfigLocation, options.FlagMasterConfigName, "", "Path to master config file (implies --host)") - cmd.Flags().StringVar(&o.NodeConfigLocation, options.FlagNodeConfigName, "", "Path to node config file (implies --host)") - cmd.Flags().BoolVar(&o.IsHost, options.FlagIsHostName, false, "If true, look for systemd and journald units even without master/node config") - cmd.Flags().StringVar(&o.ImageTemplate.Format, options.FlagImageTemplateName, o.ImageTemplate.Format, "Image template for DiagnosticPod to use in creating a pod") - cmd.Flags().BoolVar(&o.ImageTemplate.Latest, options.FlagLatestImageName, false, "If true, when expanding the image template, use latest version, not release version") - cmd.Flags().BoolVar(&o.PreventModification, options.FlagPreventModificationName, false, "If true, may be set to prevent diagnostics making any changes via the API") - cmd.Flags().StringVar(&o.NetworkOptions.LogDir, options.FlagNetworkDiagLogDir, netutil.NetworkDiagDefaultLogDir, "Path to store network diagnostic results in case of errors") - cmd.Flags().StringVar(&o.NetworkOptions.PodImage, options.FlagNetworkDiagPodImage, netutil.GetNetworkDiagDefaultPodImage(), "Image to use for network diagnostic pod") - cmd.Flags().StringVar(&o.NetworkOptions.TestPodImage, options.FlagNetworkDiagTestPodImage, netutil.GetNetworkDiagDefaultTestPodImage(), "Image to use for network diagnostic test pod") - cmd.Flags().StringVar(&o.NetworkOptions.TestPodProtocol, options.FlagNetworkDiagTestPodProtocol, netutil.NetworkDiagDefaultTestPodProtocol, "Protocol used to connect to network diagnostic test pod") - cmd.Flags().IntVar(&o.NetworkOptions.TestPodPort, options.FlagNetworkDiagTestPodPort, netutil.NetworkDiagDefaultTestPodPort, "Serving port on the network diagnostic test pod") - flagtypes.GLog(cmd.Flags()) - options.BindLoggerOptionFlags(cmd.Flags(), o.LogOptions, options.RecommendedLoggerOptionFlags()) + flags.AddFlag(o.ClientFlags.Lookup(config.OpenShiftConfigFlagName)) + flags.AddFlag(o.ClientFlags.Lookup("context")) // TODO: find k8s constant + flags.StringVar(&o.ClientClusterContext, options.FlagClusterContextName, "", "Client context to use for cluster administrator") + flags.BoolVar(&o.PreventModification, options.FlagPreventModificationName, false, "If true, may be set to prevent diagnostics making any changes via the API") +} - return cmd +// bind flags that are used by host diagnostics +func (o *DiagnosticsOptions) bindHostFlags(flags *flag.FlagSet) { + flags.StringVar(&o.MasterConfigLocation, options.FlagMasterConfigName, "", "Path to master config file (implies --host)") + flags.StringVar(&o.NodeConfigLocation, options.FlagNodeConfigName, "", "Path to node config file (implies --host)") + flags.BoolVar(&o.IsHost, options.FlagIsHostName, false, "If true, look for systemd and journald units even without master/node config") } -// Complete fills in DiagnosticsOptions needed if the command is actually invoked. -func (o *DiagnosticsOptions) Complete(args []string) error { +// bind flags for all diagnostics that have their own parameters +func (o *DiagnosticsOptions) bindRequestedIndividualFlags(flags *flag.FlagSet) { + for name, diag := range o.ParameterizedDiagnostics { + if o.RequestedDiagnostics.Has(name) { + bindIndividualFlags(diag, strings.ToLower(diag.Name()+"-"), flags) + } + } +} + +// bind flags for parameters on a single diagnostic +func bindIndividualFlags(diag types.ParameterizedDiagnostic, prefix string, flags *flag.FlagSet) { + for _, param := range diag.AvailableParameters() { + name := prefix + param.Name + switch target := param.Target.(type) { + case *string: + flags.StringVar(target, name, param.Default.(string), param.Description) + case *int: + flags.IntVar(target, name, param.Default.(int), param.Description) + case *bool: + flags.BoolVar(target, name, param.Default.(bool), param.Description) + default: + panic("Don't know what to do with parameter") + } + } +} + +// Complete fills in DiagnosticsConfig needed if the command is actually invoked. +func (o *DiagnosticsOptions) Complete(c *cobra.Command, args []string) error { var err error o.Logger, err = o.LogOptions.NewLogger() if err != nil { return err } + if len(args) > 0 { + c.Usage() + return fmt.Errorf("\nUnexpected command line argument(s): %v", args) + } + // If not given master/client config file locations, check if the defaults exist // and adjust the options accordingly: if len(o.MasterConfigLocation) == 0 { @@ -182,84 +309,14 @@ func (o *DiagnosticsOptions) Complete(args []string) error { } } - if len(o.NetworkOptions.LogDir) == 0 { - o.NetworkOptions.LogDir = netutil.NetworkDiagDefaultLogDir - } else { - logdir, err := filepath.Abs(o.NetworkOptions.LogDir) - if err != nil { - return err - } - if path, err := os.Stat(o.NetworkOptions.LogDir); err == nil && !path.Mode().IsDir() { - return fmt.Errorf("Network log path %q exists but is not a directory", o.NetworkOptions.LogDir) - } - o.NetworkOptions.LogDir = logdir - } - if len(o.NetworkOptions.PodImage) == 0 { - o.NetworkOptions.PodImage = netutil.GetNetworkDiagDefaultPodImage() - } - if len(o.NetworkOptions.TestPodImage) == 0 { - o.NetworkOptions.TestPodImage = netutil.GetNetworkDiagDefaultTestPodImage() - } - - supportedProtocols := sets.NewString(string(kapi.ProtocolTCP), string(kapi.ProtocolUDP)) - if !supportedProtocols.Has(o.NetworkOptions.TestPodProtocol) { - return fmt.Errorf("invalid protocol for network diagnostic test pod. Supported protocols: %s", strings.Join(supportedProtocols.List(), ",")) - } - if kvalidation.IsValidPortNum(o.NetworkOptions.TestPodPort) != nil { - return fmt.Errorf("invalid port for network diagnostic test pod. Must be in the range 1 to 65535.") - } - - o.RequestedDiagnostics = append(o.RequestedDiagnostics, args...) - if len(o.RequestedDiagnostics) == 0 { - o.RequestedDiagnostics = availableDiagnostics().Difference(defaultSkipDiagnostics()).List() - } - return nil } -func (o *DiagnosticsOptions) Validate() error { - available := availableDiagnostics() - - if common := available.Intersection(sets.NewString(o.RequestedDiagnostics...)); len(common) == 0 { - o.Logger.Error("CED3012", log.EvalTemplate("CED3012", "None of the requested diagnostics are available:\n {{.requested}}\nPlease try from the following:\n {{.available}}", - log.Hash{"requested": o.RequestedDiagnostics, "available": available.List()})) - return fmt.Errorf("No requested diagnostics are available: requested=%s available=%s", strings.Join(o.RequestedDiagnostics, " "), strings.Join(available.List(), " ")) - - } else if len(common) < len(o.RequestedDiagnostics) { - o.Logger.Error("CED3013", log.EvalTemplate("CED3013", ` -Of the requested diagnostics: - {{.requested}} -only these are available: - {{.common}} -The list of all possible is: - {{.available}} - `, log.Hash{"requested": o.RequestedDiagnostics, "common": common.List(), "available": available.List()})) - - return fmt.Errorf("Not all requested diagnostics are available: missing=%s requested=%s available=%s", - strings.Join(sets.NewString(o.RequestedDiagnostics...).Difference(available).List(), " "), - strings.Join(o.RequestedDiagnostics, " "), - strings.Join(available.List(), " ")) - } - - return nil -} - -func availableDiagnostics() sets.String { - available := sets.NewString() - available.Insert(availableClientDiagnostics.List()...) - available.Insert(availableClusterDiagnostics.List()...) - available.Insert(availableEtcdDiagnostics.List()...) - available.Insert(availableHostDiagnostics.List()...) - return available -} - -func defaultSkipDiagnostics() sets.String { - available := sets.NewString() - available.Insert(defaultSkipEtcdDiagnostics.List()...) - return available -} - -// RunDiagnostics builds diagnostics based on the options and executes them, returning a summary. +// RunDiagnostics builds diagnostics based on the options and executes them, returning a summary. Returns: +// failure ("true" meaning there was not a clean diagnostic result), +// error (raised during construction or execution of diagnostics; may be an aggregate error object), +// number of warnings encountered in diagnostics results, +// number of errors encountered (diagnostic results plus errors previously raised). func (o DiagnosticsOptions) RunDiagnostics() (bool, error, int, int) { failed := false warnings := []error{} @@ -274,14 +331,19 @@ func (o DiagnosticsOptions) RunDiagnostics() (bool, error, int, int) { errors = append(errors, fmt.Errorf("While building the diagnostics, a panic was encountered.\nThis is a bug in diagnostics. Error and stack trace follow: \n%v\n%s", r, stack)) } }() - detected, detectWarnings, detectErrors := o.detectClientConfig() // may log and return problems + + // build client/cluster diags if there is a client config for them to use + expected, detected, detectWarnings, detectErrors := o.detectClientConfig() // may log and return problems for _, warn := range detectWarnings { warnings = append(warnings, warn) } for _, err := range detectErrors { errors = append(errors, err) } - if !detected { // there just plain isn't any client config file available + if !expected { + // no diagnostic required a client config, nothing to do + } else if !detected { + // there just plain isn't any client config file available o.Logger.Notice("CED3014", "No client configuration specified; skipping client and cluster diagnostics.") } else if rawConfig, err := o.buildRawConfig(); err != nil { // client config is totally broken - won't parse etc (problems may have been detected and logged) o.Logger.Error("CED3015", fmt.Sprintf("Client configuration failed to load; skipping client and cluster diagnostics due to error: %s", err.Error())) @@ -306,19 +368,22 @@ func (o DiagnosticsOptions) RunDiagnostics() (bool, error, int, int) { } } - etcdDiags, ok, err := o.buildEtcdDiagnostics() - failed = failed || !ok - if ok { - diagnostics = append(diagnostics, etcdDiags...) - } - - hostDiags, ok, err := o.buildHostDiagnostics() - failed = failed || !ok - if ok { - diagnostics = append(diagnostics, hostDiags...) - } + // build host diagnostics if config is available + hostDiags, err := o.buildHostDiagnostics() if err != nil { errors = append(errors, err) + } else { + diagnostics = append(diagnostics, hostDiags...) + } + + // complete any diagnostics that require it + for _, d := range diagnostics { + if toComplete, ok := d.(types.IncompleteDiagnostic); ok { + if err := toComplete.Complete(o.Logger); err != nil { + errors = append(errors, err) + failed = true + } + } } }() @@ -336,6 +401,7 @@ func (o DiagnosticsOptions) RunDiagnostics() (bool, error, int, int) { func (o DiagnosticsOptions) Run(diagnostics []types.Diagnostic) (bool, error, int, int) { warnCount := 0 errorCount := 0 + runCount := 0 for _, diagnostic := range diagnostics { func() { // wrap diagnostic panic nicely in case of developer error defer func() { @@ -364,7 +430,12 @@ func (o DiagnosticsOptions) Run(diagnostics []types.Diagnostic) (bool, error, in } warnCount += len(r.Warnings()) errorCount += len(r.Errors()) + runCount += 1 }() } + if runCount == 0 { + o.Logger.Error("CED3016", "Requested diagnostic(s) skipped; nothing to run. See --help and consider setting flags or providing config to enable running.") + return true, nil, 0, 1 + } return errorCount > 0, nil, warnCount, errorCount } diff --git a/pkg/oc/admin/diagnostics/diagnostics/client/config_contexts.go b/pkg/oc/admin/diagnostics/diagnostics/client/config_contexts.go index 753029c2e0f5..a5569a433baf 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/client/config_contexts.go +++ b/pkg/oc/admin/diagnostics/diagnostics/client/config_contexts.go @@ -154,6 +154,9 @@ var ( // Name is part of the Diagnostic interface and just returns name. func (d ConfigContext) Name() string { + if len(d.ContextName) == 0 { + return ConfigContextsName + } return fmt.Sprintf("%s[%s]", ConfigContextsName, d.ContextName) } @@ -162,6 +165,10 @@ func (d ConfigContext) Description() string { return "Validate client config context is complete and has connectivity" } +func (d ConfigContext) Requirements() (client bool, host bool) { + return true, false +} + // CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic. func (d ConfigContext) CanRun() (bool, error) { if d.RawConfig == nil { diff --git a/pkg/oc/admin/diagnostics/diagnostics/client/run_diagnostics_pod.go b/pkg/oc/admin/diagnostics/diagnostics/client/run_diagnostics_pod.go index 2a29bdb65979..2aa41f97cc29 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/client/run_diagnostics_pod.go +++ b/pkg/oc/admin/diagnostics/diagnostics/client/run_diagnostics_pod.go @@ -20,7 +20,9 @@ import ( ) const ( - DiagnosticPodName = "DiagnosticPod" + DiagnosticPodName = "DiagnosticPod" + ImageTemplateParam = "images" + LatestImageParam = "latest-images" ) // DiagnosticPod is a diagnostic that runs a diagnostic pod and relays the results. @@ -33,6 +35,8 @@ type DiagnosticPod struct { ImageTemplate variable.ImageTemplate } +var _ types.ParameterizedDiagnostic = (*DiagnosticPod)(nil) + // Name is part of the Diagnostic interface and just returns name. func (d *DiagnosticPod) Name() string { return DiagnosticPodName @@ -43,10 +47,21 @@ func (d *DiagnosticPod) Description() string { return "Create a pod to run diagnostics from the application standpoint" } +func (d *DiagnosticPod) Requirements() (client bool, host bool) { + return true, false +} + +func (d *DiagnosticPod) AvailableParameters() []types.Parameter { + return []types.Parameter{ + {ImageTemplateParam, "Image template to use in creating a pod", &d.ImageTemplate.Format, variable.NewDefaultImageTemplate().Format}, + {LatestImageParam, "If true, when expanding the image template, use latest version, not release version", &d.ImageTemplate.Latest, false}, + } +} + // CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic. func (d *DiagnosticPod) CanRun() (bool, error) { if d.PreventModification { - return false, fmt.Errorf("running the diagnostic pod is an API change, which is prevented as you indicated") + return false, fmt.Errorf("running the diagnostic pod is an API change, which is prevented because the --prevent-modification flag was specified") } return true, nil } diff --git a/pkg/oc/admin/diagnostics/diagnostics/cluster/aggregated_logging/diagnostic.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/aggregated_logging/diagnostic.go index 3ba7e2d515c6..ce36bfce6035 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/cluster/aggregated_logging/diagnostic.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/aggregated_logging/diagnostic.go @@ -18,6 +18,7 @@ import ( configapi "github.com/openshift/origin/pkg/cmd/server/api" oauthtypedclient "github.com/openshift/origin/pkg/oauth/generated/internalclientset/typed/oauth/internalversion" hostdiag "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/host" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" projecttypedclient "github.com/openshift/origin/pkg/project/generated/internalclientset/typed/project/internalversion" routesapi "github.com/openshift/origin/pkg/route/apis/route" @@ -144,8 +145,23 @@ func (d *AggregatedLogging) Description() string { return "Check aggregated logging integration for proper configuration" } +func (d *AggregatedLogging) Requirements() (client bool, host bool) { + return true, false +} + +func (d *AggregatedLogging) Complete(logger *log.Logger) error { + if len(d.MasterConfigFile) > 0 { + var err error + d.masterConfig, err = hostdiag.GetMasterConfig(d.MasterConfigFile, logger) + if err != nil { + return err + } + } + return nil +} + func (d *AggregatedLogging) CanRun() (bool, error) { - if len(d.MasterConfigFile) == 0 { + if len(d.MasterConfigFile) == 0 || d.masterConfig == nil { return false, errors.New("No master config file was provided") } if d.OAuthClientClient == nil || d.ProjectClient == nil || d.RouteClient == nil || d.CRBClient == nil || d.DCClient == nil { @@ -154,11 +170,6 @@ func (d *AggregatedLogging) CanRun() (bool, error) { if d.KubeClient == nil { return false, errors.New("Config must include a cluster-admin context to run this diagnostic") } - var err error - d.masterConfig, err = hostdiag.GetMasterConfig(d.result, d.MasterConfigFile) - if err != nil { - return false, errors.New("Master configuration is unreadable") - } if d.masterConfig.AssetConfig.LoggingPublicURL == "" { return false, errors.New("No LoggingPublicURL is defined in the master configuration") } diff --git a/pkg/oc/admin/diagnostics/diagnostics/cluster/master_node.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/master_node.go index e0593ffea1ca..1375b66ca19c 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/cluster/master_node.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/master_node.go @@ -41,6 +41,10 @@ func (d *MasterNode) Description() string { return "Check if master is also running node (for Open vSwitch)" } +func (d *MasterNode) Requirements() (client bool, host bool) { + return true, true +} + func (d *MasterNode) CanRun() (bool, error) { if d.KubeClient == nil { return false, errors.New("must have kube client") diff --git a/pkg/oc/admin/diagnostics/diagnostics/cluster/metrics.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/metrics.go index c60921684cdd..533cf30558f5 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/cluster/metrics.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/metrics.go @@ -40,6 +40,10 @@ func (d *MetricsApiProxy) Description() string { return "Check the integrated heapster metrics can be reached via the API proxy" } +func (d *MetricsApiProxy) Requirements() (client bool, host bool) { + return true, false +} + func (d *MetricsApiProxy) CanRun() (bool, error) { if d.KubeClient == nil { return false, errors.New("must have kube client") diff --git a/pkg/oc/admin/diagnostics/diagnostics/cluster/node_definitions.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/node_definitions.go index edc732455418..fd224ea6c001 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/cluster/node_definitions.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/node_definitions.go @@ -60,9 +60,13 @@ func (d *NodeDefinitions) Description() string { return "Check node records on master" } +func (d *NodeDefinitions) Requirements() (client bool, host bool) { + return true, false +} + func (d *NodeDefinitions) CanRun() (bool, error) { if d.KubeClient == nil { - return false, errors.New("must have kube client") + return false, errors.New("must have kube client") } can, err := userCan(d.KubeClient.Authorization(), &authorization.ResourceAttributes{ Verb: "list", diff --git a/pkg/oc/admin/diagnostics/diagnostics/cluster/registry.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/registry.go index 59dc33c54704..dd280f5a4db4 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/cluster/registry.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/registry.go @@ -154,6 +154,10 @@ func (d *ClusterRegistry) Description() string { return "Check that there is a working Docker registry" } +func (d *ClusterRegistry) Requirements() (client bool, host bool) { + return true, false +} + func (d *ClusterRegistry) CanRun() (bool, error) { if d.ImageStreamClient == nil || d.KubeClient == nil { return false, fmt.Errorf("must have kube and os clients") diff --git a/pkg/oc/admin/diagnostics/diagnostics/cluster/rolebindings.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/rolebindings.go index 80da245c59cd..f5723d497701 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/cluster/rolebindings.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/rolebindings.go @@ -34,6 +34,10 @@ func (d *ClusterRoleBindings) Description() string { return "Check that the default ClusterRoleBindings are present and contain the expected subjects" } +func (d *ClusterRoleBindings) Requirements() (client bool, host bool) { + return true, false +} + func (d *ClusterRoleBindings) CanRun() (bool, error) { if d.ClusterRoleBindingsClient == nil { return false, fmt.Errorf("must have client.ClusterRoleBindingsInterface") diff --git a/pkg/oc/admin/diagnostics/diagnostics/cluster/roles.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/roles.go index 7f962ec22746..30b0880b2531 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/cluster/roles.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/roles.go @@ -62,6 +62,10 @@ func (d *ClusterRoles) Description() string { return "Check that the default ClusterRoles are present and contain the expected permissions" } +func (d *ClusterRoles) Requirements() (client bool, host bool) { + return true, false +} + func (d *ClusterRoles) CanRun() (bool, error) { if d.ClusterRolesClient == nil { return false, fmt.Errorf("must have client.ClusterRolesInterface") diff --git a/pkg/oc/admin/diagnostics/diagnostics/cluster/route_validation.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/route_validation.go index 8adbb1732cab..1af00befde63 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/cluster/route_validation.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/route_validation.go @@ -44,6 +44,10 @@ func (d *RouteCertificateValidation) Description() string { return "Check all route certificates for certificates that might be rejected by extended validation." } +func (d *RouteCertificateValidation) Requirements() (client bool, host bool) { + return true, false +} + func (d *RouteCertificateValidation) CanRun() (bool, error) { if d.RESTConfig == nil || d.SARClient == nil { return false, errors.New("must have Kube client configuration") diff --git a/pkg/oc/admin/diagnostics/diagnostics/cluster/router.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/router.go index bc4a3a48b9dc..731c85808c06 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/cluster/router.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/router.go @@ -84,13 +84,17 @@ Time: %s` ) func (d *ClusterRouter) Name() string { - return "ClusterRouterName" + return ClusterRouterName } func (d *ClusterRouter) Description() string { return "Check there is a working router" } +func (d *ClusterRouter) Requirements() (client bool, host bool) { + return true, false +} + func (d *ClusterRouter) CanRun() (bool, error) { if d.KubeClient == nil || d.DCClient == nil { return false, errors.New("must have kube and os client") diff --git a/pkg/oc/admin/diagnostics/diagnostics/cluster/service_externalip.go b/pkg/oc/admin/diagnostics/diagnostics/cluster/service_externalip.go index 2eb5781d91a3..3dcc23dc7e55 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/cluster/service_externalip.go +++ b/pkg/oc/admin/diagnostics/diagnostics/cluster/service_externalip.go @@ -9,7 +9,9 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + master "github.com/openshift/origin/pkg/cmd/server/api" hostdiag "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/host" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" "github.com/openshift/origin/pkg/service/admission" ) @@ -19,6 +21,7 @@ import ( // Background: https://github.com/openshift/origin/issues/7808 type ServiceExternalIPs struct { MasterConfigFile string + masterConfig *master.MasterConfig KclusterClient kclientset.Interface } @@ -32,8 +35,23 @@ func (d *ServiceExternalIPs) Description() string { return "Check for existing services with ExternalIPs that are disallowed by master config" } +func (d *ServiceExternalIPs) Requirements() (client bool, host bool) { + return true, true +} + +func (d *ServiceExternalIPs) Complete(logger *log.Logger) error { + if len(d.MasterConfigFile) > 0 { + masterConfig, err := hostdiag.GetMasterConfig(d.MasterConfigFile, logger) + if err != nil { + return err + } + d.masterConfig = masterConfig + } + return nil +} + func (d *ServiceExternalIPs) CanRun() (bool, error) { - if len(d.MasterConfigFile) == 0 { + if len(d.MasterConfigFile) == 0 || d.masterConfig == nil { return false, errors.New("No master config file was detected") } if d.KclusterClient == nil { @@ -45,14 +63,10 @@ func (d *ServiceExternalIPs) CanRun() (bool, error) { func (d *ServiceExternalIPs) Check() types.DiagnosticResult { r := types.NewDiagnosticResult(ServiceExternalIPsName) - masterConfig, err := hostdiag.GetMasterConfig(r, d.MasterConfigFile) - if err != nil { - r.Info("DH2004", "Unreadable master config; skipping this diagnostic.") - return r - } admit, reject := []*net.IPNet{}, []*net.IPNet{} - if cidrs := masterConfig.NetworkConfig.ExternalIPNetworkCIDRs; cidrs != nil { + var err error + if cidrs := d.masterConfig.NetworkConfig.ExternalIPNetworkCIDRs; cidrs != nil { reject, admit, err = admission.ParseRejectAdmitCIDRRules(cidrs) if err != nil { r.Error("DH2007", err, fmt.Sprintf("Could not parse master config NetworkConfig.ExternalIPNetworkCIDRs: (%[1]T) %[1]v", err)) diff --git a/pkg/oc/admin/diagnostics/diagnostics/host/check_master_config.go b/pkg/oc/admin/diagnostics/diagnostics/host/check_master_config.go index a66ce7c40e91..58a96941db2d 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/host/check_master_config.go +++ b/pkg/oc/admin/diagnostics/diagnostics/host/check_master_config.go @@ -4,37 +4,51 @@ import ( "errors" "fmt" + master "github.com/openshift/origin/pkg/cmd/server/api" configvalidation "github.com/openshift/origin/pkg/cmd/server/api/validation" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" ) // MasterConfigCheck is a Diagnostic to check that the master config file is valid type MasterConfigCheck struct { MasterConfigFile string + masterConfig *master.MasterConfig } const MasterConfigCheckName = "MasterConfigCheck" -func (d MasterConfigCheck) Name() string { +func (d *MasterConfigCheck) Name() string { return MasterConfigCheckName } -func (d MasterConfigCheck) Description() string { +func (d *MasterConfigCheck) Description() string { return "Check the master config file" } -func (d MasterConfigCheck) CanRun() (bool, error) { + +func (d *MasterConfigCheck) Requirements() (client bool, host bool) { + return false, true +} + +func (d *MasterConfigCheck) Complete(logger *log.Logger) error { + masterConfig, err := GetMasterConfig(d.MasterConfigFile, logger) + if err != nil { + return err + } + d.masterConfig = masterConfig + return nil +} + +func (d *MasterConfigCheck) CanRun() (bool, error) { if len(d.MasterConfigFile) == 0 { return false, errors.New("No master config file was detected") } return true, nil } -func (d MasterConfigCheck) Check() types.DiagnosticResult { + +func (d *MasterConfigCheck) Check() types.DiagnosticResult { r := types.NewDiagnosticResult(MasterConfigCheckName) - masterConfig, err := GetMasterConfig(r, d.MasterConfigFile) - if err != nil { - return r - } results := configvalidation.ValidateMasterConfig(masterConfig, nil) if len(results.Errors) > 0 { diff --git a/pkg/oc/admin/diagnostics/diagnostics/host/check_node_config.go b/pkg/oc/admin/diagnostics/diagnostics/host/check_node_config.go index 475fcf389459..7ff0ad22d226 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/host/check_node_config.go +++ b/pkg/oc/admin/diagnostics/diagnostics/host/check_node_config.go @@ -23,6 +23,11 @@ func (d NodeConfigCheck) Name() string { func (d NodeConfigCheck) Description() string { return "Check the node config file" } + +func (d NodeConfigCheck) Requirements() (client bool, host bool) { + return false, true +} + func (d NodeConfigCheck) CanRun() (bool, error) { if len(d.NodeConfigFile) == 0 { return false, errors.New("No node config file was detected") @@ -30,6 +35,7 @@ func (d NodeConfigCheck) CanRun() (bool, error) { return true, nil } + func (d NodeConfigCheck) Check() types.DiagnosticResult { r := types.NewDiagnosticResult(NodeConfigCheckName) r.Debug("DH1001", fmt.Sprintf("Looking for node config file at '%s'", d.NodeConfigFile)) diff --git a/pkg/oc/admin/diagnostics/diagnostics/cluster/etcd.go b/pkg/oc/admin/diagnostics/diagnostics/host/etcd.go similarity index 55% rename from pkg/oc/admin/diagnostics/diagnostics/cluster/etcd.go rename to pkg/oc/admin/diagnostics/diagnostics/host/etcd.go index 1c8ba8bdac6b..86febda32011 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/cluster/etcd.go +++ b/pkg/oc/admin/diagnostics/diagnostics/host/etcd.go @@ -1,4 +1,4 @@ -package cluster +package host import ( "context" @@ -15,38 +15,66 @@ import ( "bytes" + "github.com/openshift/origin/pkg/cmd/server/etcd" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" ) // EtcdWriteVolume is a Diagnostic to check the writes occurring against etcd // and organize them by volume. type EtcdWriteVolume struct { - V2Client etcdclient.Client - V3Client *clientv3.Client + MasterConfigLocation string + V2Client etcdclient.Client + V3Client *clientv3.Client + durationSpec string + duration time.Duration } const ( - EtcdWriteName = "EtcdWriteVolume" + EtcdWriteName = "EtcdWriteVolume" + DurationParam = "duration" + DurationDefault = "1m" ) -func (d *EtcdWriteVolume) duration() time.Duration { - s := os.Getenv("ETCD_WRITE_VOLUME_DURATION") - if len(s) == 0 { - s = "1m" - } - duration, err := time.ParseDuration(s) - if err != nil { - panic(fmt.Errorf("ETCD_WRITE_VOLUME_DURATION could not be parsed: %v", err)) - } - return duration -} - func (d *EtcdWriteVolume) Name() string { return EtcdWriteName } func (d *EtcdWriteVolume) Description() string { - return fmt.Sprintf("Check the volume of writes against etcd and classify them by operation and key for %s", d.duration()) + return fmt.Sprintf("Check the volume of writes against etcd over a time period and classify them by operation and key") +} + +func (d *EtcdWriteVolume) Requirements() (client bool, host bool) { + return false, true +} + +func (d *EtcdWriteVolume) AvailableParameters() []types.Parameter { + return []types.Parameter{ + {DurationParam, "How long to perform the write test", &d.durationSpec, DurationDefault}, + } +} + +func (d *EtcdWriteVolume) Complete(logger *log.Logger) error { + v2Client, v3Client, found, err := findEtcdClients(d.MasterConfigLocation, logger) + if err != nil || !found { + return err + } + d.V2Client, d.V3Client = v2Client, v3Client + + // determine the duration to run the check from either the deprecated env var, the flag, or the default + s := os.Getenv("ETCD_WRITE_VOLUME_DURATION") // deprecated way + if d.durationSpec != "" { + s = d.durationSpec + } + if s == "" { + s = DurationDefault + } + duration, err := time.ParseDuration(s) + if err != nil { + return fmt.Errorf("EtcdWriteVolume duration '%s' could not be parsed: %v", s, err) + } + d.duration = duration + return nil } func (d *EtcdWriteVolume) CanRun() (bool, error) { @@ -64,9 +92,8 @@ func (d *EtcdWriteVolume) Check() types.DiagnosticResult { var wg sync.WaitGroup - duration := d.duration() ctx := context.Background() - ctx, cancel := context.WithDeadline(ctx, time.Now().Add(duration)) + ctx, cancel := context.WithDeadline(ctx, time.Now().Add(d.duration)) defer cancel() keyStats := &keyCounter{} @@ -121,11 +148,46 @@ func (d *EtcdWriteVolume) Check() types.DiagnosticResult { fmt.Fprintf(tw, "%s\t%6d\t%5.1f%%\n", b.Name, b.Count, float64(b.Count)/float64(keyStats.count)*100) } tw.Flush() - r.Info("DEw2004", fmt.Sprintf("Measured %.1f writes/sec\n", float64(keyStats.count)/float64(duration/time.Second))+buf.String()) + r.Info("DEw2004", fmt.Sprintf("Measured %.1f writes/sec\n", float64(keyStats.count)/float64(d.duration/time.Second))+buf.String()) return r } +// findEtcdClients finds and loads etcd clients +func findEtcdClients(configFile string, logger *log.Logger) (etcdclient.Client, *clientv3.Client, bool, error) { + masterConfig, err := GetMasterConfig(configFile, logger) + if err != nil { + configErr := fmt.Errorf("Unreadable master config; skipping this diagnostic.") + logger.Error("DE2001", configErr.Error()) + return nil, nil, false, configErr + } + if len(masterConfig.EtcdClientInfo.URLs) == 0 { + configErr := fmt.Errorf("No etcdClientInfo.urls defined; can't contact etcd") + logger.Error("DE2002", configErr.Error()) + return nil, nil, false, configErr + } + v2Client, err := etcd.MakeEtcdClient(masterConfig.EtcdClientInfo) + if err != nil { + configErr := fmt.Errorf("Unable to create an etcd v2 client: %v", err) + logger.Error("DE2003", configErr.Error()) + return nil, nil, false, configErr + } + config, err := etcd.MakeEtcdClientV3Config(masterConfig.EtcdClientInfo) + if err != nil { + configErr := fmt.Errorf("Unable to create an etcd v3 client config: %v", err) + logger.Error("DE2004", configErr.Error()) + return nil, nil, false, configErr + } + config.DialTimeout = 5 * time.Second + v3Client, err := clientv3.New(*config) + if err != nil { + configErr := fmt.Errorf("Unable to create an etcd v3 client: %v", err) + logger.Error("DE2005", configErr.Error()) + return nil, nil, false, configErr + } + return v2Client, v3Client, true, nil +} + type KeyCounter interface { Inc(key []string) } diff --git a/pkg/oc/admin/diagnostics/diagnostics/host/util.go b/pkg/oc/admin/diagnostics/diagnostics/host/util.go index fa6d2219a607..327d5f86a42f 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/host/util.go +++ b/pkg/oc/admin/diagnostics/diagnostics/host/util.go @@ -5,7 +5,7 @@ import ( configapi "github.com/openshift/origin/pkg/cmd/server/api" configapilatest "github.com/openshift/origin/pkg/cmd/server/api/latest" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" ) // this would be bad practice if there were ever a need to load more than one master config for diagnostics. @@ -16,24 +16,24 @@ var ( masterConfigLoadError error ) -func GetMasterConfig(r types.DiagnosticResult, masterConfigFile string) (*configapi.MasterConfig, error) { +func GetMasterConfig(masterConfigFile string, logger *log.Logger) (*configapi.MasterConfig, error) { if masterConfigLoaded { // no need to do this more than once if masterConfigLoadError != nil { - printMasterConfigLoadError(r, masterConfigFile) + printMasterConfigLoadError(masterConfigFile, logger) } return masterConfig, masterConfigLoadError } - r.Debug("DH0001", fmt.Sprintf("Looking for master config file at '%s'", masterConfigFile)) + logger.Debug("DH0001", fmt.Sprintf("Looking for master config file at '%s'", masterConfigFile)) masterConfigLoaded = true masterConfig, masterConfigLoadError = configapilatest.ReadAndResolveMasterConfig(masterConfigFile) if masterConfigLoadError != nil { - printMasterConfigLoadError(r, masterConfigFile) + printMasterConfigLoadError(masterConfigFile, logger) } else { - r.Debug("DH0003", fmt.Sprintf("Found a master config file: %[1]s", masterConfigFile)) + logger.Debug("DH0003", fmt.Sprintf("Found a master config file: %[1]s", masterConfigFile)) } return masterConfig, masterConfigLoadError } -func printMasterConfigLoadError(r types.DiagnosticResult, masterConfigFile string) { - r.Error("DH0002", masterConfigLoadError, fmt.Sprintf("Could not read master config file '%s':\n(%T) %[2]v", masterConfigFile, masterConfigLoadError)) +func printMasterConfigLoadError(masterConfigFile string, logger *log.Logger) { + logger.Error("DH0002", fmt.Sprintf("Could not read master config file '%s':\n(%T) %[2]v", masterConfigFile, masterConfigLoadError)) } diff --git a/pkg/oc/admin/diagnostics/diagnostics/network/run_pod.go b/pkg/oc/admin/diagnostics/diagnostics/network/run_pod.go index 670beb647010..f5274afc2e66 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/network/run_pod.go +++ b/pkg/oc/admin/diagnostics/diagnostics/network/run_pod.go @@ -5,24 +5,34 @@ import ( "fmt" "os" "os/signal" + "path/filepath" + "strings" "syscall" "time" flag "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/util/sets" + kvalidation "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/storage/names" 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" + "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 ( - NetworkDiagnosticName = "NetworkCheck" + 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. @@ -59,6 +69,40 @@ func (d *NetworkDiagnostic) Description() string { return "Create a pod on all schedulable nodes and run network diagnostics from the application standpoint" } +func (d *NetworkDiagnostic) Requirements() (client bool, host bool) { + return true, false +} + +func (d *NetworkDiagnostic) AvailableParameters() []types.Parameter { + return []types.Parameter{ + {FlagNetworkDiagLogDir, "Path to store diagnostic results in case of errors", &d.LogDir, util.NetworkDiagDefaultLogDir}, + {FlagNetworkDiagPodImage, "Image to use for diagnostic pod", &d.PodImage, util.GetNetworkDiagDefaultPodImage()}, + {FlagNetworkDiagTestPodImage, "Image to use for diagnostic test pod", &d.TestPodImage, util.GetNetworkDiagDefaultTestPodImage()}, + {FlagNetworkDiagTestPodProtocol, "Protocol used to connect to diagnostic test pod", &d.TestPodProtocol, util.NetworkDiagDefaultTestPodProtocol}, + {FlagNetworkDiagTestPodPort, "Serving port on the diagnostic test pod", &d.TestPodPort, util.NetworkDiagDefaultTestPodPort}, + } +} + +func (d *NetworkDiagnostic) Complete(logger *log.Logger) error { + logdir, err := filepath.Abs(d.LogDir) + if err != nil { + return err + } + if path, err := os.Stat(d.LogDir); err == nil && !path.Mode().IsDir() { + return fmt.Errorf("Network log path %q exists but is not a directory", d.LogDir) + } + d.LogDir = logdir + + supportedProtocols := sets.NewString(string(kapi.ProtocolTCP), string(kapi.ProtocolUDP)) + if !supportedProtocols.Has(d.TestPodProtocol) { + return fmt.Errorf("invalid protocol for network diagnostic test pod. Supported protocols: %s", strings.Join(supportedProtocols.List(), ",")) + } + if kvalidation.IsValidPortNum(d.TestPodPort) != nil { + return fmt.Errorf("invalid port for network diagnostic test pod. Must be in the range 1 to 65535.") + } + return nil +} + // CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic. func (d *NetworkDiagnostic) CanRun() (bool, error) { if d.PreventModification { diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/collect.go b/pkg/oc/admin/diagnostics/diagnostics/networkpod/collect.go index a2dabe946fbf..521e52c8f07c 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/networkpod/collect.go +++ b/pkg/oc/admin/diagnostics/diagnostics/networkpod/collect.go @@ -30,6 +30,10 @@ func (d CollectNetworkInfo) Description() string { return "Collect network information in the cluster." } +func (d CollectNetworkInfo) Requirements() (client bool, host bool) { + return true, false +} + // CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic. func (d CollectNetworkInfo) CanRun() (bool, error) { if d.KubeClient == nil { diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/external.go b/pkg/oc/admin/diagnostics/diagnostics/networkpod/external.go index 816927a6c661..d7ea0db41602 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/networkpod/external.go +++ b/pkg/oc/admin/diagnostics/diagnostics/networkpod/external.go @@ -26,6 +26,10 @@ func (d CheckExternalNetwork) Description() string { return "Check that external network is accessible within a pod" } +func (d CheckExternalNetwork) Requirements() (client bool, host bool) { + return true, false +} + // CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic. func (d CheckExternalNetwork) CanRun() (bool, error) { return true, nil diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/node.go b/pkg/oc/admin/diagnostics/diagnostics/networkpod/node.go index f44e4c8717b9..560d679f233c 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/networkpod/node.go +++ b/pkg/oc/admin/diagnostics/diagnostics/networkpod/node.go @@ -33,6 +33,10 @@ func (d CheckNodeNetwork) Description() string { return "Check that pods in the cluster can access its own node." } +func (d CheckNodeNetwork) Requirements() (client bool, host bool) { + return true, false +} + // CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic. func (d CheckNodeNetwork) CanRun() (bool, error) { if d.KubeClient == nil { diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/pod.go b/pkg/oc/admin/diagnostics/diagnostics/networkpod/pod.go index 73abdccb4258..f4e88969d065 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/networkpod/pod.go +++ b/pkg/oc/admin/diagnostics/diagnostics/networkpod/pod.go @@ -41,6 +41,10 @@ func (d CheckPodNetwork) Description() string { return "Check pod to pod communication in the cluster. In case of ovs-subnet network plugin, all pods should be able to communicate with each other and in case of multitenant network plugin, pods in non-global projects should be isolated and pods in global projects should be able to access any pod in the cluster and vice versa." } +func (d CheckPodNetwork) Requirements() (client bool, host bool) { + return true, false +} + // CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic. func (d CheckPodNetwork) CanRun() (bool, error) { if d.KubeClient == nil { diff --git a/pkg/oc/admin/diagnostics/diagnostics/networkpod/service.go b/pkg/oc/admin/diagnostics/diagnostics/networkpod/service.go index 40f59f59c107..33e37ad768c9 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/networkpod/service.go +++ b/pkg/oc/admin/diagnostics/diagnostics/networkpod/service.go @@ -41,6 +41,10 @@ func (d CheckServiceNetwork) Description() string { return "Check pod to service communication in the cluster. In case of ovs-subnet network plugin, all pods should be able to communicate with all services and in case of multitenant network plugin, services in non-global projects should be isolated and pods in global projects should be able to access any service in the cluster." } +func (d CheckServiceNetwork) Requirements() (client bool, host bool) { + return true, false +} + // CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic. func (d CheckServiceNetwork) CanRun() (bool, error) { if d.KubeClient == nil { diff --git a/pkg/oc/admin/diagnostics/diagnostics/pod/auth.go b/pkg/oc/admin/diagnostics/diagnostics/pod/auth.go index a5056281b054..17cd353a2931 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/pod/auth.go +++ b/pkg/oc/admin/diagnostics/diagnostics/pod/auth.go @@ -42,6 +42,10 @@ func (d PodCheckAuth) Description() string { return "Check that service account credentials authenticate as expected" } +func (d PodCheckAuth) Requirements() (client bool, host bool) { + return true, false +} + // CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic. func (d PodCheckAuth) CanRun() (bool, error) { return true, nil diff --git a/pkg/oc/admin/diagnostics/diagnostics/pod/dns.go b/pkg/oc/admin/diagnostics/diagnostics/pod/dns.go index 0d701c6df29b..0f1adb28b3d1 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/pod/dns.go +++ b/pkg/oc/admin/diagnostics/diagnostics/pod/dns.go @@ -38,6 +38,10 @@ func (d PodCheckDns) Description() string { return "Check that DNS within a pod works as expected" } +func (d PodCheckDns) Requirements() (client bool, host bool) { + return true, false +} + // CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic. func (d PodCheckDns) CanRun() (bool, error) { return true, nil diff --git a/pkg/oc/admin/diagnostics/diagnostics/systemd/analyze_logs.go b/pkg/oc/admin/diagnostics/diagnostics/systemd/analyze_logs.go index 2b38287e963b..8bfe88994961 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/systemd/analyze_logs.go +++ b/pkg/oc/admin/diagnostics/diagnostics/systemd/analyze_logs.go @@ -47,6 +47,10 @@ func (d AnalyzeLogs) Description() string { return "Check for recent problems in systemd service logs" } +func (d AnalyzeLogs) Requirements() (client bool, host bool) { + return false, true +} + func (d AnalyzeLogs) CanRun() (bool, error) { if HasJournalctl() { return true, nil diff --git a/pkg/oc/admin/diagnostics/diagnostics/systemd/unit_status.go b/pkg/oc/admin/diagnostics/diagnostics/systemd/unit_status.go index 68dbea24be07..e030b8cb9943 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/systemd/unit_status.go +++ b/pkg/oc/admin/diagnostics/diagnostics/systemd/unit_status.go @@ -21,12 +21,18 @@ func (d UnitStatus) Name() string { func (d UnitStatus) Description() string { return "Check status for related systemd units" } + +func (d UnitStatus) Requirements() (client bool, host bool) { + return false, true +} + func (d UnitStatus) CanRun() (bool, error) { if HasSystemctl() { return true, nil } return false, errors.New("systemd is not present/functional on this host") } + func (d UnitStatus) Check() types.DiagnosticResult { r := types.NewDiagnosticResult(UnitStatusName) diff --git a/pkg/oc/admin/diagnostics/diagnostics/types/diagnostic.go b/pkg/oc/admin/diagnostics/diagnostics/types/diagnostic.go index 7c3517426e42..1489c5ac8325 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/types/diagnostic.go +++ b/pkg/oc/admin/diagnostics/diagnostics/types/diagnostic.go @@ -7,12 +7,14 @@ import ( "sync" "github.com/golang/glog" + "k8s.io/apimachinery/pkg/util/sets" "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" ) // Diagnostic provides the interface for building diagnostics that can execute as part of the diagnostic framework. // The Name and Description methods are used to identify which diagnostic is running in the output. +// Requirements() identifies the common parameters this diagnostic may require. // The CanRun() method provides a pre-execution check for whether the diagnostic is relevant and runnable as constructed. // If not, a user-facing reason for skipping the diagnostic can be given. // Finally, the Check() method runs the diagnostic with the resulting messages and errors returned in a result object. @@ -20,10 +22,62 @@ import ( type Diagnostic interface { Name() string Description() string + Requirements() (client bool, host bool) CanRun() (canRun bool, reason error) Check() DiagnosticResult } +// DiagnosticsList is a simple list type for providing the Names() method +type DiagnosticList []Diagnostic + +// Names returns a set of the names of the diagnostics in the list +func (d DiagnosticList) Names() sets.String { + names := sets.NewString() + for _, diag := range d { + names.Insert(diag.Name()) + } + return names +} + +// Diagnostic provides an interface for finishing initialization of a diagnostic. +type IncompleteDiagnostic interface { + // Complete runs just before CanRun; it can log issues to the logger. Returns error on misconfiguration. + Complete(*log.Logger) error +} + +// Parameter is used by an individual diagnostic to specify non-shared parameters for itself +// Name is a lowercase string that will be used to generate a CLI flag +// Description is used to describe the same flag +// Target is a pointer to what the flag should fill in +// Default is the default value for the flag description +type Parameter struct { + Name string + Description string + Target interface{} + Default interface{} +} + +// ParameterizedDiagnostic is a Diagnostic that can accept arbitrary parameters specifically for it. +// AvailableParameters is used to describe or validate the parameters given on the command line. +type ParameterizedDiagnostic interface { + Diagnostic + AvailableParameters() []Parameter +} + +// ParameterizedDiagnosticMap holds PDs by name for later lookup +type ParameterizedDiagnosticMap map[string]ParameterizedDiagnostic + +// NewParameterizedDiagnosticMap filters PDs from a list of diagnostics into a PDMap. +func NewParameterizedDiagnosticMap(diags ...Diagnostic) ParameterizedDiagnosticMap { + m := ParameterizedDiagnosticMap{} + for _, diag := range diags { + if pd, ok := diag.(ParameterizedDiagnostic); ok { + m[diag.Name()] = pd + } + } + return m +} + // DiagnosticResult provides a result object for diagnostics, accumulating the messages and errors // that the diagnostic generates as it runs. type DiagnosticResult interface { diff --git a/pkg/oc/admin/diagnostics/etcd.go b/pkg/oc/admin/diagnostics/etcd.go deleted file mode 100644 index 0e5432e31757..000000000000 --- a/pkg/oc/admin/diagnostics/etcd.go +++ /dev/null @@ -1,91 +0,0 @@ -package diagnostics - -import ( - "fmt" - "time" - - "k8s.io/apimachinery/pkg/util/sets" - - etcdclient "github.com/coreos/etcd/client" - "github.com/coreos/etcd/clientv3" - - "github.com/openshift/origin/pkg/cmd/server/etcd" - clustdiags "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/host" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" -) - -var ( - // availableEtcdDiagnostics contains the names of etcd diagnostics that can be executed - // during a single run of diagnostics. Add more diagnostics to the list as they are defined. - availableEtcdDiagnostics = sets.NewString( - clustdiags.EtcdWriteName, - ) - // defaultSkipEtcdDiagnostics is a list of diagnostics to skip by default - defaultSkipEtcdDiagnostics = sets.NewString( - clustdiags.EtcdWriteName, - ) -) - -// buildEtcdDiagnostics builds cluster Diagnostic objects if etcd is configured -func (o DiagnosticsOptions) buildEtcdDiagnostics() ([]types.Diagnostic, bool, error) { - requestedDiagnostics := availableEtcdDiagnostics.Intersection(sets.NewString(o.RequestedDiagnostics...)).List() - if len(requestedDiagnostics) == 0 { // no diagnostics to run here - return nil, true, nil // don't waste time on discovery - } - - v2Client, v3Client, found, err := o.findEtcdClients(o.MasterConfigLocation) - if !found { - o.Logger.Notice("DE2000", "Could not configure etcd clients against the current config, so etcd diagnostics will be skipped") - return nil, true, err - } - - diagnostics := []types.Diagnostic{} - for _, diagnosticName := range requestedDiagnostics { - var d types.Diagnostic - switch diagnosticName { - case clustdiags.EtcdWriteName: - d = &clustdiags.EtcdWriteVolume{V2Client: v2Client, V3Client: v3Client} - default: - return nil, false, fmt.Errorf("unknown diagnostic: %v", diagnosticName) - } - diagnostics = append(diagnostics, d) - } - return diagnostics, true, nil -} - -// findEtcdClients finds and loads etcd clients -func (o DiagnosticsOptions) findEtcdClients(configFile string) (etcdclient.Client, *clientv3.Client, bool, error) { - r := types.NewDiagnosticResult("") - masterConfig, err := host.GetMasterConfig(r, configFile) - if err != nil { - configErr := fmt.Errorf("Unreadable master config; skipping this diagnostic.") - o.Logger.Error("DE2001", configErr.Error()) - return nil, nil, false, configErr - } - if len(masterConfig.EtcdClientInfo.URLs) == 0 { - configErr := fmt.Errorf("No etcdClientInfo.urls defined; can't contact etcd") - o.Logger.Error("DE2002", configErr.Error()) - return nil, nil, false, configErr - } - v2Client, err := etcd.MakeEtcdClient(masterConfig.EtcdClientInfo) - if err != nil { - configErr := fmt.Errorf("Unable to create an etcd v2 client: %v", err) - o.Logger.Error("DE2003", configErr.Error()) - return nil, nil, false, configErr - } - config, err := etcd.MakeEtcdClientV3Config(masterConfig.EtcdClientInfo) - if err != nil { - configErr := fmt.Errorf("Unable to create an etcd v3 client config: %v", err) - o.Logger.Error("DE2004", configErr.Error()) - return nil, nil, false, configErr - } - config.DialTimeout = 5 * time.Second - v3Client, err := clientv3.New(*config) - if err != nil { - configErr := fmt.Errorf("Unable to create an etcd v3 client: %v", err) - o.Logger.Error("DE2005", configErr.Error()) - return nil, nil, false, configErr - } - return v2Client, v3Client, true, nil -} diff --git a/pkg/oc/admin/diagnostics/host.go b/pkg/oc/admin/diagnostics/host.go index e8f27b8abca4..4eaf1a4d7056 100644 --- a/pkg/oc/admin/diagnostics/host.go +++ b/pkg/oc/admin/diagnostics/host.go @@ -11,17 +11,30 @@ import ( ) var ( - // availableHostDiagnostics 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. - availableHostDiagnostics = sets.NewString(systemddiags.AnalyzeLogsName, systemddiags.UnitStatusName, hostdiags.MasterConfigCheckName, hostdiags.NodeConfigCheckName) + // defaultSkipHostDiagnostics is a list of diagnostics to skip by default + defaultSkipHostDiagnostics = sets.NewString( + hostdiags.EtcdWriteName, + ) ) +// availableHostDiagnostics 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. +func availableHostDiagnostics() types.DiagnosticList { + return types.DiagnosticList{ + &systemddiags.AnalyzeLogs{}, + &systemddiags.UnitStatus{}, + &hostdiags.MasterConfigCheck{}, + &hostdiags.NodeConfigCheck{}, + &hostdiags.EtcdWriteVolume{}, + } +} + // buildHostDiagnostics builds host Diagnostic objects based on the host environment. -// Returns the Diagnostics built, "ok" bool for whether to proceed or abort, and an error if any was encountered during the building of diagnostics.) { -func (o DiagnosticsOptions) buildHostDiagnostics() ([]types.Diagnostic, bool, error) { - requestedDiagnostics := availableHostDiagnostics.Intersection(sets.NewString(o.RequestedDiagnostics...)).List() +// Returns the Diagnostics built, and an error if any was encountered during the building of diagnostics.) { +func (o DiagnosticsOptions) buildHostDiagnostics() ([]types.Diagnostic, error) { + requestedDiagnostics := availableHostDiagnostics().Names().Intersection(sets.NewString(o.RequestedDiagnostics.List()...)).List() if len(requestedDiagnostics) == 0 { // no diagnostics to run here - return nil, true, nil // don't waste time on discovery + return nil, nil // don't waste time on discovery } isHost := o.IsHost if len(o.MasterConfigLocation) > 0 || len(o.NodeConfigLocation) > 0 { @@ -30,7 +43,7 @@ func (o DiagnosticsOptions) buildHostDiagnostics() ([]types.Diagnostic, bool, er // If we're not looking at a host, don't try the diagnostics if !isHost { - return nil, true, nil + return nil, nil } diagnostics := []types.Diagnostic{} @@ -39,18 +52,22 @@ func (o DiagnosticsOptions) buildHostDiagnostics() ([]types.Diagnostic, bool, er var d types.Diagnostic switch diagnosticName { case systemddiags.AnalyzeLogsName: - d = systemddiags.AnalyzeLogs{SystemdUnits: systemdUnits} + d = &systemddiags.AnalyzeLogs{SystemdUnits: systemdUnits} case systemddiags.UnitStatusName: - d = systemddiags.UnitStatus{SystemdUnits: systemdUnits} + d = &systemddiags.UnitStatus{SystemdUnits: systemdUnits} case hostdiags.MasterConfigCheckName: - d = hostdiags.MasterConfigCheck{MasterConfigFile: o.MasterConfigLocation} + d = &hostdiags.MasterConfigCheck{MasterConfigFile: o.MasterConfigLocation} case hostdiags.NodeConfigCheckName: - d = hostdiags.NodeConfigCheck{NodeConfigFile: o.NodeConfigLocation} + d = &hostdiags.NodeConfigCheck{NodeConfigFile: o.NodeConfigLocation} + case hostdiags.EtcdWriteName: + etcd := o.ParameterizedDiagnostics[hostdiags.EtcdWriteName].(*hostdiags.EtcdWriteVolume) + etcd.MasterConfigLocation = o.MasterConfigLocation + d = etcd default: - return diagnostics, false, fmt.Errorf("unknown diagnostic: %v", diagnosticName) + return diagnostics, fmt.Errorf("unknown diagnostic: %v", diagnosticName) } diagnostics = append(diagnostics, d) } - return diagnostics, true, nil + return diagnostics, nil } diff --git a/pkg/oc/admin/diagnostics/options/flaginfo.go b/pkg/oc/admin/diagnostics/options/flaginfo.go index 0470b941ef97..4ea4662a9634 100644 --- a/pkg/oc/admin/diagnostics/options/flaginfo.go +++ b/pkg/oc/admin/diagnostics/options/flaginfo.go @@ -50,13 +50,5 @@ const ( FlagClusterContextName = "cluster-context" FlagLevelName = "diaglevel" FlagIsHostName = "host" - FlagImageTemplateName = "images" - FlagLatestImageName = "latest-images" FlagPreventModificationName = "prevent-modification" - - FlagNetworkDiagLogDir = "network-logdir" - FlagNetworkDiagPodImage = "network-pod-image" - FlagNetworkDiagTestPodImage = "network-test-pod-image" - FlagNetworkDiagTestPodProtocol = "network-test-pod-protocol" - FlagNetworkDiagTestPodPort = "network-test-pod-port" ) diff --git a/test/cmd/diagnostics.sh b/test/cmd/diagnostics.sh index ddb8f487552e..928c831fe96d 100755 --- a/test/cmd/diagnostics.sh +++ b/test/cmd/diagnostics.sh @@ -5,7 +5,7 @@ trap os::test::junit::reconcile_output EXIT # This test validates the diagnostics command # available diagnostics (2016-09-01): -# AnalyzeLogs ClusterRegistry ClusterRoleBindings ClusterRoles ClusterRouter ConfigContexts DiagnosticPod MasterConfigCheck MasterNode NetworkCheck NodeConfigCheck NodeDefinitions UnitStatus MetricsApiProxy ServiceExternalIPs +# AnalyzeLogs ClusterRegistry ClusterRoleBindings ClusterRoles ClusterRouter ConfigContexts DiagnosticPod EtcdWriteVolume MasterConfigCheck MasterNode NetworkCheck NodeConfigCheck NodeDefinitions UnitStatus MetricsApiProxy ServiceExternalIPs # Without things feeding into systemd, AnalyzeLogs and UnitStatus are irrelevant. # The rest should be included in some fashion. @@ -25,10 +25,17 @@ os::cmd::expect_failure_and_text "oc adm diagnostics NodeConfigCheck --node-conf os::cmd::expect_success 'oc adm policy reconcile-cluster-roles --additive-only=false --confirm' -os::cmd::expect_success 'oc adm diagnostics ClusterRoleBindings ClusterRoles ConfigContexts ' +os::cmd::expect_success 'oc adm diagnostics ClusterRoleBindings ' +os::cmd::expect_success 'oc adm diagnostics ClusterRoles ' +os::cmd::expect_success 'oc adm diagnostics ConfigContexts ' # DiagnosticPod can't run without Docker, would just time out. Exercise flags instead. -os::cmd::expect_success "oc adm diagnostics DiagnosticPod --prevent-modification --images=foo" -os::cmd::expect_success "oc adm diagnostics MasterConfigCheck NodeConfigCheck ServiceExternalIPs --master-config=${MASTER_CONFIG_DIR}/master-config.yaml --node-config=${NODE_CONFIG_DIR}/node-config.yaml" +os::cmd::expect_failure_and_text "oc adm diagnostics DiagnosticPod --prevent-modification --images=foo" 'prevented because the --prevent-modification flag was specified' +# EtcdWriteVolume can't run without etcd. Just exercise flags. +os::cmd::expect_success "oc adm diagnostics EtcdWriteVolume --duration=10s --help" +os::cmd::expect_success "oc adm diagnostics MasterConfigCheck --master-config=${MASTER_CONFIG_DIR}/master-config.yaml" +os::cmd::expect_success "oc adm diagnostics masterconfigcheck --master-config=${MASTER_CONFIG_DIR}/master-config.yaml" +os::cmd::expect_success "oc adm diagnostics NodeConfigCheck --node-config=${NODE_CONFIG_DIR}/node-config.yaml" +os::cmd::expect_success "oc adm diagnostics serviceexternalips --master-config=${MASTER_CONFIG_DIR}/master-config.yaml" os::cmd::expect_failure_and_text 'oc adm diagnostics ClusterRegistry' "DClu1006 from diagnostic ClusterRegistry" # MasterNode fails in test, possibly because the hostname doesn't resolve? Disabled #os::cmd::expect_success_and_text 'oc adm diagnostics MasterNode' 'Network plugin does not require master to also run node' @@ -36,12 +43,13 @@ os::cmd::expect_failure_and_text 'oc adm diagnostics ClusterRegistry' "DClu1006 # no ordering allowed #os::cmd::expect_failure 'oc adm diagnostics ClusterRouter' # "DClu2001 from diagnostic ClusterRouter" os::cmd::expect_failure 'oc adm diagnostics NodeDefinitions' -os::cmd::expect_failure_and_text 'oc adm diagnostics FakeDiagnostic AlsoMissing' 'No requested diagnostics are available: requested=FakeDiagnostic AlsoMissing' -os::cmd::expect_failure_and_text 'oc adm diagnostics AnalyzeLogs AlsoMissing' 'Not all requested diagnostics are available: missing=AlsoMissing requested=AnalyzeLogs AlsoMissing available=' -os::cmd::expect_success_and_text 'oc adm diagnostics MetricsApiProxy' 'Skipping diagnostic: MetricsApiProxy' -os::cmd::expect_success_and_text 'oc adm diagnostics NetworkCheck --prevent-modification' 'Skipping diagnostic: NetworkCheck' +os::cmd::expect_failure_and_text 'oc adm diagnostics FakeDiagnostic' 'Unexpected command line argument.*FakeDiagnostic' +os::cmd::expect_failure_and_text 'oc adm diagnostics AnalyzeLogs FakeDiagnostic' 'Unexpected command line argument.*FakeDiagnostic' +os::cmd::expect_failure_and_text 'oc adm diagnostics all FakeDiagnostic' 'Unexpected command line argument.*FakeDiagnostic' +os::cmd::expect_failure_and_text 'oc adm diagnostics MetricsApiProxy' 'Skipping diagnostic: MetricsApiProxy' +os::cmd::expect_failure_and_text 'oc adm diagnostics NetworkCheck --prevent-modification' 'Skipping diagnostic: NetworkCheck' # oc ex diagnostics is deprecated but not removed. Make sure it works until we consciously remove it. -os::cmd::expect_success 'oc ex diagnostics ClusterRoleBindings ClusterRoles ConfigContexts ' +os::cmd::expect_success 'oc ex diagnostics ConfigContexts' echo "diagnostics: ok" os::test::junit::declare_suite_end From 8059482abd6d21cae074347e2029ea3b44ce6aa7 Mon Sep 17 00:00:00 2001 From: Luke Meyer Date: Sun, 17 Dec 2017 10:19:05 -0500 Subject: [PATCH 2/2] diagnostics: refactor build-and-run for clarity Improve the legibility of the code that builds and runs diagnostics. The main confusion was the need to track and report the number of diagnostic errors and warnings versus problems that halt execution prematurely and the need to return a correct status code at completion. In the end it seemed simplest to just have the logger report how many diagnostic errors and warnings were seen, leaving function signatures to return only build/run errors. As a side effect, I looked at the ConfigLoading code that does an early check to see if there is a client config, and concluded it was confusing and unnecessary for it to be a diagnostic, so I refactored it away. Main diagnostics as well as pod diagnostics are now implemented more uniformly. --- pkg/oc/admin/diagnostics/client.go | 10 +- pkg/oc/admin/diagnostics/cluster.go | 104 ++++---- pkg/oc/admin/diagnostics/config.go | 140 ++++++++-- pkg/oc/admin/diagnostics/diagnostics.go | 245 +++++++----------- .../diagnostics/client/config_loading.go | 150 ----------- .../admin/diagnostics/diagnostics/log/log.go | 22 +- pkg/oc/admin/diagnostics/host.go | 6 +- pkg/oc/admin/diagnostics/network_pod.go | 71 ++--- pkg/oc/admin/diagnostics/pod.go | 68 ++--- pkg/oc/admin/diagnostics/util/util.go | 15 +- 10 files changed, 347 insertions(+), 484 deletions(-) delete mode 100644 pkg/oc/admin/diagnostics/diagnostics/client/config_loading.go diff --git a/pkg/oc/admin/diagnostics/client.go b/pkg/oc/admin/diagnostics/client.go index 6c477edc81c7..922713de3608 100644 --- a/pkg/oc/admin/diagnostics/client.go +++ b/pkg/oc/admin/diagnostics/client.go @@ -18,14 +18,14 @@ func availableClientDiagnostics() types.DiagnosticList { } // buildClientDiagnostics builds client Diagnostic objects based on the rawConfig passed in. -// Returns the Diagnostics built, "ok" bool for whether to proceed or abort, and an error if any was encountered during the building of diagnostics.) { -func (o DiagnosticsOptions) buildClientDiagnostics(rawConfig *clientcmdapi.Config) ([]types.Diagnostic, bool, error) { +// Returns the Diagnostics built, and any fatal errors encountered during the building of diagnostics. +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 { - o.Logger.Notice("CED0001", "Could not configure a client, so client diagnostics are limited to testing configuration and connection") + o.Logger().Notice("CED0001", "Could not configure a client, so client diagnostics are limited to testing configuration and connection") available = sets.NewString(clientdiags.ConfigContextsName) } @@ -64,8 +64,8 @@ func (o DiagnosticsOptions) buildClientDiagnostics(rawConfig *clientcmdapi.Confi nd.PreventModification = o.PreventModification diagnostics = append(diagnostics, nd) default: - return nil, false, fmt.Errorf("unknown diagnostic: %v", diagnosticName) + return nil, fmt.Errorf("unknown diagnostic: %v", diagnosticName) } } - return diagnostics, true, clientErr + return diagnostics, clientErr } diff --git a/pkg/oc/admin/diagnostics/cluster.go b/pkg/oc/admin/diagnostics/cluster.go index 87c9c3a4ba38..8d5199e60d11 100644 --- a/pkg/oc/admin/diagnostics/cluster.go +++ b/pkg/oc/admin/diagnostics/cluster.go @@ -43,52 +43,50 @@ func availableClusterDiagnostics() types.DiagnosticList { } // buildClusterDiagnostics builds cluster Diagnostic objects if a cluster-admin client can be extracted from the rawConfig passed in. -// Returns the Diagnostics built, "ok" bool for whether to proceed or abort, and an error if any was encountered during the building of diagnostics.) { -func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Config) ([]types.Diagnostic, bool, error) { +// Returns the Diagnostics built and any fatal error encountered during the building of diagnostics. +func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Config) ([]types.Diagnostic, error) { requestedDiagnostics := availableClusterDiagnostics().Names().Intersection(sets.NewString(o.RequestedDiagnostics.List()...)).List() if len(requestedDiagnostics) == 0 { // no diagnostics to run here - return nil, true, nil // don't waste time on discovery + return nil, nil // don't waste time on discovery } - var ( - kclusterClient kclientset.Interface - ) + var kclusterClient kclientset.Interface - config, kclusterClient, found, serverUrl, err := o.findClusterClients(rawConfig) - if !found { - 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, true, err + config, kclusterClient, serverUrl, err := o.findClusterClients(rawConfig) + 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, false, err + return nil, err } imageClient, err := imageclient.NewForConfig(config) if err != nil { - return nil, false, err + return nil, err } projectClient, err := projectclient.NewForConfig(config) if err != nil { - return nil, false, err + return nil, err } routeClient, err := routeclient.NewForConfig(config) if err != nil { - return nil, false, err + return nil, err } appsClient, err := appsclient.NewForConfig(config) if err != nil { - return nil, false, err + return nil, err } oauthClient, err := oauthclient.NewForConfig(config) if err != nil { - return nil, false, err + return nil, err } oauthorizationClient, err := oauthorizationclient.NewForConfig(config) if err != nil { - return nil, false, err + return nil, err } securityClient, err := securityclient.NewForConfig(config) if err != nil { - return nil, false, err + return nil, err } diagnostics := []types.Diagnostic{} @@ -116,64 +114,68 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf case clustdiags.RouteCertificateValidationName: d = &clustdiags.RouteCertificateValidation{SARClient: kclusterClient.Authorization(), RESTConfig: config} default: - return nil, false, fmt.Errorf("unknown diagnostic: %v", diagnosticName) + return nil, fmt.Errorf("unknown diagnostic: %v", diagnosticName) } diagnostics = append(diagnostics, d) } - return diagnostics, true, nil + return diagnostics, nil } // attempts to find which context in the config might be a cluster-admin for the server in the current context. -func (o DiagnosticsOptions) findClusterClients(rawConfig *clientcmdapi.Config) (*rest.Config, kclientset.Interface, bool, string, error) { +// 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) { if o.ClientClusterContext != "" { // user has specified cluster context to use - if context, exists := rawConfig.Contexts[o.ClientClusterContext]; !exists { + 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, false, "", configErr - } else if config, kube, found, serverUrl, err := o.makeClusterClients(rawConfig, o.ClientClusterContext, context); found { - return config, kube, true, serverUrl, err - } else { - return nil, nil, false, "", err + o.Logger().Error("CED1003", configErr.Error()) + return 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 } 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, false, "", configErr + o.Logger().Error("CED1004", configErr.Error()) + return nil, nil, "", configErr } // check if current context is already cluster admin - if config, kube, found, serverUrl, err := o.makeClusterClients(rawConfig, rawConfig.CurrentContext, currentContext); found { - return config, kube, true, serverUrl, err + config, kube, serverUrl, err := o.makeClusterClients(rawConfig, rawConfig.CurrentContext, currentContext) + if err == nil && config != nil { + return config, kube, serverUrl, 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/") { - if config, kube, found, serverUrl, err := o.makeClusterClients(rawConfig, name, context); found { - return config, kube, true, serverUrl, err - } else { - return nil, nil, false, "", err // don't try more than one such context, they'll probably fail the same + config, kube, serverUrl, 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 nil, nil, false, "", nil + return 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, bool, string, error) { +func (o DiagnosticsOptions) makeClusterClients(rawConfig *clientcmdapi.Config, contextName string, context *clientcmdapi.Context) (*rest.Config, kclientset.Interface, string, error) { overrides := &clientcmd.ConfigOverrides{Context: *context} clientConfig := clientcmd.NewDefaultClientConfig(*rawConfig, overrides) serverUrl := rawConfig.Clusters[context.Cluster].Server factory := osclientcmd.NewFactory(clientConfig) 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, false, "", nil + o.Logger().Debug("CED1006", fmt.Sprintf("Error creating client for context '%s':\n%v", contextName, err)) + return nil, nil, "", nil } - o.Logger.Debug("CED1005", fmt.Sprintf("Checking if context is cluster-admin: '%s'", contextName)) + 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, false, "", 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{ @@ -187,17 +189,17 @@ func (o DiagnosticsOptions) makeClusterClients(rawConfig *clientcmdapi.Config, c } 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, false, "", nil + 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, false, "", err + 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, true, serverUrl, nil + o.Logger().Info("CED1009", fmt.Sprintf("Using context for cluster-admin access: '%s'", contextName)) + return config, kubeClient, serverUrl, nil } } - o.Logger.Debug("CED1010", fmt.Sprintf("Context does not have cluster-admin access: '%s'", contextName)) - return nil, nil, false, "", nil + o.Logger().Debug("CED1010", fmt.Sprintf("Context does not have cluster-admin access: '%s'", contextName)) + return nil, nil, "", nil } diff --git a/pkg/oc/admin/diagnostics/config.go b/pkg/oc/admin/diagnostics/config.go index 6c2d614711cf..f156a728d722 100644 --- a/pkg/oc/admin/diagnostics/config.go +++ b/pkg/oc/admin/diagnostics/config.go @@ -2,28 +2,17 @@ package diagnostics import ( "errors" + "fmt" + "io/ioutil" + "os" + "k8s.io/client-go/tools/clientcmd" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" "github.com/openshift/origin/pkg/client/config" - clientdiagnostics "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/client" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" + "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/util" ) -// determine if we even have a client config -func (o DiagnosticsOptions) detectClientConfig() (bool, bool, []types.DiagnosticError, []types.DiagnosticError) { - if o.ClientFlags == nil { - return false, false, []types.DiagnosticError{}, []types.DiagnosticError{} - } - diagnostic := &clientdiagnostics.ConfigLoading{ConfFlagName: config.OpenShiftConfigFlagName, ClientFlags: o.ClientFlags} - o.Logger.Notice("CED2011", "Determining if client configuration exists for client/cluster diagnostics") - result := diagnostic.Check() - for _, entry := range result.Logs() { - o.Logger.LogEntry(entry) - } - return true, diagnostic.SuccessfulLoad(), result.Warnings(), result.Errors() -} - // use the base factory to return a raw config (not specific to a context) func (o DiagnosticsOptions) buildRawConfig() (*clientcmdapi.Config, error) { kubeConfig, configErr := o.Factory.OpenShiftClientConfig().RawConfig() @@ -35,3 +24,122 @@ func (o DiagnosticsOptions) buildRawConfig() (*clientcmdapi.Config, error) { } return &kubeConfig, nil } + +// determine if we even have a client config +func (o DiagnosticsOptions) detectClientConfig() (expected bool, detected bool) { + if o.ClientFlags == nil { + // options for client not provided, so it must not be expected. + return false, false + } + o.Logger().Notice("CED2011", "Determining if client configuration exists for client/cluster diagnostics") + confFlagName := config.OpenShiftConfigFlagName + confFlagValue := o.ClientFlags.Lookup(confFlagName).Value.String() + successfulLoad := false + + var foundPath string + rules := config.NewOpenShiftClientConfigLoadingRules() + paths := append([]string{confFlagValue}, rules.Precedence...) + for index, path := range paths { + errmsg := "" + switch index { + case 0: + errmsg = fmt.Sprintf("--%s specified that client config should be at %s\n", confFlagName, path) + case len(paths) - 1: // config in ~/.kube + // no error message indicated if it is not there... user didn't say it would be + default: // can be multiple paths from the env var in theory; all cases should go here + if len(os.Getenv(config.OpenShiftConfigPathEnvVar)) != 0 { + errmsg = fmt.Sprintf("Env var %s specified that client config could be at %s\n", config.OpenShiftConfigPathEnvVar, path) + } + } + + if o.canOpenConfigFile(path, errmsg) && len(foundPath) == 0 { + successfulLoad = true + foundPath = path + } + } + if len(foundPath) > 0 { + if len(confFlagValue) > 0 && confFlagValue != foundPath { + // found config but not where --config said + o.Logger().Error("DCli1001", fmt.Sprintf(` +The client configuration file was not found where the --%s flag indicated: + %s +A config file was found at the following location: + %s +If you wish to use this file for client configuration, you can specify it +with the --%[1]s flag, or just not specify the flag. + `, confFlagName, confFlagValue, foundPath)) + } + } else { // not found, check for master-generated ones to recommend + if len(confFlagValue) > 0 { + o.Logger().Error("DCli1002", fmt.Sprintf("Did not find config file where --%s=%s indicated", confFlagName, confFlagValue)) + } + adminWarningF := ` +No client config file was available; however, one exists at + %[2]s +which may have been generated automatically by the master. +If you want to use this config, you should copy it to the +standard location (%[3]s), +or you can set the environment variable %[1]s: + export %[1]s=%[2]s +If not, obtain a config file and place it in the standard +location for use by the client and diagnostics. +` + // look for it in auto-generated locations when not found properly + for _, path := range util.AdminKubeConfigPaths { + msg := fmt.Sprintf("Looking for a possible client config at %s\n", path) + if o.canOpenConfigFile(path, msg) { + o.Logger().Warn("DCli1003", fmt.Sprintf(adminWarningF, config.OpenShiftConfigPathEnvVar, path, config.RecommendedHomeFile)) + break + } + } + } + return true, successfulLoad +} + +// ---------------------------------------------------------- +// Attempt to open file at path as client config +// If there is a problem and errmsg is set, log an error +func (o DiagnosticsOptions) canOpenConfigFile(path string, errmsg string) bool { + var ( + file *os.File + err error + ) + if len(path) == 0 { // empty param/envvar + return false + } else if file, err = os.Open(path); err == nil { + o.Logger().Debug("DCli1004", fmt.Sprintf("Reading client config at %s", path)) + } else if len(errmsg) == 0 { + o.Logger().Debug("DCli1005", fmt.Sprintf("Could not read client config at %s:\n%#v", path, err)) + } else if os.IsNotExist(err) { + o.Logger().Debug("DCli1006", errmsg+"but that file does not exist.") + } else if os.IsPermission(err) { + o.Logger().Error("DCli1007", errmsg+"but lack permission to read that file.") + } else { + o.Logger().Error("DCli1008", fmt.Sprintf("%sbut there was an error opening it:\n%#v", errmsg, err)) + } + if file == nil { + return false + } + + // file is open for reading + defer file.Close() + if buffer, err := ioutil.ReadAll(file); err != nil { + o.Logger().Error("DCli1009", fmt.Sprintf("Unexpected error while reading client config file (%s): %v", path, err)) + } else if _, err := clientcmd.Load(buffer); err != nil { + o.Logger().Error("DCli1010", fmt.Sprintf(` +Error reading YAML from client config file (%s): + %v +This file may have been truncated or mis-edited. +Please fix, remove, or obtain a new client config`, file.Name(), err)) + } else { + o.Logger().Info("DCli1011", fmt.Sprintf("Successfully read a client config file at '%s'", path)) + /* Note, we're not going to use this config file directly. + * Instead, we'll defer to the openshift client code to assimilate + * flags, env vars, and the potential hierarchy of config files + * into an actual configuration that the client uses. + * However, for diagnostic purposes, record the files we find. + */ + return true + } + return false +} diff --git a/pkg/oc/admin/diagnostics/diagnostics.go b/pkg/oc/admin/diagnostics/diagnostics.go index 50dc2445f314..e1b3fa22e698 100644 --- a/pkg/oc/admin/diagnostics/diagnostics.go +++ b/pkg/oc/admin/diagnostics/diagnostics.go @@ -20,6 +20,7 @@ import ( "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/log" "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" ) @@ -49,8 +50,8 @@ type DiagnosticsOptions struct { ClientClusterContext string // LogOptions determine globally what the user wants to see and how. LogOptions *log.LoggerOptions - // The Logger is built with the options and should be used for all diagnostic output. - Logger *log.Logger + // The logger is built with the options and should be used for all diagnostic output. + logger *log.Logger } const ( @@ -104,7 +105,7 @@ var ( `) ) -// NewCmdDiagnostics is the base command for running any diagnostics. +// NewCmdDiagnostics is the base command for running a standard set of diagnostics with generic options only. func NewCmdDiagnostics(name string, fullName string, out io.Writer) *cobra.Command { available := availableDiagnostics() o := &DiagnosticsOptions{ @@ -117,18 +118,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: func(c *cobra.Command, args []string) { - kcmdutil.CheckErr(o.Complete(c, args)) - - failed, err, warnCount, errorCount := o.RunDiagnostics() - o.Logger.Summary(warnCount, errorCount) - - kcmdutil.CheckErr(err) - if failed { - os.Exit(1) - } - - }, + Run: commandRunFunc(o), } cmd.SetOutput(out) // for output re: usage / help o.bindCommonFlags(cmd.Flags()) @@ -157,18 +147,7 @@ func NewCmdDiagnosticsAll(name string, fullName string, out io.Writer, available Use: name, Short: "Diagnose common cluster problems", Long: fmt.Sprintf(longDescriptionAll, fullName), - Run: func(c *cobra.Command, args []string) { - kcmdutil.CheckErr(o.Complete(c, args)) - - failed, err, warnCount, errorCount := o.RunDiagnostics() - o.Logger.Summary(warnCount, errorCount) - - kcmdutil.CheckErr(err) - if failed { - os.Exit(1) - } - - }, + Run: commandRunFunc(o), } cmd.SetOutput(out) // for output re: usage / help o.bindCommonFlags(cmd.Flags()) @@ -178,7 +157,7 @@ func NewCmdDiagnosticsAll(name string, fullName string, out io.Writer, available return cmd } -// NewCmdDiagnosticsIndividual is a generic subcommand providing a single diagnostic and its flags. +// NewCmdDiagnosticsIndividual is a parameterized subcommand providing a single diagnostic and its flags. func NewCmdDiagnosticsIndividual(name string, fullName string, out io.Writer, diagnostic types.Diagnostic) *cobra.Command { o := &DiagnosticsOptions{ RequestedDiagnostics: sets.NewString(diagnostic.Name()), @@ -187,21 +166,10 @@ func NewCmdDiagnosticsIndividual(name string, fullName string, out io.Writer, di } cmd := &cobra.Command{ - Use: name, - Short: diagnostic.Description(), - Long: fmt.Sprintf(longDescriptionIndividual, diagnostic.Name(), diagnostic.Description()), - Run: func(c *cobra.Command, args []string) { - kcmdutil.CheckErr(o.Complete(c, args)) - - failed, err, warnCount, errorCount := o.RunDiagnostics() - o.Logger.Summary(warnCount, errorCount) - - kcmdutil.CheckErr(err) - if failed { - os.Exit(1) - } - - }, + Use: name, + Short: diagnostic.Description(), + Long: fmt.Sprintf(longDescriptionIndividual, diagnostic.Name(), diagnostic.Description()), + Run: commandRunFunc(o), Aliases: []string{diagnostic.Name()}, } cmd.SetOutput(out) // for output re: usage / help @@ -219,6 +187,32 @@ 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 +} + // gather a list of all diagnostics that are available to be invoked by the main command func availableDiagnostics() types.DiagnosticList { available := availableClientDiagnostics() @@ -266,7 +260,7 @@ func (o *DiagnosticsOptions) bindRequestedIndividualFlags(flags *flag.FlagSet) { } } -// bind flags for parameters on a single diagnostic +// bind flags for parameters from a single diagnostic func bindIndividualFlags(diag types.ParameterizedDiagnostic, prefix string, flags *flag.FlagSet) { for _, param := range diag.AvailableParameters() { name := prefix + param.Name @@ -286,7 +280,7 @@ func bindIndividualFlags(diag types.ParameterizedDiagnostic, prefix string, flag // Complete fills in DiagnosticsConfig needed if the command is actually invoked. func (o *DiagnosticsOptions) Complete(c *cobra.Command, args []string) error { var err error - o.Logger, err = o.LogOptions.NewLogger() + o.logger, err = o.LogOptions.NewLogger() if err != nil { return err } @@ -312,130 +306,67 @@ func (o *DiagnosticsOptions) Complete(c *cobra.Command, args []string) error { return nil } -// RunDiagnostics builds diagnostics based on the options and executes them, returning a summary. Returns: -// failure ("true" meaning there was not a clean diagnostic result), -// error (raised during construction or execution of diagnostics; may be an aggregate error object), -// number of warnings encountered in diagnostics results, -// number of errors encountered (diagnostic results plus errors previously raised). -func (o DiagnosticsOptions) RunDiagnostics() (bool, error, int, int) { - failed := false - warnings := []error{} - errors := []error{} - diagnostics := []types.Diagnostic{} - - func() { // don't trust discovery/build of diagnostics; wrap panic nicely in case of developer error - defer func() { - if r := recover(); r != nil { - failed = true - stack := debug.Stack() - errors = append(errors, fmt.Errorf("While building the diagnostics, a panic was encountered.\nThis is a bug in diagnostics. Error and stack trace follow: \n%v\n%s", r, stack)) - } - }() +// RunDiagnostics builds diagnostics based on the options and executes them. Returns: +// error (raised during construction of diagnostics; may be an aggregate error object), +func (o DiagnosticsOptions) RunDiagnostics() error { + diagnostics, failure := o.buildDiagnostics() + if failure != nil { + return failure + } + return util.RunDiagnostics(o.Logger(), diagnostics) +} - // build client/cluster diags if there is a client config for them to use - expected, detected, detectWarnings, detectErrors := o.detectClientConfig() // may log and return problems - for _, warn := range detectWarnings { - warnings = append(warnings, warn) - } - for _, err := range detectErrors { - errors = append(errors, err) - } - if !expected { - // no diagnostic required a client config, nothing to do - } else if !detected { - // there just plain isn't any client config file available - o.Logger.Notice("CED3014", "No client configuration specified; skipping client and cluster diagnostics.") - } else if rawConfig, err := o.buildRawConfig(); err != nil { // client config is totally broken - won't parse etc (problems may have been detected and logged) - o.Logger.Error("CED3015", fmt.Sprintf("Client configuration failed to load; skipping client and cluster diagnostics due to error: %s", err.Error())) - errors = append(errors, err) - } else { - clientDiags, ok, err := o.buildClientDiagnostics(rawConfig) - failed = failed || !ok - if ok { - diagnostics = append(diagnostics, clientDiags...) - } - if err != nil { - errors = append(errors, err) - } +func (o DiagnosticsOptions) buildDiagnostics() (diags []types.Diagnostic, failure error) { + diagnostics := []types.Diagnostic{} - clusterDiags, ok, err := o.buildClusterDiagnostics(rawConfig) - failed = failed || !ok - if ok { - diagnostics = append(diagnostics, clusterDiags...) - } - if err != nil { - errors = append(errors, err) - } + // don't trust discovery/build of diagnostics; wrap panic nicely in case of developer error + defer func() { + if r := recover(); r != nil { + failure = fmt.Errorf("While building the diagnostics, a panic was encountered.\nThis is a bug in diagnostics. Error and stack trace follow: \n%v\n%s", r, debug.Stack()) } + }() - // build host diagnostics if config is available - hostDiags, err := o.buildHostDiagnostics() + // build client/cluster diags if there is a client config for them to use + expected, detected := o.detectClientConfig() // may log and return problems + if !expected { + // no diagnostic required a client config, nothing to do + } else if !detected { + // there just plain isn't any client config file available + o.Logger().Notice("CED3014", "No client configuration specified; skipping client and cluster diagnostics.") + } else if rawConfig, err := o.buildRawConfig(); err != nil { // client config is totally broken - won't parse etc (problems may have been detected and logged) + o.Logger().Error("CED3015", fmt.Sprintf("Client configuration failed to load; skipping client and cluster diagnostics due to error: %s", err.Error())) + } else { + clientDiags, err := o.buildClientDiagnostics(rawConfig) if err != nil { - errors = append(errors, err) - } else { - diagnostics = append(diagnostics, hostDiags...) + return diagnostics, err } + diagnostics = append(diagnostics, clientDiags...) - // complete any diagnostics that require it - for _, d := range diagnostics { - if toComplete, ok := d.(types.IncompleteDiagnostic); ok { - if err := toComplete.Complete(o.Logger); err != nil { - errors = append(errors, err) - failed = true - } - } + clusterDiags, err := o.buildClusterDiagnostics(rawConfig) + if err != nil { + return diagnostics, err } - }() - - if failed { - return failed, kutilerrors.NewAggregate(errors), len(warnings), len(errors) + diagnostics = append(diagnostics, clusterDiags...) } - failed, err, numWarnings, numErrors := o.Run(diagnostics) - numWarnings += len(warnings) - numErrors += len(errors) - return failed, err, numWarnings, numErrors -} - -// Run performs the actual execution of diagnostics once they're built. -func (o DiagnosticsOptions) Run(diagnostics []types.Diagnostic) (bool, error, int, int) { - warnCount := 0 - errorCount := 0 - runCount := 0 - for _, diagnostic := range diagnostics { - func() { // wrap diagnostic panic nicely in case of developer error - defer func() { - if r := recover(); r != nil { - errorCount += 1 - stack := debug.Stack() - o.Logger.Error("CED3017", - fmt.Sprintf("While running the %s diagnostic, a panic was encountered.\nThis is a bug in diagnostics. Error and stack trace follow: \n%s\n%s", - diagnostic.Name(), fmt.Sprintf("%v", r), stack)) - } - }() - - if canRun, reason := diagnostic.CanRun(); !canRun { - if reason == nil { - o.Logger.Notice("CED3018", fmt.Sprintf("Skipping diagnostic: %s\nDescription: %s", diagnostic.Name(), diagnostic.Description())) - } else { - o.Logger.Notice("CED3019", fmt.Sprintf("Skipping diagnostic: %s\nDescription: %s\nBecause: %s", diagnostic.Name(), diagnostic.Description(), reason.Error())) - } - return - } + // build host diagnostics if config is available + hostDiags, err := o.buildHostDiagnostics() + if err != nil { + return diagnostics, err + } + diagnostics = append(diagnostics, hostDiags...) - o.Logger.Notice("CED3020", fmt.Sprintf("Running diagnostic: %s\nDescription: %s", diagnostic.Name(), diagnostic.Description())) - r := diagnostic.Check() - for _, entry := range r.Logs() { - o.Logger.LogEntry(entry) + // complete any diagnostics that require it + errors := []error{} + for _, d := range diagnostics { + if toComplete, ok := d.(types.IncompleteDiagnostic); ok { + if err := toComplete.Complete(o.Logger()); err != nil { + errors = append(errors, err) } - warnCount += len(r.Warnings()) - errorCount += len(r.Errors()) - runCount += 1 - }() + } } - if runCount == 0 { - o.Logger.Error("CED3016", "Requested diagnostic(s) skipped; nothing to run. See --help and consider setting flags or providing config to enable running.") - return true, nil, 0, 1 + if len(errors) > 0 { + return diagnostics, kutilerrors.NewAggregate(errors) } - return errorCount > 0, nil, warnCount, errorCount + return diagnostics, nil } diff --git a/pkg/oc/admin/diagnostics/diagnostics/client/config_loading.go b/pkg/oc/admin/diagnostics/diagnostics/client/config_loading.go deleted file mode 100644 index 3ca1dcef5b13..000000000000 --- a/pkg/oc/admin/diagnostics/diagnostics/client/config_loading.go +++ /dev/null @@ -1,150 +0,0 @@ -package client - -import ( - "fmt" - "io/ioutil" - "os" - - flag "github.com/spf13/pflag" - "k8s.io/client-go/tools/clientcmd" - - "github.com/openshift/origin/pkg/client/config" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/types" - "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/util" -) - -// ConfigLoading is a little special in that it is run separately as a precondition -// in order to determine whether we can run other dependent diagnostics. -type ConfigLoading struct { - ConfFlagName string - ClientFlags *flag.FlagSet - successfulLoad bool // set if at least one file loaded -} - -// Name is part of the Diagnostic interface and just returns name. -func (d *ConfigLoading) Name() string { - return "ConfigLoading" -} - -// Description is part of the Diagnostic interface and provides a user-focused description of what the diagnostic does. -func (d *ConfigLoading) Description() string { - return "Try to load client config file(s) and report what happens" -} - -// CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic. -func (d *ConfigLoading) CanRun() (bool, error) { - return true, nil -} - -// SuccessfulLoad returns whether the client config was found -func (d *ConfigLoading) SuccessfulLoad() bool { - return d.successfulLoad -} - -// Check is part of the Diagnostic interface; it runs the actual diagnostic logic -func (d *ConfigLoading) Check() types.DiagnosticResult { - r := types.NewDiagnosticResult("ConfigLoading") - confFlagValue := d.ClientFlags.Lookup(d.ConfFlagName).Value.String() - - var foundPath string - rules := config.NewOpenShiftClientConfigLoadingRules() - paths := append([]string{confFlagValue}, rules.Precedence...) - for index, path := range paths { - errmsg := "" - switch index { - case 0: - errmsg = fmt.Sprintf("--%s specified that client config should be at %s\n", d.ConfFlagName, path) - case len(paths) - 1: // config in ~/.kube - // no error message indicated if it is not there... user didn't say it would be - default: // can be multiple paths from the env var in theory; all cases should go here - if len(os.Getenv(config.OpenShiftConfigPathEnvVar)) != 0 { - errmsg = fmt.Sprintf("Env var %s specified that client config could be at %s\n", config.OpenShiftConfigPathEnvVar, path) - } - } - - if d.canOpenConfigFile(path, errmsg, r) && foundPath == "" { - d.successfulLoad = true - foundPath = path - } - } - if foundPath != "" { - if confFlagValue != "" && confFlagValue != foundPath { - // found config but not where --config said - r.Error("DCli1001", nil, fmt.Sprintf(` -The client configuration file was not found where the --%s flag indicated: - %s -A config file was found at the following location: - %s -If you wish to use this file for client configuration, you can specify it -with the --%[1]s flag, or just not specify the flag. - `, d.ConfFlagName, confFlagValue, foundPath)) - } - } else { // not found, check for master-generated ones to recommend - if confFlagValue != "" { - r.Error("DCli1002", nil, fmt.Sprintf("Did not find config file where --%s=%s indicated", d.ConfFlagName, confFlagValue)) - } - adminWarningF := ` -No client config file was available; however, one exists at - %[2]s -which may have been generated automatically by the master. -If you want to use this config, you should copy it to the -standard location (%[3]s), -or you can set the environment variable %[1]s: - export %[1]s=%[2]s -If not, obtain a config file and place it in the standard -location for use by the client and diagnostics. -` - // look for it in auto-generated locations when not found properly - for _, path := range util.AdminKubeConfigPaths { - msg := fmt.Sprintf("Looking for a possible client config at %s\n", path) - if d.canOpenConfigFile(path, msg, r) { - r.Warn("DCli1003", nil, fmt.Sprintf(adminWarningF, config.OpenShiftConfigPathEnvVar, path, config.RecommendedHomeFile)) - break - } - } - } - return r -} - -// ---------------------------------------------------------- -// Attempt to open file at path as client config -// If there is a problem and errmsg is set, log an error -func (d ConfigLoading) canOpenConfigFile(path string, errmsg string, r types.DiagnosticResult) bool { - var file *os.File - var err error - if path == "" { // empty param/envvar - return false - } else if file, err = os.Open(path); err == nil { - r.Debug("DCli1004", fmt.Sprintf("Reading client config at %s", path)) - } else if errmsg == "" { - r.Debug("DCli1005", fmt.Sprintf("Could not read client config at %s:\n%#v", path, err)) - } else if os.IsNotExist(err) { - r.Debug("DCli1006", errmsg+"but that file does not exist.") - } else if os.IsPermission(err) { - r.Error("DCli1007", err, errmsg+"but lack permission to read that file.") - } else { - r.Error("DCli1008", err, fmt.Sprintf("%sbut there was an error opening it:\n%#v", errmsg, err)) - } - if file != nil { // it is open for reading - defer file.Close() - if buffer, err := ioutil.ReadAll(file); err != nil { - r.Error("DCli1009", err, fmt.Sprintf("Unexpected error while reading client config file (%s): %v", path, err)) - } else if _, err := clientcmd.Load(buffer); err != nil { - r.Error("DCli1010", err, fmt.Sprintf(` -Error reading YAML from client config file (%s): - %v -This file may have been truncated or mis-edited. -Please fix, remove, or obtain a new client config`, file.Name(), err)) - } else { - r.Info("DCli1011", fmt.Sprintf("Successfully read a client config file at '%s'", path)) - /* Note, we're not going to use this config file directly. - * Instead, we'll defer to the openshift client code to assimilate - * flags, env vars, and the potential hierarchy of config files - * into an actual configuration that the client uses. - * However, for diagnostic purposes, record the files we find. - */ - return true - } - } - return false -} diff --git a/pkg/oc/admin/diagnostics/diagnostics/log/log.go b/pkg/oc/admin/diagnostics/diagnostics/log/log.go index 034f6b0d1dbe..e794ef0457cd 100644 --- a/pkg/oc/admin/diagnostics/diagnostics/log/log.go +++ b/pkg/oc/admin/diagnostics/diagnostics/log/log.go @@ -93,23 +93,33 @@ var ( ) // Provide a summary at the end -func (l *Logger) Summary(warningsSeen int, errorsSeen int) { +func (l *Logger) Summary() { l.Notice("DL0001", fmt.Sprintf("Summary of diagnostics execution (version %v):\n", version.Get())) - if warningsSeen > 0 { - l.Notice("DL0002", fmt.Sprintf("Warnings seen: %d", warningsSeen)) + if l.warningsSeen > 0 { + l.Notice("DL0002", fmt.Sprintf("Warnings seen: %d", l.warningsSeen)) } - if errorsSeen > 0 { - l.Notice("DL0003", fmt.Sprintf("Errors seen: %d", errorsSeen)) + if l.errorsSeen > 0 { + l.Notice("DL0003", fmt.Sprintf("Errors seen: %d", l.errorsSeen)) } - if warningsSeen == 0 && errorsSeen == 0 { + if l.warningsSeen == 0 && l.errorsSeen == 0 { l.Notice("DL0004", "Completed with no errors or warnings seen.") } } +func (l *Logger) ErrorsSeen() bool { + return l.errorsSeen > 0 +} + func (l *Logger) LogEntry(entry Entry) { if l == nil { // if there's no logger, return silently return } + if entry.Level == ErrorLevel { + l.errorsSeen++ + } + if entry.Level == WarnLevel { + l.warningsSeen++ + } if entry.Level.Level < l.level.Level { // logging level says skip this entry return } diff --git a/pkg/oc/admin/diagnostics/host.go b/pkg/oc/admin/diagnostics/host.go index 4eaf1a4d7056..962961168f12 100644 --- a/pkg/oc/admin/diagnostics/host.go +++ b/pkg/oc/admin/diagnostics/host.go @@ -17,7 +17,7 @@ var ( ) ) -// availableHostDiagnostics contains the names of host diagnostics that can be executed +// availableHostDiagnostics returns host diagnostics that can be executed // during a single run of diagnostics. Add more diagnostics to the list as they are defined. func availableHostDiagnostics() types.DiagnosticList { return types.DiagnosticList{ @@ -30,7 +30,7 @@ func availableHostDiagnostics() types.DiagnosticList { } // buildHostDiagnostics builds host Diagnostic objects based on the host environment. -// Returns the Diagnostics built, and an error if any was encountered during the building of diagnostics.) { +// Returns the Diagnostics built, and an error if any was encountered during the building of diagnostics. func (o DiagnosticsOptions) buildHostDiagnostics() ([]types.Diagnostic, error) { requestedDiagnostics := availableHostDiagnostics().Names().Intersection(sets.NewString(o.RequestedDiagnostics.List()...)).List() if len(requestedDiagnostics) == 0 { // no diagnostics to run here @@ -47,7 +47,7 @@ func (o DiagnosticsOptions) buildHostDiagnostics() ([]types.Diagnostic, error) { } diagnostics := []types.Diagnostic{} - systemdUnits := systemddiags.GetSystemdUnits(o.Logger) + systemdUnits := systemddiags.GetSystemdUnits(o.Logger()) for _, diagnosticName := range requestedDiagnostics { var d types.Diagnostic switch diagnosticName { diff --git a/pkg/oc/admin/diagnostics/network_pod.go b/pkg/oc/admin/diagnostics/network_pod.go index 01df1f1345d1..0fa2cd3eed2b 100644 --- a/pkg/oc/admin/diagnostics/network_pod.go +++ b/pkg/oc/admin/diagnostics/network_pod.go @@ -3,16 +3,13 @@ package diagnostics import ( "fmt" "io" - "os" "runtime/debug" "github.com/spf13/cobra" flag "github.com/spf13/pflag" - 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/oc/admin/diagnostics/diagnostics/log" networkdiag "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/networkpod" @@ -30,7 +27,7 @@ type NetworkPodDiagnosticsOptions struct { // LogOptions determine globally what the user wants to see and how. LogOptions *log.LoggerOptions // The Logger is built with the options and should be used for all diagnostic output. - Logger *log.Logger + logger *log.Logger } var longNetworkPodDiagDescription = templates.LongDesc(` @@ -55,18 +52,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: func(c *cobra.Command, args []string) { - kcmdutil.CheckErr(o.Complete(args)) - - failed, err, warnCount, errorCount := o.BuildAndRunDiagnostics() - o.Logger.Summary(warnCount, errorCount) - - kcmdutil.CheckErr(err) - if failed { - os.Exit(255) - } - - }, + Run: commandRunFunc(o), } cmd.SetOutput(out) // for output re: usage / help @@ -75,9 +61,14 @@ func NewCommandNetworkPodDiagnostics(name string, out io.Writer) *cobra.Command return cmd } +// Logger returns the logger built according to options (must be Complete()ed) +func (o *NetworkPodDiagnosticsOptions) Logger() *log.Logger { + return o.logger +} + // Complete fills in NetworkPodDiagnosticsOptions needed if the command is actually invoked. -func (o *NetworkPodDiagnosticsOptions) Complete(args []string) (err error) { - o.Logger, err = o.LogOptions.NewLogger() +func (o *NetworkPodDiagnosticsOptions) Complete(c *cobra.Command, args []string) (err error) { + o.logger, err = o.LogOptions.NewLogger() if err != nil { return err } @@ -90,45 +81,35 @@ func (o *NetworkPodDiagnosticsOptions) Complete(args []string) (err error) { return nil } -// BuildAndRunDiagnostics builds diagnostics based on the options and executes them, returning a summary. -func (o NetworkPodDiagnosticsOptions) BuildAndRunDiagnostics() (failed bool, err error, numWarnings, numErrors int) { - failed = false - errors := []error{} +// RunDiagnostics builds diagnostics based on the options and executes them, returning a summary. +func (o NetworkPodDiagnosticsOptions) RunDiagnostics() error { + var fatal error diagnostics := []types.Diagnostic{} func() { // don't trust discovery/build of diagnostics; wrap panic nicely in case of developer error defer func() { if r := recover(); r != nil { - failed = true - stack := debug.Stack() - errors = append(errors, fmt.Errorf("While building the diagnostics, a panic was encountered.\nThis is a bug in diagnostics. Error and stack trace follow: \n%v\n%s", r, stack)) + fatal = fmt.Errorf("While building the diagnostics, a panic was encountered.\nThis is a bug in diagnostics. Error and stack trace follow: \n%v\n%s", r, debug.Stack()) } }() // deferred panic handler - networkPodDiags, ok, err := o.buildNetworkPodDiagnostics() - failed = failed || !ok - if ok { - diagnostics = append(diagnostics, networkPodDiags...) - } - if err != nil { - errors = append(errors, err...) - } + + diagnostics, fatal = o.buildNetworkPodDiagnostics() }() - if failed { - return failed, kutilerrors.NewAggregate(errors), 0, len(errors) + if fatal != nil { + return fatal } - failed, err, numWarnings, numErrors = util.RunDiagnostics(o.Logger, diagnostics, 0, len(errors)) - return failed, err, numWarnings, numErrors + return util.RunDiagnostics(o.Logger(), diagnostics) } // buildNetworkPodDiagnostics builds network Diagnostic objects based on the host environment. -// Returns the Diagnostics built, "ok" bool for whether to proceed or abort, and an error if any was encountered during the building of diagnostics. -func (o NetworkPodDiagnosticsOptions) buildNetworkPodDiagnostics() ([]types.Diagnostic, bool, []error) { +// Returns the Diagnostics built or any fatal error encountered during the building of diagnostics. +func (o NetworkPodDiagnosticsOptions) buildNetworkPodDiagnostics() ([]types.Diagnostic, error) { diagnostics := []types.Diagnostic{} - err, requestedDiagnostics := util.DetermineRequestedDiagnostics(availableNetworkPodDiagnostics.List(), o.RequestedDiagnostics, o.Logger) + err, requestedDiagnostics := util.DetermineRequestedDiagnostics(availableNetworkPodDiagnostics.List(), o.RequestedDiagnostics, o.Logger()) if err != nil { - return diagnostics, false, []error{err} // don't waste time on discovery + return nil, err // don't waste time on discovery } clientFlags := flag.NewFlagSet("client", flag.ContinueOnError) // hide the extensive set of client flags @@ -136,11 +117,11 @@ func (o NetworkPodDiagnosticsOptions) buildNetworkPodDiagnostics() ([]types.Diag kubeClient, clientErr := factory.ClientSet() if clientErr != nil { - return diagnostics, false, []error{clientErr} + return nil, clientErr } networkClient, err := factory.OpenshiftInternalNetworkClient() if err != nil { - return diagnostics, false, []error{err} + return nil, err } for _, diagnosticName := range requestedDiagnostics { @@ -174,9 +155,9 @@ func (o NetworkPodDiagnosticsOptions) buildNetworkPodDiagnostics() ([]types.Diag }) default: - return diagnostics, false, []error{fmt.Errorf("unknown diagnostic: %v", diagnosticName)} + return diagnostics, fmt.Errorf("unknown diagnostic: %v", diagnosticName) } } - return diagnostics, true, nil + return diagnostics, nil } diff --git a/pkg/oc/admin/diagnostics/pod.go b/pkg/oc/admin/diagnostics/pod.go index d6f0cd37f774..7b8ed5e8de66 100644 --- a/pkg/oc/admin/diagnostics/pod.go +++ b/pkg/oc/admin/diagnostics/pod.go @@ -3,15 +3,12 @@ package diagnostics import ( "fmt" "io" - "os" "runtime/debug" "github.com/spf13/cobra" - 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/oc/admin/diagnostics/diagnostics/log" poddiag "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/pod" @@ -28,7 +25,12 @@ type PodDiagnosticsOptions struct { // LogOptions determine globally what the user wants to see and how. LogOptions *log.LoggerOptions // The Logger is built with the options and should be used for all diagnostic output. - Logger *log.Logger + logger *log.Logger +} + +// returns the logger built according to options (must be Complete()ed) +func (o *PodDiagnosticsOptions) Logger() *log.Logger { + return o.logger } const ( @@ -53,18 +55,7 @@ func NewCommandPodDiagnostics(name string, out io.Writer) *cobra.Command { Use: name, Short: "Within a pod, run pod diagnostics", Long: fmt.Sprintf(longPodDiagDescription), - Run: func(c *cobra.Command, args []string) { - kcmdutil.CheckErr(o.Complete(args)) - - failed, err, warnCount, errorCount := o.BuildAndRunDiagnostics() - o.Logger.Summary(warnCount, errorCount) - - kcmdutil.CheckErr(err) - if failed { - os.Exit(255) - } - - }, + Run: commandRunFunc(o), } cmd.SetOutput(out) // for output re: usage / help @@ -74,9 +65,9 @@ func NewCommandPodDiagnostics(name string, out io.Writer) *cobra.Command { } // Complete fills in PodDiagnosticsOptions needed if the command is actually invoked. -func (o *PodDiagnosticsOptions) Complete(args []string) error { +func (o *PodDiagnosticsOptions) Complete(c *cobra.Command, args []string) error { var err error - o.Logger, err = o.LogOptions.NewLogger() + o.logger, err = o.LogOptions.NewLogger() if err != nil { return err } @@ -89,37 +80,26 @@ func (o *PodDiagnosticsOptions) Complete(args []string) error { return nil } -// BuildAndRunDiagnostics builds diagnostics based on the options and executes them, returning a summary. -func (o PodDiagnosticsOptions) BuildAndRunDiagnostics() (bool, error, int, int) { - failed := false - errors := []error{} - diagnostics := []types.Diagnostic{} +// RunDiagnostics builds diagnostics based on the options and executes them, returning fatal error(s) only. +func (o PodDiagnosticsOptions) RunDiagnostics() error { + var fatal error + var diagnostics []types.Diagnostic func() { // don't trust discovery/build of diagnostics; wrap panic nicely in case of developer error defer func() { if r := recover(); r != nil { - failed = true - stack := debug.Stack() - errors = append(errors, fmt.Errorf("While building the diagnostics, a panic was encountered.\nThis is a bug in diagnostics. Error and stack trace follow: \n%v\n%s", r, stack)) + fatal = fmt.Errorf("While building the diagnostics, a panic was encountered.\nThis is a bug in diagnostics. Error and stack trace follow: \n%v\n%s", r, debug.Stack()) } }() // deferred panic handler - podDiags, ok, err := o.buildPodDiagnostics() - failed = failed || !ok - if ok { - diagnostics = append(diagnostics, podDiags...) - } - if err != nil { - errors = append(errors, err...) - } + diagnostics, fatal = o.buildPodDiagnostics() }() - if failed { - return failed, kutilerrors.NewAggregate(errors), 0, len(errors) + if fatal != nil { + return fatal } - failed, err, numWarnings, numErrors := util.RunDiagnostics(o.Logger, diagnostics, 0, len(errors)) - return failed, err, numWarnings, numErrors + return util.RunDiagnostics(o.Logger(), diagnostics) } var ( @@ -129,12 +109,12 @@ var ( ) // buildPodDiagnostics builds host Diagnostic objects based on the host environment. -// Returns the Diagnostics built, "ok" bool for whether to proceed or abort, and an error if any was encountered during the building of diagnostics. -func (o PodDiagnosticsOptions) buildPodDiagnostics() ([]types.Diagnostic, bool, []error) { +// Returns the Diagnostics built, and any fatal error encountered during the building of diagnostics. +func (o PodDiagnosticsOptions) buildPodDiagnostics() ([]types.Diagnostic, error) { diagnostics := []types.Diagnostic{} - err, requestedDiagnostics := util.DetermineRequestedDiagnostics(availablePodDiagnostics.List(), o.RequestedDiagnostics, o.Logger) + err, requestedDiagnostics := util.DetermineRequestedDiagnostics(availablePodDiagnostics.List(), o.RequestedDiagnostics, o.Logger()) if err != nil { - return diagnostics, false, []error{err} // don't waste time on discovery + return diagnostics, err // don't waste time on discovery } // TODO: check we're actually in a container @@ -152,9 +132,9 @@ func (o PodDiagnosticsOptions) buildPodDiagnostics() ([]types.Diagnostic, bool, }) default: - return diagnostics, false, []error{fmt.Errorf("unknown diagnostic: %v", diagnosticName)} + return diagnostics, fmt.Errorf("unknown diagnostic: %v", diagnosticName) } } - return diagnostics, true, nil + return diagnostics, nil } diff --git a/pkg/oc/admin/diagnostics/util/util.go b/pkg/oc/admin/diagnostics/util/util.go index 183c8665c835..27a980dea986 100644 --- a/pkg/oc/admin/diagnostics/util/util.go +++ b/pkg/oc/admin/diagnostics/util/util.go @@ -31,16 +31,15 @@ func DetermineRequestedDiagnostics(available []string, requested []string, logge } // RunDiagnostics performs the actual execution of diagnostics once they're built. -func RunDiagnostics(logger *log.Logger, diagnostics []types.Diagnostic, warnCount int, errorCount int) (bool, error, int, int) { +func RunDiagnostics(logger *log.Logger, diagnostics []types.Diagnostic) error { + runCount := 0 for _, diagnostic := range diagnostics { func() { // wrap diagnostic panic nicely in case of developer error defer func() { if r := recover(); r != nil { - errorCount += 1 - stack := debug.Stack() logger.Error("CED7001", fmt.Sprintf("While running the %s diagnostic, a panic was encountered.\nThis is a bug in diagnostics. Error and stack trace follow: \n%s\n%s", - diagnostic.Name(), fmt.Sprintf("%v", r), stack)) + diagnostic.Name(), fmt.Sprintf("%v", r), debug.Stack())) } }() @@ -52,16 +51,18 @@ func RunDiagnostics(logger *log.Logger, diagnostics []types.Diagnostic, warnCoun } return } + runCount += 1 logger.Notice("CED7004", fmt.Sprintf("Running diagnostic: %s\nDescription: %s", diagnostic.Name(), diagnostic.Description())) r := diagnostic.Check() for _, entry := range r.Logs() { logger.LogEntry(entry) } - warnCount += len(r.Warnings()) - errorCount += len(r.Errors()) }() } - return errorCount > 0, nil, warnCount, errorCount + if runCount == 0 { + return fmt.Errorf("Requested diagnostic(s) skipped; nothing to run. See --help and consider setting flags or providing config to enable running.") + } + return nil }