Skip to content

Commit

Permalink
add support for attributes exposed by docker ps
Browse files Browse the repository at this point in the history
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
  • Loading branch information
ndeloof committed Aug 25, 2023
1 parent 1054792 commit 41682ac
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 34 deletions.
87 changes: 86 additions & 1 deletion cmd/formatter/container.go
Expand Up @@ -17,6 +17,9 @@
package formatter

import (
"fmt"
"strconv"
"strings"
"time"

"github.com/docker/cli/cli/command/formatter"
Expand Down Expand Up @@ -141,6 +144,22 @@ func (c *ContainerContext) Name() string {
return c.c.Name
}

// Names returns a comma-separated string of the container's names, with their
// slash (/) prefix stripped. Additional names for the container (related to the
// legacy `--link` feature) are omitted.
func (c *ContainerContext) Names() string {
names := formatter.StripNamePrefix(c.c.Names)
if c.trunc {
for _, name := range names {
if len(strings.Split(name, "/")) == 1 {
names = []string{name}
break
}
}
}
return strings.Join(names, ",")
}

func (c *ContainerContext) Service() string {
return c.c.Service
}
Expand All @@ -150,7 +169,11 @@ func (c *ContainerContext) Image() string {
}

func (c *ContainerContext) Command() string {
return c.c.Command
command := c.c.Command
if c.trunc {
command = formatter.Ellipsis(command, 20)
}
return strconv.Quote(command)
}

func (c *ContainerContext) CreatedAt() string {
Expand Down Expand Up @@ -194,3 +217,65 @@ func (c *ContainerContext) Ports() string {
}
return formatter.DisplayablePorts(ports)
}

// Labels returns a comma-separated string of labels present on the container.
func (c *ContainerContext) Labels() string {
if c.c.Labels == nil {
return ""
}

var joinLabels []string
for k, v := range c.c.Labels {
joinLabels = append(joinLabels, fmt.Sprintf("%s=%s", k, v))
}
return strings.Join(joinLabels, ",")
}

// Label returns the value of the label with the given name or an empty string
// if the given label does not exist.
func (c *ContainerContext) Label(name string) string {
if c.c.Labels == nil {
return ""
}
return c.c.Labels[name]
}

// Mounts returns a comma-separated string of mount names present on the container.
// If the trunc option is set, names can be truncated (ellipsized).
func (c *ContainerContext) Mounts() string {
var mounts []string
for _, name := range c.c.Mounts {
if c.trunc {
name = formatter.Ellipsis(name, 15)
}
mounts = append(mounts, name)
}
return strings.Join(mounts, ",")
}

// LocalVolumes returns the number of volumes using the "local" volume driver.
func (c *ContainerContext) LocalVolumes() string {
return fmt.Sprintf("%d", c.c.LocalVolumes)
}

// Networks returns a comma-separated string of networks that the container is
// attached to.
func (c *ContainerContext) Networks() string {
return strings.Join(c.c.Networks, ",")
}

// Size returns the container's size and virtual size (e.g. "2B (virtual 21.5MB)")
func (c *ContainerContext) Size() string {
if c.FieldsUsed == nil {
c.FieldsUsed = map[string]interface{}{}
}
c.FieldsUsed["Size"] = struct{}{}
srw := units.HumanSizeWithPrecision(float64(c.c.SizeRw), 3)
sv := units.HumanSizeWithPrecision(float64(c.c.SizeRootFs), 3)

sf := srw
if c.c.SizeRootFs > 0 {
sf = fmt.Sprintf("%s (virtual %s)", srw, sv)
}
return sf
}
31 changes: 19 additions & 12 deletions pkg/api/api.go
Expand Up @@ -390,18 +390,25 @@ type PortPublisher struct {

// ContainerSummary hold high-level description of a container
type ContainerSummary struct {
ID string
Name string
Image string
Command string
Project string
Service string
Created int64
State string
Status string
Health string
ExitCode int
Publishers PortPublishers
ID string
Name string
Names []string
Image string
Command string
Project string
Service string
Created int64
State string
Status string
Health string
ExitCode int
Publishers PortPublishers
Labels map[string]string
SizeRw int64 `json:",omitempty"`
SizeRootFs int64 `json:",omitempty"`
Mounts []string
Networks []string
LocalVolumes int
}

// PortPublishers is a slice of PortPublisher
Expand Down
53 changes: 41 additions & 12 deletions pkg/compose/ps.go
Expand Up @@ -78,19 +78,48 @@ func (s *composeService) Ps(ctx context.Context, projectName string, options api
}
}

var (
local int
mounts []string
)
for _, m := range container.Mounts {
name := m.Name
if name == "" {
name = m.Source
}
if m.Driver == "local" {
local++
}
mounts = append(mounts, name)
}

var networks []string
if container.NetworkSettings != nil {
for k := range container.NetworkSettings.Networks {
networks = append(networks, k)
}
}

summary[i] = api.ContainerSummary{
ID: container.ID,
Name: getCanonicalContainerName(container),
Image: container.Image,
Project: container.Labels[api.ProjectLabel],
Service: container.Labels[api.ServiceLabel],
Command: container.Command,
State: container.State,
Status: container.Status,
Created: container.Created,
Health: health,
ExitCode: exitCode,
Publishers: publishers,
ID: container.ID,
Name: getCanonicalContainerName(container),
Names: container.Names,
Image: container.Image,
Project: container.Labels[api.ProjectLabel],
Service: container.Labels[api.ServiceLabel],
Command: container.Command,
State: container.State,
Status: container.Status,
Created: container.Created,
Labels: container.Labels,
SizeRw: container.SizeRw,
SizeRootFs: container.SizeRootFs,
Mounts: mounts,
LocalVolumes: local,
Networks: networks,
Health: health,
ExitCode: exitCode,
Publishers: publishers,
}
return nil
})
Expand Down
33 changes: 27 additions & 6 deletions pkg/compose/ps_test.go
Expand Up @@ -54,13 +54,34 @@ func TestPs(t *testing.T) {
containers, err := tested.Ps(ctx, strings.ToLower(testProject), compose.PsOptions{})

expected := []compose.ContainerSummary{
{ID: "123", Name: "123", Image: "foo", Project: strings.ToLower(testProject), Service: "service1",
State: "running", Health: "healthy", Publishers: nil},
{ID: "456", Name: "456", Image: "foo", Project: strings.ToLower(testProject), Service: "service1",
{ID: "123", Name: "123", Names: []string{"/123"}, Image: "foo", Project: strings.ToLower(testProject), Service: "service1",
State: "running", Health: "healthy", Publishers: nil,
Labels: map[string]string{
compose.ProjectLabel: strings.ToLower(testProject),
compose.ConfigFilesLabel: "/src/pkg/compose/testdata/compose.yaml",
compose.WorkingDirLabel: "/src/pkg/compose/testdata",
compose.ServiceLabel: "service1",
},
},
{ID: "456", Name: "456", Names: []string{"/456"}, Image: "foo", Project: strings.ToLower(testProject), Service: "service1",
State: "running", Health: "",
Publishers: []compose.PortPublisher{{URL: "localhost", TargetPort: 90, PublishedPort: 80}}},
{ID: "789", Name: "789", Image: "foo", Project: strings.ToLower(testProject), Service: "service2",
State: "exited", Health: "", ExitCode: 130, Publishers: nil},
Publishers: []compose.PortPublisher{{URL: "localhost", TargetPort: 90, PublishedPort: 80}},
Labels: map[string]string{
compose.ProjectLabel: strings.ToLower(testProject),
compose.ConfigFilesLabel: "/src/pkg/compose/testdata/compose.yaml",
compose.WorkingDirLabel: "/src/pkg/compose/testdata",
compose.ServiceLabel: "service1",
},
},
{ID: "789", Name: "789", Names: []string{"/789"}, Image: "foo", Project: strings.ToLower(testProject), Service: "service2",
State: "exited", Health: "", ExitCode: 130, Publishers: nil,
Labels: map[string]string{
compose.ProjectLabel: strings.ToLower(testProject),
compose.ConfigFilesLabel: "/src/pkg/compose/testdata/compose.yaml",
compose.WorkingDirLabel: "/src/pkg/compose/testdata",
compose.ServiceLabel: "service2",
},
},
}
assert.NilError(t, err)
assert.DeepEqual(t, containers, expected)
Expand Down
11 changes: 8 additions & 3 deletions pkg/e2e/ps_test.go
Expand Up @@ -62,10 +62,15 @@ func TestPs(t *testing.T) {
t.Run("json", func(t *testing.T) {
res = c.RunDockerComposeCmd(t, "-f", "./fixtures/ps-test/compose.yaml", "--project-name", projectName, "ps",
"--format", "json")
var output []api.ContainerSummary
dec := json.NewDecoder(strings.NewReader(res.Stdout()))
type element struct {
Name string
Publishers api.PortPublishers
}
var output []element
out := res.Stdout()
dec := json.NewDecoder(strings.NewReader(out))
for dec.More() {
var s api.ContainerSummary
var s element
require.NoError(t, dec.Decode(&s), "Failed to unmarshal ps JSON output")
output = append(output, s)
}
Expand Down

0 comments on commit 41682ac

Please sign in to comment.