allow showing TOP of a container/service

This commit is contained in:
Jesse Duffield 2019-06-15 14:31:49 +10:00
parent 2474c0b34e
commit 344c72f91a
7 changed files with 73 additions and 4 deletions

View file

@ -418,3 +418,13 @@ func (c *Container) TTYLogsCommand() *exec.Cmd {
func (c *Container) Inspect() (types.ContainerJSON, error) {
return c.Client.ContainerInspect(context.Background(), c.ID)
}
// RenderTop returns details about the container
func (c *Container) RenderTop() (string, error) {
result, err := c.Client.ContainerTop(context.Background(), c.ID, []string{})
if err != nil {
return "", err
}
return utils.RenderTable(append([][]string{result.Titles}, result.Processes...))
}

View file

@ -78,3 +78,14 @@ func (s *Service) ViewLogs() (*exec.Cmd, error) {
return cmd, nil
}
// RenderTop renders the process list of the service
func (s *Service) RenderTop() (string, error) {
templateString := s.OSCommand.Config.UserConfig.CommandTemplates.ServiceTop
command := utils.ApplyTemplate(
templateString,
s.DockerCommand.NewCommandObject(CommandObject{Service: s}),
)
return s.OSCommand.RunCommandWithOutput(command)
}

View file

@ -118,6 +118,7 @@ type CommandTemplatesConfig struct {
ViewAllLogs string `yaml:"viewAlLogs,omitempty"`
DockerComposeConfig string `yaml:"dockerComposeConfig,omitempty"`
CheckDockerComposeConfig string `yaml:"checkDockerComposeConfig,omitempty"`
ServiceTop string `yaml:"serviceTop,omitempty"`
}
type OSConfig struct {
@ -188,6 +189,7 @@ func GetDefaultConfig() UserConfig {
ContainerLogs: "docker logs --timestamps --follow --tail=100 {{ .Container.ID }}",
ViewContainerLogs: "docker logs --timestamps --follow --tail=100 {{ .Container.ID }}",
ContainerTTYLogs: "docker logs --follow --tail=100 {{ .Container.ID }}",
ServiceTop: "{{ .DockerCompose }} top {{ .Service.Name }}",
},
CustomCommands: CustomCommands{
Containers: []CustomCommand{

View file

@ -18,11 +18,11 @@ import (
// list panel functions
func (gui *Gui) getContainerContexts() []string {
return []string{"logs", "stats", "config"}
return []string{"logs", "stats", "config", "top"}
}
func (gui *Gui) getContainerContextTitles() []string {
return []string{gui.Tr.LogsTitle, gui.Tr.StatsTitle, gui.Tr.ConfigTitle}
return []string{gui.Tr.LogsTitle, gui.Tr.StatsTitle, gui.Tr.ConfigTitle, gui.Tr.TopTitle}
}
func (gui *Gui) getSelectedContainer() (*commands.Container, error) {
@ -101,6 +101,10 @@ func (gui *Gui) handleContainerSelect(g *gocui.Gui, v *gocui.View) error {
if err := gui.renderContainerStats(container); err != nil {
return err
}
case "top":
if err := gui.renderContainerTop(container); err != nil {
return err
}
default:
return errors.New("Unknown context for containers panel")
}
@ -142,6 +146,21 @@ func (gui *Gui) renderContainerStats(container *commands.Container) error {
})
}
func (gui *Gui) renderContainerTop(container *commands.Container) error {
mainView := gui.getMainView()
mainView.Autoscroll = false
mainView.Wrap = false
return gui.T.NewTickerTask(time.Second, func(stop chan struct{}) { gui.clearMainView() }, func(stop, notifyStopped chan struct{}) {
contents, err := container.RenderTop()
if err != nil {
gui.reRenderString(gui.g, "main", err.Error())
}
gui.reRenderString(gui.g, "main", contents)
})
}
func (gui *Gui) renderContainerLogs(container *commands.Container) error {
mainView := gui.getMainView()
mainView.Autoscroll = true

View file

@ -2,6 +2,7 @@ package gui
import (
"fmt"
"time"
"github.com/fatih/color"
"github.com/go-errors/errors"
@ -13,11 +14,11 @@ import (
// list panel functions
func (gui *Gui) getServiceContexts() []string {
return []string{"logs", "stats", "container-config"}
return []string{"logs", "stats", "container-config", "top"}
}
func (gui *Gui) getServiceContextTitles() []string {
return []string{gui.Tr.LogsTitle, gui.Tr.StatsTitle, gui.Tr.ContainerConfigTitle}
return []string{gui.Tr.LogsTitle, gui.Tr.StatsTitle, gui.Tr.ContainerConfigTitle, gui.Tr.TopTitle}
}
func (gui *Gui) getSelectedService() (*commands.Service, error) {
@ -95,6 +96,10 @@ func (gui *Gui) handleServiceSelect(g *gocui.Gui, v *gocui.View) error {
if err := gui.renderContainerConfig(service.Container); err != nil {
return err
}
case "top":
if err := gui.renderServiceTop(service); err != nil {
return err
}
default:
return errors.New("Unknown context for services panel")
}
@ -110,6 +115,21 @@ func (gui *Gui) renderServiceStats(service *commands.Service) error {
return gui.renderContainerStats(service.Container)
}
func (gui *Gui) renderServiceTop(service *commands.Service) error {
mainView := gui.getMainView()
mainView.Autoscroll = false
mainView.Wrap = false
return gui.T.NewTickerTask(time.Second, func(stop chan struct{}) { gui.clearMainView() }, func(stop, notifyStopped chan struct{}) {
contents, err := service.RenderTop()
if err != nil {
gui.reRenderString(gui.g, "main", err.Error())
}
gui.reRenderString(gui.g, "main", contents)
})
}
func (gui *Gui) renderServiceLogs(service *commands.Service) error {
service, err := gui.getSelectedService()
if err != nil {

View file

@ -44,6 +44,7 @@ type TranslationSet struct {
ServicesTitle string
ContainersTitle string
StandaloneContainersTitle string
TopTitle string
ImagesTitle string
VolumesTitle string
NoContainers string
@ -128,6 +129,7 @@ func englishSet() TranslationSet {
ErrorTitle: "Error",
LogsTitle: "Logs",
ConfigTitle: "Config",
TopTitle: "Top",
StatsTitle: "Stats",
CreditsTitle: "About",
ContainerConfigTitle: "Container Config",

View file

@ -157,6 +157,11 @@ func renderDisplayableList(items []Displayable, config RenderListConfig) (string
stringArrays = append([][]string{config.Header}, stringArrays...)
}
return RenderTable(stringArrays)
}
// RenderTable takes an array of string arrays and returns a table containing the values
func RenderTable(stringArrays [][]string) (string, error) {
if !displayArraysAligned(stringArrays) {
return "", errors.New("Each item must return the same number of strings to display")
}