mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
d942c59b69
When we use the engine/env object we can run into a situation where a string is passed in as the value but later on when we json serialize the name/value pairs, because the string is made up of just numbers it appears as an integer and not a string - meaning no quotes. This can cause parsing issues for clients. I tried to find all spots where we call env.Set() and the type of the name being set might end up having a value that could look like an int (like author). In those cases I switched it to use env.SetJson() instead because that will wrap it in quotes. One interesting thing to note about the testcase that I modified is that the escaped quotes should have been there all along and we were incorrectly letting it thru. If you look at the metadata stored for that resource you can see the quotes were escaped and we lost them during the serialization steps because of the env.Set() stuff. The use of env is probably not the best way to do all of this. Closes: #9602 Signed-off-by: Doug Davis <dug@us.ibm.com>
164 lines
3.8 KiB
Go
164 lines
3.8 KiB
Go
package daemon
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/docker/docker/pkg/graphdb"
|
|
|
|
"github.com/docker/docker/engine"
|
|
"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()
|
|
}
|
|
|
|
func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
|
|
var (
|
|
foundBefore bool
|
|
displayed int
|
|
all = job.GetenvBool("all")
|
|
since = job.Getenv("since")
|
|
before = job.Getenv("before")
|
|
n = job.GetenvInt("limit")
|
|
size = job.GetenvBool("size")
|
|
psFilters filters.Args
|
|
filt_exited []int
|
|
)
|
|
outs := engine.NewTable("Created", 0)
|
|
|
|
psFilters, err := filters.FromParam(job.Getenv("filters"))
|
|
if err != nil {
|
|
return job.Error(err)
|
|
}
|
|
if i, ok := psFilters["exited"]; ok {
|
|
for _, value := range i {
|
|
code, err := strconv.Atoi(value)
|
|
if err != nil {
|
|
return job.Error(err)
|
|
}
|
|
filt_exited = append(filt_exited, code)
|
|
}
|
|
}
|
|
|
|
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 before != "" {
|
|
beforeCont = daemon.Get(before)
|
|
if beforeCont == nil {
|
|
return job.Error(fmt.Errorf("Could not find container with name or id %s", before))
|
|
}
|
|
}
|
|
|
|
if since != "" {
|
|
sinceCont = daemon.Get(since)
|
|
if sinceCont == nil {
|
|
return job.Error(fmt.Errorf("Could not find container with name or id %s", since))
|
|
}
|
|
}
|
|
|
|
errLast := errors.New("last container")
|
|
writeCont := func(container *Container) error {
|
|
container.Lock()
|
|
defer container.Unlock()
|
|
if !container.Running && !all && n <= 0 && since == "" && before == "" {
|
|
return nil
|
|
}
|
|
|
|
if !psFilters.Match("name", container.Name) {
|
|
return nil
|
|
}
|
|
|
|
if !psFilters.Match("id", container.ID) {
|
|
return nil
|
|
}
|
|
|
|
if before != "" && !foundBefore {
|
|
if container.ID == beforeCont.ID {
|
|
foundBefore = true
|
|
}
|
|
return nil
|
|
}
|
|
if n > 0 && displayed == n {
|
|
return errLast
|
|
}
|
|
if since != "" {
|
|
if container.ID == sinceCont.ID {
|
|
return errLast
|
|
}
|
|
}
|
|
if len(filt_exited) > 0 && !container.Running {
|
|
should_skip := true
|
|
for _, code := range filt_exited {
|
|
if code == container.ExitCode {
|
|
should_skip = false
|
|
break
|
|
}
|
|
}
|
|
if should_skip {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
if !psFilters.Match("status", container.State.StateString()) {
|
|
return nil
|
|
}
|
|
displayed++
|
|
out := &engine.Env{}
|
|
out.SetJson("Id", container.ID)
|
|
out.SetList("Names", names[container.ID])
|
|
out.SetJson("Image", daemon.Repositories().ImageName(container.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, " ")
|
|
|
|
out.Set("Command", fmt.Sprintf("\"%s %s\"", container.Path, argsAsString))
|
|
} else {
|
|
out.Set("Command", fmt.Sprintf("\"%s\"", container.Path))
|
|
}
|
|
out.SetInt64("Created", container.Created.Unix())
|
|
out.Set("Status", container.State.String())
|
|
str, err := container.NetworkSettings.PortMappingAPI().ToListString()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
out.Set("Ports", str)
|
|
if size {
|
|
sizeRw, sizeRootFs := container.GetSize()
|
|
out.SetInt64("SizeRw", sizeRw)
|
|
out.SetInt64("SizeRootFs", sizeRootFs)
|
|
}
|
|
outs.Add(out)
|
|
return nil
|
|
}
|
|
|
|
for _, container := range daemon.List() {
|
|
if err := writeCont(container); err != nil {
|
|
if err != errLast {
|
|
return job.Error(err)
|
|
}
|
|
break
|
|
}
|
|
}
|
|
outs.ReverseSort()
|
|
if _, err := outs.WriteListTo(job.Stdout); err != nil {
|
|
return job.Error(err)
|
|
}
|
|
return engine.StatusOK
|
|
}
|