mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
implemented docker module
This commit is contained in:
163
modules/docker/client.go
Normal file
163
modules/docker/client.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (widget *Widget) getSystemInfo() string {
|
||||
info, err := widget.cli.Info(context.Background())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get docker system info").Error()
|
||||
}
|
||||
|
||||
diskUsage, err := widget.cli.DiskUsage(context.Background())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get disk usage").Error()
|
||||
}
|
||||
|
||||
var duContainer int64
|
||||
for _, c := range diskUsage.Containers {
|
||||
duContainer += c.SizeRw
|
||||
}
|
||||
var duImg int64
|
||||
for _, im := range diskUsage.Images {
|
||||
duImg += im.Size
|
||||
}
|
||||
var duVol int64
|
||||
for _, v := range diskUsage.Volumes {
|
||||
duVol += v.UsageData.Size
|
||||
}
|
||||
|
||||
sysInfo := []struct {
|
||||
name string
|
||||
value string
|
||||
}{
|
||||
{
|
||||
name: "name:",
|
||||
value: fmt.Sprintf("[%s]%s", widget.settings.common.Foreground, info.Name),
|
||||
}, {
|
||||
name: "version:",
|
||||
value: fmt.Sprintf("[%s]%s", widget.settings.common.Foreground, info.ServerVersion),
|
||||
}, {
|
||||
name: "root:",
|
||||
value: fmt.Sprintf("[%s]%s", widget.settings.common.Foreground, info.DockerRootDir),
|
||||
},
|
||||
{
|
||||
name: "containers:",
|
||||
value: fmt.Sprintf("[lime]%d[white]/[yellow]%d[white]/[red]%d",
|
||||
info.ContainersRunning,
|
||||
info.ContainersPaused, info.ContainersStopped),
|
||||
},
|
||||
{
|
||||
name: "images:",
|
||||
value: fmt.Sprintf("[%s]%d", widget.settings.common.Foreground, info.Images),
|
||||
},
|
||||
{
|
||||
name: "volumes:",
|
||||
value: fmt.Sprintf("[%s]%v", widget.settings.common.Foreground, len(diskUsage.Volumes)),
|
||||
},
|
||||
{
|
||||
name: "memory limit:",
|
||||
value: fmt.Sprintf("[%s]%s", widget.settings.common.Foreground, humanize.Bytes(uint64(info.MemTotal))),
|
||||
},
|
||||
{
|
||||
name: "disk usage:",
|
||||
value: fmt.Sprintf(`
|
||||
[%s]* containers: [%s]%s
|
||||
[%s]* images: [%s]%s
|
||||
[%s]* volumes: [%s]%s
|
||||
[%s]* [::b]total: [%s]%s[::-]
|
||||
`,
|
||||
widget.settings.labelColor,
|
||||
widget.settings.common.Foreground,
|
||||
humanize.Bytes(uint64(duContainer)),
|
||||
|
||||
widget.settings.labelColor,
|
||||
widget.settings.common.Foreground,
|
||||
humanize.Bytes(uint64(duImg)),
|
||||
|
||||
widget.settings.labelColor,
|
||||
widget.settings.common.Foreground,
|
||||
humanize.Bytes(uint64(duVol)),
|
||||
|
||||
widget.settings.labelColor,
|
||||
widget.settings.common.Foreground,
|
||||
humanize.Bytes(uint64(duContainer+duImg+duVol))),
|
||||
},
|
||||
}
|
||||
|
||||
padSlice(true, sysInfo, func(i int) string {
|
||||
return sysInfo[i].name
|
||||
}, func(i int, newVal string) {
|
||||
sysInfo[i].name = newVal
|
||||
})
|
||||
|
||||
result := ""
|
||||
for _, info := range sysInfo {
|
||||
result += fmt.Sprintf("[%s]%s %s\n", widget.settings.labelColor, info.name, info.value)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (widget *Widget) getContainerStates() string {
|
||||
cntrs, err := widget.cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get container list").Error()
|
||||
}
|
||||
|
||||
if len(cntrs) == 0 {
|
||||
return "no containers"
|
||||
}
|
||||
|
||||
colorMap := map[string]string{
|
||||
"created": "green",
|
||||
"running": "lime",
|
||||
"paused": "yellow",
|
||||
"restarting": "yellow",
|
||||
"removing": "yellow",
|
||||
"exited": "red",
|
||||
"dead": "red",
|
||||
}
|
||||
|
||||
containers := []struct {
|
||||
name string
|
||||
state string
|
||||
}{}
|
||||
for _, c := range cntrs {
|
||||
container := struct {
|
||||
name string
|
||||
state string
|
||||
}{
|
||||
name: c.Names[0],
|
||||
state: c.State,
|
||||
}
|
||||
|
||||
container.name = strings.Replace(container.name, "/", "", -1)
|
||||
containers = append(containers, container)
|
||||
}
|
||||
|
||||
sort.Slice(containers, func(i, j int) bool {
|
||||
return containers[i].name < containers[j].name
|
||||
})
|
||||
|
||||
padSlice(false, containers, func(i int) string {
|
||||
return containers[i].name
|
||||
}, func(i int, val string) {
|
||||
containers[i].name = val
|
||||
})
|
||||
|
||||
result := ""
|
||||
for _, c := range containers {
|
||||
result += fmt.Sprintf("[white]%s [%s]%s\n", c.name, colorMap[c.state], c.state)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
37
modules/docker/example-conf.yml
Normal file
37
modules/docker/example-conf.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
wtf:
|
||||
colors:
|
||||
# background: black
|
||||
# foreground: blue
|
||||
border:
|
||||
focusable: darkslateblue
|
||||
focused: orange
|
||||
normal: gray
|
||||
checked: yellow
|
||||
highlight:
|
||||
fore: black
|
||||
back: gray
|
||||
rows:
|
||||
even: yellow
|
||||
odd: white
|
||||
grid:
|
||||
# How _wide_ the columns are, in terminal characters. In this case we have
|
||||
# four columns, each of which are 35 characters wide.
|
||||
# columns: [50, ]
|
||||
# How _high_ the rows are, in terminal lines. In this case we have four rows
|
||||
# that support ten line of text and one of four.
|
||||
# rows: [50]
|
||||
refreshInterval: 1
|
||||
openFileUtil: "open"
|
||||
mods:
|
||||
docker:
|
||||
type: docker
|
||||
title: "💻"
|
||||
enabled: true
|
||||
position:
|
||||
top: 0
|
||||
left: 0
|
||||
height: 3
|
||||
width: 3
|
||||
refreshInterval: 1
|
||||
labelColor: lightblue
|
||||
|
||||
29
modules/docker/utils.go
Normal file
29
modules/docker/utils.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func padSlice(padLeft bool, slice interface{}, getter func(i int) string, setter func(i int, newVal string)) {
|
||||
rv := reflect.ValueOf(slice)
|
||||
length := rv.Len()
|
||||
maxLen := 0
|
||||
for i := 0; i < length; i++ {
|
||||
val := getter(i)
|
||||
maxLen = int(math.Max(float64(len(val)), float64(maxLen)))
|
||||
}
|
||||
|
||||
sign := "-"
|
||||
if padLeft {
|
||||
sign = ""
|
||||
}
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
val := getter(i)
|
||||
val = fmt.Sprintf("%"+sign+strconv.Itoa(maxLen)+"s", val)
|
||||
setter(i, val)
|
||||
}
|
||||
}
|
||||
87
modules/docker/widget.go
Normal file
87
modules/docker/widget.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
|
||||
// "github.com/docker/docker/client"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/olebedev/config"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rivo/tview"
|
||||
"github.com/wtfutil/wtf/cfg"
|
||||
"github.com/wtfutil/wtf/view"
|
||||
)
|
||||
|
||||
const defaultTitle = "docker"
|
||||
|
||||
type Settings struct {
|
||||
common *cfg.Common
|
||||
labelColor string
|
||||
}
|
||||
|
||||
func NewSettingsFromYAML(name string, ymlConfig *config.Config, globalConfig *config.Config) *Settings {
|
||||
|
||||
settings := Settings{
|
||||
common: cfg.NewCommonSettingsFromModule(name, defaultTitle, ymlConfig, globalConfig),
|
||||
labelColor: ymlConfig.UString("labelColor", "labelColor"),
|
||||
}
|
||||
|
||||
return &settings
|
||||
}
|
||||
|
||||
type Widget struct {
|
||||
view.TextWidget
|
||||
cli *client.Client
|
||||
settings *Settings
|
||||
displayBuffer string
|
||||
}
|
||||
|
||||
func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
|
||||
widget := Widget{
|
||||
TextWidget: view.NewTextWidget(app, settings.common, false),
|
||||
settings: settings,
|
||||
}
|
||||
|
||||
widget.View.SetScrollable(true)
|
||||
// widget.View.SetRegions(true)
|
||||
|
||||
// os.Setenv("DOCKER_HOST", "unix:///var/run/docker.sock")
|
||||
// os.Setenv("DOCKER_API_VERSION", "1.23")
|
||||
|
||||
cli, err := client.NewEnvClient()
|
||||
if err != nil {
|
||||
widget.displayBuffer = errors.Wrap(err, "could not create client").Error()
|
||||
} else {
|
||||
widget.cli = cli
|
||||
}
|
||||
|
||||
widget.refreshDisplayBuffer()
|
||||
|
||||
return &widget
|
||||
}
|
||||
|
||||
func (widget *Widget) Refresh() {
|
||||
widget.refreshDisplayBuffer()
|
||||
widget.Redraw(widget.display)
|
||||
}
|
||||
|
||||
func (widget *Widget) display() (string, string, bool) {
|
||||
return widget.CommonSettings().Title, widget.displayBuffer, true
|
||||
}
|
||||
|
||||
func (widget *Widget) refreshDisplayBuffer() {
|
||||
|
||||
if widget.cli == nil {
|
||||
return
|
||||
}
|
||||
|
||||
widget.displayBuffer = ""
|
||||
|
||||
widget.displayBuffer += "[" + widget.settings.labelColor + "::bul]system\n"
|
||||
widget.displayBuffer += widget.getSystemInfo()
|
||||
|
||||
widget.displayBuffer += "\n"
|
||||
|
||||
widget.displayBuffer += "[" + widget.settings.labelColor + "::bul]containers\n"
|
||||
widget.displayBuffer += widget.getContainerStates()
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user