clusterinfo_dump.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package cmd
  14. import (
  15. "fmt"
  16. "io"
  17. "os"
  18. "path"
  19. "github.com/spf13/cobra"
  20. "k8s.io/kubernetes/pkg/api"
  21. "k8s.io/kubernetes/pkg/client/unversioned"
  22. "k8s.io/kubernetes/pkg/kubectl"
  23. cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
  24. )
  25. // NewCmdCreateSecret groups subcommands to create various types of secrets
  26. func NewCmdClusterInfoDump(f *cmdutil.Factory, cmdOut io.Writer) *cobra.Command {
  27. cmd := &cobra.Command{
  28. Use: "dump",
  29. Short: "Dump lots of relevant info for debugging and diagnosis",
  30. Long: dumpLong,
  31. Example: dumpExample,
  32. Run: func(cmd *cobra.Command, args []string) {
  33. cmdutil.CheckErr(dumpClusterInfo(f, cmd, args, cmdOut))
  34. },
  35. }
  36. cmd.Flags().String("output-directory", "", "Where to output the files. If empty or '-' uses stdout, otherwise creates a directory hierarchy in that directory")
  37. cmd.Flags().StringSlice("namespaces", []string{}, "A comma separated list of namespaces to dump.")
  38. cmd.Flags().Bool("all-namespaces", false, "If true, dump all namespaces. If true, --namespaces is ignored.")
  39. return cmd
  40. }
  41. const (
  42. dumpLong = `
  43. Dumps cluster info out suitable for debugging and diagnosing cluster problems. By default, dumps everything to
  44. stdout. You can optionally specify a directory with --output-directory. If you specify a directory, kubernetes will
  45. build a set of files in that directory. By default only dumps things in the 'kube-system' namespace, but you can
  46. switch to a different namespace with the --namespaces flag, or specify --all-namespaces to dump all namespaces.
  47. The command also dumps the logs of all of the pods in the cluster, these logs are dumped into different directories
  48. based on namespace and pod name.
  49. `
  50. dumpExample = `# Dump current cluster state to stdout
  51. kubectl cluster-info dump
  52. # Dump current cluster state to /path/to/cluster-state
  53. kubectl cluster-info dump --output-directory=/path/to/cluster-state
  54. # Dump all namespaces to stdout
  55. kubectl cluster-info dump --all-namespaces
  56. # Dump a set of namespaces to /path/to/cluster-state
  57. kubectl cluster-info dump --namespaces default,kube-system --output-directory=/path/to/cluster-state`
  58. )
  59. func setupOutputWriter(cmd *cobra.Command, defaultWriter io.Writer, filename string) io.Writer {
  60. dir := cmdutil.GetFlagString(cmd, "output-directory")
  61. if len(dir) == 0 || dir == "-" {
  62. return defaultWriter
  63. }
  64. fullFile := path.Join(dir, filename)
  65. parent := path.Dir(fullFile)
  66. cmdutil.CheckErr(os.MkdirAll(parent, 0755))
  67. file, err := os.Create(path.Join(dir, filename))
  68. cmdutil.CheckErr(err)
  69. return file
  70. }
  71. func dumpClusterInfo(f *cmdutil.Factory, cmd *cobra.Command, args []string, out io.Writer) error {
  72. var c *unversioned.Client
  73. var err error
  74. if c, err = f.Client(); err != nil {
  75. return err
  76. }
  77. printer, _, err := kubectl.GetPrinter("json", "", false)
  78. if err != nil {
  79. return err
  80. }
  81. nodes, err := c.Nodes().List(api.ListOptions{})
  82. if err != nil {
  83. return err
  84. }
  85. if err := printer.PrintObj(nodes, setupOutputWriter(cmd, out, "nodes.json")); err != nil {
  86. return err
  87. }
  88. var namespaces []string
  89. if cmdutil.GetFlagBool(cmd, "all-namespaces") {
  90. namespaceList, err := c.Namespaces().List(api.ListOptions{})
  91. if err != nil {
  92. return err
  93. }
  94. for ix := range namespaceList.Items {
  95. namespaces = append(namespaces, namespaceList.Items[ix].Name)
  96. }
  97. } else {
  98. namespaces = cmdutil.GetFlagStringSlice(cmd, "namespaces")
  99. if len(namespaces) == 0 {
  100. cmdNamespace, _, err := f.DefaultNamespace()
  101. if err != nil {
  102. return err
  103. }
  104. namespaces = []string{
  105. api.NamespaceSystem,
  106. cmdNamespace,
  107. }
  108. }
  109. }
  110. for _, namespace := range namespaces {
  111. // TODO: this is repetitive in the extreme. Use reflection or
  112. // something to make this a for loop.
  113. events, err := c.Events(namespace).List(api.ListOptions{})
  114. if err != nil {
  115. return err
  116. }
  117. if err := printer.PrintObj(events, setupOutputWriter(cmd, out, path.Join(namespace, "events.json"))); err != nil {
  118. return err
  119. }
  120. rcs, err := c.ReplicationControllers(namespace).List(api.ListOptions{})
  121. if err != nil {
  122. return err
  123. }
  124. if err := printer.PrintObj(rcs, setupOutputWriter(cmd, out, path.Join(namespace, "replication-controllers.json"))); err != nil {
  125. return err
  126. }
  127. svcs, err := c.Services(namespace).List(api.ListOptions{})
  128. if err != nil {
  129. return err
  130. }
  131. if err := printer.PrintObj(svcs, setupOutputWriter(cmd, out, path.Join(namespace, "services.json"))); err != nil {
  132. return err
  133. }
  134. sets, err := c.DaemonSets(namespace).List(api.ListOptions{})
  135. if err != nil {
  136. return err
  137. }
  138. if err := printer.PrintObj(sets, setupOutputWriter(cmd, out, path.Join(namespace, "daemonsets.json"))); err != nil {
  139. return err
  140. }
  141. deps, err := c.Deployments(namespace).List(api.ListOptions{})
  142. if err != nil {
  143. return err
  144. }
  145. if err := printer.PrintObj(deps, setupOutputWriter(cmd, out, path.Join(namespace, "deployments.json"))); err != nil {
  146. return err
  147. }
  148. rps, err := c.ReplicaSets(namespace).List(api.ListOptions{})
  149. if err != nil {
  150. return err
  151. }
  152. if err := printer.PrintObj(rps, setupOutputWriter(cmd, out, path.Join(namespace, "replicasets.json"))); err != nil {
  153. return err
  154. }
  155. pods, err := c.Pods(namespace).List(api.ListOptions{})
  156. if err != nil {
  157. return err
  158. }
  159. if err := printer.PrintObj(pods, setupOutputWriter(cmd, out, path.Join(namespace, "pods.json"))); err != nil {
  160. return err
  161. }
  162. for ix := range pods.Items {
  163. pod := &pods.Items[ix]
  164. writer := setupOutputWriter(cmd, out, path.Join(namespace, pod.Name, "logs.txt"))
  165. writer.Write([]byte(fmt.Sprintf("==== START logs for %s/%s ====\n", pod.Namespace, pod.Name)))
  166. request, err := f.LogsForObject(pod, &api.PodLogOptions{})
  167. if err != nil {
  168. return err
  169. }
  170. data, err := request.DoRaw()
  171. if err != nil {
  172. return err
  173. }
  174. writer.Write(data)
  175. writer.Write([]byte(fmt.Sprintf("==== END logs for %s/%s ====\n", pod.Namespace, pod.Name)))
  176. }
  177. }
  178. dir := cmdutil.GetFlagString(cmd, "output-directory")
  179. if len(dir) == 0 {
  180. dir = "."
  181. }
  182. if dir != "-" {
  183. fmt.Fprintf(out, "Cluster info dumped to %s", dir)
  184. }
  185. return nil
  186. }