summaryrefslogtreecommitdiff
path: root/cmd/kpod/info.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/kpod/info.go')
-rw-r--r--cmd/kpod/info.go200
1 files changed, 200 insertions, 0 deletions
diff --git a/cmd/kpod/info.go b/cmd/kpod/info.go
new file mode 100644
index 000000000..22ca74c73
--- /dev/null
+++ b/cmd/kpod/info.go
@@ -0,0 +1,200 @@
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "runtime"
+
+ "github.com/docker/docker/pkg/system"
+ "github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
+ "github.com/pkg/errors"
+ "github.com/urfave/cli"
+)
+
+var (
+ infoDescription = "display system information"
+ infoCommand = cli.Command{
+ Name: "info",
+ Usage: infoDescription,
+ Description: `Information display here pertain to the host, current storage stats, and build of kpod. Useful for the user and when reporting issues.`,
+ Flags: infoFlags,
+ Action: infoCmd,
+ ArgsUsage: "",
+ }
+ infoFlags = []cli.Flag{
+ cli.BoolFlag{
+ Name: "debug, D",
+ Usage: "display additional debug information",
+ },
+ cli.StringFlag{
+ Name: "format",
+ Usage: "Change the output format to JSON or a Go template",
+ },
+ }
+)
+
+func infoCmd(c *cli.Context) error {
+ if err := validateFlags(c, infoFlags); err != nil {
+ return err
+ }
+ info := map[string]interface{}{}
+
+ infoGivers := []infoGiverFunc{
+ storeInfo,
+ hostInfo,
+ }
+
+ if c.Bool("debug") {
+ infoGivers = append(infoGivers, debugInfo)
+ }
+
+ for _, giver := range infoGivers {
+ thisName, thisInfo, err := giver(c)
+ if err != nil {
+ info[thisName] = infoErr(err)
+ continue
+ }
+ info[thisName] = thisInfo
+ }
+
+ var out formats.Writer
+ infoOutputFormat := c.String("format")
+ switch infoOutputFormat {
+ case formats.JSONString:
+ out = formats.JSONStruct{Output: info}
+ case "":
+ out = formats.YAMLStruct{Output: info}
+ default:
+ out = formats.StdoutTemplate{Output: info, Template: infoOutputFormat}
+ }
+
+ formats.Writer(out).Out()
+
+ return nil
+}
+
+func infoErr(err error) map[string]interface{} {
+ return map[string]interface{}{
+ "error": err.Error(),
+ }
+}
+
+type infoGiverFunc func(c *cli.Context) (name string, info map[string]interface{}, err error)
+
+// top-level "debug" info
+func debugInfo(c *cli.Context) (string, map[string]interface{}, error) {
+ info := map[string]interface{}{}
+ info["compiler"] = runtime.Compiler
+ info["go version"] = runtime.Version()
+ info["kpod version"] = c.App.Version
+ info["git commit"] = gitCommit
+ return "debug", info, nil
+}
+
+// top-level "host" info
+func hostInfo(c *cli.Context) (string, map[string]interface{}, error) {
+ // lets say OS, arch, number of cpus, amount of memory, maybe os distribution/version, hostname, kernel version, uptime
+ info := map[string]interface{}{}
+ info["os"] = runtime.GOOS
+ info["arch"] = runtime.GOARCH
+ info["cpus"] = runtime.NumCPU()
+ mi, err := system.ReadMemInfo()
+ if err != nil {
+ info["meminfo"] = infoErr(err)
+ } else {
+ // TODO this might be a place for github.com/dustin/go-humanize
+ info["MemTotal"] = mi.MemTotal
+ info["MemFree"] = mi.MemFree
+ info["SwapTotal"] = mi.SwapTotal
+ info["SwapFree"] = mi.SwapFree
+ }
+ if kv, err := readKernelVersion(); err != nil {
+ info["kernel"] = infoErr(err)
+ } else {
+ info["kernel"] = kv
+ }
+
+ if up, err := readUptime(); err != nil {
+ info["uptime"] = infoErr(err)
+ } else {
+ info["uptime"] = up
+ }
+ if host, err := os.Hostname(); err != nil {
+ info["hostname"] = infoErr(err)
+ } else {
+ info["hostname"] = host
+ }
+ return "host", info, nil
+}
+
+// top-level "store" info
+func storeInfo(c *cli.Context) (string, map[string]interface{}, error) {
+ storeStr := "store"
+ config, err := getConfig(c)
+ if err != nil {
+ return storeStr, nil, errors.Wrapf(err, "Could not get config")
+ }
+ store, err := getStore(config)
+ if err != nil {
+ return storeStr, nil, err
+ }
+
+ // lets say storage driver in use, number of images, number of containers
+ info := map[string]interface{}{}
+ info["GraphRoot"] = store.GraphRoot()
+ info["RunRoot"] = store.RunRoot()
+ info["GraphDriverName"] = store.GraphDriverName()
+ info["GraphOptions"] = store.GraphOptions()
+ statusPairs, err := store.Status()
+ if err != nil {
+ return storeStr, nil, err
+ }
+ status := map[string]string{}
+ for _, pair := range statusPairs {
+ status[pair[0]] = pair[1]
+ }
+ info["GraphStatus"] = status
+ images, err := store.Images()
+ if err != nil {
+ info["ImageStore"] = infoErr(err)
+ } else {
+ info["ImageStore"] = map[string]interface{}{
+ "number": len(images),
+ }
+ }
+ containers, err := store.Containers()
+ if err != nil {
+ info["ContainerStore"] = infoErr(err)
+ } else {
+ info["ContainerStore"] = map[string]interface{}{
+ "number": len(containers),
+ }
+ }
+ return storeStr, info, nil
+}
+
+func readKernelVersion() (string, error) {
+ buf, err := ioutil.ReadFile("/proc/version")
+ if err != nil {
+ return "", err
+ }
+ f := bytes.Fields(buf)
+ if len(f) < 2 {
+ return string(bytes.TrimSpace(buf)), nil
+ }
+ return string(f[2]), nil
+}
+
+func readUptime() (string, error) {
+ buf, err := ioutil.ReadFile("/proc/uptime")
+ if err != nil {
+ return "", err
+ }
+ f := bytes.Fields(buf)
+ if len(f) < 1 {
+ return "", fmt.Errorf("invalid uptime")
+ }
+ return string(f[0]), nil
+}