mirror of
https://github.com/docker/compose.git
synced 2025-04-08 17:05:13 +02:00
add support for attributes exposed by docker ps
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
1054792b47
commit
41682acc77
@ -17,6 +17,9 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
@ -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
|
||||
}
|
||||
@ -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 {
|
||||
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
})
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user