diff --git a/README.md b/README.md index b735801..e175247 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This project was inspired by [RIKRUS's](https://github.com/RIKRUS/MOTD) and [Her I've decided to use Go because it is about 10x faster than a similar bash script and it makes for a great first project using the language. In my tests it typically runs in 10-20ms, a similar bash script takes 200-500ms. -The available information will depend on the user privileges, you will need to be able to run (without sudo) `systemctl status`, `docker inspect` and `zpool status` for example. +The available information will depend on the user privileges, you will need to be able to run (without sudo) `systemctl status`, `docker ps` and `zpool status` for example. Note that the BTRFS and ZFS space statistics are totals, that is to say, a RAID5 setup shows the used/total space across all drives. For example 3x4TB disks in RAIDZ1 show 10.91TB total, not the usable space which is about 7TB. @@ -62,7 +62,8 @@ Example line in `~/.zshrc` colDef: - [sysinfo] - [updates] - - [docker, systemd] + - [docker, podman] + - [systemd] - [cpu, disk] - [zfs] - [btrfs] @@ -75,7 +76,7 @@ colDef: All modules implement at least `header`/`content`. - `header`/`content` arrays define padding, first element is padding to the left (of the module name) and second to the right, before the semicolon (useful for aligning vertically) -- `warn`/`crit` unit depends on the module, for CPU/Disk temperatures it is degrees celsius, for ZFS pools it is % used +- `warn`/`crit` unit depends on the module, for CPU/Disk temperatures it is degrees celsius, for storage (ZFS/btrfs) it is % used ### Updates @@ -91,6 +92,13 @@ The drivetemp kernel module is required. ### Docker - `ignore` list of ignored container names +- `useExec` get containers by parsing `docker` command output + +### Podman + +- `ignore` list of ignored container names +- `sudo` get root containers, you should be able to run `sudo podman` without a password +- `includeSudo` includes both root and rootless containers ### Systemd @@ -108,8 +116,8 @@ import "github.com/cosandr/go-motd/utils" // These must not occur in the output string itself, if they do, feel free to use your own constants const ( - examplePadL = "^" // Default is $ - examplePadR = "&" // Default is % + examplePadL = "^" // Default is ^L^ + examplePadR = "&" // Default is ^R^ ) // Optional, can use CommonConf or CommonWithWarnConf diff --git a/config.yaml b/config.yaml index c196c0d..541e35c 100644 --- a/config.yaml +++ b/config.yaml @@ -3,9 +3,11 @@ failedOnly: false colDef: - [sysinfo] - [updates] - - [docker, systemd] + - [docker, podman] + - [systemd] - [cpu, disk] - - [zfs, btrfs] + - [zfs] + - [btrfs] colPad: 10 updates: header: [0, 3] @@ -30,11 +32,15 @@ systemd: - check-nginx-modules.service # - fictional.service docker: - useExec: false + useExec: true header: [0, 4] content: [2, 1] ignore: - code-server +podman: + includeSudo: true + header: [0, 1] + content: [0, 1] disk: useSys: true header: [0, 1] diff --git a/datasources/common_vars.go b/datasources/common_vars.go index 866e282..c3c3ba4 100644 --- a/datasources/common_vars.go +++ b/datasources/common_vars.go @@ -1,8 +1,8 @@ package datasources const ( - padL string = "$" - padR string = "%" + padL string = "^L^" + padR string = "^R^" ) // CommonConf is the common type for all modules diff --git a/datasources/container_common.go b/datasources/container_common.go new file mode 100644 index 0000000..88020fa --- /dev/null +++ b/datasources/container_common.go @@ -0,0 +1,64 @@ +package datasources + +import ( + "fmt" + "sort" + "strings" + + "github.com/cosandr/go-motd/utils" +) + +type containerStatus struct { + Name string + Status string +} + +type containerList struct { + Runtime string + Root bool + Containers []containerStatus +} + +func (cl *containerList) toHeaderContent(ignoreList []string, failedOnly bool) (header string, content string, err error) { + // Make set of ignored containers + var ignoreSet utils.StringSet + ignoreSet = ignoreSet.FromList(ignoreList) + // Process output + var goodCont = make(map[string]string) + var failedCont = make(map[string]string) + var sortedNames []string + for _, c := range cl.Containers { + if ignoreSet.Contains(c.Name) { + continue + } + status := strings.ToLower(c.Status) + if status == "up" || status == "created" || status == "running" { + goodCont[c.Name] = status + } else { + failedCont[c.Name] = status + } + sortedNames = append(sortedNames, c.Name) + } + sort.Strings(sortedNames) + + // Decide what header should be + if len(goodCont) == 0 { + header = fmt.Sprintf("%s: %s\n", utils.Wrap(cl.Runtime, padL, padR), utils.Err("critical")) + } else if len(failedCont) == 0 { + header = fmt.Sprintf("%s: %s\n", utils.Wrap(cl.Runtime, padL, padR), utils.Good("OK")) + if failedOnly { + return + } + } else if len(failedCont) < len(sortedNames) { + header = fmt.Sprintf("%s: %s\n", utils.Wrap(cl.Runtime, padL, padR), utils.Warn("warning")) + } + // Only print all containers if requested + for _, c := range sortedNames { + if val, ok := goodCont[c]; ok && !failedOnly { + content += fmt.Sprintf("%s: %s\n", utils.Wrap(c, padL, padR), utils.Good(val)) + } else if val, ok := failedCont[c]; ok { + content += fmt.Sprintf("%s: %s\n", utils.Wrap(c, padL, padR), utils.Err(val)) + } + } + return +} diff --git a/datasources/container_exec.go b/datasources/container_exec.go new file mode 100644 index 0000000..a49f73f --- /dev/null +++ b/datasources/container_exec.go @@ -0,0 +1,42 @@ +package datasources + +import ( + "bytes" + "os/exec" + "strings" +) + +// getContainersExec returns container status using os/exec, ~5x slower than API +func getContainersExec(podman bool, sudo bool) (cl containerList, err error) { + var stdout bytes.Buffer + cl.Root = sudo + if podman { + cl.Runtime = "Podman" + } else { + cl.Runtime = "Docker" + } + var cmd *exec.Cmd + if sudo { + cmd = exec.Command("sudo", strings.ToLower(cl.Runtime), "ps", "--format", `"{{.Names}} {{.Status}}"`, "-a") + } else { + cmd = exec.Command(strings.ToLower(cl.Runtime), "ps", "--format", `"{{.Names}} {{.Status}}"`, "-a") + } + cmd.Stdout = &stdout + err = cmd.Run() + if err != nil { + return + } + for _, c := range strings.Split(stdout.String(), "\n") { + var tmp = strings.Split(strings.Trim(c, `"`), " ") + if len(tmp) < 2 { + continue + } + // tmp[0] - container name + // tmp[1] - container status (up/created/exited) + cl.Containers = append(cl.Containers, containerStatus{ + Name: tmp[0], + Status: tmp[1], + }) + } + return +} diff --git a/datasources/docker.go b/datasources/docker.go index 83ea718..3179c3b 100644 --- a/datasources/docker.go +++ b/datasources/docker.go @@ -3,7 +3,6 @@ package datasources import ( "context" "fmt" - "sort" "strings" "github.com/cosandr/go-motd/utils" @@ -24,12 +23,19 @@ type DockerConf struct { // GetDocker docker container status using the API func GetDocker(ret chan<- string, c *DockerConf) { + var err error + var cl containerList var header string var content string if c.Exec { - header, content, _ = checkContainersExec(c.Ignore, *c.FailedOnly) + cl, err = getContainersExec(false, false) } else { - header, content, _ = checkContainers(c.Ignore, *c.FailedOnly) + cl, err = getDockerContainers() + } + if err != nil { + header = fmt.Sprintf("%s: %s\n", utils.Wrap("Docker", padL, padR), utils.Warn("unavailable")) + } else { + header, content, _ = cl.toHeaderContent(c.Ignore, *c.FailedOnly) } // Pad header var p = utils.Pad{Delims: map[string]int{padL: c.Header[0], padR: c.Header[1]}, Content: header} @@ -44,57 +50,21 @@ func GetDocker(ret chan<- string, c *DockerConf) { ret <- header + "\n" + content } -func checkContainers(ignoreList []string, failedOnly bool) (header string, content string, err error) { +func getDockerContainers() (cl containerList, err error) { cli, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion(dockerMinAPI)) if err != nil { - header = fmt.Sprintf("%s: %s\n", utils.Wrap("Docker", padL, padR), utils.Warn("unavailable")) return } allContainers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true}) if err != nil { - header = fmt.Sprintf("%s: %s\n", utils.Wrap("Docker", padL, padR), utils.Warn("unavailable")) return } - // Make set of ignored containers - var ignoreSet utils.StringSet - ignoreSet = ignoreSet.FromList(ignoreList) - // Process output - var goodCont = make(map[string]string) - var failedCont = make(map[string]string) - var sortedNames []string for _, container := range allContainers { - var cleanName = strings.TrimPrefix(container.Names[0], "/") - if ignoreSet.Contains(cleanName) { - continue - } - if container.State != "running" { - failedCont[cleanName] = container.State - } else { - goodCont[cleanName] = container.State - } - sortedNames = append(sortedNames, cleanName) - } - sort.Strings(sortedNames) - - // Decide what header should be - if len(goodCont) == 0 { - header = fmt.Sprintf("%s: %s\n", utils.Wrap("Docker", padL, padR), utils.Err("critical")) - } else if len(failedCont) == 0 { - header = fmt.Sprintf("%s: %s\n", utils.Wrap("Docker", padL, padR), utils.Good("OK")) - if failedOnly { - return - } - } else if len(failedCont) < len(allContainers) { - header = fmt.Sprintf("%s: %s\n", utils.Wrap("Docker", padL, padR), utils.Warn("warning")) - } - // Only print all containers if requested - for _, c := range sortedNames { - if val, ok := goodCont[c]; ok && !failedOnly { - content += fmt.Sprintf("%s: %s\n", utils.Wrap(c, padL, padR), utils.Good(val)) - } else if val, ok := failedCont[c]; ok { - content += fmt.Sprintf("%s: %s\n", utils.Wrap(c, padL, padR), utils.Err(val)) - } + cl.Containers = append(cl.Containers, containerStatus{ + Name: strings.TrimPrefix(container.Names[0], "/"), + Status: container.State, + }) } return } diff --git a/datasources/docker_exec.go b/datasources/docker_exec.go deleted file mode 100644 index 5d71464..0000000 --- a/datasources/docker_exec.go +++ /dev/null @@ -1,68 +0,0 @@ -package datasources - -import ( - "bytes" - "fmt" - "os/exec" - "sort" - "strings" - - "github.com/cosandr/go-motd/utils" -) - -// checkContainersExec returns container status using os/exec, ~5x slower than API -func checkContainersExec(ignoreList []string, failedOnly bool) (header string, content string, err error) { - var stdout bytes.Buffer - cmd := exec.Command("docker", "ps", "--format", `"{{.Names}} {{.Status}}"`, "-a") - cmd.Stdout = &stdout - err = cmd.Run() - if err != nil { - header = fmt.Sprintf("%s: %s\n", utils.Wrap("Docker", padL, padR), utils.Warn("unavailable")) - return - } - // Make set of ignored containers - var ignoreSet utils.StringSet - ignoreSet = ignoreSet.FromList(ignoreList) - // Process output - var goodCont = make(map[string]string) - var failedCont = make(map[string]string) - var sortedNames []string - for _, c := range strings.Split(stdout.String(), "\n") { - var tmp = strings.Split(c, " ") - if len(tmp) < 2 { - continue - } - var cleanName = strings.TrimPrefix(tmp[0], `"`) - if ignoreSet.Contains(cleanName) { - continue - } - if tmp[1] == "Up" { - goodCont[cleanName] = tmp[1] - } else { - failedCont[cleanName] = tmp[1] - } - sortedNames = append(sortedNames, cleanName) - } - sort.Strings(sortedNames) - - // Decide what header should be - if len(goodCont) == 0 { - header = fmt.Sprintf("%s: %s\n", utils.Wrap("Docker", padL, padR), utils.Err("critical")) - } else if len(failedCont) == 0 { - header = fmt.Sprintf("%s: %s\n", utils.Wrap("Docker", padL, padR), utils.Good("OK")) - if failedOnly { - return - } - } else if len(failedCont) < len(sortedNames) { - header = fmt.Sprintf("%s: %s\n", utils.Wrap("Docker", padL, padR), utils.Warn("warning")) - } - // Only print all containers if requested - for _, c := range sortedNames { - if val, ok := goodCont[c]; ok && !failedOnly { - content += fmt.Sprintf("%s: %s\n", utils.Wrap(c, padL, padR), utils.Good(val)) - } else if val, ok := failedCont[c]; ok { - content += fmt.Sprintf("%s: %s\n", utils.Wrap(c, padL, padR), utils.Err(val)) - } - } - return -} diff --git a/datasources/podman.go b/datasources/podman.go new file mode 100644 index 0000000..c679c34 --- /dev/null +++ b/datasources/podman.go @@ -0,0 +1,64 @@ +package datasources + +import ( + "fmt" + + "github.com/cosandr/go-motd/utils" +) + +// PodmanConf extends CommonConf with a list of containers to ignore +type PodmanConf struct { + CommonConf `yaml:",inline"` + Sudo bool `yaml:"sudo"` + IncludeSudo bool `yaml:"includeSudo"` + Ignore []string `yaml:"ignore"` +} + +// GetPodman podman container status by parsing cli output +func GetPodman(ret chan<- string, c *PodmanConf) { + var header string + var content string + if !c.IncludeSudo { + cl, err := getContainersExec(true, c.Sudo) + if err != nil { + header = fmt.Sprintf("%s: %s\n", utils.Wrap("Podman", padL, padR), utils.Warn("unavailable")) + } else { + header, content, _ = cl.toHeaderContent(c.Ignore, *c.FailedOnly) + } + } else { + clUser, errUser := getContainersExec(true, false) + clRoot, errRoot := getContainersExec(true, true) + // Combine lists for now + cl := containerList{Runtime: "Podman", Root: true} + // Add # in front of root containers + for _, c := range clRoot.Containers { + cl.Containers = append(cl.Containers, containerStatus{ + Name: "# " + c.Name, + Status: c.Status, + }) + } + // Add $ in front of user containers + for _, c := range clUser.Containers { + cl.Containers = append(cl.Containers, containerStatus{ + Name: "$ " + c.Name, + Status: c.Status, + }) + } + if len(cl.Containers) == 0 && (errUser != nil || errRoot != nil) { + header = fmt.Sprintf("%s: %s\n", utils.Wrap("Podman", padL, padR), utils.Warn("unavailable")) + } else { + header, content, _ = cl.toHeaderContent(c.Ignore, *c.FailedOnly) + } + } + // Pad header + var p = utils.Pad{Delims: map[string]int{padL: c.Header[0], padR: c.Header[1]}, Content: header} + header = p.Do() + if len(content) == 0 { + ret <- header + return + } + // Pad container list + p = utils.Pad{Delims: map[string]int{padL: c.Content[0], padR: c.Content[1]}, Content: content} + content = p.Do() + ret <- header + "\n" + content +} diff --git a/go.mod b/go.mod index aded29e..32fe6ce 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect - github.com/Microsoft/go-winio v0.4.14 // indirect + github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 // indirect github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/containerd/containerd v1.3.4 // indirect github.com/coreos/go-systemd/v22 v22.0.0 @@ -15,18 +15,25 @@ require ( github.com/docker/go-units v0.4.0 // indirect github.com/go-ole/go-ole v1.2.4 // indirect github.com/gogo/protobuf v1.3.1 // indirect + github.com/golang/protobuf v1.4.2 // indirect github.com/gorilla/mux v1.7.4 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/olekukonko/tablewriter v0.0.4 github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/shirou/gopsutil v2.20.4+incompatible + github.com/sirupsen/logrus v1.6.0 // indirect github.com/stretchr/testify v1.5.1 // indirect golang.org/x/net v0.0.0-20200513185701-a91f0712d120 // indirect - golang.org/x/sys v0.0.0-20200513112337-417ce2331b5c // indirect + golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 // indirect + golang.org/x/text v0.3.2 // indirect golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect + google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587 // indirect google.golang.org/grpc v1.29.1 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v2 v2.3.0 gotest.tools v2.2.0+incompatible // indirect ) diff --git a/go.sum b/go.sum index 4b43fbb..9212fad 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,10 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -28,6 +29,7 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= @@ -42,34 +44,58 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 h1:yN8BPXVwMBAm3Cuvh1L5XE8XpvYRMdsVLd82ILprhUU= +github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/shirou/gopsutil v2.20.4+incompatible h1:cMT4rxS55zx9NVUnCkrmXCsEB/RNfG9SwHY9evtX8Ng= github.com/shirou/gopsutil v2.20.4+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -93,31 +119,50 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200513112337-417ce2331b5c h1:kISX68E8gSkNYAFRFiDU8rl5RIn1sJYKYb/r2vMLDrU= -golang.org/x/sys v0.0.0-20200513112337-417ce2331b5c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587 h1:1Ym+vvUpq1ZHvxzn34gENJX8U4aKO+vhy2P/2+Xl6qQ= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/motd.go b/motd.go index bea2b04..18295be 100644 --- a/motd.go +++ b/motd.go @@ -15,7 +15,7 @@ import ( var ( defaultCfgPath = "./config.yaml" - defaultOrder = []string{"sysinfo", "updates", "systemd", "docker", "disk", "cpu", "zfs", "btrfs"} + defaultOrder = []string{"sysinfo", "updates", "systemd", "docker", "podman", "disk", "cpu", "zfs", "btrfs"} ) // Conf is the global config struct, defines YAML file @@ -27,6 +27,7 @@ type Conf struct { CPU datasources.CPUTempConf Disk datasources.DiskConf Docker datasources.DockerConf + Podman datasources.PodmanConf SysInfo datasources.CommonConf Systemd datasources.SystemdConf Updates datasources.UpdatesConf @@ -40,6 +41,7 @@ func (c *Conf) Init() { c.CPU.CommonConf.Init() c.Disk.CommonConf.Init() c.Docker.CommonConf.Init() + c.Podman.CommonConf.Init() c.SysInfo.Init() c.Systemd.CommonConf.Init() c.Updates.CommonConf.Init() @@ -83,6 +85,15 @@ func getDocker(ret chan<- string, c Conf, endTime chan<- time.Time) { endTime <- time.Now() } +func getPodman(ret chan<- string, c Conf, endTime chan<- time.Time) { + // Check for failedOnly override + if c.Podman.FailedOnly == nil { + c.Podman.FailedOnly = &c.FailedOnly + } + datasources.GetPodman(ret, &c.Podman) + endTime <- time.Now() +} + func getSysInfo(ret chan<- string, c Conf, endTime chan<- time.Time) { datasources.GetSysInfo(ret, &c.SysInfo) endTime <- time.Now() @@ -276,6 +287,8 @@ func main() { switch k { case "docker": go getDocker(outCh[k], c, endTimes[k]) + case "podman": + go getPodman(outCh[k], c, endTimes[k]) case "systemd": go getSystemD(outCh[k], c, endTimes[k]) case "sysinfo":