From 3c9fb1b651aa0b076d1310fc2c82e8f624413cb8 Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Thu, 4 Feb 2016 14:12:05 -0800 Subject: [PATCH 1/4] Add a 'kubectl clusterinfo dump' option --- .generated_docs | 2 + contrib/completions/bash/kubectl | 47 ++++ docs/man/man1/kubectl-cluster-info.1 | 2 +- .../kubectl/kubectl_cluster-info.md | 3 +- docs/yaml/kubectl/kubectl_cluster-info.yaml | 1 + pkg/kubectl/cmd/clusterinfo.go | 1 + pkg/kubectl/cmd/clusterinfo_dump.go | 204 ++++++++++++++++++ 7 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 pkg/kubectl/cmd/clusterinfo_dump.go diff --git a/.generated_docs b/.generated_docs index 5a9c70fc215..2ae3910be6b 100644 --- a/.generated_docs +++ b/.generated_docs @@ -10,6 +10,7 @@ docs/man/man1/kubectl-api-versions.1 docs/man/man1/kubectl-apply.1 docs/man/man1/kubectl-attach.1 docs/man/man1/kubectl-autoscale.1 +docs/man/man1/kubectl-cluster-info-dump.1 docs/man/man1/kubectl-cluster-info.1 docs/man/man1/kubectl-config-current-context.1 docs/man/man1/kubectl-config-set-cluster.1 @@ -65,6 +66,7 @@ docs/user-guide/kubectl/kubectl_apply.md docs/user-guide/kubectl/kubectl_attach.md docs/user-guide/kubectl/kubectl_autoscale.md docs/user-guide/kubectl/kubectl_cluster-info.md +docs/user-guide/kubectl/kubectl_cluster-info_dump.md docs/user-guide/kubectl/kubectl_config.md docs/user-guide/kubectl/kubectl_config_current-context.md docs/user-guide/kubectl/kubectl_config_set-cluster.md diff --git a/contrib/completions/bash/kubectl b/contrib/completions/bash/kubectl index 528ae4c6d6a..992bafa999e 100644 --- a/contrib/completions/bash/kubectl +++ b/contrib/completions/bash/kubectl @@ -3361,10 +3361,57 @@ _kubectl_config() noun_aliases=() } +_kubectl_cluster-info_dump() +{ + last_command="kubectl_cluster-info_dump" + commands=() + + flags=() + two_word_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("--namespaces=") + flags+=("--output-directory=") + flags+=("--alsologtostderr") + flags+=("--api-version=") + flags+=("--as=") + flags+=("--certificate-authority=") + flags+=("--client-certificate=") + flags+=("--client-key=") + flags+=("--cluster=") + flags+=("--context=") + flags+=("--insecure-skip-tls-verify") + flags+=("--kubeconfig=") + flags+=("--log-backtrace-at=") + flags+=("--log-dir=") + flags+=("--log-flush-frequency=") + flags+=("--logtostderr") + flags+=("--match-server-version") + flags+=("--namespace=") + flags_with_completion+=("--namespace") + flags_completion+=("__kubectl_get_namespaces") + flags+=("--password=") + flags+=("--server=") + two_word_flags+=("-s") + flags+=("--stderrthreshold=") + flags+=("--token=") + flags+=("--user=") + flags+=("--username=") + flags+=("--v=") + flags+=("--vmodule=") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _kubectl_cluster-info() { last_command="kubectl_cluster-info" commands=() + commands+=("dump") flags=() two_word_flags=() diff --git a/docs/man/man1/kubectl-cluster-info.1 b/docs/man/man1/kubectl-cluster-info.1 index fb63196cb08..459594a3366 100644 --- a/docs/man/man1/kubectl-cluster-info.1 +++ b/docs/man/man1/kubectl-cluster-info.1 @@ -122,7 +122,7 @@ Display addresses of the master and services with label kubernetes.io/cluster\-s .SH SEE ALSO .PP -\fBkubectl(1)\fP, +\fBkubectl(1)\fP, \fBkubectl\-cluster\-info\-dump(1)\fP, .SH HISTORY diff --git a/docs/user-guide/kubectl/kubectl_cluster-info.md b/docs/user-guide/kubectl/kubectl_cluster-info.md index 82caed80e7b..e65ab21a3bb 100644 --- a/docs/user-guide/kubectl/kubectl_cluster-info.md +++ b/docs/user-guide/kubectl/kubectl_cluster-info.md @@ -82,8 +82,9 @@ kubectl cluster-info ### SEE ALSO * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager +* [kubectl cluster-info dump](kubectl_cluster-info_dump.md) - Dump lots of relevant info for debugging and diagnosis. -###### Auto generated by spf13/cobra on 5-Apr-2016 +###### Auto generated by spf13/cobra on 27-Apr-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_cluster-info.md?pixel)]() diff --git a/docs/yaml/kubectl/kubectl_cluster-info.yaml b/docs/yaml/kubectl/kubectl_cluster-info.yaml index 9aeee3f3de4..44ad329311a 100644 --- a/docs/yaml/kubectl/kubectl_cluster-info.yaml +++ b/docs/yaml/kubectl/kubectl_cluster-info.yaml @@ -70,3 +70,4 @@ inherited_options: comma-separated list of pattern=N settings for file-filtered logging see_also: - kubectl +- dump diff --git a/pkg/kubectl/cmd/clusterinfo.go b/pkg/kubectl/cmd/clusterinfo.go index 9fc3035865b..b5f90730ee0 100644 --- a/pkg/kubectl/cmd/clusterinfo.go +++ b/pkg/kubectl/cmd/clusterinfo.go @@ -43,6 +43,7 @@ func NewCmdClusterInfo(f *cmdutil.Factory, out io.Writer) *cobra.Command { }, } cmdutil.AddInclude3rdPartyFlags(cmd) + cmd.AddCommand(NewCmdClusterInfoDump(f, out)) return cmd } diff --git a/pkg/kubectl/cmd/clusterinfo_dump.go b/pkg/kubectl/cmd/clusterinfo_dump.go new file mode 100644 index 00000000000..36e543a61c9 --- /dev/null +++ b/pkg/kubectl/cmd/clusterinfo_dump.go @@ -0,0 +1,204 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "fmt" + "io" + "os" + "path" + + "github.com/spf13/cobra" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/client/unversioned" + "k8s.io/kubernetes/pkg/kubectl" + cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" +) + +// NewCmdCreateSecret groups subcommands to create various types of secrets +func NewCmdClusterInfoDump(f *cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "dump", + Short: "Dump lots of relevant info for debugging and diagnosis.", + Long: dumpLong, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(dumpClusterInfo(f, cmd, args, cmdOut)) + }, + } + cmd.Flags().String("output-directory", "", "Where to output the files. If empty or '-' uses stdout, otherwise creates a directory hierarchy in that directory") + cmd.Flags().StringSlice("namespaces", []string{}, "A comma separated list of namespaces to dump.") + cmd.Flags().Bool("all-namespaces", false, "If true, dump all namespaces. If true, --namespaces is ignored.") + return cmd +} + +const ( + dumpLong = ` +Dumps cluster info out suitable for debugging and diagnosing cluster problems. By default, dumps everything to +stdout. You can optionally specify a directory with --output-directory. If you specify a directory, kubernetes will +build a set of files in that directory. By default only dumps things in the 'kube-system' namespace, but you can +switch to a different namespace with the --namespaces flag, or specify --all-namespaces to dump all namespaces. +` + + dumpExample = ` # Dump current cluster state to stdout + kubectl cluster-info dump + + # Dump current cluster state to /tmp + kubectl cluster-info dump --output-directory=/tmp + + # Dump all namespaces to stdout + kubectl cluster-info dump --all-namespaces + + # Dump a set of namespaces to /tmp + kubectl cluster-info dump --namespaces default,kube-system --output-directory=/tmp` +) + +func getWriter(cmd *cobra.Command, out io.Writer, filename string) io.Writer { + dir := cmdutil.GetFlagString(cmd, "output-directory") + if len(dir) == 0 || dir == "-" { + return out + } + fullFile := path.Join(dir, filename) + parent := path.Dir(fullFile) + cmdutil.CheckErr(os.MkdirAll(parent, 0755)) + + file, err := os.Create(path.Join(dir, filename)) + cmdutil.CheckErr(err) + return file +} + +func dumpClusterInfo(f *cmdutil.Factory, cmd *cobra.Command, args []string, out io.Writer) error { + var c *unversioned.Client + var err error + if c, err = f.Client(); err != nil { + return err + } + printer, _, err := kubectl.GetPrinter("json", "") + if err != nil { + return err + } + + nodes, err := c.Nodes().List(api.ListOptions{}) + if err != nil { + return err + } + + if err := printer.PrintObj(nodes, getWriter(cmd, out, "nodes.json")); err != nil { + return err + } + + var namespaces []string + if cmdutil.GetFlagBool(cmd, "all-namespaces") { + namespaceList, err := c.Namespaces().List(api.ListOptions{}) + if err != nil { + return err + } + for ix := range namespaceList.Items { + namespaces = append(namespaces, namespaceList.Items[ix].Name) + } + } else { + namespaces = cmdutil.GetFlagStringSlice(cmd, "namespaces") + if len(namespaces) == 0 { + cmdNamespace, _, err := f.DefaultNamespace() + if err != nil { + return err + } + namespaces = []string{ + api.NamespaceSystem, + cmdNamespace, + } + } + } + for _, namespace := range namespaces { + // TODO: this is repetitive in the extreme. Use reflection or + // something to make this a for loop. + events, err := c.Events(namespace).List(api.ListOptions{}) + if err != nil { + return err + } + if err := printer.PrintObj(events, getWriter(cmd, out, path.Join(namespace, "events.json"))); err != nil { + return err + } + + rcs, err := c.ReplicationControllers(namespace).List(api.ListOptions{}) + if err != nil { + return err + } + if err := printer.PrintObj(rcs, getWriter(cmd, out, path.Join(namespace, "replication-controllers.json"))); err != nil { + return err + } + + svcs, err := c.Services(namespace).List(api.ListOptions{}) + if err != nil { + return err + } + if err := printer.PrintObj(svcs, getWriter(cmd, out, path.Join(namespace, "services.json"))); err != nil { + return err + } + + sets, err := c.DaemonSets(namespace).List(api.ListOptions{}) + if err != nil { + return err + } + if err := printer.PrintObj(sets, getWriter(cmd, out, path.Join(namespace, "daemonsets.json"))); err != nil { + return err + } + + deps, err := c.Deployments(namespace).List(api.ListOptions{}) + if err != nil { + return err + } + if err := printer.PrintObj(deps, getWriter(cmd, out, path.Join(namespace, "deployments.json"))); err != nil { + return err + } + + rps, err := c.ReplicaSets(namespace).List(api.ListOptions{}) + if err != nil { + return err + } + if err := printer.PrintObj(rps, getWriter(cmd, out, path.Join(namespace, "replicasets.json"))); err != nil { + return err + } + + pods, err := c.Pods(namespace).List(api.ListOptions{}) + if err != nil { + return err + } + + if err := printer.PrintObj(pods, getWriter(cmd, out, path.Join(namespace, "pods.json"))); err != nil { + return err + } + + for ix := range pods.Items { + pod := &pods.Items[ix] + writer := getWriter(cmd, out, path.Join(namespace, pod.Name, "logs.txt")) + writer.Write([]byte(fmt.Sprintf("==== START logs for %s/%s ====\n", pod.Namespace, pod.Name))) + request, err := f.LogsForObject(pod, &api.PodLogOptions{}) + if err != nil { + return err + } + + data, err := request.DoRaw() + if err != nil { + return err + } + writer.Write(data) + writer.Write([]byte(fmt.Sprintf("==== END logs for %s/%s ====\n", pod.Namespace, pod.Name))) + } + } + return nil +} From 092afb6285ed23217a77b78e027c4b4ecd24604d Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Fri, 25 Mar 2016 09:25:24 -0700 Subject: [PATCH 2/4] Address comments. --- docs/man/man1/kubectl-cluster-info-dump.1 | 141 ++++++++++++++++++ .../kubectl/kubectl_cluster-info_dump.md | 92 ++++++++++++ hack/verify-flags/known-flags.txt | 1 + pkg/kubectl/cmd/clusterinfo_dump.go | 4 +- pkg/kubectl/cmd/clusterinfo_dump_test.go | 68 +++++++++ 5 files changed, 304 insertions(+), 2 deletions(-) create mode 100644 docs/man/man1/kubectl-cluster-info-dump.1 create mode 100644 docs/user-guide/kubectl/kubectl_cluster-info_dump.md create mode 100644 pkg/kubectl/cmd/clusterinfo_dump_test.go diff --git a/docs/man/man1/kubectl-cluster-info-dump.1 b/docs/man/man1/kubectl-cluster-info-dump.1 new file mode 100644 index 00000000000..208b672aa8d --- /dev/null +++ b/docs/man/man1/kubectl-cluster-info-dump.1 @@ -0,0 +1,141 @@ +.TH "KUBERNETES" "1" " kubernetes User Manuals" "Eric Paris" "Jan 2015" "" + + +.SH NAME +.PP +kubectl cluster\-info dump \- Dump lots of relevant info for debugging and diagnosis. + + +.SH SYNOPSIS +.PP +\fBkubectl cluster\-info dump\fP [OPTIONS] + + +.SH DESCRIPTION +.PP +Dumps cluster info out suitable for debugging and diagnosing cluster problems. By default, dumps everything to +stdout. You can optionally specify a directory with \-\-output\-directory. If you specify a directory, kubernetes will +build a set of files in that directory. By default only dumps things in the 'kube\-system' namespace, but you can +switch to a different namespace with the \-\-namespaces flag, or specify \-\-all\-namespaces to dump all namespaces. + + +.SH OPTIONS +.PP +\fB\-\-all\-namespaces\fP=false + If true, dump all namespaces. If true, \-\-namespaces is ignored. + +.PP +\fB\-\-namespaces\fP=[] + A comma separated list of namespaces to dump. + +.PP +\fB\-\-output\-directory\fP="" + Where to output the files. If empty or '\-' uses stdout, otherwise creates a directory hierarchy in that directory + + +.SH OPTIONS INHERITED FROM PARENT COMMANDS +.PP +\fB\-\-alsologtostderr\fP=false + log to standard error as well as files + +.PP +\fB\-\-api\-version\fP="" + DEPRECATED: The API version to use when talking to the server + +.PP +\fB\-\-as\fP="" + Username to impersonate for the operation. + +.PP +\fB\-\-certificate\-authority\fP="" + Path to a cert. file for the certificate authority. + +.PP +\fB\-\-client\-certificate\fP="" + Path to a client certificate file for TLS. + +.PP +\fB\-\-client\-key\fP="" + Path to a client key file for TLS. + +.PP +\fB\-\-cluster\fP="" + The name of the kubeconfig cluster to use + +.PP +\fB\-\-context\fP="" + The name of the kubeconfig context to use + +.PP +\fB\-\-insecure\-skip\-tls\-verify\fP=false + If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + +.PP +\fB\-\-kubeconfig\fP="" + Path to the kubeconfig file to use for CLI requests. + +.PP +\fB\-\-log\-backtrace\-at\fP=:0 + when logging hits line file:N, emit a stack trace + +.PP +\fB\-\-log\-dir\fP="" + If non\-empty, write log files in this directory + +.PP +\fB\-\-log\-flush\-frequency\fP=5s + Maximum number of seconds between log flushes + +.PP +\fB\-\-logtostderr\fP=true + log to standard error instead of files + +.PP +\fB\-\-match\-server\-version\fP=false + Require server version to match client version + +.PP +\fB\-\-namespace\fP="" + If present, the namespace scope for this CLI request. + +.PP +\fB\-\-password\fP="" + Password for basic authentication to the API server. + +.PP +\fB\-s\fP, \fB\-\-server\fP="" + The address and port of the Kubernetes API server + +.PP +\fB\-\-stderrthreshold\fP=2 + logs at or above this threshold go to stderr + +.PP +\fB\-\-token\fP="" + Bearer token for authentication to the API server. + +.PP +\fB\-\-user\fP="" + The name of the kubeconfig user to use + +.PP +\fB\-\-username\fP="" + Username for basic authentication to the API server. + +.PP +\fB\-\-v\fP=0 + log level for V logs + +.PP +\fB\-\-vmodule\fP= + comma\-separated list of pattern=N settings for file\-filtered logging + + +.SH SEE ALSO +.PP +\fBkubectl\-cluster\-info(1)\fP, + + +.SH HISTORY +.PP +January 2015, Originally compiled by Eric Paris (eparis at redhat dot com) based on the kubernetes source material, but hopefully they have been automatically generated since! diff --git a/docs/user-guide/kubectl/kubectl_cluster-info_dump.md b/docs/user-guide/kubectl/kubectl_cluster-info_dump.md new file mode 100644 index 00000000000..1fa6fbb550f --- /dev/null +++ b/docs/user-guide/kubectl/kubectl_cluster-info_dump.md @@ -0,0 +1,92 @@ + + + + +WARNING +WARNING +WARNING +WARNING +WARNING + +

PLEASE NOTE: This document applies to the HEAD of the source tree

+ +If you are using a released version of Kubernetes, you should +refer to the docs that go with that version. + +Documentation for other releases can be found at +[releases.k8s.io](http://releases.k8s.io). + +-- + + + + + +## kubectl cluster-info dump + +Dump lots of relevant info for debugging and diagnosis. + +### Synopsis + + + +Dumps cluster info out suitable for debugging and diagnosing cluster problems. By default, dumps everything to +stdout. You can optionally specify a directory with --output-directory. If you specify a directory, kubernetes will +build a set of files in that directory. By default only dumps things in the 'kube-system' namespace, but you can +switch to a different namespace with the --namespaces flag, or specify --all-namespaces to dump all namespaces. + + +``` +kubectl cluster-info dump +``` + +### Options + +``` + --all-namespaces[=false]: If true, dump all namespaces. If true, --namespaces is ignored. + --namespaces=[]: A comma separated list of namespaces to dump. + --output-directory="": Where to output the files. If empty or '-' uses stdout, otherwise creates a directory hierarchy in that directory +``` + +### Options inherited from parent commands + +``` + --alsologtostderr[=false]: log to standard error as well as files + --as="": Username to impersonate for the operation. + --certificate-authority="": Path to a cert. file for the certificate authority. + --client-certificate="": Path to a client certificate file for TLS. + --client-key="": Path to a client key file for TLS. + --cluster="": The name of the kubeconfig cluster to use + --context="": The name of the kubeconfig context to use + --insecure-skip-tls-verify[=false]: If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure. + --kubeconfig="": Path to the kubeconfig file to use for CLI requests. + --log-backtrace-at=:0: when logging hits line file:N, emit a stack trace + --log-dir="": If non-empty, write log files in this directory + --log-flush-frequency=5s: Maximum number of seconds between log flushes + --logtostderr[=true]: log to standard error instead of files + --match-server-version[=false]: Require server version to match client version + --namespace="": If present, the namespace scope for this CLI request. + --password="": Password for basic authentication to the API server. + -s, --server="": The address and port of the Kubernetes API server + --stderrthreshold=2: logs at or above this threshold go to stderr + --token="": Bearer token for authentication to the API server. + --user="": The name of the kubeconfig user to use + --username="": Username for basic authentication to the API server. + --v=0: log level for V logs + --vmodule=: comma-separated list of pattern=N settings for file-filtered logging +``` + +### SEE ALSO + +* [kubectl cluster-info](kubectl_cluster-info.md) - Display cluster info + +###### Auto generated by spf13/cobra on 27-Apr-2016 + + +[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_cluster-info_dump.md?pixel)]() + diff --git a/hack/verify-flags/known-flags.txt b/hack/verify-flags/known-flags.txt index 6befaeb17d1..231dc0c01d6 100644 --- a/hack/verify-flags/known-flags.txt +++ b/hack/verify-flags/known-flags.txt @@ -306,6 +306,7 @@ os-distro out-version outofdisk-transition-frequency output-base +output-directory output-package output-print-type output-version diff --git a/pkg/kubectl/cmd/clusterinfo_dump.go b/pkg/kubectl/cmd/clusterinfo_dump.go index 36e543a61c9..abc6411a631 100644 --- a/pkg/kubectl/cmd/clusterinfo_dump.go +++ b/pkg/kubectl/cmd/clusterinfo_dump.go @@ -67,10 +67,10 @@ switch to a different namespace with the --namespaces flag, or specify --all-nam kubectl cluster-info dump --namespaces default,kube-system --output-directory=/tmp` ) -func getWriter(cmd *cobra.Command, out io.Writer, filename string) io.Writer { +func getWriter(cmd *cobra.Command, defaultWriter io.Writer, filename string) io.Writer { dir := cmdutil.GetFlagString(cmd, "output-directory") if len(dir) == 0 || dir == "-" { - return out + return defaultWriter } fullFile := path.Join(dir, filename) parent := path.Dir(fullFile) diff --git a/pkg/kubectl/cmd/clusterinfo_dump_test.go b/pkg/kubectl/cmd/clusterinfo_dump_test.go new file mode 100644 index 00000000000..9467e5f96ef --- /dev/null +++ b/pkg/kubectl/cmd/clusterinfo_dump_test.go @@ -0,0 +1,68 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "bytes" + "io/ioutil" + "os" + "path" + "testing" +) + +func TestGetWriterNoOp(t *testing.T) { + tests := []string{"", "-"} + for _, test := range tests { + out := &bytes.Buffer{} + f, _, _ := NewAPIFactory() + cmd := NewCmdClusterInfoDump(f, os.Stdout) + cmd.Flag("output-directory").Value.Set(test) + writer := getWriter(cmd, out, "/some/file/that/should/be/ignored") + if writer != out { + t.Errorf("expected: %v, saw: %v", out, writer) + } + } +} + +func TestGetWriterFile(t *testing.T) { + file := "output.json" + dir, err := ioutil.TempDir(os.TempDir(), "out") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + fullPath := path.Join(dir, file) + defer os.RemoveAll(dir) + + out := &bytes.Buffer{} + f, _, _ := NewAPIFactory() + cmd := NewCmdClusterInfoDump(f, os.Stdout) + cmd.Flag("output-directory").Value.Set(dir) + writer := getWriter(cmd, out, file) + if writer == out { + t.Errorf("expected: %v, saw: %v", out, writer) + } + output := "some data here" + writer.Write([]byte(output)) + + data, err := ioutil.ReadFile(fullPath) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if string(data) != output { + t.Errorf("expected: %v, saw: %v", output, data) + } +} From d8daa07f08434e7fca25ad8060fd04bf44182d16 Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Wed, 11 May 2016 11:17:26 -0700 Subject: [PATCH 3/4] address comments --- pkg/kubectl/cmd/clusterinfo.go | 6 ++++- pkg/kubectl/cmd/clusterinfo_dump.go | 40 ++++++++++++++++++----------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/pkg/kubectl/cmd/clusterinfo.go b/pkg/kubectl/cmd/clusterinfo.go index b5f90730ee0..a333eef3a64 100644 --- a/pkg/kubectl/cmd/clusterinfo.go +++ b/pkg/kubectl/cmd/clusterinfo.go @@ -30,13 +30,16 @@ import ( "github.com/spf13/cobra" ) +var longDescr = `Display addresses of the master and services with label kubernetes.io/cluster-service=true +To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.` + func NewCmdClusterInfo(f *cmdutil.Factory, out io.Writer) *cobra.Command { cmd := &cobra.Command{ Use: "cluster-info", // clusterinfo is deprecated. Aliases: []string{"clusterinfo"}, Short: "Display cluster info", - Long: "Display addresses of the master and services with label kubernetes.io/cluster-service=true", + Long: longDescr, Run: func(cmd *cobra.Command, args []string) { err := RunClusterInfo(f, out, cmd) cmdutil.CheckErr(err) @@ -102,6 +105,7 @@ func RunClusterInfo(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command) error } return nil }) + out.Write([]byte("\nTo further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.\n")) return nil // TODO consider printing more information about cluster diff --git a/pkg/kubectl/cmd/clusterinfo_dump.go b/pkg/kubectl/cmd/clusterinfo_dump.go index abc6411a631..e40d287ad1f 100644 --- a/pkg/kubectl/cmd/clusterinfo_dump.go +++ b/pkg/kubectl/cmd/clusterinfo_dump.go @@ -35,7 +35,7 @@ func NewCmdClusterInfoDump(f *cmdutil.Factory, cmdOut io.Writer) *cobra.Command cmd := &cobra.Command{ Use: "dump", Short: "Dump lots of relevant info for debugging and diagnosis.", - Long: dumpLong, + Long: dumpLong + "\n" + dumpExample, Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(dumpClusterInfo(f, cmd, args, cmdOut)) }, @@ -52,22 +52,25 @@ Dumps cluster info out suitable for debugging and diagnosing cluster problems. stdout. You can optionally specify a directory with --output-directory. If you specify a directory, kubernetes will build a set of files in that directory. By default only dumps things in the 'kube-system' namespace, but you can switch to a different namespace with the --namespaces flag, or specify --all-namespaces to dump all namespaces. + +The command also dumps the logs of all of the pods in the cluster, these logs are dumped into different directories +based on namespace and pod name. ` dumpExample = ` # Dump current cluster state to stdout kubectl cluster-info dump - # Dump current cluster state to /tmp - kubectl cluster-info dump --output-directory=/tmp + # Dump current cluster state to /path/to/cluster-state + kubectl cluster-info dump --output-directory=/path/to/cluster-state # Dump all namespaces to stdout kubectl cluster-info dump --all-namespaces - # Dump a set of namespaces to /tmp - kubectl cluster-info dump --namespaces default,kube-system --output-directory=/tmp` + # Dump a set of namespaces to /path/to/cluster-state + kubectl cluster-info dump --namespaces default,kube-system --output-directory=/path/to/cluster-state` ) -func getWriter(cmd *cobra.Command, defaultWriter io.Writer, filename string) io.Writer { +func setupOutputWriter(cmd *cobra.Command, defaultWriter io.Writer, filename string) io.Writer { dir := cmdutil.GetFlagString(cmd, "output-directory") if len(dir) == 0 || dir == "-" { return defaultWriter @@ -97,7 +100,7 @@ func dumpClusterInfo(f *cmdutil.Factory, cmd *cobra.Command, args []string, out return err } - if err := printer.PrintObj(nodes, getWriter(cmd, out, "nodes.json")); err != nil { + if err := printer.PrintObj(nodes, setupOutputWriter(cmd, out, "nodes.json")); err != nil { return err } @@ -130,7 +133,7 @@ func dumpClusterInfo(f *cmdutil.Factory, cmd *cobra.Command, args []string, out if err != nil { return err } - if err := printer.PrintObj(events, getWriter(cmd, out, path.Join(namespace, "events.json"))); err != nil { + if err := printer.PrintObj(events, setupOutputWriter(cmd, out, path.Join(namespace, "events.json"))); err != nil { return err } @@ -138,7 +141,7 @@ func dumpClusterInfo(f *cmdutil.Factory, cmd *cobra.Command, args []string, out if err != nil { return err } - if err := printer.PrintObj(rcs, getWriter(cmd, out, path.Join(namespace, "replication-controllers.json"))); err != nil { + if err := printer.PrintObj(rcs, setupOutputWriter(cmd, out, path.Join(namespace, "replication-controllers.json"))); err != nil { return err } @@ -146,7 +149,7 @@ func dumpClusterInfo(f *cmdutil.Factory, cmd *cobra.Command, args []string, out if err != nil { return err } - if err := printer.PrintObj(svcs, getWriter(cmd, out, path.Join(namespace, "services.json"))); err != nil { + if err := printer.PrintObj(svcs, setupOutputWriter(cmd, out, path.Join(namespace, "services.json"))); err != nil { return err } @@ -154,7 +157,7 @@ func dumpClusterInfo(f *cmdutil.Factory, cmd *cobra.Command, args []string, out if err != nil { return err } - if err := printer.PrintObj(sets, getWriter(cmd, out, path.Join(namespace, "daemonsets.json"))); err != nil { + if err := printer.PrintObj(sets, setupOutputWriter(cmd, out, path.Join(namespace, "daemonsets.json"))); err != nil { return err } @@ -162,7 +165,7 @@ func dumpClusterInfo(f *cmdutil.Factory, cmd *cobra.Command, args []string, out if err != nil { return err } - if err := printer.PrintObj(deps, getWriter(cmd, out, path.Join(namespace, "deployments.json"))); err != nil { + if err := printer.PrintObj(deps, setupOutputWriter(cmd, out, path.Join(namespace, "deployments.json"))); err != nil { return err } @@ -170,7 +173,7 @@ func dumpClusterInfo(f *cmdutil.Factory, cmd *cobra.Command, args []string, out if err != nil { return err } - if err := printer.PrintObj(rps, getWriter(cmd, out, path.Join(namespace, "replicasets.json"))); err != nil { + if err := printer.PrintObj(rps, setupOutputWriter(cmd, out, path.Join(namespace, "replicasets.json"))); err != nil { return err } @@ -179,13 +182,13 @@ func dumpClusterInfo(f *cmdutil.Factory, cmd *cobra.Command, args []string, out return err } - if err := printer.PrintObj(pods, getWriter(cmd, out, path.Join(namespace, "pods.json"))); err != nil { + if err := printer.PrintObj(pods, setupOutputWriter(cmd, out, path.Join(namespace, "pods.json"))); err != nil { return err } for ix := range pods.Items { pod := &pods.Items[ix] - writer := getWriter(cmd, out, path.Join(namespace, pod.Name, "logs.txt")) + writer := setupOutputWriter(cmd, out, path.Join(namespace, pod.Name, "logs.txt")) writer.Write([]byte(fmt.Sprintf("==== START logs for %s/%s ====\n", pod.Namespace, pod.Name))) request, err := f.LogsForObject(pod, &api.PodLogOptions{}) if err != nil { @@ -200,5 +203,12 @@ func dumpClusterInfo(f *cmdutil.Factory, cmd *cobra.Command, args []string, out writer.Write([]byte(fmt.Sprintf("==== END logs for %s/%s ====\n", pod.Namespace, pod.Name))) } } + dir := cmdutil.GetFlagString(cmd, "output-directory") + if len(dir) == 0 { + dir = "." + } + if dir != "-" { + fmt.Fprintf(out, "Cluster info dumped to %s", dir) + } return nil } From 178b5f76381fe532dc024e006f6d786582fa662e Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Mon, 16 May 2016 16:50:13 -0700 Subject: [PATCH 4/4] address comments --- docs/man/man1/kubectl-cluster-info-dump.1 | 25 +++++++++++++++++++ docs/man/man1/kubectl-cluster-info.1 | 1 + .../kubectl/kubectl_cluster-info.md | 3 ++- .../kubectl/kubectl_cluster-info_dump.md | 21 +++++++++++++++- docs/yaml/kubectl/kubectl_cluster-info.yaml | 3 ++- pkg/kubectl/cmd/clusterinfo_dump.go | 23 +++++++++-------- pkg/kubectl/cmd/clusterinfo_dump_test.go | 8 +++--- 7 files changed, 66 insertions(+), 18 deletions(-) diff --git a/docs/man/man1/kubectl-cluster-info-dump.1 b/docs/man/man1/kubectl-cluster-info-dump.1 index 208b672aa8d..9d4111da139 100644 --- a/docs/man/man1/kubectl-cluster-info-dump.1 +++ b/docs/man/man1/kubectl-cluster-info-dump.1 @@ -18,6 +18,10 @@ stdout. You can optionally specify a directory with \-\-output\-directory. If y build a set of files in that directory. By default only dumps things in the 'kube\-system' namespace, but you can switch to a different namespace with the \-\-namespaces flag, or specify \-\-all\-namespaces to dump all namespaces. +.PP +The command also dumps the logs of all of the pods in the cluster, these logs are dumped into different directories +based on namespace and pod name. + .SH OPTIONS .PP @@ -131,6 +135,27 @@ switch to a different namespace with the \-\-namespaces flag, or specify \-\-all comma\-separated list of pattern=N settings for file\-filtered logging +.SH EXAMPLE +.PP +.RS + +.nf +# Dump current cluster state to stdout +kubectl cluster\-info dump + +# Dump current cluster state to /path/to/cluster\-state +kubectl cluster\-info dump \-\-output\-directory=/path/to/cluster\-state + +# Dump all namespaces to stdout +kubectl cluster\-info dump \-\-all\-namespaces + +# Dump a set of namespaces to /path/to/cluster\-state +kubectl cluster\-info dump \-\-namespaces default,kube\-system \-\-output\-directory=/path/to/cluster\-state + +.fi +.RE + + .SH SEE ALSO .PP \fBkubectl\-cluster\-info(1)\fP, diff --git a/docs/man/man1/kubectl-cluster-info.1 b/docs/man/man1/kubectl-cluster-info.1 index 459594a3366..a67f5209b01 100644 --- a/docs/man/man1/kubectl-cluster-info.1 +++ b/docs/man/man1/kubectl-cluster-info.1 @@ -14,6 +14,7 @@ kubectl cluster\-info \- Display cluster info .SH DESCRIPTION .PP Display addresses of the master and services with label kubernetes.io/cluster\-service=true +To further debug and diagnose cluster problems, use 'kubectl cluster\-info dump'. .SH OPTIONS diff --git a/docs/user-guide/kubectl/kubectl_cluster-info.md b/docs/user-guide/kubectl/kubectl_cluster-info.md index e65ab21a3bb..6cc2c282412 100644 --- a/docs/user-guide/kubectl/kubectl_cluster-info.md +++ b/docs/user-guide/kubectl/kubectl_cluster-info.md @@ -40,6 +40,7 @@ Display cluster info Display addresses of the master and services with label kubernetes.io/cluster-service=true +To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. ``` kubectl cluster-info @@ -84,7 +85,7 @@ kubectl cluster-info * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager * [kubectl cluster-info dump](kubectl_cluster-info_dump.md) - Dump lots of relevant info for debugging and diagnosis. -###### Auto generated by spf13/cobra on 27-Apr-2016 +###### Auto generated by spf13/cobra on 16-May-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_cluster-info.md?pixel)]() diff --git a/docs/user-guide/kubectl/kubectl_cluster-info_dump.md b/docs/user-guide/kubectl/kubectl_cluster-info_dump.md index 1fa6fbb550f..a946b835f20 100644 --- a/docs/user-guide/kubectl/kubectl_cluster-info_dump.md +++ b/docs/user-guide/kubectl/kubectl_cluster-info_dump.md @@ -40,11 +40,30 @@ stdout. You can optionally specify a directory with --output-directory. If you build a set of files in that directory. By default only dumps things in the 'kube-system' namespace, but you can switch to a different namespace with the --namespaces flag, or specify --all-namespaces to dump all namespaces. +The command also dumps the logs of all of the pods in the cluster, these logs are dumped into different directories +based on namespace and pod name. + ``` kubectl cluster-info dump ``` +### Examples + +``` +# Dump current cluster state to stdout +kubectl cluster-info dump + +# Dump current cluster state to /path/to/cluster-state +kubectl cluster-info dump --output-directory=/path/to/cluster-state + +# Dump all namespaces to stdout +kubectl cluster-info dump --all-namespaces + +# Dump a set of namespaces to /path/to/cluster-state +kubectl cluster-info dump --namespaces default,kube-system --output-directory=/path/to/cluster-state +``` + ### Options ``` @@ -85,7 +104,7 @@ kubectl cluster-info dump * [kubectl cluster-info](kubectl_cluster-info.md) - Display cluster info -###### Auto generated by spf13/cobra on 27-Apr-2016 +###### Auto generated by spf13/cobra on 16-May-2016 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_cluster-info_dump.md?pixel)]() diff --git a/docs/yaml/kubectl/kubectl_cluster-info.yaml b/docs/yaml/kubectl/kubectl_cluster-info.yaml index 44ad329311a..bc017e4cfd1 100644 --- a/docs/yaml/kubectl/kubectl_cluster-info.yaml +++ b/docs/yaml/kubectl/kubectl_cluster-info.yaml @@ -1,7 +1,8 @@ name: cluster-info synopsis: Display cluster info -description: | +description: |- Display addresses of the master and services with label kubernetes.io/cluster-service=true + To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. options: - name: include-extended-apis default_value: "true" diff --git a/pkg/kubectl/cmd/clusterinfo_dump.go b/pkg/kubectl/cmd/clusterinfo_dump.go index e40d287ad1f..9a1865902a7 100644 --- a/pkg/kubectl/cmd/clusterinfo_dump.go +++ b/pkg/kubectl/cmd/clusterinfo_dump.go @@ -33,9 +33,10 @@ import ( // NewCmdCreateSecret groups subcommands to create various types of secrets func NewCmdClusterInfoDump(f *cmdutil.Factory, cmdOut io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "dump", - Short: "Dump lots of relevant info for debugging and diagnosis.", - Long: dumpLong + "\n" + dumpExample, + Use: "dump", + Short: "Dump lots of relevant info for debugging and diagnosis.", + Long: dumpLong, + Example: dumpExample, Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(dumpClusterInfo(f, cmd, args, cmdOut)) }, @@ -57,17 +58,17 @@ The command also dumps the logs of all of the pods in the cluster, these logs ar based on namespace and pod name. ` - dumpExample = ` # Dump current cluster state to stdout - kubectl cluster-info dump + dumpExample = `# Dump current cluster state to stdout +kubectl cluster-info dump - # Dump current cluster state to /path/to/cluster-state - kubectl cluster-info dump --output-directory=/path/to/cluster-state +# Dump current cluster state to /path/to/cluster-state +kubectl cluster-info dump --output-directory=/path/to/cluster-state - # Dump all namespaces to stdout - kubectl cluster-info dump --all-namespaces +# Dump all namespaces to stdout +kubectl cluster-info dump --all-namespaces - # Dump a set of namespaces to /path/to/cluster-state - kubectl cluster-info dump --namespaces default,kube-system --output-directory=/path/to/cluster-state` +# Dump a set of namespaces to /path/to/cluster-state +kubectl cluster-info dump --namespaces default,kube-system --output-directory=/path/to/cluster-state` ) func setupOutputWriter(cmd *cobra.Command, defaultWriter io.Writer, filename string) io.Writer { diff --git a/pkg/kubectl/cmd/clusterinfo_dump_test.go b/pkg/kubectl/cmd/clusterinfo_dump_test.go index 9467e5f96ef..35314525895 100644 --- a/pkg/kubectl/cmd/clusterinfo_dump_test.go +++ b/pkg/kubectl/cmd/clusterinfo_dump_test.go @@ -24,21 +24,21 @@ import ( "testing" ) -func TestGetWriterNoOp(t *testing.T) { +func TestSetupOutputWriterNoOp(t *testing.T) { tests := []string{"", "-"} for _, test := range tests { out := &bytes.Buffer{} f, _, _ := NewAPIFactory() cmd := NewCmdClusterInfoDump(f, os.Stdout) cmd.Flag("output-directory").Value.Set(test) - writer := getWriter(cmd, out, "/some/file/that/should/be/ignored") + writer := setupOutputWriter(cmd, out, "/some/file/that/should/be/ignored") if writer != out { t.Errorf("expected: %v, saw: %v", out, writer) } } } -func TestGetWriterFile(t *testing.T) { +func TestSetupOutputWriterFile(t *testing.T) { file := "output.json" dir, err := ioutil.TempDir(os.TempDir(), "out") if err != nil { @@ -51,7 +51,7 @@ func TestGetWriterFile(t *testing.T) { f, _, _ := NewAPIFactory() cmd := NewCmdClusterInfoDump(f, os.Stdout) cmd.Flag("output-directory").Value.Set(dir) - writer := getWriter(cmd, out, file) + writer := setupOutputWriter(cmd, out, file) if writer == out { t.Errorf("expected: %v, saw: %v", out, writer) }