2014-07-31 21:26:25 +00:00
|
|
|
package daemon
|
2014-07-30 02:04:39 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2014-06-02 19:08:39 +00:00
|
|
|
"strconv"
|
2014-07-30 02:04:39 +00:00
|
|
|
"strings"
|
|
|
|
|
2015-04-04 00:39:06 +00:00
|
|
|
"github.com/docker/docker/api/types"
|
2014-07-30 02:04:39 +00:00
|
|
|
"github.com/docker/docker/pkg/graphdb"
|
2015-06-30 16:41:01 +00:00
|
|
|
"github.com/docker/docker/pkg/nat"
|
2014-06-02 19:08:39 +00:00
|
|
|
"github.com/docker/docker/pkg/parsers/filters"
|
2014-07-30 02:04:39 +00:00
|
|
|
)
|
|
|
|
|
2014-07-31 21:26:25 +00:00
|
|
|
// List returns an array of all containers registered in the daemon.
|
|
|
|
func (daemon *Daemon) List() []*Container {
|
|
|
|
return daemon.containers.List()
|
|
|
|
}
|
|
|
|
|
2015-04-07 19:34:30 +00:00
|
|
|
type ContainersConfig struct {
|
|
|
|
All bool
|
|
|
|
Since string
|
|
|
|
Before string
|
|
|
|
Limit int
|
|
|
|
Size bool
|
|
|
|
Filters string
|
|
|
|
}
|
2015-04-04 00:39:06 +00:00
|
|
|
|
2015-04-07 19:34:30 +00:00
|
|
|
func (daemon *Daemon) Containers(config *ContainersConfig) ([]*types.Container, error) {
|
2014-07-30 02:04:39 +00:00
|
|
|
var (
|
|
|
|
foundBefore bool
|
|
|
|
displayed int
|
2015-04-07 19:34:30 +00:00
|
|
|
all = config.All
|
|
|
|
n = config.Limit
|
2014-06-02 19:08:39 +00:00
|
|
|
psFilters filters.Args
|
2015-03-26 01:40:23 +00:00
|
|
|
filtExited []int
|
2014-07-30 02:04:39 +00:00
|
|
|
)
|
2015-04-07 19:34:30 +00:00
|
|
|
containers := []*types.Container{}
|
2014-07-30 02:04:39 +00:00
|
|
|
|
2015-04-07 19:34:30 +00:00
|
|
|
psFilters, err := filters.FromParam(config.Filters)
|
2014-06-02 19:08:39 +00:00
|
|
|
if err != nil {
|
2015-04-07 19:34:30 +00:00
|
|
|
return nil, err
|
2014-06-02 19:08:39 +00:00
|
|
|
}
|
|
|
|
if i, ok := psFilters["exited"]; ok {
|
|
|
|
for _, value := range i {
|
|
|
|
code, err := strconv.Atoi(value)
|
|
|
|
if err != nil {
|
2015-04-07 19:34:30 +00:00
|
|
|
return nil, err
|
2014-06-02 19:08:39 +00:00
|
|
|
}
|
2015-03-26 01:40:23 +00:00
|
|
|
filtExited = append(filtExited, code)
|
2014-06-02 19:08:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-08 23:14:04 +00:00
|
|
|
if i, ok := psFilters["status"]; ok {
|
|
|
|
for _, value := range i {
|
2015-06-30 21:40:27 +00:00
|
|
|
if !isValidStateString(value) {
|
|
|
|
return nil, errors.New("Unrecognised filter value for status")
|
|
|
|
}
|
2015-05-20 21:51:58 +00:00
|
|
|
if value == "exited" || value == "created" {
|
2015-01-08 23:14:04 +00:00
|
|
|
all = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-30 02:04:39 +00:00
|
|
|
names := map[string][]string{}
|
2014-07-31 21:26:25 +00:00
|
|
|
daemon.ContainerGraph().Walk("/", func(p string, e *graphdb.Entity) error {
|
2014-07-30 02:04:39 +00:00
|
|
|
names[e.ID()] = append(names[e.ID()], p)
|
|
|
|
return nil
|
2015-01-14 23:26:42 +00:00
|
|
|
}, 1)
|
2014-07-30 02:04:39 +00:00
|
|
|
|
2014-07-31 21:26:25 +00:00
|
|
|
var beforeCont, sinceCont *Container
|
2015-04-07 19:34:30 +00:00
|
|
|
if config.Before != "" {
|
|
|
|
beforeCont, err = daemon.Get(config.Before)
|
2014-12-16 23:06:35 +00:00
|
|
|
if err != nil {
|
2015-04-07 19:34:30 +00:00
|
|
|
return nil, err
|
2014-07-30 02:04:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-07 19:34:30 +00:00
|
|
|
if config.Since != "" {
|
|
|
|
sinceCont, err = daemon.Get(config.Since)
|
2014-12-16 23:06:35 +00:00
|
|
|
if err != nil {
|
2015-04-07 19:34:30 +00:00
|
|
|
return nil, err
|
2014-07-30 02:04:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
errLast := errors.New("last container")
|
2014-07-31 21:26:25 +00:00
|
|
|
writeCont := func(container *Container) error {
|
2014-07-30 02:04:39 +00:00
|
|
|
container.Lock()
|
|
|
|
defer container.Unlock()
|
2015-04-07 19:34:30 +00:00
|
|
|
if !container.Running && !all && n <= 0 && config.Since == "" && config.Before == "" {
|
2014-07-30 02:04:39 +00:00
|
|
|
return nil
|
|
|
|
}
|
2014-10-13 06:12:44 +00:00
|
|
|
if !psFilters.Match("name", container.Name) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if !psFilters.Match("id", container.ID) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-01-07 00:04:10 +00:00
|
|
|
if !psFilters.MatchKVList("label", container.Config.Labels) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-04-07 19:34:30 +00:00
|
|
|
if config.Before != "" && !foundBefore {
|
2014-07-30 02:04:39 +00:00
|
|
|
if container.ID == beforeCont.ID {
|
|
|
|
foundBefore = true
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if n > 0 && displayed == n {
|
|
|
|
return errLast
|
|
|
|
}
|
2015-04-07 19:34:30 +00:00
|
|
|
if config.Since != "" {
|
2014-07-30 02:04:39 +00:00
|
|
|
if container.ID == sinceCont.ID {
|
|
|
|
return errLast
|
|
|
|
}
|
|
|
|
}
|
2015-03-26 01:40:23 +00:00
|
|
|
if len(filtExited) > 0 {
|
|
|
|
shouldSkip := true
|
|
|
|
for _, code := range filtExited {
|
2015-01-08 22:51:47 +00:00
|
|
|
if code == container.ExitCode && !container.Running {
|
2015-03-26 01:40:23 +00:00
|
|
|
shouldSkip = false
|
2014-06-02 19:08:39 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2015-03-26 01:40:23 +00:00
|
|
|
if shouldSkip {
|
2014-06-02 19:08:39 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
2014-10-13 06:12:44 +00:00
|
|
|
|
|
|
|
if !psFilters.Match("status", container.State.StateString()) {
|
|
|
|
return nil
|
2014-09-26 23:25:50 +00:00
|
|
|
}
|
2014-07-30 02:04:39 +00:00
|
|
|
displayed++
|
2015-04-07 19:34:30 +00:00
|
|
|
newC := &types.Container{
|
2015-04-04 00:39:06 +00:00
|
|
|
ID: container.ID,
|
|
|
|
Names: names[container.ID],
|
|
|
|
}
|
2015-05-01 01:13:18 +00:00
|
|
|
|
|
|
|
img, err := daemon.Repositories().LookupImage(container.Config.Image)
|
|
|
|
if err != nil {
|
|
|
|
// If the image can no longer be found by its original reference,
|
|
|
|
// it makes sense to show the ID instead of a stale reference.
|
|
|
|
newC.Image = container.ImageID
|
|
|
|
} else if container.ImageID == img.ID {
|
|
|
|
newC.Image = container.Config.Image
|
|
|
|
} else {
|
|
|
|
newC.Image = container.ImageID
|
|
|
|
}
|
|
|
|
|
2014-07-30 02:04:39 +00:00
|
|
|
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, " ")
|
|
|
|
|
2015-04-04 00:39:06 +00:00
|
|
|
newC.Command = fmt.Sprintf("%s %s", container.Path, argsAsString)
|
2014-07-30 02:04:39 +00:00
|
|
|
} else {
|
2015-04-04 00:39:06 +00:00
|
|
|
newC.Command = fmt.Sprintf("%s", container.Path)
|
|
|
|
}
|
2015-07-23 21:19:58 +00:00
|
|
|
newC.Created = container.Created.Unix()
|
2015-04-04 00:39:06 +00:00
|
|
|
newC.Status = container.State.String()
|
2015-07-30 20:25:31 +00:00
|
|
|
newC.HostConfig.NetworkMode = string(container.hostConfig.NetworkMode)
|
2015-04-04 00:39:06 +00:00
|
|
|
|
|
|
|
newC.Ports = []types.Port{}
|
|
|
|
for port, bindings := range container.NetworkSettings.Ports {
|
2015-07-16 03:45:48 +00:00
|
|
|
p, err := nat.ParsePort(port.Port())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-04 00:39:06 +00:00
|
|
|
if len(bindings) == 0 {
|
|
|
|
newC.Ports = append(newC.Ports, types.Port{
|
|
|
|
PrivatePort: p,
|
|
|
|
Type: port.Proto(),
|
|
|
|
})
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, binding := range bindings {
|
2015-07-16 03:45:48 +00:00
|
|
|
h, err := nat.ParsePort(binding.HostPort)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-04 00:39:06 +00:00
|
|
|
newC.Ports = append(newC.Ports, types.Port{
|
|
|
|
PrivatePort: p,
|
|
|
|
PublicPort: h,
|
|
|
|
Type: port.Proto(),
|
2015-07-21 13:43:32 +00:00
|
|
|
IP: binding.HostIP,
|
2015-04-04 00:39:06 +00:00
|
|
|
})
|
|
|
|
}
|
2014-07-30 02:04:39 +00:00
|
|
|
}
|
2015-04-04 00:39:06 +00:00
|
|
|
|
2015-04-07 19:34:30 +00:00
|
|
|
if config.Size {
|
2014-07-30 02:04:39 +00:00
|
|
|
sizeRw, sizeRootFs := container.GetSize()
|
2015-07-23 21:19:58 +00:00
|
|
|
newC.SizeRw = sizeRw
|
|
|
|
newC.SizeRootFs = sizeRootFs
|
2014-07-30 02:04:39 +00:00
|
|
|
}
|
2015-04-04 00:39:06 +00:00
|
|
|
newC.Labels = container.Config.Labels
|
|
|
|
containers = append(containers, newC)
|
2014-07-30 02:04:39 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-07-31 21:26:25 +00:00
|
|
|
for _, container := range daemon.List() {
|
2014-07-30 02:04:39 +00:00
|
|
|
if err := writeCont(container); err != nil {
|
|
|
|
if err != errLast {
|
2015-04-07 19:34:30 +00:00
|
|
|
return nil, err
|
2014-07-30 02:04:39 +00:00
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2015-04-07 19:34:30 +00:00
|
|
|
return containers, nil
|
2014-07-30 02:04:39 +00:00
|
|
|
}
|
2015-06-12 13:25:32 +00:00
|
|
|
|
|
|
|
func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, error) {
|
|
|
|
var volumesOut []*types.Volume
|
|
|
|
volFilters, err := filters.FromParam(filter)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
filterUsed := false
|
|
|
|
if i, ok := volFilters["dangling"]; ok {
|
|
|
|
if len(i) > 1 {
|
|
|
|
return nil, fmt.Errorf("Conflict: cannot use more than 1 value for `dangling` filter")
|
|
|
|
}
|
|
|
|
|
|
|
|
filterValue := i[0]
|
|
|
|
if strings.ToLower(filterValue) == "true" || filterValue == "1" {
|
|
|
|
filterUsed = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
volumes := daemon.volumes.List()
|
|
|
|
for _, v := range volumes {
|
|
|
|
if filterUsed && daemon.volumes.Count(v) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
volumesOut = append(volumesOut, volumeToAPIType(v))
|
|
|
|
}
|
|
|
|
return volumesOut, nil
|
|
|
|
}
|