mirror of
https://gitea.elkins.co/Networking/ccl.git
synced 2025-03-09 20:51:39 -05:00
ls enhancement: show running stats
Mainly for zabbix, but why not. Format of both json and text output of ls has changed.
This commit is contained in:
parent
13e35e9c4d
commit
139ea8707c
56
cmd/ls.go
56
cmd/ls.go
@ -48,6 +48,20 @@ type lsContainerObj struct {
|
|||||||
Running bool `json:"running"`
|
Running bool `json:"running"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type lsContainerStatsObj struct {
|
||||||
|
CPU float64 `json:"cpu_usage_pct"`
|
||||||
|
CPUNano uint64 `json:"cpu_nano"`
|
||||||
|
MemUsage uint64 `json:"mem_usage_bytes"`
|
||||||
|
MemLimit uint64 `json:"mem_limit_bytes"`
|
||||||
|
MemPerc float64 `json:"mem_usage_pct"`
|
||||||
|
NetInput uint64 `json:"net_input_bytes"`
|
||||||
|
NetOutput uint64 `json:"net_output_bytes"`
|
||||||
|
BlockInput uint64 `json:"block_input_bytes"`
|
||||||
|
BlockOutput uint64 `json:"block_output_bytes"`
|
||||||
|
UpTime uint64 `json:"uptime_sec"`
|
||||||
|
lsContainerObj
|
||||||
|
}
|
||||||
|
|
||||||
// lsCmd represents the ls command
|
// lsCmd represents the ls command
|
||||||
var lsCmd = &cobra.Command{
|
var lsCmd = &cobra.Command{
|
||||||
Use: "ls",
|
Use: "ls",
|
||||||
@ -90,20 +104,41 @@ ccl ls squid`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if lsJsonFormat {
|
if lsJsonFormat {
|
||||||
out := make([]lsContainerObj, 0)
|
out := make([]interface{}, 0)
|
||||||
for _, c := range conts {
|
for _, c := range conts {
|
||||||
run, cre := false, false
|
run, cre := false, false
|
||||||
if conn != nil {
|
if conn != nil {
|
||||||
run, cre = c.IsRunning(), c.IsCreated()
|
run, cre = c.IsRunning(), c.IsCreated()
|
||||||
}
|
}
|
||||||
out = append(out, lsContainerObj{
|
baseObj := lsContainerObj{
|
||||||
Category: c.Category,
|
Category: c.Category,
|
||||||
StartGroup: c.StartGroup,
|
StartGroup: c.StartGroup,
|
||||||
Name: c.Name,
|
Name: c.Name,
|
||||||
Image: c.Image,
|
Image: c.Image,
|
||||||
Running: run,
|
Running: run,
|
||||||
Created: cre,
|
Created: cre,
|
||||||
|
}
|
||||||
|
if run {
|
||||||
|
if stats := c.GetStats(); stats != nil {
|
||||||
|
out = append(out, lsContainerStatsObj{
|
||||||
|
CPUNano: stats.CPUNano,
|
||||||
|
CPU: stats.CPU,
|
||||||
|
MemUsage: stats.MemUsage,
|
||||||
|
MemLimit: stats.MemLimit,
|
||||||
|
MemPerc: stats.MemPerc,
|
||||||
|
NetInput: stats.NetInput,
|
||||||
|
NetOutput: stats.NetOutput,
|
||||||
|
BlockInput: stats.BlockInput,
|
||||||
|
BlockOutput: stats.BlockOutput,
|
||||||
|
UpTime: uint64(c.RunningTime().Seconds()),
|
||||||
|
lsContainerObj: baseObj,
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
out = append(out, baseObj)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out = append(out, baseObj)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val, err := json.Marshal(out)
|
val, err := json.Marshal(out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -117,7 +152,8 @@ ccl ls squid`,
|
|||||||
defer tw.Flush()
|
defer tw.Flush()
|
||||||
|
|
||||||
if conn != nil {
|
if conn != nil {
|
||||||
titlemsg := "CATEGORY\tGROUP\tNAME\tIMAGE\tCREATED\tRUNNING"
|
titlemsg := "CATEGORY\tGROUP\tNAME\tIMAGE\tCREATED\t RUNNING\tCPU%\tMEM%"
|
||||||
|
block := "%s\t%5d\t%s\t%s\t%s\t%s\t%.1f\t%.1f\n"
|
||||||
fmt.Fprintf(tw, "%s\n", titlemsg)
|
fmt.Fprintf(tw, "%s\n", titlemsg)
|
||||||
for _, c := range conts {
|
for _, c := range conts {
|
||||||
data := []interface{}{c.Category, c.StartGroup, c.Name, c.Image}
|
data := []interface{}{c.Category, c.StartGroup, c.Name, c.Image}
|
||||||
@ -127,11 +163,21 @@ ccl ls squid`,
|
|||||||
data = append(data, "")
|
data = append(data, "")
|
||||||
}
|
}
|
||||||
if c.IsRunning() {
|
if c.IsRunning() {
|
||||||
data = append(data, " ✓")
|
raw := int64(c.RunningTime().Seconds())
|
||||||
|
seconds := raw % 60
|
||||||
|
minutes := (raw / 60) % 60
|
||||||
|
hours := (raw / 60) / 60
|
||||||
|
disp := fmt.Sprintf("%3d:%02d:%02d", hours, minutes, seconds)
|
||||||
|
data = append(data, disp)
|
||||||
} else {
|
} else {
|
||||||
data = append(data, "")
|
data = append(data, "")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(tw, "%s\t%5d\t%s\t%s\t%s\t%s\n", data...)
|
if stats := c.GetStats(); c.IsRunning() && stats != nil {
|
||||||
|
data = append(data, stats.CPU, stats.MemPerc)
|
||||||
|
} else {
|
||||||
|
data = append(data, 0.0, 0.0)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(tw, block, data...)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
titlemsg := "CATEGORY\tGROUP\tNAME\tIMAGE"
|
titlemsg := "CATEGORY\tGROUP\tNAME\tIMAGE"
|
||||||
|
@ -28,8 +28,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"time"
|
||||||
|
|
||||||
cmd "gitea.elkins.co/Networking/ccl/internal/pkg/command"
|
cmd "gitea.elkins.co/Networking/ccl/internal/pkg/command"
|
||||||
"gitea.elkins.co/Networking/ccl/internal/pkg/network"
|
"gitea.elkins.co/Networking/ccl/internal/pkg/network"
|
||||||
@ -390,6 +392,14 @@ func (c *Container) IsCreated() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Container) RunningTime() time.Duration {
|
||||||
|
cdata := c.getCData()
|
||||||
|
if cdata == nil || cdata.State == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return time.Since(cdata.State.StartedAt)
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateCommands will pull the image (to force updates) and then recreate the
|
// UpdateCommands will pull the image (to force updates) and then recreate the
|
||||||
// container. It will be stopped first.
|
// container. It will be stopped first.
|
||||||
func (c *Container) UpdateCommands() cmd.Set {
|
func (c *Container) UpdateCommands() cmd.Set {
|
||||||
@ -503,6 +513,26 @@ func (c *Container) watchCData() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Container) GetStats() *define.ContainerStats {
|
||||||
|
no := false
|
||||||
|
reportChan, err := containers.Stats(c.conn, []string{c.getCData().ID}, &containers.StatsOptions{Stream: &no})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "containers.stats returned error (%s): %s\n", c.Name, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case report := <-reportChan:
|
||||||
|
if report.Error != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "containers.stats returned error in the channel (%s): %s\n", c.Name, report.Error)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return &report.Stats[0]
|
||||||
|
case <-time.After(250 * time.Millisecond):
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Pid will return the host process id of the main container process (pid
|
// Pid will return the host process id of the main container process (pid
|
||||||
// 1 inside the container)
|
// 1 inside the container)
|
||||||
func (c *Container) Pid() int {
|
func (c *Container) Pid() int {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user