mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
1f61084d83
Some structures use int for sizes and UNIX timestamps. On some platforms, int is 32 bits, so this can lead to the year 2038 issues and overflows when dealing with large containers or layers. Consistently use int64 to store sizes and UNIX timestamps in api/types/types.go. Update related to code accordingly (i.e. strconv.FormatInt instead of strconv.Itoa). Use int64 in progressreader package to avoid integer overflow when dealing with large quantities. Update related code accordingly. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
205 lines
4.4 KiB
Go
205 lines
4.4 KiB
Go
package daemon
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/pkg/graphdb"
|
|
"github.com/docker/docker/pkg/nat"
|
|
"github.com/docker/docker/pkg/parsers/filters"
|
|
)
|
|
|
|
// List returns an array of all containers registered in the daemon.
|
|
func (daemon *Daemon) List() []*Container {
|
|
return daemon.containers.List()
|
|
}
|
|
|
|
type ContainersConfig struct {
|
|
All bool
|
|
Since string
|
|
Before string
|
|
Limit int
|
|
Size bool
|
|
Filters string
|
|
}
|
|
|
|
func (daemon *Daemon) Containers(config *ContainersConfig) ([]*types.Container, error) {
|
|
var (
|
|
foundBefore bool
|
|
displayed int
|
|
all = config.All
|
|
n = config.Limit
|
|
psFilters filters.Args
|
|
filtExited []int
|
|
)
|
|
containers := []*types.Container{}
|
|
|
|
psFilters, err := filters.FromParam(config.Filters)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if i, ok := psFilters["exited"]; ok {
|
|
for _, value := range i {
|
|
code, err := strconv.Atoi(value)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
filtExited = append(filtExited, code)
|
|
}
|
|
}
|
|
|
|
if i, ok := psFilters["status"]; ok {
|
|
for _, value := range i {
|
|
if !isValidStateString(value) {
|
|
return nil, errors.New("Unrecognised filter value for status")
|
|
}
|
|
if value == "exited" || value == "created" {
|
|
all = true
|
|
}
|
|
}
|
|
}
|
|
names := map[string][]string{}
|
|
daemon.ContainerGraph().Walk("/", func(p string, e *graphdb.Entity) error {
|
|
names[e.ID()] = append(names[e.ID()], p)
|
|
return nil
|
|
}, 1)
|
|
|
|
var beforeCont, sinceCont *Container
|
|
if config.Before != "" {
|
|
beforeCont, err = daemon.Get(config.Before)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if config.Since != "" {
|
|
sinceCont, err = daemon.Get(config.Since)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
errLast := errors.New("last container")
|
|
writeCont := func(container *Container) error {
|
|
container.Lock()
|
|
defer container.Unlock()
|
|
if !container.Running && !all && n <= 0 && config.Since == "" && config.Before == "" {
|
|
return nil
|
|
}
|
|
if !psFilters.Match("name", container.Name) {
|
|
return nil
|
|
}
|
|
|
|
if !psFilters.Match("id", container.ID) {
|
|
return nil
|
|
}
|
|
|
|
if !psFilters.MatchKVList("label", container.Config.Labels) {
|
|
return nil
|
|
}
|
|
|
|
if config.Before != "" && !foundBefore {
|
|
if container.ID == beforeCont.ID {
|
|
foundBefore = true
|
|
}
|
|
return nil
|
|
}
|
|
if n > 0 && displayed == n {
|
|
return errLast
|
|
}
|
|
if config.Since != "" {
|
|
if container.ID == sinceCont.ID {
|
|
return errLast
|
|
}
|
|
}
|
|
if len(filtExited) > 0 {
|
|
shouldSkip := true
|
|
for _, code := range filtExited {
|
|
if code == container.ExitCode && !container.Running {
|
|
shouldSkip = false
|
|
break
|
|
}
|
|
}
|
|
if shouldSkip {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
if !psFilters.Match("status", container.State.StateString()) {
|
|
return nil
|
|
}
|
|
displayed++
|
|
newC := &types.Container{
|
|
ID: container.ID,
|
|
Names: names[container.ID],
|
|
}
|
|
newC.Image = container.Config.Image
|
|
if len(container.Args) > 0 {
|
|
args := []string{}
|
|
for _, arg := range container.Args {
|
|
if strings.Contains(arg, " ") {
|
|
args = append(args, fmt.Sprintf("'%s'", arg))
|
|
} else {
|
|
args = append(args, arg)
|
|
}
|
|
}
|
|
argsAsString := strings.Join(args, " ")
|
|
|
|
newC.Command = fmt.Sprintf("%s %s", container.Path, argsAsString)
|
|
} else {
|
|
newC.Command = fmt.Sprintf("%s", container.Path)
|
|
}
|
|
newC.Created = container.Created.Unix()
|
|
newC.Status = container.State.String()
|
|
newC.HostConfig.NetworkMode = string(container.hostConfig.NetworkMode)
|
|
|
|
newC.Ports = []types.Port{}
|
|
for port, bindings := range container.NetworkSettings.Ports {
|
|
p, err := nat.ParsePort(port.Port())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(bindings) == 0 {
|
|
newC.Ports = append(newC.Ports, types.Port{
|
|
PrivatePort: p,
|
|
Type: port.Proto(),
|
|
})
|
|
continue
|
|
}
|
|
for _, binding := range bindings {
|
|
h, err := nat.ParsePort(binding.HostPort)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
newC.Ports = append(newC.Ports, types.Port{
|
|
PrivatePort: p,
|
|
PublicPort: h,
|
|
Type: port.Proto(),
|
|
IP: binding.HostIP,
|
|
})
|
|
}
|
|
}
|
|
|
|
if config.Size {
|
|
sizeRw, sizeRootFs := container.GetSize()
|
|
newC.SizeRw = sizeRw
|
|
newC.SizeRootFs = sizeRootFs
|
|
}
|
|
newC.Labels = container.Config.Labels
|
|
containers = append(containers, newC)
|
|
return nil
|
|
}
|
|
|
|
for _, container := range daemon.List() {
|
|
if err := writeCont(container); err != nil {
|
|
if err != errLast {
|
|
return nil, err
|
|
}
|
|
break
|
|
}
|
|
}
|
|
return containers, nil
|
|
}
|