// verifyContainerSettings performs validation of the hostconfig and config // structures. func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) { // First perform verification of settings common across all platforms. if config != nil { if config.WorkingDir != "" && !filepath.IsAbs(config.WorkingDir) { return nil, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path.", config.WorkingDir) } } if hostConfig == nil { return nil, nil } for port := range hostConfig.PortBindings { _, portStr := nat.SplitProtoPort(string(port)) if _, err := nat.ParsePort(portStr); err != nil { return nil, fmt.Errorf("Invalid port specification: %q", portStr) } for _, pb := range hostConfig.PortBindings[port] { _, err := nat.NewPort(nat.SplitProtoPort(pb.HostPort)) if err != nil { return nil, fmt.Errorf("Invalid port specification: %q", pb.HostPort) } } } // Now do platform-specific verification return verifyPlatformContainerSettings(daemon, hostConfig, config) }
// verifyContainerSettings performs validation of the hostconfig and config // structures. func (daemon *Daemon) verifyContainerSettings(ctx context.Context, hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) { // First perform verification of settings common across all platforms. if config != nil { if config.WorkingDir != "" { config.WorkingDir = filepath.FromSlash(config.WorkingDir) // Ensure in platform semantics if !system.IsAbs(config.WorkingDir) { return nil, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path.", config.WorkingDir) } } if len(config.StopSignal) > 0 { _, err := signal.ParseSignal(config.StopSignal) if err != nil { return nil, err } } } if hostConfig == nil { return nil, nil } for port := range hostConfig.PortBindings { _, portStr := nat.SplitProtoPort(string(port)) if _, err := nat.ParsePort(portStr); err != nil { return nil, fmt.Errorf("Invalid port specification: %q", portStr) } for _, pb := range hostConfig.PortBindings[port] { _, err := nat.NewPort(nat.SplitProtoPort(pb.HostPort)) if err != nil { return nil, fmt.Errorf("Invalid port specification: %q", pb.HostPort) } } } // Now do platform-specific verification return verifyPlatformContainerSettings(ctx, daemon, hostConfig, config) }
// transformContainer generates the container type expected by the docker ps command. func (daemon *Daemon) transformContainer(container *Container, ctx *listContext) (*types.Container, error) { newC := &types.Container{ ID: container.ID, Names: ctx.names[container.ID], ImageID: container.ImageID, } if newC.Names == nil { // Dead containers will often have no name, so make sure the response isn't null newC.Names = []string{} } 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 } 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 = 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 nil, 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 nil, err } newC.Ports = append(newC.Ports, types.Port{ PrivatePort: p, PublicPort: h, Type: port.Proto(), IP: binding.HostIP, }) } } if ctx.Size { sizeRw, sizeRootFs := container.getSize() newC.SizeRw = sizeRw newC.SizeRootFs = sizeRootFs } newC.Labels = container.Config.Labels return newC, nil }
func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) { var warnings []string if config != nil { // The check for a valid workdir path is made on the server rather than in the // client. This is because we don't know the type of path (Linux or Windows) // to validate on the client. if config.WorkingDir != "" && !filepath.IsAbs(config.WorkingDir) { return warnings, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path.", config.WorkingDir) } } if hostConfig == nil { return warnings, nil } for port := range hostConfig.PortBindings { _, portStr := nat.SplitProtoPort(string(port)) if _, err := nat.ParsePort(portStr); err != nil { return warnings, fmt.Errorf("Invalid port specification: %q", portStr) } for _, pb := range hostConfig.PortBindings[port] { _, err := nat.NewPort(nat.SplitProtoPort(pb.HostPort)) if err != nil { return warnings, fmt.Errorf("Invalid port specification: %q", pb.HostPort) } } } if hostConfig.LxcConf.Len() > 0 && !strings.Contains(daemon.ExecutionDriver().Name(), "lxc") { return warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver().Name()) } if hostConfig.Memory != 0 && hostConfig.Memory < 4194304 { return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB") } if hostConfig.Memory > 0 && !daemon.SystemConfig().MemoryLimit { warnings = append(warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.") logrus.Warnf("Your kernel does not support memory limit capabilities. Limitation discarded.") hostConfig.Memory = 0 } if hostConfig.Memory > 0 && hostConfig.MemorySwap != -1 && !daemon.SystemConfig().SwapLimit { warnings = append(warnings, "Your kernel does not support swap limit capabilities, memory limited without swap.") logrus.Warnf("Your kernel does not support swap limit capabilities, memory limited without swap.") hostConfig.MemorySwap = -1 } if hostConfig.Memory > 0 && hostConfig.MemorySwap > 0 && hostConfig.MemorySwap < hostConfig.Memory { return warnings, fmt.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage.") } if hostConfig.Memory == 0 && hostConfig.MemorySwap > 0 { return warnings, fmt.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage.") } if hostConfig.MemorySwappiness != -1 && !daemon.SystemConfig().MemorySwappiness { warnings = append(warnings, "Your kernel does not support memory swappiness capabilities, memory swappiness discarded.") logrus.Warnf("Your kernel does not support memory swappiness capabilities, memory swappiness discarded.") hostConfig.MemorySwappiness = -1 } if hostConfig.MemorySwappiness != -1 && (hostConfig.MemorySwappiness < 0 || hostConfig.MemorySwappiness > 100) { return warnings, fmt.Errorf("Invalid value: %d, valid memory swappiness range is 0-100.", hostConfig.MemorySwappiness) } if hostConfig.CpuPeriod > 0 && !daemon.SystemConfig().CpuCfsPeriod { warnings = append(warnings, "Your kernel does not support CPU cfs period. Period discarded.") logrus.Warnf("Your kernel does not support CPU cfs period. Period discarded.") hostConfig.CpuPeriod = 0 } if hostConfig.CpuQuota > 0 && !daemon.SystemConfig().CpuCfsQuota { warnings = append(warnings, "Your kernel does not support CPU cfs quota. Quota discarded.") logrus.Warnf("Your kernel does not support CPU cfs quota. Quota discarded.") hostConfig.CpuQuota = 0 } if hostConfig.BlkioWeight > 0 && (hostConfig.BlkioWeight < 10 || hostConfig.BlkioWeight > 1000) { return warnings, fmt.Errorf("Range of blkio weight is from 10 to 1000.") } if hostConfig.OomKillDisable && !daemon.SystemConfig().OomKillDisable { hostConfig.OomKillDisable = false return warnings, fmt.Errorf("Your kernel does not support oom kill disable.") } if daemon.SystemConfig().IPv4ForwardingDisabled { warnings = append(warnings, "IPv4 forwarding is disabled. Networking will not work.") logrus.Warnf("IPv4 forwarding is disabled. Networking will not work") } return warnings, nil }
// transformContainer generates the container type expected by the docker ps command. func (daemon *Daemon) transformContainer(container *container.Container, ctx *listContext) (*types.Container, error) { newC := &types.Container{ ID: container.ID, Names: ctx.names[container.ID], ImageID: container.ImageID.String(), } if newC.Names == nil { // Dead containers will often have no name, so make sure the response isn't null newC.Names = []string{} } image := container.Config.Image // if possible keep the original ref if image != container.ImageID.String() { id, err := daemon.GetImageID(image) if _, isDNE := err.(ErrImageDoesNotExist); err != nil && !isDNE { return nil, err } if err != nil || id != container.ImageID { image = container.ImageID.String() } } newC.Image = 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 = 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 nil, 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 nil, err } newC.Ports = append(newC.Ports, types.Port{ PrivatePort: p, PublicPort: h, Type: port.Proto(), IP: binding.HostIP, }) } } if ctx.Size { sizeRw, sizeRootFs := daemon.getSize(container) newC.SizeRw = sizeRw newC.SizeRootFs = sizeRootFs } newC.Labels = container.Config.Labels return newC, nil }
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 = int(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, _ := nat.ParsePort(port.Port()) if len(bindings) == 0 { newC.Ports = append(newC.Ports, types.Port{ PrivatePort: p, Type: port.Proto(), }) continue } for _, binding := range bindings { h, _ := nat.ParsePort(binding.HostPort) 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 = int(sizeRw) newC.SizeRootFs = int(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 }
// Containers returns a list of all the containers. func (daemon *Daemon) Containers(config *ContainersConfig) ([]*types.Container, error) { var ( foundBefore bool displayed int ancestorFilter bool all = config.All n = config.Limit psFilters filters.Args filtExited []int ) imagesFilter := map[string]bool{} 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 } } } if ancestors, ok := psFilters["ancestor"]; ok { ancestorFilter = true byParents := daemon.Graph().ByParent() // The idea is to walk the graph down the most "efficient" way. for _, ancestor := range ancestors { // First, get the imageId of the ancestor filter (yay) image, err := daemon.Repositories().LookupImage(ancestor) if err != nil { logrus.Warnf("Error while looking up for image %v", ancestor) continue } if imagesFilter[ancestor] { // Already seen this ancestor, skip it continue } // Then walk down the graph and put the imageIds in imagesFilter populateImageFilterByParents(imagesFilter, image.ID, byParents) } } 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 } if ancestorFilter { if len(imagesFilter) == 0 { return nil } if !imagesFilter[container.ImageID] { return nil } } displayed++ newC := &types.Container{ ID: container.ID, Names: names[container.ID], } 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 } 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 }