Compare commits

..

2 Commits

Author SHA1 Message Date
Antonio Murdaca 24a4d5767f Dockerfile: add kvmtool and linux-container for clr execdriver
This patch adds the needed pkgs to docker/docker development Dockerfile
in order to test the clr execdriver in the development container.

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
2015-10-28 16:56:43 +00:00
James Hunt c156bd83c4 Clear Containers for Docker Engine (v1.9.0)
Signed-off-by: James Hunt <james.o.hunt@intel.com>
2015-10-28 16:50:00 +00:00
165 changed files with 2757 additions and 5662 deletions
+6
View File
@@ -61,6 +61,12 @@ RUN apt-get update && apt-get install -y \
libzfs-dev \
--no-install-recommends
# clr
RUN echo deb http://download.opensuse.org/repositories/home:/clearlinux:/preview/xUbuntu_15.04/ / > /etc/apt/sources.list.d/clear-containers-docker.list
RUN apt-get --allow-unauthenticated update && apt-get install -y --force-yes \
kvmtool\
linux-container
# Get lvm2 source for compiling statically
RUN git clone -b v2_02_103 https://git.fedorahosted.org/git/lvm2.git /usr/local/lvm2
# see https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
+1 -1
View File
@@ -58,7 +58,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
dockerfileName := cmd.String([]string{"f", "-file"}, "", "Name of the Dockerfile (Default is 'PATH/Dockerfile')")
flMemoryString := cmd.String([]string{"m", "-memory"}, "", "Memory limit")
flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Total memory (memory + swap), '-1' to disable swap")
flCPUShares := cmd.Int64([]string{"#c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
flCPUShares := cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
flCPUPeriod := cmd.Int64([]string{"-cpu-period"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) period")
flCPUQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota")
flCPUSetCpus := cmd.String([]string{"-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
+1 -1
View File
@@ -35,7 +35,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
fmt.Fprintf(cli.out, "Containers: %d\n", info.Containers)
fmt.Fprintf(cli.out, "Images: %d\n", info.Images)
ioutils.FprintfIfNotEmpty(cli.out, "Server Version: %s\n", info.ServerVersion)
fmt.Fprintf(cli.out, "Engine Version: %s\n", info.ServerVersion)
ioutils.FprintfIfNotEmpty(cli.out, "Storage Driver: %s\n", info.Driver)
if info.DriverStatus != nil {
for _, pair := range info.DriverStatus {
+2 -5
View File
@@ -34,7 +34,6 @@ func (cli *DockerCli) CmdNetwork(args ...string) error {
func (cli *DockerCli) CmdNetworkCreate(args ...string) error {
cmd := Cli.Subcmd("network create", []string{"NETWORK-NAME"}, "Creates a new network with a name specified by the user", false)
flDriver := cmd.String([]string{"d", "-driver"}, "bridge", "Driver to manage the Network")
flOpts := opts.NewMapOpts(nil, nil)
flIpamDriver := cmd.String([]string{"-ipam-driver"}, "default", "IP Address Management Driver")
flIpamSubnet := opts.NewListOpts(nil)
@@ -42,11 +41,10 @@ func (cli *DockerCli) CmdNetworkCreate(args ...string) error {
flIpamGateway := opts.NewListOpts(nil)
flIpamAux := opts.NewMapOpts(nil, nil)
cmd.Var(&flIpamSubnet, []string{"-subnet"}, "subnet in CIDR format that represents a network segment")
cmd.Var(&flIpamSubnet, []string{"-subnet"}, "Subnet in CIDR format that represents a network segment")
cmd.Var(&flIpamIPRange, []string{"-ip-range"}, "allocate container ip from a sub-range")
cmd.Var(&flIpamGateway, []string{"-gateway"}, "ipv4 or ipv6 Gateway for the master subnet")
cmd.Var(flIpamAux, []string{"-aux-address"}, "auxiliary ipv4 or ipv6 addresses used by Network driver")
cmd.Var(flOpts, []string{"o", "-opt"}, "set driver specific options")
cmd.Var(flIpamAux, []string{"-aux-address"}, "Auxiliary ipv4 or ipv6 addresses used by network driver")
cmd.Require(flag.Exact, 1)
err := cmd.ParseFlags(args, true)
@@ -64,7 +62,6 @@ func (cli *DockerCli) CmdNetworkCreate(args ...string) error {
Name: cmd.Arg(0),
Driver: *flDriver,
IPAM: network.IPAM{Driver: *flIpamDriver, Config: ipamCfg},
Options: flOpts.GetAll(),
CheckDuplicate: true,
}
obj, _, err := readBody(cli.call("POST", "/networks/create", nc, nil))
+1 -1
View File
@@ -18,7 +18,7 @@ import (
// Common constants for daemon and client.
const (
// Version of Current REST API
Version version.Version = "1.22"
Version version.Version = "1.21"
// MinVersion represents Minimun REST API version supported
MinVersion version.Version = "1.12"
+3
View File
@@ -55,6 +55,9 @@ type ArchiveOptions struct {
// ArchiveFormValues parses form values and turns them into ArchiveOptions.
// It fails if the archive name and path are not in the request.
func ArchiveFormValues(r *http.Request, vars map[string]string) (ArchiveOptions, error) {
if vars == nil {
return ArchiveOptions{}, fmt.Errorf("Missing parameter")
}
if err := ParseForm(r); err != nil {
return ArchiveOptions{}, err
}
+56
View File
@@ -56,6 +56,9 @@ func (s *router) getContainersStats(ctx context.Context, w http.ResponseWriter,
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
stream := httputils.BoolValueOrDefault(r, "stream", true)
var out io.Writer
@@ -85,6 +88,9 @@ func (s *router) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
// Args are validated before the stream starts because when it starts we're
// sending HTTP 200 by writing an empty chunk of data to tell the client that
@@ -144,10 +150,18 @@ func (s *router) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
}
func (s *router) getContainersExport(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
return s.daemon.ContainerExport(vars["name"], w)
}
func (s *router) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
// If contentLength is -1, we can assumed chunked encoding
// or more technically that the length is unknown
// https://golang.org/src/pkg/net/http/request.go#L139
@@ -179,6 +193,9 @@ func (s *router) postContainersStop(ctx context.Context, w http.ResponseWriter,
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
seconds, _ := strconv.Atoi(r.Form.Get("t"))
@@ -191,6 +208,9 @@ func (s *router) postContainersStop(ctx context.Context, w http.ResponseWriter,
}
func (s *router) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := httputils.ParseForm(r); err != nil {
return err
}
@@ -227,6 +247,9 @@ func (s *router) postContainersRestart(ctx context.Context, w http.ResponseWrite
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
timeout, _ := strconv.Atoi(r.Form.Get("t"))
@@ -240,6 +263,9 @@ func (s *router) postContainersRestart(ctx context.Context, w http.ResponseWrite
}
func (s *router) postContainersPause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := httputils.ParseForm(r); err != nil {
return err
}
@@ -254,6 +280,9 @@ func (s *router) postContainersPause(ctx context.Context, w http.ResponseWriter,
}
func (s *router) postContainersUnpause(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := httputils.ParseForm(r); err != nil {
return err
}
@@ -268,6 +297,10 @@ func (s *router) postContainersUnpause(ctx context.Context, w http.ResponseWrite
}
func (s *router) postContainersWait(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
status, err := s.daemon.ContainerWait(vars["name"], -1*time.Second)
if err != nil {
return err
@@ -279,6 +312,10 @@ func (s *router) postContainersWait(ctx context.Context, w http.ResponseWriter,
}
func (s *router) getContainersChanges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
changes, err := s.daemon.ContainerChanges(vars["name"])
if err != nil {
return err
@@ -288,6 +325,10 @@ func (s *router) getContainersChanges(ctx context.Context, w http.ResponseWriter
}
func (s *router) getContainersTop(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := httputils.ParseForm(r); err != nil {
return err
}
@@ -304,6 +345,9 @@ func (s *router) postContainerRename(ctx context.Context, w http.ResponseWriter,
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
newName := r.Form.Get("name")
@@ -343,6 +387,9 @@ func (s *router) deleteContainers(ctx context.Context, w http.ResponseWriter, r
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
config := &daemon.ContainerRmConfig{
@@ -368,6 +415,9 @@ func (s *router) postContainersResize(ctx context.Context, w http.ResponseWriter
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
height, err := strconv.Atoi(r.Form.Get("h"))
if err != nil {
@@ -385,6 +435,9 @@ func (s *router) postContainersAttach(ctx context.Context, w http.ResponseWriter
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
containerName := vars["name"]
if !s.daemon.Exists(containerName) {
@@ -424,6 +477,9 @@ func (s *router) wsContainersAttach(ctx context.Context, w http.ResponseWriter,
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
containerName := vars["name"]
if !s.daemon.Exists(containerName) {
+4
View File
@@ -16,6 +16,10 @@ import (
// postContainersCopy is deprecated in favor of getContainersArchive.
func (s *router) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := httputils.CheckForJSON(r); err != nil {
return err
}
+8
View File
@@ -16,6 +16,10 @@ import (
)
func (s *router) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter 'id'")
}
eConfig, err := s.daemon.ContainerExecInspect(vars["id"])
if err != nil {
return err
@@ -114,6 +118,10 @@ func (s *router) postContainerExecResize(ctx context.Context, w http.ResponseWri
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
height, err := strconv.Atoi(r.Form.Get("h"))
if err != nil {
return err
+26 -4
View File
@@ -16,7 +16,6 @@ import (
"github.com/docker/docker/builder/dockerfile"
"github.com/docker/docker/cliconfig"
"github.com/docker/docker/daemon/daemonbuilder"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/graph"
"github.com/docker/docker/graph/tags"
"github.com/docker/docker/pkg/archive"
@@ -64,11 +63,12 @@ func (s *router) postCommit(ctx context.Context, w http.ResponseWriter, r *http.
Config: c,
}
if !s.daemon.Exists(cname) {
return derr.ErrorCodeNoSuchContainer.WithArgs(cname)
container, err := s.daemon.Get(cname)
if err != nil {
return err
}
imgID, err := dockerfile.Commit(cname, s.daemon, commitCfg)
imgID, err := dockerfile.Commit(container, s.daemon, commitCfg)
if err != nil {
return err
}
@@ -156,6 +156,10 @@ func (s *router) postImagesCreate(ctx context.Context, w http.ResponseWriter, r
}
func (s *router) postImagesPush(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
metaHeaders := map[string][]string{}
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Meta-") {
@@ -204,6 +208,9 @@ func (s *router) postImagesPush(ctx context.Context, w http.ResponseWriter, r *h
}
func (s *router) getImagesGet(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := httputils.ParseForm(r); err != nil {
return err
}
@@ -236,6 +243,9 @@ func (s *router) deleteImages(ctx context.Context, w http.ResponseWriter, r *htt
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
@@ -255,6 +265,10 @@ func (s *router) deleteImages(ctx context.Context, w http.ResponseWriter, r *htt
}
func (s *router) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
imageInspect, err := s.daemon.LookupImage(vars["name"])
if err != nil {
return err
@@ -442,6 +456,10 @@ func (s *router) getImagesJSON(ctx context.Context, w http.ResponseWriter, r *ht
}
func (s *router) getImagesHistory(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
history, err := s.daemon.ImageHistory(name)
if err != nil {
@@ -455,6 +473,10 @@ func (s *router) postImagesTag(ctx context.Context, w http.ResponseWriter, r *ht
if err := httputils.ParseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
repo := r.Form.Get("repo")
tag := r.Form.Get("tag")
name := vars["name"]
+4
View File
@@ -1,6 +1,7 @@
package local
import (
"fmt"
"net/http"
"github.com/docker/docker/api/server/httputils"
@@ -10,6 +11,9 @@ import (
// getContainersByName inspects containers configuration and serializes it as json.
func (s *router) getContainersByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
displaySize := httputils.BoolValue(r, "size")
if vars == nil {
return fmt.Errorf("Missing parameter")
}
var json interface{}
var err error
+11 -4
View File
@@ -96,7 +96,7 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID())
}
nw, err = n.daemon.CreateNetwork(create.Name, create.Driver, create.IPAM, create.Options)
nw, err = n.daemon.CreateNetwork(create.Name, create.Driver, create.IPAM)
if err != nil {
return err
}
@@ -126,7 +126,11 @@ func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseW
return err
}
return n.daemon.ConnectContainerToNetwork(connect.Container, nw.Name())
container, err := n.daemon.Get(connect.Container)
if err != nil {
return fmt.Errorf("invalid container %s : %v", container, err)
}
return container.ConnectToNetwork(nw.Name())
}
func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
@@ -148,7 +152,11 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon
return err
}
return n.daemon.DisconnectContainerFromNetwork(disconnect.Container, nw)
container, err := n.daemon.Get(disconnect.Container)
if err != nil {
return fmt.Errorf("invalid container %s : %v", container, err)
}
return container.DisconnectFromNetwork(nw)
}
func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
@@ -174,7 +182,6 @@ func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
r.ID = nw.ID()
r.Scope = nw.Info().Scope()
r.Driver = nw.Type()
r.Options = nw.Info().DriverOptions()
r.Containers = make(map[string]types.EndpointResource)
buildIpamResources(r, nw)
+1 -6
View File
@@ -153,12 +153,7 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
ctx := context.Background()
handlerFunc := s.handleWithGlobalMiddlewares(handler)
vars := mux.Vars(r)
if vars == nil {
vars = make(map[string]string)
}
if err := handlerFunc(ctx, w, r, vars); err != nil {
if err := handlerFunc(ctx, w, r, mux.Vars(r)); err != nil {
logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.URL.Path, utils.GetErrorMessage(err))
httputils.WriteError(w, err)
}
+4 -6
View File
@@ -319,7 +319,6 @@ type NetworkResource struct {
Driver string `json:"driver"`
IPAM network.IPAM `json:"ipam"`
Containers map[string]EndpointResource `json:"containers"`
Options map[string]string `json:"options"`
}
//EndpointResource contains network resources allocated and usd for a container in a network
@@ -332,11 +331,10 @@ type EndpointResource struct {
// NetworkCreate is the expected body of the "create network" http request message
type NetworkCreate struct {
Name string `json:"name"`
CheckDuplicate bool `json:"check_duplicate"`
Driver string `json:"driver"`
IPAM network.IPAM `json:"ipam"`
Options map[string]string `json:"options"`
Name string `json:"name"`
CheckDuplicate bool `json:"check_duplicate"`
Driver string `json:"driver"`
IPAM network.IPAM `json:"ipam"`
}
// NetworkCreateResponse is the response message sent by the server for network create call
+1 -6
View File
@@ -256,12 +256,7 @@ func BuildFromConfig(config *runconfig.Config, changes []string) (*runconfig.Con
// Commit will create a new image from a container's changes
// TODO: remove daemon, make Commit a method on *Builder ?
func Commit(containerName string, d *daemon.Daemon, c *CommitConfig) (string, error) {
container, err := d.Get(containerName)
if err != nil {
return "", err
}
func Commit(container *daemon.Container, d *daemon.Daemon, c *CommitConfig) (string, error) {
// It is not possible to commit a running container on Windows
if runtime.GOOS == "windows" && container.IsRunning() {
return "", fmt.Errorf("Windows does not support commit of a running container")
+7 -15
View File
@@ -557,9 +557,8 @@ func (b *Builder) run(c *daemon.Container) error {
go func() {
select {
case <-b.cancelled:
logrus.Debugln("Build cancelled, killing and removing container:", c.ID)
logrus.Debugln("Build cancelled, killing container:", c.ID)
c.Kill()
b.removeContainer(c.ID)
case <-finished:
}
}()
@@ -583,21 +582,14 @@ func (b *Builder) run(c *daemon.Container) error {
return nil
}
func (b *Builder) removeContainer(c string) error {
rmConfig := &daemon.ContainerRmConfig{
ForceRemove: true,
RemoveVolume: true,
}
if err := b.docker.Remove(c, rmConfig); err != nil {
fmt.Fprintf(b.Stdout, "Error removing intermediate container %s: %v\n", stringid.TruncateID(c), err)
return err
}
return nil
}
func (b *Builder) clearTmp() {
for c := range b.tmpContainers {
if err := b.removeContainer(c); err != nil {
rmConfig := &daemon.ContainerRmConfig{
ForceRemove: true,
RemoveVolume: true,
}
if err := b.docker.Remove(c, rmConfig); err != nil {
fmt.Fprintf(b.Stdout, "Error removing intermediate container %s: %v\n", stringid.TruncateID(c), err)
return
}
delete(b.tmpContainers, c)
-1
View File
@@ -45,7 +45,6 @@ var dockerCommands = []Command{
{"login", "Register or log in to a Docker registry"},
{"logout", "Log out from a Docker registry"},
{"logs", "Fetch the logs of a container"},
{"network", "Manage Docker networks"},
{"pause", "Pause all processes within a container"},
{"port", "List port mappings or a specific mapping for the CONTAINER"},
{"ps", "List containers"},
+1 -1
View File
@@ -6,7 +6,7 @@ FROM debian:jessie
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
@@ -6,7 +6,7 @@ FROM debian:stretch
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
+1 -1
View File
@@ -6,7 +6,7 @@ FROM debian:wheezy-backports
RUN apt-get update && apt-get install -y bash-completion btrfs-tools/wheezy-backports build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
@@ -6,7 +6,7 @@ FROM ubuntu:precise
RUN apt-get update && apt-get install -y bash-completion build-essential curl ca-certificates debhelper git libapparmor-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
+1 -1
View File
@@ -6,7 +6,7 @@ FROM ubuntu:trusty
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
+1 -1
View File
@@ -6,7 +6,7 @@ FROM ubuntu:vivid
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
+1 -1
View File
@@ -6,7 +6,7 @@ FROM ubuntu:wily
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
+1 -1
View File
@@ -8,7 +8,7 @@ RUN yum groupinstall -y "Development Tools"
RUN yum -y swap -- remove systemd-container systemd-container-libs -- install systemd systemd-libs
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
+1 -1
View File
@@ -7,7 +7,7 @@ FROM fedora:21
RUN yum install -y @development-tools fedora-packager
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
+1 -1
View File
@@ -7,7 +7,7 @@ FROM fedora:22
RUN yum install -y @development-tools fedora-packager
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
+1 -1
View File
@@ -7,7 +7,7 @@ FROM opensuse:13.2
RUN zypper --non-interactive install ca-certificates* curl gzip rpm-build
RUN zypper --non-interactive install libbtrfs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
+1 -1
View File
@@ -7,7 +7,7 @@ FROM oraclelinux:6
RUN yum groupinstall -y "Development Tools"
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
+1 -1
View File
@@ -7,7 +7,7 @@ FROM oraclelinux:7
RUN yum groupinstall -y "Development Tools"
RUN yum install -y --enablerepo=ol7_optional_latest btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
ENV GO_VERSION 1.4.3
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
+12 -50
View File
@@ -461,37 +461,8 @@ _docker_attach() {
}
_docker_build() {
local options_with_args="
--build-arg
--cgroup-parent
--cpuset-cpus
--cpuset-mems
--cpu-shares
--cpu-period
--cpu-quota
--file -f
--memory -m
--memory-swap
--tag -t
--ulimit
"
local boolean_options="
--disable-content-trust=false
--force-rm
--help
--no-cache
--pull
--quiet -q
--rm
"
local all_options="$options_with_args $boolean_options"
case "$prev" in
--build-arg)
COMPREPLY=( $( compgen -e -- "$cur" ) )
__docker_nospace
--cgroup-parent|--cpuset-cpus|--cpuset-mems|--cpu-shares|-c|--cpu-period|--cpu-quota|--memory|-m|--memory-swap)
return
;;
--file|-f)
@@ -502,17 +473,14 @@ _docker_build() {
__docker_image_repos_and_tags
return
;;
$(__docker_to_extglob "$options_with_args") )
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "$all_options" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--cgroup-parent --cpuset-cpus --cpuset-mems --cpu-shares -c --cpu-period --cpu-quota --file -f --force-rm --help --memory -m --memory-swap --no-cache --pull --quiet -q --rm --tag -t --ulimit" -- "$cur" ) )
;;
*)
local counter=$( __docker_pos_first_nonflag $( __docker_to_alternatives "$options_with_args" ) )
local counter="$(__docker_pos_first_nonflag '--cgroup-parent|--cpuset-cpus|--cpuset-mems|--cpu-shares|-c|--cpu-period|--cpu-quota|--file|-f|--memory|-m|--memory-swap|--tag|-t')"
if [ $cword -eq $counter ]; then
_filedir -d
fi
@@ -897,18 +865,12 @@ _docker_images() {
}
_docker_import() {
case "$prev" in
--change|-c|--message|-m)
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--change -c --help --message -m" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
;;
*)
local counter=$(__docker_pos_first_nonflag '--change|-c|--message|-m')
local counter=$(__docker_pos_first_nonflag)
if [ $cword -eq $counter ]; then
return
fi
@@ -944,7 +906,7 @@ _docker_inspect() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--format -f --help --size -s --type" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--format -f --type --help" -- "$cur" ) )
;;
*)
case $(__docker_value_of_option --type) in
@@ -1098,7 +1060,7 @@ _docker_network_ls() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--help --no-trunc --quiet -q" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--help --latest -l -n --no-trunc --quiet -q" -- "$cur" ) )
;;
esac
}
@@ -1310,7 +1272,7 @@ _docker_run() {
--cpu-quota
--cpuset-cpus
--cpuset-mems
--cpu-shares
--cpu-shares -c
--device
--dns
--dns-opt
@@ -1349,7 +1311,7 @@ _docker_run() {
--workdir -w
"
local boolean_options="
local all_options="$options_with_args
--disable-content-trust=false
--help
--interactive -i
@@ -1360,14 +1322,14 @@ _docker_run() {
--tty -t
"
local all_options="$options_with_args $boolean_options"
[ "$command" = "run" ] && all_options="$all_options
--detach -d
--rm
--sig-proxy=false
"
local options_with_args_glob=$(__docker_to_extglob "$options_with_args")
case "$prev" in
--add-host)
case "$cur" in
@@ -1492,7 +1454,7 @@ _docker_run() {
__docker_containers_all
return
;;
$(__docker_to_extglob "$options_with_args") )
$options_with_args_glob )
return
;;
esac
+1 -1
View File
@@ -116,7 +116,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from cp' -l help -d 'Print u
complete -c docker -f -n '__fish_docker_no_subcommand' -a create -d 'Create a new container'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s a -l attach -d 'Attach to STDIN, STDOUT or STDERR.'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l add-host -d 'Add a custom host-to-IP mapping (host:ip)'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cpu-shares -d 'CPU shares (relative weight)'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s c -l cpu-shares -d 'CPU shares (relative weight)'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cap-add -d 'Add Linux capabilities'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cap-drop -d 'Drop Linux capabilities'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cidfile -d 'Write the container ID to the file'
+112 -117
View File
@@ -253,11 +253,6 @@ __docker_network_subcommand() {
_arguments -A '-*' \
$opts_help \
"($help -d --driver)"{-d,--driver=}"[Driver to manage the Network]:driver:(null host bridge overlay)" \
"($help)--ipam-driver=[IP Address Management Driver]:driver:(default)" \
"($help)*--subnet=[Subnet in CIDR format that represents a network segment]:IP/mask: " \
"($help)*--ip-range=[Allocate container ip from a sub-range]:IP/mask: " \
"($help)*--gateway=[ipv4 or ipv6 Gateway for the master subnet]:IP: " \
"($help)*--aux-address[Auxiliary ipv4 or ipv6 addresses used by network driver]:key=IP: " \
"($help -)1:Network Name: " && ret=0
;;
(inspect|rm)
@@ -268,6 +263,8 @@ __docker_network_subcommand() {
(ls)
_arguments \
$opts_help \
"($help -l --latest)"{-l,--latest}"[Show the latest network created]" \
"($help)-n=-[Show n last created networks]:Number of networks: " \
"($help)--no-trunc[Do not truncate the output]" \
"($help -q --quiet)"{-q,--quiet}"[Only display numeric IDs]" && ret=0
;;
@@ -333,20 +330,20 @@ __docker_volume_subcommand() {
(create)
_arguments \
$opts_help \
"($help -d --driver)"{-d,--driver=}"[Specify volume driver name]:Driver name: " \
"($help)--name=[Specify volume name]" \
"($help -o --opt)*"{-o,--opt=}"[Set driver specific options]:Driver option: " && ret=0
"($help -d --driver)"{-d,--driver=-}"[Specify volume driver name]:Driver name: " \
"($help)--name=-[Specify volume name]" \
"($help -o --opt)*"{-o,--opt=-}"[Set driver specific options]:Driver option: " && ret=0
;;
(inspect)
_arguments \
$opts_help \
"($help -f --format)"{-f,--format=}"[Format the output using the given go template]:template: " \
"($help -f --format)"{-f,--format=-}"[Format the output using the given go template]:template: " \
"($help -)1:volume:__docker_volumes" && ret=0
;;
(ls)
_arguments \
$opts_help \
"($help -f --filter)*"{-f,--filter=}"[Provide filter values (i.e. 'dangling=true')]:filter: " \
"($help -f --filter)*"{-f,--filter=-}"[Provide filter values (i.e. 'dangling=true')]:filter: " \
"($help -q --quiet)"{-q,--quiet}"[Only display volume names]" && ret=0
;;
(rm)
@@ -394,57 +391,57 @@ __docker_subcommand() {
opts_help=("(: -)--help[Print usage]")
opts_cpumemlimit=(
"($help)--cpu-shares=[CPU shares (relative weight)]:CPU shares:(0 10 100 200 500 800 1000)"
"($help)--cgroup-parent=[Parent cgroup for the container]:cgroup: "
"($help)--cpu-period=[Limit the CPU CFS (Completely Fair Scheduler) period]:CPU period: "
"($help)--cpu-quota=[Limit the CPU CFS (Completely Fair Scheduler) quota]:CPU quota: "
"($help)--cpuset-cpus=[CPUs in which to allow execution]:CPUs: "
"($help)--cpuset-mems=[MEMs in which to allow execution]:MEMs: "
"($help -m --memory)"{-m,--memory=}"[Memory limit]:Memory limit: "
"($help)--memory-swap=[Total memory limit with swap]:Memory limit: "
"($help)*--ulimit=[ulimit options]:ulimit: "
"($help -c --cpu-shares)"{-c,--cpu-shares=-}"[CPU shares (relative weight)]:CPU shares:(0 10 100 200 500 800 1000)"
"($help)--cgroup-parent=-[Parent cgroup for the container]:cgroup: "
"($help)--cpu-period=-[Limit the CPU CFS (Completely Fair Scheduler) period]:CPU period: "
"($help)--cpu-quota=-[Limit the CPU CFS (Completely Fair Scheduler) quota]:CPU quota: "
"($help)--cpuset-cpus=-[CPUs in which to allow execution]:CPUs: "
"($help)--cpuset-mems=-[MEMs in which to allow execution]:MEMs: "
"($help -m --memory)"{-m,--memory=-}"[Memory limit]:Memory limit: "
"($help)--memory-swap=-[Total memory limit with swap]:Memory limit: "
"($help)*--ulimit=-[ulimit options]:ulimit: "
)
opts_create=(
"($help -a --attach)"{-a,--attach=}"[Attach to stdin, stdout or stderr]:device:(STDIN STDOUT STDERR)"
"($help)*--add-host=[Add a custom host-to-IP mapping]:host\:ip mapping: "
"($help)--blkio-weight=[Block IO (relative weight), between 10 and 1000]:Block IO weight:(10 100 500 1000)"
"($help)*--cap-add=[Add Linux capabilities]:capability: "
"($help)*--cap-drop=[Drop Linux capabilities]:capability: "
"($help)--cidfile=[Write the container ID to the file]:CID file:_files"
"($help)*--device=[Add a host device to the container]:device:_files"
"($help)*--dns=[Set custom DNS servers]:DNS server: "
"($help)*--dns-opt=[Set custom DNS options]:DNS option: "
"($help)*--dns-search=[Set custom DNS search domains]:DNS domains: "
"($help)*"{-e,--env=}"[Set environment variables]:environment variable: "
"($help)--entrypoint=[Overwrite the default entrypoint of the image]:entry point: "
"($help)*--env-file=[Read environment variables from a file]:environment file:_files"
"($help)*--expose=[Expose a port from the container without publishing it]: "
"($help)*--group-add=[Add additional groups to run as]:group:_groups"
"($help -h --hostname)"{-h,--hostname=}"[Container host name]:hostname:_hosts"
"($help -a --attach)"{-a,--attach=-}"[Attach to stdin, stdout or stderr]:device:(STDIN STDOUT STDERR)"
"($help)*--add-host=-[Add a custom host-to-IP mapping]:host\:ip mapping: "
"($help)--blkio-weight=-[Block IO (relative weight), between 10 and 1000]:Block IO weight:(10 100 500 1000)"
"($help)*--cap-add=-[Add Linux capabilities]:capability: "
"($help)*--cap-drop=-[Drop Linux capabilities]:capability: "
"($help)--cidfile=-[Write the container ID to the file]:CID file:_files"
"($help)*--device=-[Add a host device to the container]:device:_files"
"($help)*--dns=-[Set custom DNS servers]:DNS server: "
"($help)*--dns-opt=-[Set custom DNS options]:DNS option: "
"($help)*--dns-search=-[Set custom DNS search domains]:DNS domains: "
"($help)*"{-e,--env=-}"[Set environment variables]:environment variable: "
"($help)--entrypoint=-[Overwrite the default entrypoint of the image]:entry point: "
"($help)*--env-file=-[Read environment variables from a file]:environment file:_files"
"($help)*--expose=-[Expose a port from the container without publishing it]: "
"($help)*--group-add=-[Add additional groups to run as]:group:_groups"
"($help -h --hostname)"{-h,--hostname=-}"[Container host name]:hostname:_hosts"
"($help -i --interactive)"{-i,--interactive}"[Keep stdin open even if not attached]"
"($help)--ipc=[IPC namespace to use]:IPC namespace: "
"($help)--ipc=-[IPC namespace to use]:IPC namespace: "
"($help)--kernel-memory[Kernel memory limit in bytes.]:Memory limit: "
"($help)*--link=[Add link to another container]:link:->link"
"($help)*"{-l,--label=}"[Set meta data on a container]:label: "
"($help)--log-driver=[Default driver for container logs]:Logging driver:(json-file syslog journald gelf fluentd awslogs none)"
"($help)*--log-opt=[Log driver specific options]:log driver options: "
"($help)*--lxc-conf=[Add custom lxc options]:lxc options: "
"($help)--mac-address=[Container MAC address]:MAC address: "
"($help)--name=[Container name]:name: "
"($help)--net=[Connect a container to a network]:network mode:(bridge none container host)"
"($help)*--link=-[Add link to another container]:link:->link"
"($help)*"{-l,--label=-}"[Set meta data on a container]:label: "
"($help)--log-driver=-[Default driver for container logs]:Logging driver:(json-file syslog journald gelf fluentd awslogs none)"
"($help)*--log-opt=-[Log driver specific options]:log driver options: "
"($help)*--lxc-conf=-[Add custom lxc options]:lxc options: "
"($help)--mac-address=-[Container MAC address]:MAC address: "
"($help)--name=-[Container name]:name: "
"($help)--net=-[Connect a container to a network]:network mode:(bridge none container host)"
"($help)--oom-kill-disable[Disable OOM Killer]"
"($help -P --publish-all)"{-P,--publish-all}"[Publish all exposed ports]"
"($help)*"{-p,--publish=}"[Expose a container's port to the host]:port:_ports"
"($help)--pid=[PID namespace to use]:PID: "
"($help)*"{-p,--publish=-}"[Expose a container's port to the host]:port:_ports"
"($help)--pid=-[PID namespace to use]:PID: "
"($help)--privileged[Give extended privileges to this container]"
"($help)--read-only[Mount the container's root filesystem as read only]"
"($help)--restart=[Restart policy]:restart policy:(no on-failure always unless-stopped)"
"($help)*--security-opt=[Security options]:security option: "
"($help)--restart=-[Restart policy]:restart policy:(no on-failure always)"
"($help)*--security-opt=-[Security options]:security option: "
"($help -t --tty)"{-t,--tty}"[Allocate a pseudo-tty]"
"($help -u --user)"{-u,--user=}"[Username or UID]:user:_users"
"($help -u --user)"{-u,--user=-}"[Username or UID]:user:_users"
"($help)*-v[Bind mount a volume]:volume: "
"($help)*--volumes-from=[Mount volumes from the specified container]:volume: "
"($help -w --workdir)"{-w,--workdir=}"[Working directory inside the container]:directory:_directories"
"($help)*--volumes-from=-[Mount volumes from the specified container]:volume: "
"($help -w --workdir)"{-w,--workdir=-}"[Working directory inside the container]:directory:_directories"
)
case "$words[1]" in
@@ -459,22 +456,21 @@ __docker_subcommand() {
_arguments \
$opts_help \
$opts_cpumemlimit \
"($help)*--build-arg[Set build-time variables]:<varname>=<value>: " \
"($help -f --file)"{-f,--file=}"[Name of the Dockerfile]:Dockerfile:_files" \
"($help -f --file)"{-f,--file=-}"[Name of the Dockerfile]:Dockerfile:_files" \
"($help)--force-rm[Always remove intermediate containers]" \
"($help)--no-cache[Do not use cache when building the image]" \
"($help)--pull[Attempt to pull a newer version of the image]" \
"($help -q --quiet)"{-q,--quiet}"[Suppress verbose build output]" \
"($help)--rm[Remove intermediate containers after a successful build]" \
"($help -t --tag)"{-t,--tag=}"[Repository, name and tag for the image]: :__docker_repositories_with_tags" \
"($help -t --tag)"{-t,--tag=-}"[Repository, name and tag for the image]: :__docker_repositories_with_tags" \
"($help -):path or URL:_directories" && ret=0
;;
(commit)
_arguments \
$opts_help \
"($help -a --author)"{-a,--author=}"[Author]:author: " \
"($help -c --change)*"{-c,--change=}"[Apply Dockerfile instruction to the created image]:Dockerfile:_files" \
"($help -m --message)"{-m,--message=}"[Commit message]:message: " \
"($help -a --author)"{-a,--author=-}"[Author]:author: " \
"($help -c --change)*"{-c,--change=-}"[Apply Dockerfile instruction to the created image]:Dockerfile:_files" \
"($help -m --message)"{-m,--message=-}"[Commit message]:message: " \
"($help -p --pause)"{-p,--pause}"[Pause container during commit]" \
"($help -):container:__docker_containers" \
"($help -): :__docker_repositories_with_tags" && ret=0
@@ -517,49 +513,49 @@ __docker_subcommand() {
(daemon)
_arguments \
$opts_help \
"($help)--api-cors-header=[Set CORS headers in the remote API]:CORS headers: " \
"($help -b --bridge)"{-b,--bridge=}"[Attach containers to a network bridge]:bridge:_net_interfaces" \
"($help)--bip=[Specify network bridge IP]" \
"($help)--api-cors-header=-[Set CORS headers in the remote API]:CORS headers: " \
"($help -b --bridge)"{-b,--bridge=-}"[Attach containers to a network bridge]:bridge:_net_interfaces" \
"($help)--bip=-[Specify network bridge IP]" \
"($help -D --debug)"{-D,--debug}"[Enable debug mode]" \
"($help)--default-gateway[Container default gateway IPv4 address]:IPv4 address: " \
"($help)--default-gateway-v6[Container default gateway IPv6 address]:IPv6 address: " \
"($help)--cluster-store=[URL of the distributed storage backend]:Cluster Store:->cluster-store" \
"($help)--cluster-advertise=[Address of the daemon instance to advertise]:Instance to advertise (host\:port): " \
"($help)--cluster-store=-[URL of the distributed storage backend]:Cluster Store:->cluster-store" \
"($help)--cluster-advertise=-[Address of the daemon instance to advertise]:Instance to advertise (host\:port): " \
"($help)*--cluster-store-opt[Set cluster options]:Cluster options:->cluster-store-options" \
"($help)*--dns=[DNS server to use]:DNS: " \
"($help)*--dns-search=[DNS search domains to use]:DNS search: " \
"($help)*--dns-opt=[DNS options to use]:DNS option: " \
"($help)*--default-ulimit=[Set default ulimit settings for containers]:ulimit: " \
"($help)*--dns=-[DNS server to use]:DNS: " \
"($help)*--dns-search=-[DNS search domains to use]:DNS search: " \
"($help)*--dns-opt=-[DNS options to use]:DNS option: " \
"($help)*--default-ulimit=-[Set default ulimit settings for containers]:ulimit: " \
"($help)--disable-legacy-registry[Do not contact legacy registries]" \
"($help -e --exec-driver)"{-e,--exec-driver=}"[Exec driver to use]:driver:(native lxc windows)" \
"($help)*--exec-opt=[Set exec driver options]:exec driver options: " \
"($help)--exec-root=[Root of the Docker execdriver]:path:_directories" \
"($help)--fixed-cidr=[IPv4 subnet for fixed IPs]:IPv4 subnet: " \
"($help)--fixed-cidr-v6=[IPv6 subnet for fixed IPs]:IPv6 subnet: " \
"($help -G --group)"{-G,--group=}"[Group for the unix socket]:group:_groups" \
"($help -g --graph)"{-g,--graph=}"[Root of the Docker runtime]:path:_directories" \
"($help -H --host)"{-H,--host=}"[tcp://host:port to bind/connect to]:host: " \
"($help -e --exec-driver)"{-e,--exec-driver=-}"[Exec driver to use]:driver:(native lxc windows)" \
"($help)*--exec-opt=-[Set exec driver options]:exec driver options: " \
"($help)--exec-root=-[Root of the Docker execdriver]:path:_directories" \
"($help)--fixed-cidr=-[IPv4 subnet for fixed IPs]:IPv4 subnet: " \
"($help)--fixed-cidr-v6=-[IPv6 subnet for fixed IPs]:IPv6 subnet: " \
"($help -G --group)"{-G,--group=-}"[Group for the unix socket]:group:_groups" \
"($help -g --graph)"{-g,--graph=-}"[Root of the Docker runtime]:path:_directories" \
"($help -H --host)"{-H,--host=-}"[tcp://host:port to bind/connect to]:host: " \
"($help)--icc[Enable inter-container communication]" \
"($help)*--insecure-registry=[Enable insecure registry communication]:registry: " \
"($help)--ip=[Default IP when binding container ports]" \
"($help)*--insecure-registry=-[Enable insecure registry communication]:registry: " \
"($help)--ip=-[Default IP when binding container ports]" \
"($help)--ip-forward[Enable net.ipv4.ip_forward]" \
"($help)--ip-masq[Enable IP masquerading]" \
"($help)--iptables[Enable addition of iptables rules]" \
"($help)--ipv6[Enable IPv6 networking]" \
"($help -l --log-level)"{-l,--log-level=}"[Set the logging level]:level:(debug info warn error fatal)" \
"($help)*--label=[Set key=value labels to the daemon]:label: " \
"($help)--log-driver=[Default driver for container logs]:Logging driver:(json-file syslog journald gelf fluentd awslogs none)" \
"($help)*--log-opt=[Log driver specific options]:log driver options: " \
"($help)--mtu=[Set the containers network MTU]:mtu:(0 576 1420 1500 9000)" \
"($help -p --pidfile)"{-p,--pidfile=}"[Path to use for daemon PID file]:PID file:_files" \
"($help)*--registry-mirror=[Preferred Docker registry mirror]:registry mirror: " \
"($help -s --storage-driver)"{-s,--storage-driver=}"[Storage driver to use]:driver:(aufs devicemapper btrfs zfs overlay)" \
"($help -l --log-level)"{-l,--log-level=-}"[Set the logging level]:level:(debug info warn error fatal)" \
"($help)*--label=-[Set key=value labels to the daemon]:label: " \
"($help)--log-driver=-[Default driver for container logs]:Logging driver:(json-file syslog journald gelf fluentd awslogs none)" \
"($help)*--log-opt=-[Log driver specific options]:log driver options: " \
"($help)--mtu=-[Set the containers network MTU]:mtu:(0 576 1420 1500 9000)" \
"($help -p --pidfile)"{-p,--pidfile=-}"[Path to use for daemon PID file]:PID file:_files" \
"($help)*--registry-mirror=-[Preferred Docker registry mirror]:registry mirror: " \
"($help -s --storage-driver)"{-s,--storage-driver=-}"[Storage driver to use]:driver:(aufs devicemapper btrfs zfs overlay)" \
"($help)--selinux-enabled[Enable selinux support]" \
"($help)*--storage-opt=[Set storage driver options]:storage driver options: " \
"($help)*--storage-opt=-[Set storage driver options]:storage driver options: " \
"($help)--tls[Use TLS]" \
"($help)--tlscacert=[Trust certs signed only by this CA]:PEM file:_files -g "*.(pem|crt)"" \
"($help)--tlscert=[Path to TLS certificate file]:PEM file:_files -g "*.(pem|crt)"" \
"($help)--tlskey=[Path to TLS key file]:Key file:_files -g "*.(pem|key)"" \
"($help)--tlscacert=-[Trust certs signed only by this CA]:PEM file:_files -g "*.(pem|crt)"" \
"($help)--tlscert=-[Path to TLS certificate file]:PEM file:_files -g "*.(pem|crt)"" \
"($help)--tlskey=-[Path to TLS key file]:Key file:_files -g "*.(pem|key)"" \
"($help)--tlsverify[Use TLS and verify the remote]" \
"($help)--userland-proxy[Use userland proxy for loopback traffic]" && ret=0
@@ -590,9 +586,9 @@ __docker_subcommand() {
(events)
_arguments \
$opts_help \
"($help)*"{-f,--filter=}"[Filter values]:filter: " \
"($help)--since=[Events created since this timestamp]:timestamp: " \
"($help)--until=[Events created until this timestamp]:timestamp: " && ret=0
"($help)*"{-f,--filter=-}"[Filter values]:filter: " \
"($help)--since=-[Events created since this timestamp]:timestamp: " \
"($help)--until=-[Events created until this timestamp]:timestamp: " && ret=0
;;
(exec)
local state
@@ -602,7 +598,7 @@ __docker_subcommand() {
"($help -i --interactive)"{-i,--interactive}"[Keep stdin open even if not attached]" \
"($help)--privileged[Give extended Linux capabilities to the command]" \
"($help -t --tty)"{-t,--tty}"[Allocate a pseudo-tty]" \
"($help -u --user)"{-u,--user=}"[Username or UID]:user:_users" \
"($help -u --user)"{-u,--user=-}"[Username or UID]:user:_users" \
"($help -):containers:__docker_runningcontainers" \
"($help -)*::command:->anycommand" && ret=0
@@ -617,7 +613,7 @@ __docker_subcommand() {
(export)
_arguments \
$opts_help \
"($help -o --output)"{-o,--output=}"[Write to a file, instead of stdout]:output file:_files" \
"($help -o --output)"{-o,--output=-}"[Write to a file, instead of stdout]:output file:_files" \
"($help -)*:containers:__docker_containers" && ret=0
;;
(history)
@@ -633,7 +629,7 @@ __docker_subcommand() {
$opts_help \
"($help -a --all)"{-a,--all}"[Show all images]" \
"($help)--digest[Show digests]" \
"($help)*"{-f,--filter=}"[Filter values]:filter: " \
"($help)*"{-f,--filter=-}"[Filter values]:filter: " \
"($help)--no-trunc[Do not truncate output]" \
"($help -q --quiet)"{-q,--quiet}"[Only show numeric IDs]" \
"($help -): :__docker_repositories" && ret=0
@@ -641,8 +637,7 @@ __docker_subcommand() {
(import)
_arguments \
$opts_help \
"($help -c --change)*"{-c,--change=}"[Apply Dockerfile instruction to the created image]:Dockerfile:_files" \
"($help -m --message)"{-m,--message=}"[Set commit message for imported image]:message: " \
"($help -c --change)*"{-c,--change=-}"[Apply Dockerfile instruction to the created image]:Dockerfile:_files" \
"($help -):URL:(- http:// file://)" \
"($help -): :__docker_repositories_with_tags" && ret=0
;;
@@ -654,9 +649,9 @@ __docker_subcommand() {
local state
_arguments \
$opts_help \
"($help -f --format)"{-f,--format=}"[Format the output using the given go template]:template: " \
"($help -f --format=-)"{-f,--format=-}"[Format the output using the given go template]:template: " \
"($help -s --size)"{-s,--size}"[Display total file sizes if the type is container]" \
"($help)--type=[Return JSON for specified type]:type:(image container)" \
"($help)--type=-[Return JSON for specified type]:type:(image container)" \
"($help -)*: :->values" && ret=0
case $state in
@@ -674,20 +669,20 @@ __docker_subcommand() {
(kill)
_arguments \
$opts_help \
"($help -s --signal)"{-s,--signal=}"[Signal to send]:signal:_signals" \
"($help -s --signal)"{-s,--signal=-}"[Signal to send]:signal:_signals" \
"($help -)*:containers:__docker_runningcontainers" && ret=0
;;
(load)
_arguments \
$opts_help \
"($help -i --input)"{-i,--input=}"[Read from tar archive file]:archive file:_files -g "*.((tar|TAR)(.gz|.GZ|.Z|.bz2|.lzma|.xz|)|(tbz|tgz|txz))(-.)"" && ret=0
"($help -i --input)"{-i,--input=-}"[Read from tar archive file]:archive file:_files -g "*.((tar|TAR)(.gz|.GZ|.Z|.bz2|.lzma|.xz|)|(tbz|tgz|txz))(-.)"" && ret=0
;;
(login)
_arguments \
$opts_help \
"($help -e --email)"{-e,--email=}"[Email]:email: " \
"($help -p --password)"{-p,--password=}"[Password]:password: " \
"($help -u --user)"{-u,--user=}"[Username]:username: " \
"($help -e --email)"{-e,--email=-}"[Email]:email: " \
"($help -p --password)"{-p,--password=-}"[Password]:password: " \
"($help -u --user)"{-u,--user=-}"[Username]:username: " \
"($help -)1:server: " && ret=0
;;
(logout)
@@ -699,9 +694,9 @@ __docker_subcommand() {
_arguments \
$opts_help \
"($help -f --follow)"{-f,--follow}"[Follow log output]" \
"($help -s --since)"{-s,--since=}"[Show logs since this timestamp]:timestamp: " \
"($help -s --since)"{-s,--since=-}"[Show logs since this timestamp]:timestamp: " \
"($help -t --timestamps)"{-t,--timestamps}"[Show timestamps]" \
"($help)--tail=[Output the last K lines]:lines:(1 10 20 50 all)" \
"($help)--tail=-[Output the last K lines]:lines:(1 10 20 50 all)" \
"($help -)*:containers:__docker_containers" && ret=0
;;
(network)
@@ -736,15 +731,15 @@ __docker_subcommand() {
_arguments \
$opts_help \
"($help -a --all)"{-a,--all}"[Show all containers]" \
"($help)--before=[Show only container created before...]:containers:__docker_containers" \
"($help)*"{-f,--filter=}"[Filter values]:filter: " \
"($help)--before=-[Show only container created before...]:containers:__docker_containers" \
"($help)*"{-f,--filter=-}"[Filter values]:filter: " \
"($help)--format[Pretty-print containers using a Go template]:format: " \
"($help -l --latest)"{-l,--latest}"[Show only the latest created container]" \
"($help)-n[Show n last created containers, include non-running one]:n:(1 5 10 25 50)" \
"($help)--no-trunc[Do not truncate output]" \
"($help -q --quiet)"{-q,--quiet}"[Only show numeric IDs]" \
"($help -s --size)"{-s,--size}"[Display total file sizes]" \
"($help)--since=[Show only containers created since...]:containers:__docker_containers" && ret=0
"($help)--since=-[Show only containers created since...]:containers:__docker_containers" && ret=0
;;
(pull)
_arguments \
@@ -766,7 +761,7 @@ __docker_subcommand() {
(restart|stop)
_arguments \
$opts_help \
"($help -t --time)"{-t,--time=}"[Number of seconds to try to stop for before killing the container]:seconds to before killing:(1 5 10 30 60)" \
"($help -t --time=-)"{-t,--time=-}"[Number of seconds to try to stop for before killing the container]:seconds to before killing:(1 5 10 30 60)" \
"($help -)*:containers:__docker_runningcontainers" && ret=0
;;
(rm)
@@ -792,7 +787,7 @@ __docker_subcommand() {
"($help -d --detach)"{-d,--detach}"[Detached mode: leave the container running in the background]" \
"($help)--rm[Remove intermediate containers when it exits]" \
"($help)--sig-proxy[Proxy all received signals to the process (non-TTY mode only)]" \
"($help)--stop-signal=[Signal to kill a container]:signal:_signals" \
"($help)--stop-signal=-[Signal to kill a container]:signal:_signals" \
"($help -): :__docker_images" \
"($help -):command: _command_names -e" \
"($help -)*::arguments: _normal" && ret=0
@@ -811,7 +806,7 @@ __docker_subcommand() {
(save)
_arguments \
$opts_help \
"($help -o --output)"{-o,--output=}"[Write to file]:file:_files" \
"($help -o --output)"{-o,--output=-}"[Write to file]:file:_files" \
"($help -)*: :__docker_images" && ret=0
;;
(search)
@@ -819,7 +814,7 @@ __docker_subcommand() {
$opts_help \
"($help)--automated[Only show automated builds]" \
"($help)--no-trunc[Do not truncate output]" \
"($help -s --stars)"{-s,--stars=}"[Only display with at least X stars]:stars:(0 10 100 1000)" \
"($help -s --stars)"{-s,--stars=-}"[Only display with at least X stars]:stars:(0 10 100 1000)" \
"($help -):term: " && ret=0
;;
(start)
@@ -900,12 +895,12 @@ _docker() {
"(: -)"{-h,--help}"[Print usage]" \
"($help)--config[Location of client config files]:path:_directories" \
"($help -D --debug)"{-D,--debug}"[Enable debug mode]" \
"($help -H --host)"{-H,--host=}"[tcp://host:port to bind/connect to]:host: " \
"($help -l --log-level)"{-l,--log-level=}"[Set the logging level]:level:(debug info warn error fatal)" \
"($help -H --host)"{-H,--host=-}"[tcp://host:port to bind/connect to]:host: " \
"($help -l --log-level)"{-l,--log-level=-}"[Set the logging level]:level:(debug info warn error fatal)" \
"($help)--tls[Use TLS]" \
"($help)--tlscacert=[Trust certs signed only by this CA]:PEM file:_files -g "*.(pem|crt)"" \
"($help)--tlscert=[Path to TLS certificate file]:PEM file:_files -g "*.(pem|crt)"" \
"($help)--tlskey=[Path to TLS key file]:Key file:_files -g "*.(pem|key)"" \
"($help)--tlscacert=-[Trust certs signed only by this CA]:PEM file:_files -g "*.(pem|crt)"" \
"($help)--tlscert=-[Path to TLS certificate file]:PEM file:_files -g "*.(pem|crt)"" \
"($help)--tlskey=-[Path to TLS key file]:Key file:_files -g "*.(pem|key)"" \
"($help)--tlsverify[Use TLS and verify the remote]" \
"($help)--userland-proxy[Use userland proxy for loopback traffic]" \
"($help -v --version)"{-v,--version}"[Print version information and quit]" \
+720
View File
@@ -0,0 +1,720 @@
// +build linux
package clr
import (
"fmt"
"io"
"io/ioutil"
"math"
"net"
"net/http"
"os"
"os/exec"
"path"
"strconv"
"strings"
"sync"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/pkg/mount"
sysinfo "github.com/docker/docker/pkg/system"
"github.com/docker/docker/pkg/term"
"github.com/docker/libnetwork/netlabel"
"github.com/kr/pty"
"github.com/opencontainers/runc/libcontainer/configs"
)
const (
// Clear Linux for Intel(R) Architecture
driverName = "clr"
envVarPrefix = "CLR_"
// Command used for lkvm control
lkvmName = "lkvm"
// local "latest" information
clrFile = "latest"
// upstream base URL
clrURL = "https://download.clearlinux.org"
// upstream latest release file
latestFile = "https://download.clearlinux.org/latest"
// clr kernel (not bzimage)
clrKernel = "/usr/lib/kernel/vmlinux.container"
)
type driver struct {
root string // root path for the driver to use
libPath string
initPath string
version string
apparmor bool
sharedRoot bool
activeContainers map[string]*activeContainer
machineMemory int64
containerPid int
sync.Mutex
}
type activeContainer struct {
container *configs.Config
cmd *exec.Cmd
}
func getTapIf(c *execdriver.Command) string {
return fmt.Sprintf("tb-%s", c.ID[:12])
}
func getClrVersion(libPath string) string {
txt, err := ioutil.ReadFile(path.Join(libPath, clrFile))
if err != nil {
return ""
}
return strings.Split(string(txt), "\n")[0]
}
func fetchLatest(libPath string) error {
out, err := os.Create(path.Join(libPath, clrFile))
if err != nil {
return err
}
defer out.Close()
resp, err := http.Get(latestFile)
if err != nil {
return err
}
defer resp.Body.Close()
_, err = io.Copy(out, resp.Body)
return err
}
func fetchImage(version, libPath string) error {
// TODO: Add checksum validation
outfile := fmt.Sprintf("clear-%s-containers.img.xz", version)
url := fmt.Sprintf("%s/releases/%s/clear/%s", clrURL, version, outfile)
outpath := path.Join(libPath, outfile)
var output []byte
logrus.Debugf("Fetching clr version: %s, %s", version, outpath)
out, err := os.Create(outpath)
if err != nil {
return err
}
defer out.Close()
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
// Consider progress feedback ?
_, err = io.Copy(out, resp.Body)
if err != nil {
return err
}
// decompress the file
cmd := exec.Command("unxz", outpath)
cmd.Dir = libPath
if output, err = cmd.CombinedOutput(); err != nil {
logrus.Debugf("Unable to extract image %s: %s", version, output)
return err
}
return nil
}
// NewDriver creates a new clear linux execution driver.
func NewDriver(root, libPath, initPath string, apparmor bool) (*driver, error) {
if err := os.MkdirAll(root, 0700); err != nil {
return nil, err
}
meminfo, err := sysinfo.ReadMemInfo()
if err != nil {
return nil, err
}
version, err := prepareClr(libPath)
if err != nil {
return nil, err
}
return &driver{
apparmor: apparmor,
root: root,
libPath: libPath,
initPath: initPath,
version: version,
sharedRoot: false,
activeContainers: make(map[string]*activeContainer),
// FIXME:
machineMemory: meminfo.MemTotal,
}, nil
}
func prepareClr(libPath string) (string, error) {
var version = getClrVersion(libPath)
var nversion string
logrus.Debugf("%s preparing environment", driverName)
err := fetchLatest(libPath)
if err != nil {
return "", err
}
nversion = getClrVersion(libPath)
if nversion != version && version != "" {
logrus.Debugf("Updating to clr version: %s", nversion)
err = fetchImage(nversion, libPath)
} else if version == "" {
logrus.Debugf("Installing clr version: %s", nversion)
err = fetchImage(nversion, libPath)
} else {
logrus.Debugf("Using clr version: %s", nversion)
}
return nversion, nil
}
func (d *driver) Name() string {
return fmt.Sprintf("%s-%s", driverName, d.version)
}
func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
var (
term execdriver.Terminal
err error
)
container, err := d.createContainer(c)
if err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
memoryMiB := c.HostConfig.Memory
if memoryMiB == 0 {
memoryMiB = 1024
} else {
// docker passes the value as bytes
memoryMiB = memoryMiB / int64(math.Pow(2, 20))
}
workingDirVar := fmt.Sprintf("%s%s=%q", envVarPrefix, "WORKINGDIR", c.WorkingDir)
c.ProcessConfig.Cmd.Env = append(c.ProcessConfig.Cmd.Env, workingDirVar)
userVar := fmt.Sprintf("%s%s=%q", envVarPrefix, "USER", c.ProcessConfig.User)
c.ProcessConfig.Cmd.Env = append(c.ProcessConfig.Cmd.Env, userVar)
if err := d.setupNetwork(c); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
if c.ProcessConfig.Tty {
term, err = NewTtyConsole(&c.ProcessConfig, pipes)
} else {
term, err = execdriver.NewStdConsole(&c.ProcessConfig, pipes)
}
if err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
c.ProcessConfig.Terminal = term
d.Lock()
d.activeContainers[c.ID] = &activeContainer{
container: container,
cmd: &c.ProcessConfig.Cmd,
}
d.Unlock()
if err := d.generateEnvConfig(c); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
if err := d.generateDockerInit(c); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
for _, m := range c.Mounts {
dest := path.Join(c.Rootfs, m.Destination)
if m.Destination == "/etc/hostname" {
continue
}
if !pathExists(m.Source) {
continue
}
opts := "bind"
if m.Private {
opts = opts + ",rprivate"
}
if m.Slave {
opts = opts + ",rslave"
}
// This may look racy, but it isn't since the VM isn't
// running yet.
//
// The check is necessary to handle bind mounting of
// regular files correctly since without it we may be
// attempting to create a directory where there already
// exists a normal file.
if !pathExists(dest) {
if err := os.MkdirAll(dest, 0750); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
}
if err := mount.Mount(m.Source, dest, "", opts); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
if !m.Writable {
if err := mount.Mount("", dest, "", "bind,remount,ro"); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
}
defer mount.Unmount(dest)
}
var args []string
// various things for lkvm
ifname := getTapIf(c)
// FIXME: Should be real hostname from like process/container struct
hostname := c.ID[0:12]
img := fmt.Sprintf("%s/clear-%s-containers.img", d.libPath, d.version)
memory := fmt.Sprintf("%d", memoryMiB)
// FIXME: Locked cores to 6 ?
cores := fmt.Sprintf("%d", 6)
ipaddr := c.NetworkSettings.IPAddress
gateway := c.NetworkSettings.Gateway
macaddr := c.NetworkSettings.MacAddress
args = append(args, c.ProcessConfig.Entrypoint)
args = append(args, c.ProcessConfig.Arguments...)
rootParams := fmt.Sprintf("root=/dev/plkvm0p1 rootfstype=ext4 rootflags=dax,data=ordered "+
"init=/usr/lib/systemd/systemd systemd.unit=container.target rw tsc=reliable "+
"systemd.show_status=false "+
"no_timer_check rcupdate.rcu_expedited=1 console=hvc0 quiet ip=%s::%s::%s::off",
ipaddr, gateway, hostname)
params := []string{
lkvmName, "run", "-c", cores, "-m", memory,
"--name", c.ID, "--console", "virtio",
"--kernel", clrKernel,
"--params", rootParams,
"--shmem", fmt.Sprintf("0x200000000:0:file=%s:private", img),
"--network", fmt.Sprintf("mode=tap,script=none,tapif=%s,guest_mac=%s", ifname, macaddr),
"--9p", fmt.Sprintf("%s,rootfs", c.Rootfs),
}
logrus.Debugf("%s params %s", driverName, params)
var (
name = params[0]
arg = params[1:]
)
aname, err := exec.LookPath(name)
if err != nil {
aname = name
}
c.ProcessConfig.Path = aname
c.ProcessConfig.Args = append([]string{name}, arg...)
c.ProcessConfig.Env = []string{fmt.Sprintf("HOME=%s", d.root)}
// Start the container. Since it runs synchronously, we don't Wait()
// for it since we need to check the status to determine if it did
// actually start successfully.
if err := c.ProcessConfig.Start(); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
var (
waitErr error
waitLock = make(chan struct{})
)
go func() {
if err := c.ProcessConfig.Wait(); err != nil {
if _, ok := err.(*exec.ExitError); !ok { // Do not propagate the error if it's simply a status code != 0
waitErr = err
}
}
close(waitLock)
}()
// FIXME: need to create state.json for Stats() to work.
c.ContainerPid = c.ProcessConfig.Process.Pid
d.containerPid = c.ProcessConfig.Process.Pid
// FIXME:
oomKill := false
// Wait for the VM to shutdown
<-waitLock
exitCode := getExitCode(c)
cExitStatus, cerr := d.cleanupVM(c)
if cerr != nil {
waitErr = cerr
exitCode = cExitStatus
}
// check oom error
if oomKill {
exitCode = 137
}
return execdriver.ExitStatus{ExitCode: exitCode, OOMKilled: false}, waitErr
}
func pathExists(path string) bool {
if _, err := os.Stat(path); err == nil {
return true
}
return false
}
func pathExecutable(path string) bool {
s, err := os.Stat(path)
if err != nil {
return false
}
mode := s.Mode()
if mode&0111 != 0 {
return true
}
return false
}
func (d *driver) cleanupVM(c *execdriver.Command) (exitStatus int, err error) {
cmd := exec.Command("ip", "tuntap", "del", "dev", getTapIf(c), "mode", "tap")
var output []byte
if output, err = cmd.CombinedOutput(); err != nil {
if exitError, ok := err.(*exec.ExitError); ok {
waitStatus := exitError.Sys().(syscall.WaitStatus)
exitStatus = waitStatus.ExitStatus()
}
logrus.Debugf("teardown failed for vm %s: %s (%s)", c.ID, string(output), err.Error())
}
// doesn't matter if this fails
// lkvm could have removed it, and stale sockets are not fatal
_ = os.Remove(fmt.Sprintf("%s/.lkvm/%s.sock", d.root, c.ID))
return exitStatus, err
}
// createContainer populates and configures the container type with the
// data provided by the execdriver.Command
func (d *driver) createContainer(c *execdriver.Command) (*configs.Config, error) {
return execdriver.InitContainer(c), nil
}
/// Return the exit code of the process
// if the process has not exited -1 will be returned
func getExitCode(c *execdriver.Command) int {
if c.ProcessConfig.ProcessState == nil {
return -1
}
return c.ProcessConfig.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
}
func (d *driver) lkvmCommand(c *execdriver.Command, arg string) ([]byte, error) {
args := append([]string{lkvmName}, arg)
if c != nil {
args = append(args, "--name", c.ID)
}
cmd := exec.Command(lkvmName, args...)
cmd.Env = []string{fmt.Sprintf("HOME=%s", d.root)}
return cmd.Output()
}
// Kill sends a signal to workload
func (d *driver) Kill(c *execdriver.Command, sig int) error {
// Not supported
return nil
}
func (d *driver) Pause(c *execdriver.Command) error {
_, err := d.lkvmCommand(c, "pause")
return err
}
func (d *driver) Unpause(c *execdriver.Command) error {
_, err := d.lkvmCommand(c, "resume")
return err
}
// Terminate forcibly stops a container
func (d *driver) Terminate(c *execdriver.Command) error {
_, err := d.lkvmCommand(c, "stop")
return err
}
func (d *driver) containerDir(containerID string) string {
return path.Join(d.libPath, "containers", containerID)
}
// isDigit returns true if s can be represented as an integer
func isDigit(s string) bool {
if _, err := strconv.Atoi(s); err == nil {
return true
}
return false
}
func (d *driver) getInfo(id string) ([]byte, error) {
output, err := d.lkvmCommand(nil, "list")
if err != nil {
return nil, err
}
for i, line := range strings.Split(string(output), "\n") {
if i < 2 {
continue
}
fields := strings.Fields(strings.TrimSpace(line))
if len(fields) != 3 {
continue
}
if !isDigit(fields[0]) {
continue
}
if fields[1] != id {
continue
}
return []byte(line), nil
}
return []byte(fmt.Sprintf("-1 %s stopped", id)), nil
}
type info struct {
ID string
driver *driver
}
func (i *info) IsRunning() bool {
output, err := i.driver.getInfo(i.ID)
if err != nil {
logrus.Errorf("Error getting info for %s container %s: %s (%s)",
driverName, i.ID, err, output)
return false
}
clrInfo, err := parseClrInfo(i.ID, string(output))
if err != nil {
return false
}
return clrInfo.Running
}
func (d *driver) Info(id string) execdriver.Info {
return &info{
ID: id,
driver: d,
}
}
func (d *driver) GetPidsForContainer(id string) ([]int, error) {
// The VM doesn't expose the worload pid(s), so the only meaningful
// pid is that of the VM
return []int{d.containerPid}, nil
}
// TtyConsole is a type to represent a pseud-oterminal (see pty(7))
type TtyConsole struct {
MasterPty *os.File
SlavePty *os.File
}
// NewTtyConsole returns a new TtyConsole object.
func NewTtyConsole(processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes) (*TtyConsole, error) {
// lxc is special in that we cannot create the master outside of the container without
// opening the slave because we have nothing to provide to the cmd. We have to open both then do
// the crazy setup on command right now instead of passing the console path to lxc and telling it
// to open up that console. we save a couple of openfiles in the native driver because we can do
// this.
ptyMaster, ptySlave, err := pty.Open()
if err != nil {
return nil, err
}
tty := &TtyConsole{
MasterPty: ptyMaster,
SlavePty: ptySlave,
}
if err := tty.AttachPipes(&processConfig.Cmd, pipes); err != nil {
tty.Close()
return nil, err
}
processConfig.Console = tty.SlavePty.Name()
return tty, nil
}
// Master returns the master end of the pty
func (t *TtyConsole) Master() *os.File {
return t.MasterPty
}
// Resize modifies the size of the pty terminal being used.
func (t *TtyConsole) Resize(h, w int) error {
return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
}
// AttachPipes associates the specified pipes with the pty master.
func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) error {
command.Stdout = t.SlavePty
command.Stderr = t.SlavePty
go func() {
if wb, ok := pipes.Stdout.(interface {
CloseWriters() error
}); ok {
defer wb.CloseWriters()
}
io.Copy(pipes.Stdout, t.MasterPty)
}()
if pipes.Stdin != nil {
command.Stdin = t.SlavePty
command.SysProcAttr.Setctty = true
go func() {
io.Copy(t.MasterPty, pipes.Stdin)
pipes.Stdin.Close()
}()
}
return nil
}
// Close closes both ends of the pty.
func (t *TtyConsole) Close() error {
t.SlavePty.Close()
return t.MasterPty.Close()
}
func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
return -1, fmt.Errorf("Unsupported: Exec is not supported by the %q driver", driverName)
}
// Clean up after an Exec
func (d *driver) Clean(id string) error {
return nil
}
func (d *driver) generateEnvConfig(c *execdriver.Command) error {
data := []byte(strings.Join(c.ProcessConfig.Env, "\n"))
p := path.Join(d.libPath, "containers", c.ID, "config.env")
c.Mounts = append(c.Mounts, execdriver.Mount{
Source: p,
Destination: "/.dockerenv",
Writable: false,
Private: true,
})
return ioutil.WriteFile(p, data, 0600)
}
func (d *driver) generateDockerInit(c *execdriver.Command) error {
p := fmt.Sprintf("%s/.containerexec", c.Rootfs)
var args []string
if pathExecutable(p) {
return nil
}
args = append(args, c.ProcessConfig.Entrypoint)
args = append(args, c.ProcessConfig.Arguments...)
data := []byte(fmt.Sprintf("#!/bin/sh\n%s\n", strings.Join(args, " ")))
return ioutil.WriteFile(p, data, 0755)
}
func (d *driver) setupNetwork(c *execdriver.Command) error {
ifname := getTapIf(c)
var bridgeName string
var bridgeLinkName string
var output []byte
var err error
for _, info := range c.EndpointInfo {
if mac, ok := info[netlabel.MacAddress].(net.HardwareAddr); ok {
if mac.String() == c.NetworkSettings.MacAddress {
bridgeName = info[netlabel.BridgeName].(string)
bridgeLinkName = info[netlabel.BridgeLinkName].(string)
}
}
}
// Strip existing veth
cmd := exec.Command("ip", "link", "del", bridgeLinkName)
if output, err = cmd.CombinedOutput(); err != nil {
logrus.Debugf("%s setupNetwork error: %v, %s", driverName, cmd.Args, output)
return err
}
cmd = exec.Command("ip", "tuntap", "add", "dev", ifname, "mode", "tap", "vnet_hdr")
if output, err = cmd.CombinedOutput(); err != nil {
logrus.Debugf("%s setupNetwork error: %v, %s", driverName, cmd.Args, output)
return err
}
cmd = exec.Command("ip", "link", "set", "dev", ifname, "master", bridgeName)
if output, err = cmd.CombinedOutput(); err != nil {
logrus.Debugf("%s setupNetwork error: %v, %s", driverName, cmd.Args, output)
return err
}
cmd = exec.Command("ip", "link", "set", "dev", ifname, "up")
if output, err = cmd.CombinedOutput(); err != nil {
logrus.Debugf("%s setupNetwork error: %v, %s", driverName, cmd.Args, output)
return err
}
return err
}
func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) {
if _, ok := d.activeContainers[id]; !ok {
return nil, fmt.Errorf("%s is not a key in active containers", id)
}
// FIXME:
return execdriver.Stats(d.containerDir(id), d.activeContainers[id].container.Cgroups.Memory, d.machineMemory)
}
func (d *driver) SupportsHooks() bool {
return false
}
+51
View File
@@ -0,0 +1,51 @@
// +build linux
package clr
import (
"errors"
"strconv"
"strings"
)
var (
ErrCannotParse = errors.New("cannot parse raw input")
)
type clrInfo struct {
Running bool
Pid int
}
func parseClrInfo(name, raw string) (*clrInfo, error) {
if raw == "" {
return nil, ErrCannotParse
}
var (
err error
info = &clrInfo{}
)
fields := strings.Fields(strings.TrimSpace(raw))
// The format is expected to be:
//
// <pid> <name> <state>
//
if len(fields) != 3 {
return nil, ErrCannotParse
}
info.Pid, err = strconv.Atoi(fields[0])
if err != nil {
return nil, ErrCannotParse
}
if fields[1] != name {
return nil, ErrCannotParse
}
info.Running = fields[2] == "running"
return info, nil
}
+97
View File
@@ -0,0 +1,97 @@
// +build linux
package clr
import (
"encoding/json"
"flag"
"fmt"
"os"
"strings"
"syscall"
)
// Args provided to the init function for a driver
type InitArgs struct {
User string
Gateway string
Ip string
WorkDir string
Privileged bool
Env []string
Args []string
Mtu int
Console string
Pipe int
Root string
CapAdd string
CapDrop string
}
func getArgs() *InitArgs {
var (
// Get cmdline arguments
user = flag.String("u", "", "username or uid")
gateway = flag.String("g", "", "gateway address")
ip = flag.String("i", "", "ip address")
workDir = flag.String("w", "", "workdir")
privileged = flag.Bool("privileged", false, "privileged mode")
mtu = flag.Int("mtu", 1500, "interface mtu")
capAdd = flag.String("cap-add", "", "capabilities to add")
capDrop = flag.String("cap-drop", "", "capabilities to drop")
)
flag.Parse()
return &InitArgs{
User: *user,
Gateway: *gateway,
Ip: *ip,
WorkDir: *workDir,
Privileged: *privileged,
Args: flag.Args(),
Mtu: *mtu,
CapAdd: *capAdd,
CapDrop: *capDrop,
}
}
// Clear environment pollution introduced by lxc-start
func setupEnv(args *InitArgs) error {
// Get env
var env []string
dockerenv, err := os.Open(".dockerenv")
if err != nil {
return fmt.Errorf("Unable to load environment variables: %v", err)
}
defer dockerenv.Close()
if err := json.NewDecoder(dockerenv).Decode(&env); err != nil {
return fmt.Errorf("Unable to decode environment variables: %v", err)
}
// Propagate the plugin-specific container env variable
env = append(env, "container="+os.Getenv("container"))
args.Env = env
os.Clearenv()
for _, kv := range args.Env {
parts := strings.SplitN(kv, "=", 2)
if len(parts) == 1 {
parts = append(parts, "")
}
os.Setenv(parts[0], parts[1])
}
return nil
}
// Setup working directory
func setupWorkingDirectory(args *InitArgs) error {
if args.WorkDir == "" {
return nil
}
if err := syscall.Chdir(args.WorkDir); err != nil {
return fmt.Errorf("Unable to change dir to %v: %v", args.WorkDir, err)
}
return nil
}
+6
View File
@@ -8,7 +8,9 @@ import (
"github.com/docker/docker/pkg/idtools"
// TODO Windows: Factor out ulimit
"github.com/docker/docker/daemon/network"
"github.com/docker/docker/pkg/ulimit"
"github.com/docker/docker/runconfig"
"github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/runc/libcontainer/configs"
)
@@ -230,4 +232,8 @@ type Command struct {
LayerPaths []string `json:"layer_paths"` // Windows needs to know the layer paths and folder for a command
LayerFolder string `json:"layer_folder"`
Hostname string `json:"hostname"` // Windows sets the hostname in the execdriver
NetworkSettings *network.Settings `json:"network_settings"`
EndpointInfo []map[string]interface{} `json:"endpoint_info"`
HostConfig *runconfig.HostConfig `json:"hostconfig"`
}
@@ -8,6 +8,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/daemon/execdriver/clr"
"github.com/docker/docker/daemon/execdriver/lxc"
"github.com/docker/docker/daemon/execdriver/native"
"github.com/docker/docker/pkg/sysinfo"
@@ -15,7 +16,10 @@ import (
// NewDriver returns a new execdriver.Driver from the given name configured with the provided options.
func NewDriver(name string, options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
rootPath := path.Join(root, "execdriver", name)
switch name {
case "clr":
return clr.NewDriver(rootPath, libPath, initPath, sysInfo.AppArmor)
case "lxc":
// we want to give the lxc driver the full docker root because it needs
// to access and write config and template files in /var/lib/docker/containers/*
@@ -23,7 +27,7 @@ func NewDriver(name string, options []string, root, libPath, initPath string, sy
logrus.Warn("LXC built-in support is deprecated.")
return lxc.NewDriver(root, libPath, initPath, sysInfo.AppArmor)
case "native":
return native.NewDriver(path.Join(root, "execdriver", "native"), initPath, options)
return native.NewDriver(rootPath, initPath, options)
}
return nil, fmt.Errorf("unknown exec driver %s", name)
}
+11 -25
View File
@@ -324,20 +324,24 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
c.ContainerPid = pid
oomKill := false
oomKillNotification, err := notifyOnOOM(cgroupPaths)
if hooks.Start != nil {
logrus.Debugf("Invoking startCallback")
chOOM := make(chan struct{})
close(chOOM)
hooks.Start(&c.ProcessConfig, pid, chOOM)
}
hooks.Start(&c.ProcessConfig, pid, oomKillNotification)
oomKillNotification := notifyChannelOOM(cgroupPaths)
}
<-waitLock
exitCode := getExitCode(c)
_, oomKill := <-oomKillNotification
logrus.Debugf("oomKill error: %v, waitErr: %v", oomKill, waitErr)
if err == nil {
_, oomKill = <-oomKillNotification
logrus.Debugf("oomKill error: %v, waitErr: %v", oomKill, waitErr)
} else {
logrus.Warnf("Your kernel does not support OOM notifications: %s", err)
}
// check oom error
if oomKill {
@@ -347,17 +351,6 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
return execdriver.ExitStatus{ExitCode: exitCode, OOMKilled: oomKill}, waitErr
}
func notifyChannelOOM(paths map[string]string) <-chan struct{} {
oom, err := notifyOnOOM(paths)
if err != nil {
logrus.Warnf("Your kernel does not support OOM notifications: %s", err)
c := make(chan struct{})
close(c)
return c
}
return oom
}
// copy from libcontainer
func notifyOnOOM(paths map[string]string) (<-chan struct{}, error) {
dir := paths["memory"]
@@ -393,13 +386,11 @@ func notifyOnOOM(paths map[string]string) (<-chan struct{}, error) {
buf := make([]byte, 8)
for {
if _, err := eventfd.Read(buf); err != nil {
logrus.Warn(err)
return
}
// When a cgroup is destroyed, an event is sent to eventfd.
// So if the control path is gone, return instead of notifying.
if _, err := os.Lstat(eventControlPath); os.IsNotExist(err) {
logrus.Warn(err)
return
}
ch <- struct{}{}
@@ -433,11 +424,6 @@ func cgroupPaths(containerID string) (map[string]string, error) {
//unsupported subystem
continue
}
// if we are running dind
dockerPathIdx := strings.LastIndex(cgroupDir, "docker")
if dockerPathIdx != -1 {
cgroupDir = cgroupDir[:dockerPathIdx-1]
}
path := filepath.Join(cgroupRoot, cgroupDir, "lxc", containerID)
paths[subsystem] = path
}
+12 -2
View File
@@ -91,9 +91,9 @@ lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabS
{{if .Resources}}
{{if .Resources.Memory}}
lxc.cgroup.memory.limit_in_bytes = {{.Resources.Memory}}
{{with $memSwap := getMemorySwap .Resources}}
lxc.cgroup.memory.memsw.limit_in_bytes = {{$memSwap}}
{{end}}
{{if gt .Resources.MemorySwap 0}}
lxc.cgroup.memory.memsw.limit_in_bytes = {{.Resources.MemorySwap}}
{{end}}
{{if gt .Resources.MemoryReservation 0}}
lxc.cgroup.memory.soft_limit_in_bytes = {{.Resources.MemoryReservation}}
@@ -209,6 +209,15 @@ func isDirectory(source string) string {
return "file"
}
func getMemorySwap(v *execdriver.Resources) int64 {
// By default, MemorySwap is set to twice the size of RAM.
// If you want to omit MemorySwap, set it to `-1'.
if v.MemorySwap < 0 {
return 0
}
return v.Memory * 2
}
func getLabel(c map[string][]string, name string) string {
label := c["label"]
for _, l := range label {
@@ -233,6 +242,7 @@ func getHostname(env []string) string {
func init() {
var err error
funcMap := template.FuncMap{
"getMemorySwap": getMemorySwap,
"escapeFstabSpaces": escapeFstabSpaces,
"formatMountLabel": label.FormatMountLabel,
"isDirectory": isDirectory,
@@ -34,7 +34,6 @@ func TestLXCConfig(t *testing.T) {
memMin = 33554432
memMax = 536870912
mem = memMin + r.Intn(memMax-memMin)
swap = memMax
cpuMin = 100
cpuMax = 10000
cpu = cpuMin + r.Intn(cpuMax-cpuMin)
@@ -47,9 +46,8 @@ func TestLXCConfig(t *testing.T) {
command := &execdriver.Command{
ID: "1",
Resources: &execdriver.Resources{
Memory: int64(mem),
MemorySwap: int64(swap),
CPUShares: int64(cpu),
Memory: int64(mem),
CPUShares: int64(cpu),
},
Network: &execdriver.Network{
Mtu: 1500,
@@ -65,7 +63,7 @@ func TestLXCConfig(t *testing.T) {
fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem))
grepFile(t, p,
fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", swap))
fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", mem*2))
}
func TestCustomLxcConfig(t *testing.T) {
+1
View File
@@ -167,6 +167,7 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
oom := notifyOnOOM(cont)
if hooks.Start != nil {
pid, err := p.Pid()
if err != nil {
p.Signal(os.Kill)
+4 -8
View File
@@ -18,7 +18,6 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo
term execdriver.Terminal
err error
exitCode int32
errno uint32
)
active := d.activeContainers[c.ID]
@@ -78,15 +77,12 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo
hooks.Start(&c.ProcessConfig, int(pid), chOOM)
}
if exitCode, errno, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid, hcsshim.TimeoutInfinite); err != nil {
if errno == hcsshim.Win32PipeHasBeenEnded {
logrus.Debugf("Exiting Run() after WaitForProcessInComputeSystem failed with recognised error 0x%X", errno)
return hcsshim.WaitErrExecFailed, nil
}
logrus.Warnf("WaitForProcessInComputeSystem failed (container may have been killed): 0x%X %s", errno, err)
if exitCode, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid); err != nil {
logrus.Errorf("Failed to WaitForProcessInComputeSystem %s", err)
return -1, err
}
logrus.Debugln("Exiting Run()", c.ID)
// TODO Windows - Do something with this exit code
logrus.Debugln("Exiting Run() with ExitCode 0", c.ID)
return int(exitCode), nil
}
+2 -11
View File
@@ -3,7 +3,6 @@
package windows
import (
"fmt"
"io"
"github.com/Sirupsen/logrus"
@@ -23,11 +22,7 @@ func startStdinCopy(dst io.WriteCloser, src io.Reader) {
go func() {
defer dst.Close()
bytes, err := io.Copy(dst, src)
log := fmt.Sprintf("Copied %d bytes from stdin.", bytes)
if err != nil {
log = log + " err=" + err.Error()
}
logrus.Debugf(log)
logrus.Debugf("Copied %d bytes from stdin err=%s", bytes, err)
}()
}
@@ -40,11 +35,7 @@ func startStdouterrCopy(dst io.Writer, src io.ReadCloser, name string) {
go func() {
defer src.Close()
bytes, err := io.Copy(dst, src)
log := fmt.Sprintf("Copied %d bytes from %s.", bytes, name)
if err != nil {
log = log + " err=" + err.Error()
}
logrus.Debugf(log)
logrus.Debugf("Copied %d bytes from %s err=%s", bytes, name, err)
}()
}
+17 -23
View File
@@ -220,19 +220,22 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
}
defer func() {
// Stop the container
if forceKill {
logrus.Debugf("Forcibly terminating container %s", c.ID)
if errno, err := hcsshim.TerminateComputeSystem(c.ID, hcsshim.TimeoutInfinite, "exec-run-defer"); err != nil {
logrus.Warnf("Ignoring error from TerminateComputeSystem 0x%X %s", errno, err)
if terminateMode {
logrus.Debugf("Terminating container %s", c.ID)
if err := hcsshim.TerminateComputeSystem(c.ID); err != nil {
// IMPORTANT: Don't fail if fails to change state. It could already
// have been stopped through kill().
// Otherwise, the docker daemon will hang in job wait()
logrus.Warnf("Ignoring error from TerminateComputeSystem %s", err)
}
} else {
logrus.Debugf("Shutting down container %s", c.ID)
if errno, err := hcsshim.ShutdownComputeSystem(c.ID, hcsshim.TimeoutInfinite, "exec-run-defer"); err != nil {
if errno != hcsshim.Win32SystemShutdownIsInProgress &&
errno != hcsshim.Win32SpecifiedPathInvalid &&
errno != hcsshim.Win32SystemCannotFindThePathSpecified {
logrus.Warnf("Ignoring error from ShutdownComputeSystem 0x%X %s", errno, err)
}
if err := hcsshim.ShutdownComputeSystem(c.ID); err != nil {
// IMPORTANT: Don't fail if fails to change state. It could already
// have been stopped through kill().
// Otherwise, the docker daemon will hang in job wait()
logrus.Warnf("Ignoring error from ShutdownComputeSystem %s", err)
}
}
}()
@@ -300,20 +303,11 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
hooks.Start(&c.ProcessConfig, int(pid), chOOM)
}
var (
exitCode int32
errno uint32
)
exitCode, errno, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid, hcsshim.TimeoutInfinite)
var exitCode int32
exitCode, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid)
if err != nil {
if errno != hcsshim.Win32PipeHasBeenEnded {
logrus.Warnf("WaitForProcessInComputeSystem failed (container may have been killed): %s", err)
}
// Do NOT return err here as the container would have
// started, otherwise docker will deadlock. It's perfectly legitimate
// for WaitForProcessInComputeSystem to fail in situations such
// as the container being killed on another thread.
return execdriver.ExitStatus{ExitCode: hcsshim.WaitErrExecFailed}, nil
logrus.Errorf("Failed to WaitForProcessInComputeSystem %s", err)
return execdriver.ExitStatus{ExitCode: -1}, err
}
logrus.Debugf("Exiting Run() exitCode %d id=%s", exitCode, c.ID)
+18 -20
View File
@@ -3,9 +3,6 @@
package windows
import (
"fmt"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/execdriver"
"github.com/microsoft/hcsshim"
@@ -13,36 +10,37 @@ import (
// Terminate implements the exec driver Driver interface.
func (d *Driver) Terminate(p *execdriver.Command) error {
return kill(p.ID, p.ContainerPid, syscall.SIGTERM)
logrus.Debugf("WindowsExec: Terminate() id=%s", p.ID)
return kill(p.ID, p.ContainerPid)
}
// Kill implements the exec driver Driver interface.
func (d *Driver) Kill(p *execdriver.Command, sig int) error {
return kill(p.ID, p.ContainerPid, syscall.Signal(sig))
logrus.Debugf("WindowsExec: Kill() id=%s sig=%d", p.ID, sig)
return kill(p.ID, p.ContainerPid)
}
func kill(id string, pid int, sig syscall.Signal) error {
logrus.Debugf("WindowsExec: kill() id=%s pid=%d sig=%d", id, pid, sig)
func kill(id string, pid int) error {
logrus.Debugln("kill() ", id, pid)
var err error
context := fmt.Sprintf("kill: sig=%d pid=%d", sig, pid)
if sig == syscall.SIGKILL || forceKill {
// Terminate Process
if err = hcsshim.TerminateProcessInComputeSystem(id, uint32(pid)); err != nil {
logrus.Warnf("Failed to terminate pid %d in %s: %q", pid, id, err)
// Ignore errors
err = nil
}
if terminateMode {
// Terminate the compute system
if errno, err := hcsshim.TerminateComputeSystem(id, hcsshim.TimeoutInfinite, context); err != nil {
logrus.Errorf("Failed to terminate %s - 0x%X %q", id, errno, err)
if err = hcsshim.TerminateComputeSystem(id); err != nil {
logrus.Errorf("Failed to terminate %s - %q", id, err)
}
} else {
// Terminate Process
if err = hcsshim.TerminateProcessInComputeSystem(id, uint32(pid)); err != nil {
logrus.Warnf("Failed to terminate pid %d in %s: %q", pid, id, err)
// Ignore errors
err = nil
}
// Shutdown the compute system
if errno, err := hcsshim.ShutdownComputeSystem(id, hcsshim.TimeoutInfinite, context); err != nil {
logrus.Errorf("Failed to shutdown %s - 0x%X %q", id, errno, err)
if err = hcsshim.ShutdownComputeSystem(id); err != nil {
logrus.Errorf("Failed to shutdown %s - %q", id, err)
}
}
return err
+4 -5
View File
@@ -18,8 +18,7 @@ import (
var dummyMode bool
// This allows the daemon to terminate containers rather than shutdown
// This allows the daemon to force kill (HCS terminate) rather than shutdown
var forceKill bool
var terminateMode bool
// Define name and version for windows
var (
@@ -63,11 +62,11 @@ func NewDriver(root, initPath string, options []string) (*Driver, error) {
logrus.Warn("Using dummy mode in Windows exec driver. This is for development use only!")
}
case "forcekill":
case "terminate":
switch val {
case "1":
forceKill = true
logrus.Warn("Using force kill mode in Windows exec driver. This is for testing purposes only.")
terminateMode = true
logrus.Warn("Using terminate mode in Windows exec driver. This is for testing purposes only.")
}
default:
+1 -11
View File
@@ -1,12 +1,6 @@
package daemon
import (
"fmt"
"runtime"
"syscall"
"github.com/docker/docker/pkg/signal"
)
import "syscall"
// ContainerKill send signal to the container
// If no signal is given (sig 0), then Kill with SIGKILL and wait
@@ -18,10 +12,6 @@ func (daemon *Daemon) ContainerKill(name string, sig uint64) error {
return err
}
if sig != 0 && !signal.ValidSignalForPlatform(syscall.Signal(sig)) {
return fmt.Errorf("The %s daemon does not support signal %d", runtime.GOOS, sig)
}
// If no signal is passed, or SIGKILL, perform regular Kill (SIGKILL + wait())
if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL {
if err := container.Kill(); err != nil {
+8 -22
View File
@@ -9,7 +9,6 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/graph"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/graphdb"
"github.com/docker/docker/pkg/nat"
@@ -286,24 +285,6 @@ func includeContainerInList(container *Container, ctx *listContext) iterationAct
return includeContainer
}
func getImage(s *graph.TagStore, img, imgID string) (string, error) {
// both Image and ImageID is actually ids, nothing to guess
if strings.HasPrefix(imgID, img) {
return img, nil
}
id, err := s.GetID(img)
if err != nil {
if err == graph.ErrNameIsNotExist {
return imgID, nil
}
return "", err
}
if id != imgID {
return imgID, nil
}
return img, nil
}
// 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{
@@ -316,11 +297,16 @@ func (daemon *Daemon) transformContainer(container *Container, ctx *listContext)
newC.Names = []string{}
}
showImg, err := getImage(daemon.repositories, container.Config.Image, container.ImageID)
img, err := daemon.repositories.LookupImage(container.Config.Image)
if err != nil {
return nil, err
// 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
}
newC.Image = showImg
if len(container.Args) > 0 {
args := []string{}
+26
View File
@@ -142,6 +142,32 @@ func (m *containerMonitor) Start() error {
m.lastStartTime = time.Now()
// Make the network settings available to the execution
// driver to allow for integration with libnetwork networking.
m.container.command.NetworkSettings = m.container.NetworkSettings
// Allow the execution driver to query memory limits
m.container.command.HostConfig = m.container.hostConfig
// Make the network endpoint details available to the execution
// driver as well.
for _, name := range m.container.NetworkSettings.Networks {
n, _err := m.container.daemon.netController.NetworkByID(name)
if _err == nil {
var eps []map[string]interface{}
for _, ep := range n.Endpoints() {
info, err := ep.DriverInfo()
if err != nil {
continue
}
eps = append(eps, info)
}
m.container.command.EndpointInfo = eps
}
}
if exitStatus, err = m.container.daemon.run(m.container, pipes, m.callback); err != nil {
// if we receive an internal error from the initial start of a container then lets
// return it instead of entering the restart loop
+1 -23
View File
@@ -80,7 +80,7 @@ func (daemon *Daemon) GetNetworksByID(partialID string) []libnetwork.Network {
}
// CreateNetwork creates a network with the given name, driver and other optional parameters
func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, options map[string]string) (libnetwork.Network, error) {
func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM) (libnetwork.Network, error) {
c := daemon.netController
if driver == "" {
driver = c.Config().Daemon.DefaultDriver
@@ -96,7 +96,6 @@ func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, opti
if len(ipam.Config) > 0 {
nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf))
}
nwOptions = append(nwOptions, libnetwork.NetworkOptionDriverOpts(options))
return c.NewNetwork(driver, name, nwOptions...)
}
@@ -121,24 +120,3 @@ func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnet
}
return ipamV4Cfg, ipamV6Cfg, nil
}
// ConnectContainerToNetwork connects the given container to the given
// network. If either cannot be found, an err is returned. If the
// network cannot be set up, an err is returned.
func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string) error {
container, err := daemon.Get(containerName)
if err != nil {
return err
}
return container.ConnectToNetwork(networkName)
}
// DisconnectContainerFromNetwork disconnects the given container from
// the given network. If either cannot be found, an err is returned.
func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, network libnetwork.Network) error {
container, err := daemon.Get(containerName)
if err != nil {
return err
}
return container.DisconnectFromNetwork(network)
}
+6 -6
View File
@@ -59,7 +59,7 @@ There are two ways to install Docker Engine. You can install with the `yum` pac
For Fedora 22 run:
$ cat >/etc/yum.repos.d/docker.repo <<-EOF
$ cat >/etc/yum.repos.d/docker.repo <<-EOF
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/fedora/22
@@ -74,7 +74,7 @@ There are two ways to install Docker Engine. You can install with the `yum` pac
5. Start the Docker daemon.
$ sudo systemctl start docker
$ sudo service docker start
6. Verify `docker` is installed correctly by running a test image in a container.
@@ -123,13 +123,13 @@ There are two ways to install Docker Engine. You can install with the `yum` pac
4. Start the Docker daemon.
$ sudo systemctl start docker
$ sudo service docker start
5. Verify `docker` is installed correctly by running a test image in a container.
$ sudo docker run hello-world
## Create a docker group
## Create a docker group
The `docker` daemon binds to a Unix socket instead of a TCP port. By default
that Unix socket is owned by the user `root` and other users can access it with
@@ -163,7 +163,7 @@ To create the `docker` group and add your user:
To ensure Docker starts when you boot your system, do the following:
$ sudo systemctl enable docker
$ sudo chkconfig docker on
If you need to add an HTTP Proxy, set a different directory or partition for the
Docker runtime files, or make other customizations, read our Systemd article to
@@ -190,7 +190,7 @@ This configuration allows IP forwarding from the container as expected.
## Uninstall
You can uninstall the Docker software with `yum`.
You can uninstall the Docker software with `yum`.
1. List the package you have installed.
-2
View File
@@ -21,8 +21,6 @@ The following short variant options are deprecated in favor of their long
variants:
docker run -c (--cpu-shares)
docker build -c (--cpu-shares)
docker create -c (--cpu-shares)
### Driver Specific Log Tags
**Deprecated In Release: v1.9**
+3 -9
View File
@@ -23,15 +23,14 @@ client must have `root` access to interact with the daemon. If a group named
`docker` exists on your system, `docker` applies ownership of the socket to the
group.
The current version of the API is v1.22 which means calling `/info` is the same
as calling `/v1.22/info`. To call an older version of the API use
`/v1.21/info`.
The current version of the API is v1.21 which means calling `/info` is the same
as calling `/v1.21/info`. To call an older version of the API use
`/v1.20/info`.
Use the table below to find the API version for a Docker version:
Docker version | API version | Changes
----------------|-------------------------------------------------|-----------------------------
1.10.x | [1.22](/reference/api/docker_remote_api_v1.22/) | [API changes](/reference/api/docker_remote_api/#v1-22-api-changes)
1.9.x | [1.21](/reference/api/docker_remote_api_v1.21/) | [API changes](/reference/api/docker_remote_api/#v1-21-api-changes)
1.8.x | [1.20](/reference/api/docker_remote_api_v1.20/) | [API changes](/reference/api/docker_remote_api/#v1-20-api-changes)
1.7.x | [1.19](/reference/api/docker_remote_api_v1.19/) | [API changes](/reference/api/docker_remote_api/#v1-19-api-changes)
@@ -90,11 +89,6 @@ Running `docker rmi` emits an **untag** event when removing an image name. The
This section lists each version from latest to oldest. Each listing includes a link to the full documentation set and the changes relevant in that release.
### v1.22 API changes
[Docker Remote API v1.22](docker_remote_api_v1.22.md) documentation
### v1.21 API changes
[Docker Remote API v1.21](docker_remote_api_v1.21.md) documentation
@@ -1465,15 +1465,12 @@ a base64-encoded AuthConfig object.
Query Parameters:
- **fromImage** Name of the image to pull. The name may include a tag or
digest. This parameter may only be used when pulling an image.
- **fromImage** Name of the image to pull.
- **fromSrc** Source to import. The value may be a URL from which the image
can be retrieved or `-` to read the image from the request body.
This parameter may only be used when importing an image.
- **repo** Repository name given to an image when it is imported.
The repo may include a tag. This parameter may only be used when importing
an image.
- **tag** Tag or digest.
- **repo** Repository name.
- **tag** Tag.
- **registry** The registry to pull from.
Request Headers:
File diff suppressed because it is too large Load Diff
+20 -38
View File
@@ -15,7 +15,7 @@ parent = "smn_cli"
Build a new image from the source code at PATH
--build-arg=[] Set build-time variables
--cpu-shares CPU Shares (relative weight)
-c, --cpu-shares CPU Shares (relative weight)
--cgroup-parent="" Optional parent cgroup for the container
--cpu-period=0 Limit the CPU CFS (Completely Fair Scheduler) period
--cpu-quota=0 Limit the CPU CFS (Completely Fair Scheduler) quota
@@ -128,8 +128,6 @@ See also:
## Examples
### Build with PATH
$ docker build .
Uploading context 10240 bytes
Step 1 : FROM busybox
@@ -170,31 +168,6 @@ The transfer of context from the local machine to the Docker daemon is what the
If you wish to keep the intermediate containers after the build is complete,
you must use `--rm=false`. This does not affect the build cache.
### Build with URL
$ docker build github.com/creack/docker-firefox
This will clone the GitHub repository and use the cloned repository as context.
The Dockerfile at the root of the repository is used as Dockerfile. Note that
you can specify an arbitrary Git repository by using the `git://` or `git@`
schema.
### Build with -
$ docker build - < Dockerfile
This will read a Dockerfile from `STDIN` without context. Due to the lack of a
context, no contents of any local directory will be sent to the Docker daemon.
Since there is no context, a Dockerfile `ADD` only works if it refers to a
remote URL.
$ docker build - < context.tar.gz
This will build an image for a compressed context read from `STDIN`. Supported
formats are: bzip2, gzip and xz.
### Usage of .dockerignore
$ docker build .
Uploading context 18.829 MB
Uploading context
@@ -220,14 +193,29 @@ directory from the context. Its effect can be seen in the changed size of the
uploaded context. The builder reference contains detailed information on
[creating a .dockerignore file](../builder.md#dockerignore-file)
### Tag image (-t)
$ docker build -t vieux/apache:2.0 .
This will build like the previous example, but it will then tag the resulting
image. The repository name will be `vieux/apache` and the tag will be `2.0`
### Specify Dockerfile (-f)
$ docker build - < Dockerfile
This will read a Dockerfile from `STDIN` without context. Due to the lack of a
context, no contents of any local directory will be sent to the Docker daemon.
Since there is no context, a Dockerfile `ADD` only works if it refers to a
remote URL.
$ docker build - < context.tar.gz
This will build an image for a compressed context read from `STDIN`. Supported
formats are: bzip2, gzip and xz.
$ docker build github.com/creack/docker-firefox
This will clone the GitHub repository and use the cloned repository as context.
The Dockerfile at the root of the repository is used as Dockerfile. Note that
you can specify an arbitrary Git repository by using the `git://` or `git@`
schema.
$ docker build -f Dockerfile.debug .
@@ -260,20 +248,14 @@ the command line.
> repeatable builds on remote Docker hosts. This is also the reason why
> `ADD ../file` will not work.
### Optional parent cgroup (--cgroup-parent)
When `docker build` is run with the `--cgroup-parent` option the containers
used in the build will be run with the [corresponding `docker run`
flag](../run.md#specifying-custom-cgroups).
### Set ulimits in container (--ulimit)
Using the `--ulimit` option with `docker build` will cause each build step's
container to be started using those [`--ulimit`
flag values](../run.md#setting-ulimits-in-a-container).
### Set build-time variables (--build-arg)
You can use `ENV` instructions in a Dockerfile to define variable
values. These values persist in the built image. However, often
persistence is not what you want. Users want to specify variables differently
@@ -281,7 +263,7 @@ depending on which host they build an image on.
A good example is `http_proxy` or source versions for pulling intermediate
files. The `ARG` instruction lets Dockerfile authors define values that users
can set at build-time using the `--build-arg` flag:
can set at build-time using the `---build-arg` flag:
$ docker build --build-arg HTTP_PROXY=http://10.20.30.2:1234 .
+1 -1
View File
@@ -121,7 +121,7 @@ To list the help on any command just execute the command, followed by the
Run a command in a new container
-a, --attach=[] Attach to STDIN, STDOUT or STDERR
--cpu-shares=0 CPU shares (relative weight)
-c, --cpu-shares=0 CPU shares (relative weight)
...
## Option types
+1 -1
View File
@@ -19,7 +19,7 @@ Creates a new container.
-a, --attach=[] Attach to STDIN, STDOUT or STDERR
--add-host=[] Add a custom host-to-IP mapping (host:ip)
--blkio-weight=0 Block IO weight (relative weight)
--cpu-shares=0 CPU shares (relative weight)
-c, --cpu-shares=0 CPU shares (relative weight)
--cap-add=[] Add Linux capabilities
--cap-drop=[] Drop Linux capabilities
--cgroup-parent="" Optional parent cgroup for the container
+23 -36
View File
@@ -205,10 +205,9 @@ options for `zfs` start with `zfs`.
Example use:
$ docker daemon \
--storage-opt dm.thinpooldev=/dev/mapper/thin-pool
docker daemon --storage-opt dm.thinpooldev=/dev/mapper/thin-pool
* `dm.basesize`
* `dm.basesize`
Specifies the size to use when creating the base device, which limits the
size of images and containers. The default value is 100G. Note, thin devices
@@ -228,11 +227,9 @@ options for `zfs` start with `zfs`.
$ docker daemon --storage-opt dm.basesize=20G
* `dm.loopdatasize`
* `dm.loopdatasize`
> **Note**:
> This option configures devicemapper loopback, which should not
> be used in production.
>**Note**: This option configures devicemapper loopback, which should not be used in production.
Specifies the size to use when creating the loopback file for the
"data" device which is used for the thin pool. The default size is
@@ -243,11 +240,9 @@ options for `zfs` start with `zfs`.
$ docker daemon --storage-opt dm.loopdatasize=200G
* `dm.loopmetadatasize`
* `dm.loopmetadatasize`
> **Note**:
> This option configures devicemapper loopback, which should not
> be used in production.
>**Note**: This option configures devicemapper loopback, which should not be used in production.
Specifies the size to use when creating the loopback file for the
"metadata" device which is used for the thin pool. The default size
@@ -258,7 +253,7 @@ options for `zfs` start with `zfs`.
$ docker daemon --storage-opt dm.loopmetadatasize=4G
* `dm.fs`
* `dm.fs`
Specifies the filesystem type to use for the base device. The supported
options are "ext4" and "xfs". The default is "ext4"
@@ -267,7 +262,7 @@ options for `zfs` start with `zfs`.
$ docker daemon --storage-opt dm.fs=xfs
* `dm.mkfsarg`
* `dm.mkfsarg`
Specifies extra mkfs arguments to be used when creating the base device.
@@ -275,7 +270,7 @@ options for `zfs` start with `zfs`.
$ docker daemon --storage-opt "dm.mkfsarg=-O ^has_journal"
* `dm.mountopt`
* `dm.mountopt`
Specifies extra mount options used when mounting the thin devices.
@@ -283,7 +278,7 @@ options for `zfs` start with `zfs`.
$ docker daemon --storage-opt dm.mountopt=nodiscard
* `dm.datadev`
* `dm.datadev`
(Deprecated, use `dm.thinpooldev`)
@@ -295,11 +290,9 @@ options for `zfs` start with `zfs`.
Example use:
$ docker daemon \
--storage-opt dm.datadev=/dev/sdb1 \
--storage-opt dm.metadatadev=/dev/sdc1
$ docker daemon --storage-opt dm.datadev=/dev/sdb1 --storage-opt dm.metadatadev=/dev/sdc1
* `dm.metadatadev`
* `dm.metadatadev`
(Deprecated, use `dm.thinpooldev`)
@@ -311,15 +304,13 @@ options for `zfs` start with `zfs`.
If setting up a new metadata pool it is required to be valid. This can be
achieved by zeroing the first 4k to indicate empty metadata, like this:
$ dd if=/dev/zero of=$metadata_dev bs=4096 count=1
$ dd if=/dev/zero of=$metadata_dev bs=4096 count=1
Example use:
$ docker daemon \
--storage-opt dm.datadev=/dev/sdb1 \
--storage-opt dm.metadatadev=/dev/sdc1
$ docker daemon --storage-opt dm.datadev=/dev/sdb1 --storage-opt dm.metadatadev=/dev/sdc1
* `dm.blocksize`
* `dm.blocksize`
Specifies a custom blocksize to use for the thin pool. The default
blocksize is 64K.
@@ -328,7 +319,7 @@ options for `zfs` start with `zfs`.
$ docker daemon --storage-opt dm.blocksize=512K
* `dm.blkdiscard`
* `dm.blkdiscard`
Enables or disables the use of blkdiscard when removing devicemapper
devices. This is enabled by default (only) if using loopback devices and is
@@ -342,7 +333,7 @@ options for `zfs` start with `zfs`.
$ docker daemon --storage-opt dm.blkdiscard=false
* `dm.override_udev_sync_check`
* `dm.override_udev_sync_check`
Overrides the `udev` synchronization checks between `devicemapper` and `udev`.
`udev` is the device manager for the Linux kernel.
@@ -378,7 +369,7 @@ options for `zfs` start with `zfs`.
> Otherwise, set this flag for migrating existing Docker daemons to
> a daemon with a supported environment.
* `dm.use_deferred_removal`
* `dm.use_deferred_removal`
Enables use of deferred device removal if `libdm` and the kernel driver
support the mechanism.
@@ -394,25 +385,21 @@ options for `zfs` start with `zfs`.
system to schedule the device for deferred removal. It does not wait in a
loop trying to remove a busy device.
Example use:
Example use: `docker daemon --storage-opt dm.use_deferred_removal=true`
$ docker daemon --storage-opt dm.use_deferred_removal=true
* `dm.use_deferred_deletion`
* `dm.use_deferred_deletion`
Enables use of deferred device deletion for thin pool devices. By default,
thin pool device deletion is synchronous. Before a container is deleted,
the Docker daemon removes any associated devices. If the storage driver
can not remove a device, the container deletion fails and daemon returns.
Error deleting container: Error response from daemon: Cannot destroy container
`Error deleting container: Error response from daemon: Cannot destroy container`
To avoid this failure, enable both deferred device deletion and deferred
device removal on the daemon.
$ docker daemon \
--storage-opt dm.use_deferred_deletion=true \
--storage-opt dm.use_deferred_removal=true
`docker daemon --storage-opt dm.use_deferred_deletion=true --storage-opt dm.use_deferred_removal=true`
With these two options enabled, if a device is busy when the driver is
deleting a container, the driver marks the device as deleted. Later, when
@@ -424,7 +411,7 @@ options for `zfs` start with `zfs`.
Currently supported options of `zfs`:
* `zfs.fsname`
* `zfs.fsname`
Set zfs filesystem under which docker will create its own datasets.
By default docker will pick up the zfs filesystem where docker graph
+1 -1
View File
@@ -22,7 +22,7 @@ For example:
$ docker -D info
Containers: 14
Images: 52
Server Version: 1.9.0
Engine Version: 1.9.0
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
+2
View File
@@ -14,6 +14,8 @@ parent = "smn_cli"
Lists all the networks created by the user
--help=false Print usage
-l, --latest=false Show the latest network created
-n=-1 Show n last created networks
--no-trunc=false Do not truncate the output
-q, --quiet=false Only display numeric IDs
+39 -62
View File
@@ -17,7 +17,7 @@ parent = "smn_cli"
-a, --attach=[] Attach to STDIN, STDOUT or STDERR
--add-host=[] Add a custom host-to-IP mapping (host:ip)
--blkio-weight=0 Block IO weight (relative weight)
--cpu-shares=0 CPU shares (relative weight)
-c, --cpu-shares=0 CPU shares (relative weight)
--cap-add=[] Add Linux capabilities
--cap-drop=[] Drop Linux capabilities
--cgroup-parent="" Optional parent cgroup for the container
@@ -92,8 +92,6 @@ and linking containers.
## Examples
### Assign name and allocate psuedo-TTY (--name, -it)
$ docker run --name test -it debian
root@d6c0fe130dba:/# exit 13
$ echo $?
@@ -108,8 +106,6 @@ In the example, the `bash` shell is quit by entering
`exit 13`. This exit code is passed on to the caller of
`docker run`, and is recorded in the `test` container's metadata.
### Capture container ID (--cidfile)
$ docker run --cidfile /tmp/docker_test.cid ubuntu echo "test"
This will create a container and print `test` to the console. The `cidfile`
@@ -117,8 +113,6 @@ flag makes Docker attempt to create a new file and write the container ID to it.
If the file exists already, Docker will return an error. Docker will close this
file when `docker run` exits.
### Full container capabilities (--privileged)
$ docker run -t -i --rm ubuntu bash
root@bc338942ef20:/# mount -t tmpfs none /mnt
mount: permission denied
@@ -138,15 +132,11 @@ lifts all the limitations enforced by the `device` cgroup controller. In other
words, the container can then do almost everything that the host can do. This
flag exists to allow special use-cases, like running Docker within Docker.
### Set working directory (-w)
$ docker run -w /path/to/dir/ -i -t ubuntu pwd
The `-w` lets the command being executed inside directory given, here
`/path/to/dir/`. If the path does not exists it is created inside the container.
### Mount volume (-v, --read-only)
$ docker run -v `pwd`:`pwd` -w `pwd` -i -t ubuntu pwd
The `-v` flag mounts the current working directory into the container. The `-w`
@@ -176,8 +166,6 @@ binary (such as that provided by [https://get.docker.com](
https://get.docker.com)), you give the container the full access to create and
manipulate the host's Docker daemon.
### Publish or expose port (-p, --expose)
$ docker run -p 127.0.0.1:80:8080 ubuntu bash
This binds port `8080` of the container to port `80` on `127.0.0.1` of
@@ -191,8 +179,6 @@ publishing the port to the host system's interfaces. The [Docker User
Guide](../../userguide/dockerlinks.md) explains in detail how to manipulate
ports in Docker.
### Set environment variables (-e, --env, --env-file)
$ docker run -e MYVAR1 --env MYVAR2=foo --env-file ./env.list ubuntu bash
This sets environmental variables in the container. For illustration all three
@@ -261,9 +247,7 @@ An example of a file passed with `--env-file`
123qwe=bar
org.spring.config=something
### Set metadata on container (-l, --label, --label-file)
A label is a `key=value` pair that applies metadata to a container. To label a container with two labels:
A label is a a `key=value` pair that applies metadata to a container. To label a container with two labels:
$ docker run -l my-label --label com.example.foo=bar ubuntu bash
@@ -297,8 +281,6 @@ For additional information on working with labels, see [*Labels - custom
metadata in Docker*](../../userguide/labels-custom-metadata.md) in the Docker User
Guide.
### Add link to another container (--link)
$ docker run --link /redis:redis --name console ubuntu bash
The `--link` flag will link the container named `/redis` into the newly
@@ -313,8 +295,6 @@ example as:
The `--name` flag will assign the name `console` to the newly created
container.
### Mount volumes from container (--volumes-from)
$ docker run --volumes-from 777f7dc92da7 --volumes-from ba8c0c54f0f2:ro -i -t ubuntu pwd
The `--volumes-from` flag mounts all the defined volumes from the referenced
@@ -337,8 +317,6 @@ content label. Shared volume labels allow all containers to read/write content.
The `Z` option tells Docker to label the content with a private unshared label.
Only the current container can use a private volume.
### Attach to STDIN/STDOUT/STDERR (-a)
The `-a` flag tells `docker run` to bind to the container's `STDIN`, `STDOUT`
or `STDERR`. This makes it possible to manipulate the output and input as
needed.
@@ -362,8 +340,6 @@ logs could be retrieved using `docker logs`. This is
useful if you need to pipe a file or something else into a container and
retrieve the container's ID once the container has finished running.
### Add host device to container (--device)
$ docker run --device=/dev/sdc:/dev/xvdc --device=/dev/sdd --device=/dev/zero:/dev/nulo -i -t ubuntu ls -l /dev/{xvdc,sdd,nulo}
brw-rw---- 1 root disk 8, 2 Feb 9 16:05 /dev/xvdc
brw-rw---- 1 root disk 8, 3 Feb 9 16:05 /dev/sdd
@@ -399,7 +375,38 @@ flag:
> that may be removed should not be added to untrusted containers with
> `--device`.
### Restart policies (--restart)
**A complete example:**
$ docker run -d --name static static-web-files sh
$ docker run -d --expose=8098 --name riak riakserver
$ docker run -d -m 100m -e DEVELOPMENT=1 -e BRANCH=example-code -v $(pwd):/app/bin:ro --name app appserver
$ docker run -d -p 1443:443 --dns=10.0.0.1 --dns-search=dev.org -v /var/log/httpd --volumes-from static --link riak --link app -h www.sven.dev.org --name web webserver
$ docker run -t -i --rm --volumes-from web -w /var/log/httpd busybox tail -f access.log
This example shows five containers that might be set up to test a web
application change:
1. Start a pre-prepared volume image `static-web-files` (in the background)
that has CSS, image and static HTML in it, (with a `VOLUME` instruction in
the Dockerfile to allow the web server to use those files);
2. Start a pre-prepared `riakserver` image, give the container name `riak` and
expose port `8098` to any containers that link to it;
3. Start the `appserver` image, restricting its memory usage to 100MB, setting
two environment variables `DEVELOPMENT` and `BRANCH` and bind-mounting the
current directory (`$(pwd)`) in the container in read-only mode as `/app/bin`;
4. Start the `webserver`, mapping port `443` in the container to port `1443` on
the Docker server, setting the DNS server to `10.0.0.1` and DNS search
domain to `dev.org`, creating a volume to put the log files into (so we can
access it from another container), then importing the files from the volume
exposed by the `static` container, and linking to all exposed ports from
`riak` and `app`. Lastly, we set the hostname to `web.sven.dev.org` so its
consistent with the pre-generated SSL certificate;
5. Finally, we create a container that runs `tail -f access.log` using the logs
volume from the `web` container, setting the workdir to `/var/log/httpd`. The
`--rm` option means that when the container exits, the container's layer is
removed.
## Restart policies
Use Docker's `--restart` to specify a container's *restart policy*. A restart
policy controls whether the Docker daemon restarts a container after exit.
@@ -461,7 +468,7 @@ More detailed information on restart policies can be found in the
[Restart Policies (--restart)](../run.md#restart-policies-restart)
section of the Docker run reference page.
### Add entries to container hosts file (--add-host)
## Adding entries to a container hosts file
You can add other hosts into a container's `/etc/hosts` file by using one or
more `--add-host` flags. This example adds a static address for a host named
@@ -492,7 +499,7 @@ For IPv6 use the `-6` flag instead of the `-4` flag. For other network
devices, replace `eth0` with the correct device name (for example `docker0`
for the bridge device).
### Set ulimits in container (--ulimit)
### Setting ulimits in a container
Since setting `ulimit` settings in a container requires extra privileges not
available in the default container, you can set these using the `--ulimit` flag.
@@ -512,12 +519,13 @@ available in the default container, you can set these using the `--ulimit` flag.
The values are sent to the appropriate `syscall` as they are set.
Docker doesn't perform any byte conversion. Take this into account when setting the values.
#### For `nproc` usage
#### For `nproc` usage:
Be careful setting `nproc` with the `ulimit` flag as `nproc` is designed by Linux to set the
maximum number of processes available to a user, not to a container. For example, start four
containers with `daemon` user:
docker run -d -u daemon --ulimit nproc=3 busybox top
docker run -d -u daemon --ulimit nproc=3 busybox top
docker run -d -u daemon --ulimit nproc=3 busybox top
@@ -527,39 +535,8 @@ The 4th container fails and reports "[8] System error: resource temporarily unav
This fails because the caller set `nproc=3` resulting in the first three containers using up
the three processes quota set for the `daemon` user.
### Stop container with signal (--stop-signal)
### Stopping a container with a specific signal
The `--stop-signal` flag sets the system call signal that will be sent to the container to exit.
This signal can be a valid unsigned number that matches a position in the kernel's syscall table, for instance 9,
or a signal name in the format SIGNAME, for instance SIGKILL.
### A complete example
$ docker run -d --name static static-web-files sh
$ docker run -d --expose=8098 --name riak riakserver
$ docker run -d -m 100m -e DEVELOPMENT=1 -e BRANCH=example-code -v $(pwd):/app/bin:ro --name app appserver
$ docker run -d -p 1443:443 --dns=10.0.0.1 --dns-search=dev.org -v /var/log/httpd --volumes-from static --link riak --link app -h www.sven.dev.org --name web webserver
$ docker run -t -i --rm --volumes-from web -w /var/log/httpd busybox tail -f access.log
This example shows five containers that might be set up to test a web
application change:
1. Start a pre-prepared volume image `static-web-files` (in the background)
that has CSS, image and static HTML in it, (with a `VOLUME` instruction in
the Dockerfile to allow the web server to use those files);
2. Start a pre-prepared `riakserver` image, give the container name `riak` and
expose port `8098` to any containers that link to it;
3. Start the `appserver` image, restricting its memory usage to 100MB, setting
two environment variables `DEVELOPMENT` and `BRANCH` and bind-mounting the
current directory (`$(pwd)`) in the container in read-only mode as `/app/bin`;
4. Start the `webserver`, mapping port `443` in the container to port `1443` on
the Docker server, setting the DNS server to `10.0.0.1` and DNS search
domain to `dev.org`, creating a volume to put the log files into (so we can
access it from another container), then importing the files from the volume
exposed by the `static` container, and linking to all exposed ports from
`riak` and `app`. Lastly, we set the hostname to `web.sven.dev.org` so its
consistent with the pre-generated SSL certificate;
5. Finally, we create a container that runs `tail -f access.log` using the logs
volume from the `web` container, setting the workdir to `/var/log/httpd`. The
`--rm` option means that when the container exits, the container's layer is
removed.
+1 -1
View File
@@ -39,7 +39,7 @@ Then, run a container and specify values for the `labels` or `env`. For example
```
docker run --label foo=bar -e fizz=buzz -d -P training/webapp python app.py
```
````
This adds additional fields to the log depending on the driver, e.g. for
`json-file` that looks like:
+5
View File
@@ -59,6 +59,11 @@ This will create a new volume inside a container at `/webapp`.
> You can also use the `VOLUME` instruction in a `Dockerfile` to add one or
> more new volumes to any container created from that image.
Docker volumes default to mount in read-write mode, but you can also set it to be mounted read-only.
$ docker run -d -P --name web -v /opt/webapp:ro training/webapp python app.py
### Locating a volume
You can locate the volume on the host by utilizing the 'docker inspect' command.
+1 -1
View File
@@ -188,7 +188,7 @@ These labels appear as part of the `docker info` output for the daemon:
$ docker -D info
Containers: 12
Images: 672
Server Version: 1.9.0
Engine Version: 1.9.0
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
+1 -3
View File
@@ -51,10 +51,8 @@ func (s *TagStore) Images(filterArgs, filter string, all bool) ([]*types.Image,
if i, ok := imageFilters["dangling"]; ok {
for _, value := range i {
if v := strings.ToLower(value); v == "true" {
if strings.ToLower(value) == "true" {
filtTagged = false
} else if v != "false" {
return nil, fmt.Errorf("Invalid filter 'dangling=%s'", v)
}
}
}
-23
View File
@@ -24,9 +24,6 @@ import (
"github.com/docker/libtrust"
)
// ErrNameIsNotExist returned when there is no image with requested name.
var ErrNameIsNotExist = errors.New("image with specified name does not exist")
// TagStore manages repositories. It encompasses the Graph used for versioned
// storage, as well as various services involved in pushing and pulling
// repositories.
@@ -167,26 +164,6 @@ func (store *TagStore) LookupImage(name string) (*image.Image, error) {
return img, nil
}
// GetID returns ID for image name.
func (store *TagStore) GetID(name string) (string, error) {
repoName, ref := parsers.ParseRepositoryTag(name)
if ref == "" {
ref = tags.DefaultTag
}
store.Lock()
defer store.Unlock()
repoName = registry.NormalizeLocalName(repoName)
repo, ok := store.Repositories[repoName]
if !ok {
return "", ErrNameIsNotExist
}
id, ok := repo[ref]
if !ok {
return "", ErrNameIsNotExist
}
return id, nil
}
// ByID returns a reverse-lookup table of all the names which refer to each
// image - e.g. {"43b5f19b10584": {"base:latest", "base:v1"}}
func (store *TagStore) ByID() map[string][]string {
+2 -62
View File
@@ -80,16 +80,6 @@ check_forked() {
fi
}
rpm_import_repository_key() {
local key=$1; shift
local tmpdir=$(mktemp -d)
chmod 600 "$tmpdir"
gpg --homedir "$tmpdir" --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"
gpg --homedir "$tmpdir" --export --armor "$key" > "$tmpdir"/repo.key
rpm --import "$tmpdir"/repo.key
rm -rf "$tmpdir"
}
do_install() {
case "$(uname -m)" in
*64)
@@ -241,60 +231,10 @@ do_install() {
exit 0
;;
'opensuse project'|opensuse)
echo 'Going to perform the following operations:'
if [ "$repo" != 'main' ]; then
echo ' * add repository obs://Virtualization:containers'
fi
echo ' * install Docker'
$sh_c 'echo "Press CTRL-C to abort"; sleep 3'
if [ "$repo" != 'main' ]; then
# install experimental packages from OBS://Virtualization:containers
(
set -x
zypper -n ar -f obs://Virtualization:containers Virtualization:containers
rpm_import_repository_key 55A0B34D49501BB7CA474F5AA193FBB572174FC2
)
fi
'opensuse project'|opensuse|'suse linux'|sle[sd])
(
set -x
zypper -n install docker
)
echo_docker_as_nonroot
exit 0
;;
'suse linux'|sle[sd])
echo 'Going to perform the following operations:'
if [ "$repo" != 'main' ]; then
echo ' * add repository obs://Virtualization:containers'
echo ' * install experimental Docker using packages NOT supported by SUSE'
else
echo ' * add the "Containers" module'
echo ' * install Docker using packages supported by SUSE'
fi
$sh_c 'echo "Press CTRL-C to abort"; sleep 3'
if [ "$repo" != 'main' ]; then
# install experimental packages from OBS://Virtualization:containers
echo >&2 'Warning: installing experimental packages from OBS, these packages are NOT supported by SUSE'
(
set -x
zypper -n ar -f obs://Virtualization:containers/SLE_12 Virtualization:containers
rpm_import_repository_key 55A0B34D49501BB7CA474F5AA193FBB572174FC2
)
else
# Add the containers module
# Note well-1: the SLE machine must already be registered against SUSE Customer Center
# Note well-2: the `-r ""` is required to workaround a known issue of SUSEConnect
(
set -x
SUSEConnect -p sle-module-containers/12/x86_64 -r ""
)
fi
(
set -x
zypper -n install docker
$sh_c 'sleep 3; zypper -n install docker'
)
echo_docker_as_nonroot
exit 0
+1 -15
View File
@@ -46,20 +46,6 @@ set -e
./man/md2man-all.sh -q || true
# TODO decide if it's worth getting go-md2man in _each_ builder environment to avoid this
# Convert the CHANGELOG.md file into RPM changelog format
VERSION_REGEX="^\W\W (.*) \((.*)\)$"
ENTRY_REGEX="^[-+*] (.*)$"
while read -r line || [[ -n "$line" ]]; do
if [ -z "$line" ]; then continue; fi
if [[ "$line" =~ $VERSION_REGEX ]]; then
echo >> contrib/builder/rpm/changelog
echo "* `date -d ${BASH_REMATCH[2]} '+%a %b %d %Y'` ${rpmPackager} - ${BASH_REMATCH[1]}" >> contrib/builder/rpm/changelog
fi
if [[ "$line" =~ $ENTRY_REGEX ]]; then
echo "- ${BASH_REMATCH[1]//\`}" >> contrib/builder/rpm/changelog
fi
done < CHANGELOG.md
# TODO add a configurable knob for _which_ rpms to build so we don't have to modify the file or build all of them every time we need to test
for dir in contrib/builder/rpm/*/; do
version="$(basename "$dir")"
@@ -85,7 +71,7 @@ set -e
RUN ln -sfv /usr/src/${rpmName}/hack/make/.build-rpm SPECS
WORKDIR /root/rpmbuild/SPECS
RUN tar -cz -C /usr/src -f /root/rpmbuild/SOURCES/${rpmName}.tar.gz ${rpmName}
RUN { cat /usr/src/${rpmName}/contrib/builder/rpm/changelog; } >> ${rpmName}.spec && tail >&2 ${rpmName}.spec
RUN { echo '* $rpmDate $rpmPackager $rpmVersion-$rpmRelease'; echo '* Version: $VERSION'; } >> ${rpmName}.spec && tail >&2 ${rpmName}.spec
RUN rpmbuild -ba --define '_release $rpmRelease' --define '_version $rpmVersion' --define '_origversion $VERSION' ${rpmName}.spec
EOF
# selinux policy referencing systemd things won't work on non-systemd versions
-74
View File
@@ -1,74 +0,0 @@
#!/bin/bash
set -e
# This script generates index files for the directory structure
# of the apt and yum repos
: ${DOCKER_RELEASE_DIR:=$DEST}
APTDIR=$DOCKER_RELEASE_DIR/apt
YUMDIR=$DOCKER_RELEASE_DIR/yum
if [ ! -d $APTDIR ] && [ ! -d $YUMDIR ]; then
echo >&2 'release-rpm or release-deb must be run before generate-index-listing'
exit 1
fi
create_index() {
local directory=$1
local original=$2
local cleaned=${directory#$original}
# the index file to create
local index_file="${directory}/index"
# cd into dir & touch the index file
cd $directory
touch $index_file
# print the html header
cat <<-EOF > "$index_file"
<!DOCTYPE html>
<html>
<head><title>Index of ${cleaned}/</title></head>
<body bgcolor="white">
<h1>Index of ${cleaned}/</h1><hr>
<pre><a href="../">../</a>
EOF
# start of content output
(
# change IFS locally within subshell so the for loop saves line correctly to L var
IFS=$'\n';
# pretty sweet, will mimick the normal apache output
for L in $(find -L . -mount -depth -maxdepth 1 -type f ! -name 'index' -printf "<a href=\"%f\">%-44f@_@%Td-%Tb-%TY %Tk:%TM @%f@\n"|sort|sed 's,\([\ ]\+\)@_@,</a>\1,g');
do
# file
F=$(sed -e 's,^.*@\([^@]\+\)@.*$,\1,g'<<<"$L");
# file with file size
F=$(du -bh $F | cut -f1);
# output with correct format
sed -e 's,\ @.*$, '"$F"',g'<<<"$L";
done;
) >> $index_file;
# now output a list of all directories in this dir (maxdepth 1) other than '.' outputting in a sorted manner exactly like apache
find -L . -mount -depth -maxdepth 1 -type d ! -name '.' -printf "<a href=\"%f\">%-43f@_@%Td-%Tb-%TY %Tk:%TM -\n"|sort -d|sed 's,\([\ ]\+\)@_@,/</a>\1,g' >> $index_file
# print the footer html
echo "</pre><hr></body></html>" >> $index_file
}
get_dirs() {
local directory=$1
for d in `find ${directory} -type d`; do
create_index $d $directory
done
}
get_dirs $APTDIR
get_dirs $YUMDIR
-2
View File
@@ -104,8 +104,6 @@ for dir in contrib/builder/deb/*/; do
-name *~${codename#*-}*.deb > "$APTDIR/dists/$codename/$component/filelist"
done
# clean the databases
apt-ftparchive clean "$APTDIR/conf/apt-ftparchive.conf"
# run the apt-ftparchive commands so we can have pinning
apt-ftparchive generate "$APTDIR/conf/apt-ftparchive.conf"
+5 -6
View File
@@ -9,19 +9,18 @@ source 'hack/.vendor-helpers.sh'
clone git github.com/Azure/go-ansiterm 70b2c90b260171e829f1ebd7c17f600c11858dbe
clone git github.com/Sirupsen/logrus v0.8.2 # logrus is a common dependency among multiple deps
clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
clone git github.com/go-check/check 11d3bc7aa68e238947792f30573146a3231fc0f1
clone git github.com/go-check/check 64131543e7896d5bcc6bd5a76287eb75ea96c673
clone git github.com/gorilla/context 14f550f51a
clone git github.com/gorilla/mux e444e69cbd
clone git github.com/kr/pty 5cf931ef8f
clone git github.com/mattn/go-sqlite3 v1.1.0
clone git github.com/microsoft/hcsshim 325e531f8c49dd78580d5fd197ddb972fa4610e7
clone git github.com/microsoft/hcsshim 7f646aa6b26bcf90caee91e93cde4a80d0d8a83e
clone git github.com/mistifyio/go-zfs v2.1.1
clone git github.com/tchap/go-patricia v2.1.0
clone git github.com/vdemeester/shakers 3c10293ce22b900c27acad7b28656196fcc2f73b
clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
#get libnetwork packages
clone git github.com/docker/libnetwork 2934f6bf585fa24c86048cc85f7506a5bb626bf5
clone git github.com/docker/libnetwork dd1c5f0ffe7697f75a82bd8e4bbd6f225ec5e383
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
@@ -42,8 +41,8 @@ clone git github.com/boltdb/bolt v1.0
clone git github.com/docker/distribution 20c4b7a1805a52753dfd593ee1cc35558722a0ce # docker/1.9 branch
clone git github.com/vbatts/tar-split v0.9.10
clone git github.com/docker/notary 089d8450d8928aa1c58fd03f09cabbde9bcb4590
clone git github.com/endophage/gotuf 876c31a61bc4aa0dae09bb8ef3946dc26dd04924
clone git github.com/docker/notary ac05822d7d71ef077df3fc24f506672282a1feea
clone git github.com/endophage/gotuf 9bcdad0308e34a49f38448b8ad436ad8860825ce
clone git github.com/jfrazelle/go 6e461eb70cb4187b41a84e9a567d7137bdbe0f16
clone git github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
-1
View File
@@ -31,7 +31,6 @@ func (s *DockerSuite) TearDownTest(c *check.C) {
deleteAllContainers()
deleteAllImages()
deleteAllVolumes()
deleteAllNetworks()
}
func init() {
+116 -88
View File
@@ -4,8 +4,8 @@ import (
"archive/tar"
"bytes"
"net/http"
"strings"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -17,29 +17,31 @@ func (s *DockerSuite) TestBuildApiDockerfilePath(c *check.C) {
defer tw.Close()
dockerfile := []byte("FROM busybox")
err := tw.WriteHeader(&tar.Header{
if err := tw.WriteHeader(&tar.Header{
Name: "Dockerfile",
Size: int64(len(dockerfile)),
})
//failed to write tar file header
c.Assert(err, checker.IsNil)
_, err = tw.Write(dockerfile)
// failed to write tar file content
c.Assert(err, checker.IsNil)
// failed to close tar archive
c.Assert(tw.Close(), checker.IsNil)
}); err != nil {
c.Fatalf("failed to write tar file header: %v", err)
}
if _, err := tw.Write(dockerfile); err != nil {
c.Fatalf("failed to write tar file content: %v", err)
}
if err := tw.Close(); err != nil {
c.Fatalf("failed to close tar archive: %v", err)
}
res, body, err := sockRequestRaw("POST", "/build?dockerfile=../Dockerfile", buffer, "application/x-tar")
c.Assert(err, checker.IsNil)
c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
c.Assert(err, check.IsNil)
c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
out, err := readBody(body)
c.Assert(err, checker.IsNil)
if err != nil {
c.Fatal(err)
}
// Didn't complain about leaving build context
c.Assert(string(out), checker.Contains, "Forbidden path outside the build context")
if !strings.Contains(string(out), "Forbidden path outside the build context") {
c.Fatalf("Didn't complain about leaving build context: %s", out)
}
}
func (s *DockerSuite) TestBuildApiDockerFileRemote(c *check.C) {
@@ -51,21 +53,27 @@ COPY * /tmp/
RUN find / -name ba*
RUN find /tmp/`,
})
c.Assert(err, checker.IsNil)
if err != nil {
c.Fatal(err)
}
defer server.Close()
res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+server.URL()+"/testD", nil, "application/json")
c.Assert(err, checker.IsNil)
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
c.Assert(res.StatusCode, check.Equals, http.StatusOK)
buf, err := readBody(body)
c.Assert(err, checker.IsNil)
if err != nil {
c.Fatal(err)
}
// Make sure Dockerfile exists.
// Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL
out := string(buf)
c.Assert(out, checker.Contains, "/tmp/Dockerfile")
c.Assert(out, checker.Not(checker.Contains), "baz")
if !strings.Contains(out, "/tmp/Dockerfile") ||
strings.Contains(out, "baz") {
c.Fatalf("Incorrect output: %s", out)
}
}
func (s *DockerSuite) TestBuildApiRemoteTarballContext(c *check.C) {
@@ -75,30 +83,29 @@ func (s *DockerSuite) TestBuildApiRemoteTarballContext(c *check.C) {
defer tw.Close()
dockerfile := []byte("FROM busybox")
err := tw.WriteHeader(&tar.Header{
if err := tw.WriteHeader(&tar.Header{
Name: "Dockerfile",
Size: int64(len(dockerfile)),
})
// failed to write tar file header
c.Assert(err, checker.IsNil)
_, err = tw.Write(dockerfile)
// failed to write tar file content
c.Assert(err, checker.IsNil)
// failed to close tar archive
c.Assert(tw.Close(), checker.IsNil)
}); err != nil {
c.Fatalf("failed to write tar file header: %v", err)
}
if _, err := tw.Write(dockerfile); err != nil {
c.Fatalf("failed to write tar file content: %v", err)
}
if err := tw.Close(); err != nil {
c.Fatalf("failed to close tar archive: %v", err)
}
server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
"testT.tar": buffer,
})
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
defer server.Close()
res, b, err := sockRequestRaw("POST", "/build?remote="+server.URL()+"/testT.tar", nil, "application/tar")
c.Assert(err, checker.IsNil)
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
c.Assert(res.StatusCode, check.Equals, http.StatusOK)
b.Close()
}
@@ -110,52 +117,51 @@ func (s *DockerSuite) TestBuildApiRemoteTarballContextWithCustomDockerfile(c *ch
dockerfile := []byte(`FROM busybox
RUN echo 'wrong'`)
err := tw.WriteHeader(&tar.Header{
if err := tw.WriteHeader(&tar.Header{
Name: "Dockerfile",
Size: int64(len(dockerfile)),
})
// failed to write tar file header
c.Assert(err, checker.IsNil)
_, err = tw.Write(dockerfile)
// failed to write tar file content
c.Assert(err, checker.IsNil)
}); err != nil {
c.Fatalf("failed to write tar file header: %v", err)
}
if _, err := tw.Write(dockerfile); err != nil {
c.Fatalf("failed to write tar file content: %v", err)
}
custom := []byte(`FROM busybox
RUN echo 'right'
`)
err = tw.WriteHeader(&tar.Header{
if err := tw.WriteHeader(&tar.Header{
Name: "custom",
Size: int64(len(custom)),
})
}); err != nil {
c.Fatalf("failed to write tar file header: %v", err)
}
if _, err := tw.Write(custom); err != nil {
c.Fatalf("failed to write tar file content: %v", err)
}
// failed to write tar file header
c.Assert(err, checker.IsNil)
_, err = tw.Write(custom)
// failed to write tar file content
c.Assert(err, checker.IsNil)
// failed to close tar archive
c.Assert(tw.Close(), checker.IsNil)
if err := tw.Close(); err != nil {
c.Fatalf("failed to close tar archive: %v", err)
}
server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
"testT.tar": buffer,
})
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
defer server.Close()
url := "/build?dockerfile=custom&remote=" + server.URL() + "/testT.tar"
res, body, err := sockRequestRaw("POST", url, nil, "application/tar")
c.Assert(err, checker.IsNil)
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
c.Assert(res.StatusCode, check.Equals, http.StatusOK)
defer body.Close()
content, err := readBody(body)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
// Build used the wrong dockerfile.
c.Assert(string(content), checker.Not(checker.Contains), "wrong")
if strings.Contains(string(content), "wrong") {
c.Fatalf("Build used the wrong dockerfile.")
}
}
func (s *DockerSuite) TestBuildApiLowerDockerfile(c *check.C) {
@@ -164,18 +170,24 @@ func (s *DockerSuite) TestBuildApiLowerDockerfile(c *check.C) {
"dockerfile": `FROM busybox
RUN echo from dockerfile`,
}, false)
c.Assert(err, checker.IsNil)
if err != nil {
c.Fatal(err)
}
defer git.Close()
res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
c.Assert(err, checker.IsNil)
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
c.Assert(res.StatusCode, check.Equals, http.StatusOK)
buf, err := readBody(body)
c.Assert(err, checker.IsNil)
if err != nil {
c.Fatal(err)
}
out := string(buf)
c.Assert(out, checker.Contains, "from dockerfile")
if !strings.Contains(out, "from dockerfile") {
c.Fatalf("Incorrect output: %s", out)
}
}
func (s *DockerSuite) TestBuildApiBuildGitWithF(c *check.C) {
@@ -186,19 +198,25 @@ RUN echo from baz`,
"Dockerfile": `FROM busybox
RUN echo from Dockerfile`,
}, false)
c.Assert(err, checker.IsNil)
if err != nil {
c.Fatal(err)
}
defer git.Close()
// Make sure it tries to 'dockerfile' query param value
res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+git.RepoURL, nil, "application/json")
c.Assert(err, checker.IsNil)
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
c.Assert(res.StatusCode, check.Equals, http.StatusOK)
buf, err := readBody(body)
c.Assert(err, checker.IsNil)
if err != nil {
c.Fatal(err)
}
out := string(buf)
c.Assert(out, checker.Contains, "from baz")
if !strings.Contains(out, "from baz") {
c.Fatalf("Incorrect output: %s", out)
}
}
func (s *DockerSuite) TestBuildApiDoubleDockerfile(c *check.C) {
@@ -209,19 +227,25 @@ RUN echo from Dockerfile`,
"dockerfile": `FROM busybox
RUN echo from dockerfile`,
}, false)
c.Assert(err, checker.IsNil)
if err != nil {
c.Fatal(err)
}
defer git.Close()
// Make sure it tries to 'dockerfile' query param value
res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
c.Assert(err, checker.IsNil)
c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
c.Assert(res.StatusCode, check.Equals, http.StatusOK)
buf, err := readBody(body)
c.Assert(err, checker.IsNil)
if err != nil {
c.Fatal(err)
}
out := string(buf)
c.Assert(out, checker.Contains, "from Dockerfile")
if !strings.Contains(out, "from Dockerfile") {
c.Fatalf("Incorrect output: %s", out)
}
}
func (s *DockerSuite) TestBuildApiDockerfileSymlink(c *check.C) {
@@ -231,27 +255,31 @@ func (s *DockerSuite) TestBuildApiDockerfileSymlink(c *check.C) {
tw := tar.NewWriter(buffer)
defer tw.Close()
err := tw.WriteHeader(&tar.Header{
if err := tw.WriteHeader(&tar.Header{
Name: "Dockerfile",
Typeflag: tar.TypeSymlink,
Linkname: "/etc/passwd",
})
// failed to write tar file header
c.Assert(err, checker.IsNil)
// failed to close tar archive
c.Assert(tw.Close(), checker.IsNil)
}); err != nil {
c.Fatalf("failed to write tar file header: %v", err)
}
if err := tw.Close(); err != nil {
c.Fatalf("failed to close tar archive: %v", err)
}
res, body, err := sockRequestRaw("POST", "/build", buffer, "application/x-tar")
c.Assert(err, checker.IsNil)
c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
c.Assert(err, check.IsNil)
c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
out, err := readBody(body)
c.Assert(err, checker.IsNil)
if err != nil {
c.Fatal(err)
}
// The reason the error is "Cannot locate specified Dockerfile" is because
// in the builder, the symlink is resolved within the context, therefore
// Dockerfile -> /etc/passwd becomes etc/passwd from the context which is
// a nonexistent file.
c.Assert(string(out), checker.Contains, "Cannot locate specified Dockerfile: Dockerfile", check.Commentf("Didn't complain about leaving build context"))
if !strings.Contains(string(out), "Cannot locate specified Dockerfile: Dockerfile") {
c.Fatalf("Didn't complain about leaving build context: %s", out)
}
}
+2 -3
View File
@@ -4,7 +4,6 @@ import (
"net/http"
"time"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -22,8 +21,8 @@ func (s *DockerSuite) TestEventsApiEmptyOutput(c *check.C) {
select {
case r := <-chResp:
c.Assert(r.err, checker.IsNil)
c.Assert(r.resp.StatusCode, checker.Equals, http.StatusOK)
c.Assert(r.err, check.IsNil)
c.Assert(r.resp.StatusCode, check.Equals, http.StatusOK)
case <-time.After(3 * time.Second):
c.Fatal("timeout waiting for events api to respond, should have responded immediately")
}
@@ -9,7 +9,6 @@ import (
"strings"
"sync"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -20,8 +19,8 @@ func (s *DockerSuite) TestExecResizeApiHeightWidthNoInt(c *check.C) {
endpoint := "/exec/" + cleanedContainerID + "/resize?h=foo&w=bar"
status, _, err := sockRequest("POST", endpoint, nil)
c.Assert(err, checker.IsNil)
c.Assert(status, checker.Equals, http.StatusInternalServerError)
c.Assert(status, check.Equals, http.StatusInternalServerError)
c.Assert(err, check.IsNil)
}
// Part of #14845
+8 -9
View File
@@ -8,7 +8,6 @@ import (
"strings"
"time"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -16,7 +15,7 @@ func (s *DockerSuite) TestLogsApiWithStdout(c *check.C) {
testRequires(c, DaemonIsLinux)
out, _ := dockerCmd(c, "run", "-d", "-t", "busybox", "/bin/sh", "-c", "while true; do echo hello; sleep 1; done")
id := strings.TrimSpace(out)
c.Assert(waitRun(id), checker.IsNil)
c.Assert(waitRun(id), check.IsNil)
type logOut struct {
out string
@@ -42,8 +41,8 @@ func (s *DockerSuite) TestLogsApiWithStdout(c *check.C) {
select {
case l := <-chLog:
c.Assert(l.err, checker.IsNil)
c.Assert(l.res.StatusCode, checker.Equals, http.StatusOK)
c.Assert(l.err, check.IsNil)
c.Assert(l.res.StatusCode, check.Equals, http.StatusOK)
if !strings.HasSuffix(l.out, "hello") {
c.Fatalf("expected log output to container 'hello', but it does not")
}
@@ -58,8 +57,8 @@ func (s *DockerSuite) TestLogsApiNoStdoutNorStderr(c *check.C) {
dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
status, body, err := sockRequest("GET", fmt.Sprintf("/containers/%s/logs", name), nil)
c.Assert(status, checker.Equals, http.StatusBadRequest)
c.Assert(err, checker.IsNil)
c.Assert(status, check.Equals, http.StatusBadRequest)
c.Assert(err, check.IsNil)
expected := "Bad parameters: you must choose at least one stream"
if !bytes.Contains(body, []byte(expected)) {
@@ -76,7 +75,7 @@ func (s *DockerSuite) TestLogsApiFollowEmptyOutput(c *check.C) {
_, body, err := sockRequestRaw("GET", fmt.Sprintf("/containers/%s/logs?follow=1&stdout=1&stderr=1&tail=all", name), bytes.NewBuffer(nil), "")
t1 := time.Now()
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
body.Close()
elapsed := t1.Sub(t0).Seconds()
if elapsed > 5.0 {
@@ -87,6 +86,6 @@ func (s *DockerSuite) TestLogsApiFollowEmptyOutput(c *check.C) {
func (s *DockerSuite) TestLogsAPIContainerNotFound(c *check.C) {
name := "nonExistentContainer"
resp, _, err := sockRequestRaw("GET", fmt.Sprintf("/containers/%s/logs?follow=1&stdout=1&stderr=1&tail=all", name), bytes.NewBuffer(nil), "")
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, http.StatusNotFound)
c.Assert(err, check.IsNil)
c.Assert(resp.StatusCode, check.Equals, http.StatusNotFound)
}
+59 -64
View File
@@ -10,7 +10,6 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/daemon/network"
"github.com/docker/docker/pkg/integration/checker"
"github.com/docker/docker/pkg/parsers/filters"
"github.com/go-check/check"
)
@@ -19,7 +18,7 @@ func (s *DockerSuite) TestApiNetworkGetDefaults(c *check.C) {
// By default docker daemon creates 3 networks. check if they are present
defaults := []string{"bridge", "host", "none"}
for _, nn := range defaults {
c.Assert(isNetworkAvailable(c, nn), checker.Equals, true)
c.Assert(isNetworkAvailable(c, nn), check.Equals, true)
}
}
@@ -31,25 +30,25 @@ func (s *DockerSuite) TestApiNetworkCreateDelete(c *check.C) {
CheckDuplicate: true,
}
id := createNetwork(c, config, true)
c.Assert(isNetworkAvailable(c, name), checker.Equals, true)
c.Assert(isNetworkAvailable(c, name), check.Equals, true)
// POST another network with same name and CheckDuplicate must fail
createNetwork(c, config, false)
// delete the network and make sure it is deleted
deleteNetwork(c, id, true)
c.Assert(isNetworkAvailable(c, name), checker.Equals, false)
c.Assert(isNetworkAvailable(c, name), check.Equals, false)
}
func (s *DockerSuite) TestApiNetworkFilter(c *check.C) {
nr := getNetworkResource(c, getNetworkIDByName(c, "bridge"))
c.Assert(nr.Name, checker.Equals, "bridge")
c.Assert(nr.Name, check.Equals, "bridge")
}
func (s *DockerSuite) TestApiNetworkInspect(c *check.C) {
// Inspect default bridge network
nr := getNetworkResource(c, "bridge")
c.Assert(nr.Name, checker.Equals, "bridge")
c.Assert(nr.Name, check.Equals, "bridge")
// run a container and attach it to the default bridge network
out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
@@ -58,15 +57,15 @@ func (s *DockerSuite) TestApiNetworkInspect(c *check.C) {
// inspect default bridge network again and make sure the container is connected
nr = getNetworkResource(c, nr.ID)
c.Assert(nr.Driver, checker.Equals, "bridge")
c.Assert(nr.Scope, checker.Equals, "local")
c.Assert(nr.IPAM.Driver, checker.Equals, "default")
c.Assert(len(nr.Containers), checker.Equals, 1)
c.Assert(nr.Containers[containerID], checker.NotNil)
c.Assert(nr.Driver, check.Equals, "bridge")
c.Assert(nr.Scope, check.Equals, "local")
c.Assert(nr.IPAM.Driver, check.Equals, "default")
c.Assert(len(nr.Containers), check.Equals, 1)
c.Assert(nr.Containers[containerID], check.NotNil)
ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
c.Assert(err, checker.IsNil)
c.Assert(ip.String(), checker.Equals, containerIP)
c.Assert(err, check.IsNil)
c.Assert(ip.String(), check.Equals, containerIP)
// IPAM configuration inspect
ipam := network.IPAM{
@@ -74,25 +73,21 @@ func (s *DockerSuite) TestApiNetworkInspect(c *check.C) {
Config: []network.IPAMConfig{{Subnet: "172.28.0.0/16", IPRange: "172.28.5.0/24", Gateway: "172.28.5.254"}},
}
config := types.NetworkCreate{
Name: "br0",
Driver: "bridge",
IPAM: ipam,
Options: map[string]string{"foo": "bar", "opts": "dopts"},
Name: "br0",
Driver: "bridge",
IPAM: ipam,
}
id0 := createNetwork(c, config, true)
c.Assert(isNetworkAvailable(c, "br0"), checker.Equals, true)
c.Assert(isNetworkAvailable(c, "br0"), check.Equals, true)
nr = getNetworkResource(c, id0)
c.Assert(len(nr.IPAM.Config), checker.Equals, 1)
c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "172.28.0.0/16")
c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24")
c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254")
c.Assert(nr.Options["foo"], checker.Equals, "bar")
c.Assert(nr.Options["opts"], checker.Equals, "dopts")
c.Assert(len(nr.IPAM.Config), check.Equals, 1)
c.Assert(nr.IPAM.Config[0].Subnet, check.Equals, "172.28.0.0/16")
c.Assert(nr.IPAM.Config[0].IPRange, check.Equals, "172.28.5.0/24")
c.Assert(nr.IPAM.Config[0].Gateway, check.Equals, "172.28.5.254")
// delete the network and make sure it is deleted
deleteNetwork(c, id0, true)
c.Assert(isNetworkAvailable(c, "br0"), checker.Equals, false)
c.Assert(isNetworkAvailable(c, "br0"), check.Equals, false)
}
func (s *DockerSuite) TestApiNetworkConnectDisconnect(c *check.C) {
@@ -103,9 +98,9 @@ func (s *DockerSuite) TestApiNetworkConnectDisconnect(c *check.C) {
}
id := createNetwork(c, config, true)
nr := getNetworkResource(c, id)
c.Assert(nr.Name, checker.Equals, name)
c.Assert(nr.ID, checker.Equals, id)
c.Assert(len(nr.Containers), checker.Equals, 0)
c.Assert(nr.Name, check.Equals, name)
c.Assert(nr.ID, check.Equals, id)
c.Assert(len(nr.Containers), check.Equals, 0)
// run a container
out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
@@ -116,20 +111,20 @@ func (s *DockerSuite) TestApiNetworkConnectDisconnect(c *check.C) {
// inspect the network to make sure container is connected
nr = getNetworkResource(c, nr.ID)
c.Assert(len(nr.Containers), checker.Equals, 1)
c.Assert(nr.Containers[containerID], checker.NotNil)
c.Assert(len(nr.Containers), check.Equals, 1)
c.Assert(nr.Containers[containerID], check.NotNil)
// check if container IP matches network inspect
ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
containerIP := findContainerIP(c, "test")
c.Assert(ip.String(), checker.Equals, containerIP)
c.Assert(ip.String(), check.Equals, containerIP)
// disconnect container from the network
disconnectNetwork(c, nr.ID, containerID)
nr = getNetworkResource(c, nr.ID)
c.Assert(nr.Name, checker.Equals, name)
c.Assert(len(nr.Containers), checker.Equals, 0)
c.Assert(nr.Name, check.Equals, name)
c.Assert(len(nr.Containers), check.Equals, 0)
// delete the network
deleteNetwork(c, nr.ID, true)
@@ -147,7 +142,7 @@ func (s *DockerSuite) TestApiNetworkIpamMultipleBridgeNetworks(c *check.C) {
IPAM: ipam0,
}
id0 := createNetwork(c, config0, true)
c.Assert(isNetworkAvailable(c, "test0"), checker.Equals, true)
c.Assert(isNetworkAvailable(c, "test0"), check.Equals, true)
ipam1 := network.IPAM{
Driver: "default",
@@ -160,7 +155,7 @@ func (s *DockerSuite) TestApiNetworkIpamMultipleBridgeNetworks(c *check.C) {
IPAM: ipam1,
}
createNetwork(c, config1, false)
c.Assert(isNetworkAvailable(c, "test1"), checker.Equals, false)
c.Assert(isNetworkAvailable(c, "test1"), check.Equals, false)
ipam2 := network.IPAM{
Driver: "default",
@@ -173,20 +168,20 @@ func (s *DockerSuite) TestApiNetworkIpamMultipleBridgeNetworks(c *check.C) {
IPAM: ipam2,
}
createNetwork(c, config2, true)
c.Assert(isNetworkAvailable(c, "test2"), checker.Equals, true)
c.Assert(isNetworkAvailable(c, "test2"), check.Equals, true)
// remove test0 and retry to create test1
deleteNetwork(c, id0, true)
createNetwork(c, config1, true)
c.Assert(isNetworkAvailable(c, "test1"), checker.Equals, true)
c.Assert(isNetworkAvailable(c, "test1"), check.Equals, true)
// for networks w/o ipam specified, docker will choose proper non-overlapping subnets
createNetwork(c, types.NetworkCreate{Name: "test3"}, true)
c.Assert(isNetworkAvailable(c, "test3"), checker.Equals, true)
c.Assert(isNetworkAvailable(c, "test3"), check.Equals, true)
createNetwork(c, types.NetworkCreate{Name: "test4"}, true)
c.Assert(isNetworkAvailable(c, "test4"), checker.Equals, true)
c.Assert(isNetworkAvailable(c, "test4"), check.Equals, true)
createNetwork(c, types.NetworkCreate{Name: "test5"}, true)
c.Assert(isNetworkAvailable(c, "test5"), checker.Equals, true)
c.Assert(isNetworkAvailable(c, "test5"), check.Equals, true)
for i := 1; i < 6; i++ {
deleteNetwork(c, fmt.Sprintf("test%d", i), true)
@@ -195,12 +190,12 @@ func (s *DockerSuite) TestApiNetworkIpamMultipleBridgeNetworks(c *check.C) {
func isNetworkAvailable(c *check.C, name string) bool {
status, body, err := sockRequest("GET", "/networks", nil)
c.Assert(status, checker.Equals, http.StatusOK)
c.Assert(err, checker.IsNil)
c.Assert(status, check.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
nJSON := []types.NetworkResource{}
err = json.Unmarshal(body, &nJSON)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
for _, n := range nJSON {
if n.Name == name {
@@ -217,28 +212,28 @@ func getNetworkIDByName(c *check.C, name string) string {
)
filterArgs["name"] = []string{name}
filterJSON, err := filters.ToParam(filterArgs)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
v.Set("filters", filterJSON)
status, body, err := sockRequest("GET", "/networks?"+v.Encode(), nil)
c.Assert(status, checker.Equals, http.StatusOK)
c.Assert(err, checker.IsNil)
c.Assert(status, check.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
nJSON := []types.NetworkResource{}
err = json.Unmarshal(body, &nJSON)
c.Assert(err, checker.IsNil)
c.Assert(len(nJSON), checker.Equals, 1)
c.Assert(err, check.IsNil)
c.Assert(len(nJSON), check.Equals, 1)
return nJSON[0].ID
}
func getNetworkResource(c *check.C, id string) *types.NetworkResource {
_, obj, err := sockRequest("GET", "/networks/"+id, nil)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
nr := types.NetworkResource{}
err = json.Unmarshal(obj, &nr)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
return &nr
}
@@ -246,16 +241,16 @@ func getNetworkResource(c *check.C, id string) *types.NetworkResource {
func createNetwork(c *check.C, config types.NetworkCreate, shouldSucceed bool) string {
status, resp, err := sockRequest("POST", "/networks/create", config)
if !shouldSucceed {
c.Assert(status, checker.Not(checker.Equals), http.StatusCreated)
c.Assert(status, check.Not(check.Equals), http.StatusCreated)
return ""
}
c.Assert(status, checker.Equals, http.StatusCreated)
c.Assert(err, checker.IsNil)
c.Assert(status, check.Equals, http.StatusCreated)
c.Assert(err, check.IsNil)
var nr types.NetworkCreateResponse
err = json.Unmarshal(resp, &nr)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
return nr.ID
}
@@ -266,8 +261,8 @@ func connectNetwork(c *check.C, nid, cid string) {
}
status, _, err := sockRequest("POST", "/networks/"+nid+"/connect", config)
c.Assert(status, checker.Equals, http.StatusOK)
c.Assert(err, checker.IsNil)
c.Assert(status, check.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
}
func disconnectNetwork(c *check.C, nid, cid string) {
@@ -276,17 +271,17 @@ func disconnectNetwork(c *check.C, nid, cid string) {
}
status, _, err := sockRequest("POST", "/networks/"+nid+"/disconnect", config)
c.Assert(status, checker.Equals, http.StatusOK)
c.Assert(err, checker.IsNil)
c.Assert(status, check.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
}
func deleteNetwork(c *check.C, id string, shouldSucceed bool) {
status, _, err := sockRequest("DELETE", "/networks/"+id, nil)
if !shouldSucceed {
c.Assert(status, checker.Not(checker.Equals), http.StatusOK)
c.Assert(err, checker.NotNil)
c.Assert(status, check.Not(check.Equals), http.StatusOK)
c.Assert(err, check.NotNil)
return
}
c.Assert(status, checker.Equals, http.StatusOK)
c.Assert(err, checker.IsNil)
c.Assert(status, check.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
}
+8 -6
View File
@@ -6,18 +6,20 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
func (s *DockerSuite) TestGetVersion(c *check.C) {
status, body, err := sockRequest("GET", "/version", nil)
c.Assert(status, checker.Equals, http.StatusOK)
c.Assert(err, checker.IsNil)
c.Assert(status, check.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
var v types.Version
if err := json.Unmarshal(body, &v); err != nil {
c.Fatal(err)
}
c.Assert(json.Unmarshal(body, &v), checker.IsNil)
c.Assert(v.Version, checker.Equals, dockerversion.VERSION, check.Commentf("Version mismatch"))
if v.Version != dockerversion.VERSION {
c.Fatal("Version mismatch")
}
}
+36 -11
View File
@@ -22,8 +22,9 @@ func (s *DockerSuite) TestAttachMultipleAndRestart(c *check.C) {
endGroup.Add(3)
startGroup.Add(3)
err := waitForContainer("attacher", "-d", "busybox", "/bin/sh", "-c", "while true; do sleep 1; echo hello; done")
c.Assert(err, check.IsNil)
if err := waitForContainer("attacher", "-d", "busybox", "/bin/sh", "-c", "while true; do sleep 1; echo hello; done"); err != nil {
c.Fatal(err)
}
startDone := make(chan struct{})
endDone := make(chan struct{})
@@ -83,6 +84,7 @@ func (s *DockerSuite) TestAttachMultipleAndRestart(c *check.C) {
case <-time.After(attachWait):
c.Fatalf("Attaches did not finish properly")
}
}
func (s *DockerSuite) TestAttachTtyWithoutStdin(c *check.C) {
@@ -92,6 +94,13 @@ func (s *DockerSuite) TestAttachTtyWithoutStdin(c *check.C) {
id := strings.TrimSpace(out)
c.Assert(waitRun(id), check.IsNil)
defer func() {
cmd := exec.Command(dockerBinary, "kill", id)
if out, _, err := runCommandWithOutput(cmd); err != nil {
c.Fatalf("failed to kill container: %v (%v)", out, err)
}
}()
done := make(chan error)
go func() {
defer close(done)
@@ -132,21 +141,37 @@ func (s *DockerSuite) TestAttachDisconnect(c *check.C) {
}
defer stdin.Close()
stdout, err := cmd.StdoutPipe()
c.Assert(err, check.IsNil)
if err != nil {
c.Fatal(err)
}
defer stdout.Close()
c.Assert(cmd.Start(), check.IsNil)
if err := cmd.Start(); err != nil {
c.Fatal(err)
}
defer cmd.Process.Kill()
_, err = stdin.Write([]byte("hello\n"))
c.Assert(err, check.IsNil)
if _, err := stdin.Write([]byte("hello\n")); err != nil {
c.Fatal(err)
}
out, err = bufio.NewReader(stdout).ReadString('\n')
c.Assert(err, check.IsNil)
c.Assert(strings.TrimSpace(out), check.Equals, "hello")
if err != nil {
c.Fatal(err)
}
if strings.TrimSpace(out) != "hello" {
c.Fatalf("expected 'hello', got %q", out)
}
c.Assert(stdin.Close(), check.IsNil)
if err := stdin.Close(); err != nil {
c.Fatal(err)
}
// Expect container to still be running after stdin is closed
running, err := inspectField(id, "State.Running")
c.Assert(err, check.IsNil)
c.Assert(running, check.Equals, "true")
if err != nil {
c.Fatal(err)
}
if running != "true" {
c.Fatal("expected container to still be running")
}
}
+11 -7
View File
@@ -3,7 +3,6 @@ package main
import (
"strings"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -23,7 +22,9 @@ func (s *DockerSuite) TestDiffFilenameShownInOutput(c *check.C) {
break
}
}
c.Assert(found, checker.True)
if !found {
c.Errorf("couldn't find the new file in docker diff's output: %v", out)
}
}
// test to ensure GH #3840 doesn't occur any more
@@ -42,7 +43,9 @@ func (s *DockerSuite) TestDiffEnsureDockerinitFilesAreIgnored(c *check.C) {
out, _ = dockerCmd(c, "diff", cleanCID)
for _, filename := range dockerinitFiles {
c.Assert(out, checker.Not(checker.Contains), filename)
if strings.Contains(out, filename) {
c.Errorf("found file which should've been ignored %v in diff output", filename)
}
}
}
}
@@ -58,7 +61,6 @@ func (s *DockerSuite) TestDiffEnsureOnlyKmsgAndPtmx(c *check.C) {
"C /dev": true,
"A /dev/full": true, // busybox
"C /dev/ptmx": true, // libcontainer
"A /dev/mqueue": true, // lxc
"A /dev/kmsg": true, // lxc
"A /dev/fd": true,
"A /dev/fuse": true,
@@ -75,13 +77,15 @@ func (s *DockerSuite) TestDiffEnsureOnlyKmsgAndPtmx(c *check.C) {
}
for _, line := range strings.Split(out, "\n") {
c.Assert(line == "" || expected[line], checker.True)
if line != "" && !expected[line] {
c.Errorf("%q is shown in the diff but shouldn't", line)
}
}
}
// https://github.com/docker/docker/pull/14381#discussion_r33859347
func (s *DockerSuite) TestDiffEmptyArgClientError(c *check.C) {
out, _, err := dockerCmdWithError("diff", "")
c.Assert(err, checker.NotNil)
c.Assert(strings.TrimSpace(out), checker.Equals, "Container name cannot be empty")
c.Assert(err, check.NotNil)
c.Assert(strings.TrimSpace(out), check.Equals, "Container name cannot be empty")
}
@@ -56,7 +56,6 @@ func (s *DockerSuite) TestEventsRedirectStdout(c *check.C) {
func (s *DockerSuite) TestEventsOOMDisableFalse(c *check.C) {
testRequires(c, DaemonIsLinux)
testRequires(c, NativeExecDriver)
testRequires(c, oomControl)
errChan := make(chan error)
@@ -104,7 +103,6 @@ func (s *DockerSuite) TestEventsOOMDisableFalse(c *check.C) {
func (s *DockerSuite) TestEventsOOMDisableTrue(c *check.C) {
testRequires(c, DaemonIsLinux)
testRequires(c, NativeExecDriver)
testRequires(c, oomControl)
errChan := make(chan error)
+14 -10
View File
@@ -9,7 +9,6 @@ import (
"strings"
"time"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
"github.com/kr/pty"
)
@@ -22,7 +21,9 @@ func (s *DockerSuite) TestExecInteractiveStdinClose(c *check.C) {
cmd := exec.Command(dockerBinary, "exec", "-i", contID, "echo", "-n", "hello")
p, err := pty.Start(cmd)
c.Assert(err, checker.IsNil)
if err != nil {
c.Fatal(err)
}
b := bytes.NewBuffer(nil)
go io.Copy(b, p)
@@ -32,9 +33,12 @@ func (s *DockerSuite) TestExecInteractiveStdinClose(c *check.C) {
select {
case err := <-ch:
c.Assert(err, checker.IsNil)
output := b.String()
c.Assert(strings.TrimSpace(output), checker.Equals, "hello")
if err != nil {
c.Errorf("cmd finished with error %v", err)
}
if output := b.String(); strings.TrimSpace(output) != "hello" {
c.Fatalf("Unexpected output %s", output)
}
case <-time.After(1 * time.Second):
c.Fatal("timed out running docker exec")
}
@@ -46,11 +50,11 @@ func (s *DockerSuite) TestExecTTY(c *check.C) {
cmd := exec.Command(dockerBinary, "exec", "-it", "test", "sh")
p, err := pty.Start(cmd)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
defer p.Close()
_, err = p.Write([]byte("cat /foo && exit\n"))
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
chErr := make(chan error)
go func() {
@@ -58,13 +62,13 @@ func (s *DockerSuite) TestExecTTY(c *check.C) {
}()
select {
case err := <-chErr:
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
case <-time.After(3 * time.Second):
c.Fatal("timeout waiting for exec to exit")
}
buf := make([]byte, 256)
read, err := p.Read(buf)
c.Assert(err, checker.IsNil)
c.Assert(bytes.Contains(buf, []byte("hello")), checker.Equals, true, check.Commentf(string(buf[:read])))
c.Assert(err, check.IsNil)
c.Assert(bytes.Contains(buf, []byte("hello")), check.Equals, true, check.Commentf(string(buf[:read])))
}
@@ -7,7 +7,6 @@ import (
"strings"
"time"
"github.com/docker/docker/pkg/integration/checker"
"github.com/docker/docker/pkg/stringid"
"github.com/go-check/check"
)
@@ -198,9 +197,3 @@ func (s *DockerSuite) TestImagesEnsureDanglingImageOnlyListedOnce(c *check.C) {
c.Fatalf("expected 1 dangling image, got %d: %s", a, out)
}
}
func (s *DockerSuite) TestImagesWithIncorrectFilter(c *check.C) {
out, _, err := dockerCmdWithError("images", "-f", "dangling=invalid")
c.Assert(err, check.NotNil)
c.Assert(out, checker.Contains, "Invalid filter")
}
@@ -4,7 +4,6 @@ package main
import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -13,22 +12,34 @@ func (s *DockerSuite) TestInspectNamedMountPoint(c *check.C) {
dockerCmd(c, "run", "-d", "--name", "test", "-v", "data:/data", "busybox", "cat")
vol, err := inspectFieldJSON("test", "Mounts")
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
var mp []types.MountPoint
err = unmarshalJSON([]byte(vol), &mp)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
c.Assert(mp, checker.HasLen, 1, check.Commentf("Expected 1 mount point"))
if len(mp) != 1 {
c.Fatalf("Expected 1 mount point, was %v\n", len(mp))
}
m := mp[0]
c.Assert(m.Name, checker.Equals, "data", check.Commentf("Expected name data"))
if m.Name != "data" {
c.Fatalf("Expected name data, was %s\n", m.Name)
}
c.Assert(m.Driver, checker.Equals, "local", check.Commentf("Expected driver local"))
if m.Driver != "local" {
c.Fatalf("Expected driver local, was %s\n", m.Driver)
}
c.Assert(m.Source, checker.Not(checker.Equals), "", check.Commentf("Expected source to not be empty"))
if m.Source == "" {
c.Fatalf("Expected source to not be empty")
}
c.Assert(m.RW, checker.Equals, true)
if m.RW != true {
c.Fatalf("Expected rw to be true")
}
c.Assert(m.Destination, checker.Equals, "/data", check.Commentf("Expected destination /data"))
if m.Destination != "/data" {
c.Fatalf("Expected destination /data, was %s\n", m.Destination)
}
}
+120 -85
View File
@@ -10,7 +10,6 @@ import (
"strings"
"time"
"github.com/docker/docker/pkg/integration/checker"
"github.com/docker/docker/pkg/timeutils"
"github.com/go-check/check"
)
@@ -20,13 +19,13 @@ func (s *DockerSuite) TestLogsContainerSmallerThanPage(c *check.C) {
testRequires(c, DaemonIsLinux)
testLen := 32767
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
cleanedContainerID := strings.TrimSpace(out)
id := strings.TrimSpace(out)
dockerCmd(c, "wait", id)
out, _ = dockerCmd(c, "logs", id)
c.Assert(out, checker.HasLen, testLen+1)
dockerCmd(c, "wait", cleanedContainerID)
out, _ = dockerCmd(c, "logs", cleanedContainerID)
if len(out) != testLen+1 {
c.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
}
}
// Regression test: When going over the PageSize, it used to panic (gh#4851)
@@ -35,12 +34,14 @@ func (s *DockerSuite) TestLogsContainerBiggerThanPage(c *check.C) {
testLen := 32768
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
id := strings.TrimSpace(out)
dockerCmd(c, "wait", id)
cleanedContainerID := strings.TrimSpace(out)
dockerCmd(c, "wait", cleanedContainerID)
out, _ = dockerCmd(c, "logs", id)
out, _ = dockerCmd(c, "logs", cleanedContainerID)
c.Assert(out, checker.HasLen, testLen+1)
if len(out) != testLen+1 {
c.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
}
}
// Regression test: When going much over the PageSize, it used to block (gh#4851)
@@ -49,12 +50,14 @@ func (s *DockerSuite) TestLogsContainerMuchBiggerThanPage(c *check.C) {
testLen := 33000
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
id := strings.TrimSpace(out)
dockerCmd(c, "wait", id)
cleanedContainerID := strings.TrimSpace(out)
dockerCmd(c, "wait", cleanedContainerID)
out, _ = dockerCmd(c, "logs", id)
out, _ = dockerCmd(c, "logs", cleanedContainerID)
c.Assert(out, checker.HasLen, testLen+1)
if len(out) != testLen+1 {
c.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
}
}
func (s *DockerSuite) TestLogsTimestamps(c *check.C) {
@@ -62,23 +65,28 @@ func (s *DockerSuite) TestLogsTimestamps(c *check.C) {
testLen := 100
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo =; done;", testLen))
id := strings.TrimSpace(out)
dockerCmd(c, "wait", id)
cleanedContainerID := strings.TrimSpace(out)
dockerCmd(c, "wait", cleanedContainerID)
out, _ = dockerCmd(c, "logs", "-t", id)
out, _ = dockerCmd(c, "logs", "-t", cleanedContainerID)
lines := strings.Split(out, "\n")
c.Assert(lines, checker.HasLen, testLen+1)
if len(lines) != testLen+1 {
c.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines))
}
ts := regexp.MustCompile(`^.* `)
for _, l := range lines {
if l != "" {
_, err := time.Parse(timeutils.RFC3339NanoFixed+" ", ts.FindString(l))
c.Assert(err, checker.IsNil, check.Commentf("Failed to parse timestamp from %v", l))
// ensure we have padded 0's
c.Assert(l[29], checker.Equals, uint8('Z'))
if err != nil {
c.Fatalf("Failed to parse timestamp from %v: %v", l, err)
}
if l[29] != 'Z' { // ensure we have padded 0's
c.Fatalf("Timestamp isn't padded properly: %s", l)
}
}
}
}
@@ -88,16 +96,19 @@ func (s *DockerSuite) TestLogsSeparateStderr(c *check.C) {
msg := "stderr_log"
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("echo %s 1>&2", msg))
id := strings.TrimSpace(out)
dockerCmd(c, "wait", id)
cleanedContainerID := strings.TrimSpace(out)
dockerCmd(c, "wait", cleanedContainerID)
stdout, stderr, _ := dockerCmdWithStdoutStderr(c, "logs", id)
stdout, stderr, _ := dockerCmdWithStdoutStderr(c, "logs", cleanedContainerID)
c.Assert(stdout, checker.Equals, "")
if stdout != "" {
c.Fatalf("Expected empty stdout stream, got %v", stdout)
}
stderr = strings.TrimSpace(stderr)
c.Assert(stderr, checker.Equals, msg)
if stderr != msg {
c.Fatalf("Expected %v in stderr stream, got %v", msg, stderr)
}
}
func (s *DockerSuite) TestLogsStderrInStdout(c *check.C) {
@@ -105,14 +116,18 @@ func (s *DockerSuite) TestLogsStderrInStdout(c *check.C) {
msg := "stderr_log"
out, _ := dockerCmd(c, "run", "-d", "-t", "busybox", "sh", "-c", fmt.Sprintf("echo %s 1>&2", msg))
id := strings.TrimSpace(out)
dockerCmd(c, "wait", id)
cleanedContainerID := strings.TrimSpace(out)
dockerCmd(c, "wait", cleanedContainerID)
stdout, stderr, _ := dockerCmdWithStdoutStderr(c, "logs", id)
c.Assert(stderr, checker.Equals, "")
stdout, stderr, _ := dockerCmdWithStdoutStderr(c, "logs", cleanedContainerID)
if stderr != "" {
c.Fatalf("Expected empty stderr stream, got %v", stderr)
}
stdout = strings.TrimSpace(stdout)
c.Assert(stdout, checker.Equals, msg)
if stdout != msg {
c.Fatalf("Expected %v in stdout stream, got %v", msg, stdout)
}
}
func (s *DockerSuite) TestLogsTail(c *check.C) {
@@ -120,37 +135,43 @@ func (s *DockerSuite) TestLogsTail(c *check.C) {
testLen := 100
out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo =; done;", testLen))
id := strings.TrimSpace(out)
dockerCmd(c, "wait", id)
cleanedContainerID := strings.TrimSpace(out)
dockerCmd(c, "wait", cleanedContainerID)
out, _ = dockerCmd(c, "logs", "--tail", "5", id)
out, _ = dockerCmd(c, "logs", "--tail", "5", cleanedContainerID)
lines := strings.Split(out, "\n")
c.Assert(lines, checker.HasLen, 6)
out, _ = dockerCmd(c, "logs", "--tail", "all", id)
if len(lines) != 6 {
c.Fatalf("Expected log %d lines, received %d\n", 6, len(lines))
}
out, _ = dockerCmd(c, "logs", "--tail", "all", cleanedContainerID)
lines = strings.Split(out, "\n")
c.Assert(lines, checker.HasLen, testLen+1)
out, _, _ = dockerCmdWithStdoutStderr(c, "logs", "--tail", "random", id)
if len(lines) != testLen+1 {
c.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines))
}
out, _, _ = dockerCmdWithStdoutStderr(c, "logs", "--tail", "random", cleanedContainerID)
lines = strings.Split(out, "\n")
c.Assert(lines, checker.HasLen, testLen+1)
if len(lines) != testLen+1 {
c.Fatalf("Expected log %d lines, received %d\n", testLen+1, len(lines))
}
}
func (s *DockerSuite) TestLogsFollowStopped(c *check.C) {
testRequires(c, DaemonIsLinux)
out, _ := dockerCmd(c, "run", "-d", "busybox", "echo", "hello")
id := strings.TrimSpace(out)
dockerCmd(c, "wait", id)
cleanedContainerID := strings.TrimSpace(out)
dockerCmd(c, "wait", cleanedContainerID)
logsCmd := exec.Command(dockerBinary, "logs", "-f", id)
c.Assert(logsCmd.Start(), checker.IsNil)
logsCmd := exec.Command(dockerBinary, "logs", "-f", cleanedContainerID)
if err := logsCmd.Start(); err != nil {
c.Fatal(err)
}
errChan := make(chan error)
go func() {
@@ -160,7 +181,7 @@ func (s *DockerSuite) TestLogsFollowStopped(c *check.C) {
select {
case err := <-errChan:
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
case <-time.After(1 * time.Second):
c.Fatal("Following logs is hanged")
}
@@ -173,14 +194,16 @@ func (s *DockerSuite) TestLogsSince(c *check.C) {
log2Line := strings.Split(strings.Split(out, "\n")[1], " ")
t, err := strconv.ParseInt(log2Line[0], 10, 64) // the timestamp log2 is written
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
since := t + 1 // add 1s so log1 & log2 doesn't show up
out, _ = dockerCmd(c, "logs", "-t", fmt.Sprintf("--since=%v", since), name)
// Skip 2 seconds
unexpected := []string{"log1", "log2"}
for _, v := range unexpected {
c.Assert(out, checker.Not(checker.Contains), v, check.Commentf("unexpected log message returned, since=%v", since))
if strings.Contains(out, v) {
c.Fatalf("unexpected log message returned=%v, since=%v\nout=%v", v, since, out)
}
}
// Test with default value specified and parameter omitted
expected := []string{"log1", "log2", "log3"}
@@ -189,9 +212,13 @@ func (s *DockerSuite) TestLogsSince(c *check.C) {
exec.Command(dockerBinary, "logs", "-t", "--since=0", name),
} {
out, _, err = runCommandWithOutput(cmd)
c.Assert(err, checker.IsNil, check.Commentf("failed to log container: %s", out))
if err != nil {
c.Fatalf("failed to log container: %s, %v", out, err)
}
for _, v := range expected {
c.Assert(out, checker.Contains, v)
if !strings.Contains(out, v) {
c.Fatalf("'%v' does not contain=%v\nout=%s", cmd.Args, v, out)
}
}
}
}
@@ -199,17 +226,23 @@ func (s *DockerSuite) TestLogsSince(c *check.C) {
func (s *DockerSuite) TestLogsSinceFutureFollow(c *check.C) {
testRequires(c, DaemonIsLinux)
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", `for i in $(seq 1 5); do date +%s; sleep 1; done`)
id := strings.TrimSpace(out)
cleanedContainerID := strings.TrimSpace(out)
now := daemonTime(c).Unix()
since := now + 2
out, _ = dockerCmd(c, "logs", "-f", fmt.Sprintf("--since=%v", since), id)
out, _ = dockerCmd(c, "logs", "-f", fmt.Sprintf("--since=%v", since), cleanedContainerID)
lines := strings.Split(strings.TrimSpace(out), "\n")
c.Assert(lines, checker.Not(checker.HasLen), 0)
if len(lines) == 0 {
c.Fatal("got no log lines")
}
for _, v := range lines {
ts, err := strconv.ParseInt(v, 10, 64)
c.Assert(err, checker.IsNil, check.Commentf("cannot parse timestamp output from log: '%v'\nout=%s", v, out))
c.Assert(ts >= since, checker.Equals, true, check.Commentf("earlier log found. since=%v logdate=%v", since, ts))
if err != nil {
c.Fatalf("cannot parse timestamp output from log: '%v'\nout=%s", v, out)
}
if ts < since {
c.Fatalf("earlier log found. since=%v logdate=%v", since, ts)
}
}
}
@@ -218,31 +251,33 @@ func (s *DockerSuite) TestLogsFollowSlowStdoutConsumer(c *check.C) {
testRequires(c, DaemonIsLinux)
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", `usleep 200000;yes X | head -c 200000`)
id := strings.TrimSpace(out)
cleanedContainerID := strings.TrimSpace(out)
stopSlowRead := make(chan bool)
go func() {
exec.Command(dockerBinary, "wait", id).Run()
exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
stopSlowRead <- true
}()
logCmd := exec.Command(dockerBinary, "logs", "-f", id)
logCmd := exec.Command(dockerBinary, "logs", "-f", cleanedContainerID)
stdout, err := logCmd.StdoutPipe()
c.Assert(err, checker.IsNil)
c.Assert(logCmd.Start(), checker.IsNil)
c.Assert(err, check.IsNil)
c.Assert(logCmd.Start(), check.IsNil)
// First read slowly
bytes1, err := consumeWithSpeed(stdout, 10, 50*time.Millisecond, stopSlowRead)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
// After the container has finished we can continue reading fast
bytes2, err := consumeWithSpeed(stdout, 32*1024, 0, nil)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
actual := bytes1 + bytes2
expected := 200000
c.Assert(actual, checker.Equals, expected)
if actual != expected {
c.Fatalf("Invalid bytes read: %d, expected %d", actual, expected)
}
}
@@ -250,7 +285,7 @@ func (s *DockerSuite) TestLogsFollowGoroutinesWithStdout(c *check.C) {
testRequires(c, DaemonIsLinux)
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "while true; do echo hello; sleep 2; done")
id := strings.TrimSpace(out)
c.Assert(waitRun(id), checker.IsNil)
c.Assert(waitRun(id), check.IsNil)
type info struct {
NGoroutines int
@@ -258,9 +293,9 @@ func (s *DockerSuite) TestLogsFollowGoroutinesWithStdout(c *check.C) {
getNGoroutines := func() int {
var i info
status, b, err := sockRequest("GET", "/info", nil)
c.Assert(err, checker.IsNil)
c.Assert(status, checker.Equals, 200)
c.Assert(json.Unmarshal(b, &i), checker.IsNil)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, 200)
c.Assert(json.Unmarshal(b, &i), check.IsNil)
return i.NGoroutines
}
@@ -269,7 +304,7 @@ func (s *DockerSuite) TestLogsFollowGoroutinesWithStdout(c *check.C) {
cmd := exec.Command(dockerBinary, "logs", "-f", id)
r, w := io.Pipe()
cmd.Stdout = w
c.Assert(cmd.Start(), checker.IsNil)
c.Assert(cmd.Start(), check.IsNil)
// Make sure pipe is written to
chErr := make(chan error)
@@ -278,17 +313,17 @@ func (s *DockerSuite) TestLogsFollowGoroutinesWithStdout(c *check.C) {
_, err := r.Read(b)
chErr <- err
}()
c.Assert(<-chErr, checker.IsNil)
c.Assert(cmd.Process.Kill(), checker.IsNil)
c.Assert(<-chErr, check.IsNil)
c.Assert(cmd.Process.Kill(), check.IsNil)
// NGoroutines is not updated right away, so we need to wait before failing
t := time.After(30 * time.Second)
for {
select {
case <-t:
n := getNGoroutines()
c.Assert(n <= nroutines, checker.Equals, true, check.Commentf("leaked goroutines: expected less than or equal to %d, got: %d", nroutines, n))
if n := getNGoroutines(); n > nroutines {
c.Fatalf("leaked goroutines: expected less than or equal to %d, got: %d", nroutines, n)
}
default:
if n := getNGoroutines(); n <= nroutines {
return
@@ -302,7 +337,7 @@ func (s *DockerSuite) TestLogsFollowGoroutinesNoOutput(c *check.C) {
testRequires(c, DaemonIsLinux)
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "while true; do sleep 2; done")
id := strings.TrimSpace(out)
c.Assert(waitRun(id), checker.IsNil)
c.Assert(waitRun(id), check.IsNil)
type info struct {
NGoroutines int
@@ -310,27 +345,27 @@ func (s *DockerSuite) TestLogsFollowGoroutinesNoOutput(c *check.C) {
getNGoroutines := func() int {
var i info
status, b, err := sockRequest("GET", "/info", nil)
c.Assert(err, checker.IsNil)
c.Assert(status, checker.Equals, 200)
c.Assert(json.Unmarshal(b, &i), checker.IsNil)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, 200)
c.Assert(json.Unmarshal(b, &i), check.IsNil)
return i.NGoroutines
}
nroutines := getNGoroutines()
cmd := exec.Command(dockerBinary, "logs", "-f", id)
c.Assert(cmd.Start(), checker.IsNil)
c.Assert(cmd.Start(), check.IsNil)
time.Sleep(200 * time.Millisecond)
c.Assert(cmd.Process.Kill(), checker.IsNil)
c.Assert(cmd.Process.Kill(), check.IsNil)
// NGoroutines is not updated right away, so we need to wait before failing
t := time.After(30 * time.Second)
for {
select {
case <-t:
n := getNGoroutines()
c.Assert(n <= nroutines, checker.Equals, true, check.Commentf("leaked goroutines: expected less than or equal to %d, got: %d", nroutines, n))
if n := getNGoroutines(); n > nroutines {
c.Fatalf("leaked goroutines: expected less than or equal to %d, got: %d", nroutines, n)
}
default:
if n := getNGoroutines(); n <= nroutines {
return
@@ -344,5 +379,5 @@ func (s *DockerSuite) TestLogsCLIContainerNotFound(c *check.C) {
name := "testlogsnocontainer"
out, _, _ := dockerCmdWithError("logs", name)
message := fmt.Sprintf(".*no such id: %s.*\n", name)
c.Assert(out, checker.Matches, message)
c.Assert(out, check.Matches, message)
}
+30 -16
View File
@@ -6,7 +6,6 @@ import (
"net"
"strings"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -18,7 +17,9 @@ func startServerContainer(c *check.C, msg string, port int) string {
"busybox",
"sh", "-c", fmt.Sprintf("echo %q | nc -lp %d", msg, port),
}
c.Assert(waitForContainer(name, cmd...), check.IsNil)
if err := waitForContainer(name, cmd...); err != nil {
c.Fatalf("Failed to launch server container: %v", err)
}
return name
}
@@ -29,11 +30,14 @@ func getExternalAddress(c *check.C) net.IP {
}
ifaceAddrs, err := iface.Addrs()
c.Assert(err, check.IsNil)
c.Assert(ifaceAddrs, checker.Not(checker.HasLen), 0)
if err != nil || len(ifaceAddrs) == 0 {
c.Fatalf("Error retrieving addresses for eth0: %v (%d addresses)", err, len(ifaceAddrs))
}
ifaceIP, _, err := net.ParseCIDR(ifaceAddrs[0].String())
c.Assert(err, check.IsNil)
if err != nil {
c.Fatalf("Error retrieving the up for eth0: %s", err)
}
return ifaceIP
}
@@ -56,14 +60,18 @@ func (s *DockerSuite) TestNetworkNat(c *check.C) {
startServerContainer(c, msg, 8080)
endpoint := getExternalAddress(c)
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", endpoint.String(), 8080))
c.Assert(err, check.IsNil)
if err != nil {
c.Fatalf("Failed to connect to container (%v)", err)
}
data, err := ioutil.ReadAll(conn)
conn.Close()
c.Assert(err, check.IsNil)
if err != nil {
c.Fatal(err)
}
final := strings.TrimRight(string(data), "\n")
c.Assert(final, checker.Equals, msg)
if final != msg {
c.Fatalf("Expected message %q but received %q", msg, final)
}
}
func (s *DockerSuite) TestNetworkLocalhostTCPNat(c *check.C) {
@@ -74,14 +82,18 @@ func (s *DockerSuite) TestNetworkLocalhostTCPNat(c *check.C) {
)
startServerContainer(c, msg, 8081)
conn, err := net.Dial("tcp", "localhost:8081")
c.Assert(err, check.IsNil)
if err != nil {
c.Fatalf("Failed to connect to container (%v)", err)
}
data, err := ioutil.ReadAll(conn)
conn.Close()
c.Assert(err, check.IsNil)
if err != nil {
c.Fatal(err)
}
final := strings.TrimRight(string(data), "\n")
c.Assert(final, checker.Equals, msg)
if final != msg {
c.Fatalf("Expected message %q but received %q", msg, final)
}
}
func (s *DockerSuite) TestNetworkLoopbackNat(c *check.C) {
@@ -93,5 +105,7 @@ func (s *DockerSuite) TestNetworkLoopbackNat(c *check.C) {
out, _ := dockerCmd(c, "run", "-t", "--net=container:server", "busybox",
"sh", "-c", fmt.Sprintf("stty raw && nc -w 5 %s 8080", endpoint.String()))
final := strings.TrimRight(string(out), "\n")
c.Assert(final, checker.Equals, msg)
if final != msg {
c.Fatalf("Expected message %q but received %q", msg, final)
}
}
+25 -48
View File
@@ -13,17 +13,12 @@ import (
"strings"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/integration/checker"
"github.com/docker/libnetwork/driverapi"
remoteapi "github.com/docker/libnetwork/drivers/remote/api"
"github.com/docker/libnetwork/netlabel"
"github.com/go-check/check"
)
const dummyNetworkDriver = "dummy-network-driver"
var remoteDriverNetworkRequest remoteapi.CreateNetworkRequest
func init() {
check.Suite(&DockerNetworkSuite{
ds: &DockerSuite{},
@@ -48,7 +43,9 @@ func (s *DockerNetworkSuite) TearDownTest(c *check.C) {
func (s *DockerNetworkSuite) SetUpSuite(c *check.C) {
mux := http.NewServeMux()
s.server = httptest.NewServer(mux)
c.Assert(s.server, check.NotNil, check.Commentf("Failed to start a HTTP Server"))
if s.server == nil {
c.Fatal("Failed to start a HTTP Server")
}
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
@@ -61,11 +58,6 @@ func (s *DockerNetworkSuite) SetUpSuite(c *check.C) {
})
mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
if err != nil {
http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintf(w, "null")
})
@@ -75,12 +67,14 @@ func (s *DockerNetworkSuite) SetUpSuite(c *check.C) {
fmt.Fprintf(w, "null")
})
err := os.MkdirAll("/etc/docker/plugins", 0755)
c.Assert(err, checker.IsNil)
if err := os.MkdirAll("/etc/docker/plugins", 0755); err != nil {
c.Fatal(err)
}
fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", dummyNetworkDriver)
err = ioutil.WriteFile(fileName, []byte(s.server.URL), 0644)
c.Assert(err, checker.IsNil)
if err := ioutil.WriteFile(fileName, []byte(s.server.URL), 0644); err != nil {
c.Fatal(err)
}
}
func (s *DockerNetworkSuite) TearDownSuite(c *check.C) {
@@ -90,8 +84,9 @@ func (s *DockerNetworkSuite) TearDownSuite(c *check.C) {
s.server.Close()
err := os.RemoveAll("/etc/docker/plugins")
c.Assert(err, checker.IsNil)
if err := os.RemoveAll("/etc/docker/plugins"); err != nil {
c.Fatal(err)
}
}
func assertNwIsAvailable(c *check.C, name string) {
@@ -140,18 +135,13 @@ func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *check.C) {
assertNwNotAvailable(c, "test")
}
func (s *DockerSuite) TestDockerNetworkDeleteNotExists(c *check.C) {
out, _, err := dockerCmdWithError("network", "rm", "test")
c.Assert(err, checker.NotNil, check.Commentf("%v", out))
}
func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) {
dockerCmd(c, "network", "create", "test")
assertNwIsAvailable(c, "test")
nr := getNwResource(c, "test")
c.Assert(nr.Name, checker.Equals, "test")
c.Assert(len(nr.Containers), checker.Equals, 0)
c.Assert(nr.Name, check.Equals, "test")
c.Assert(len(nr.Containers), check.Equals, 0)
// run a container
out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
@@ -163,20 +153,20 @@ func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) {
// inspect the network to make sure container is connected
nr = getNetworkResource(c, nr.ID)
c.Assert(len(nr.Containers), checker.Equals, 1)
c.Assert(len(nr.Containers), check.Equals, 1)
c.Assert(nr.Containers[containerID], check.NotNil)
// check if container IP matches network inspect
ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
c.Assert(err, check.IsNil)
containerIP := findContainerIP(c, "test")
c.Assert(ip.String(), checker.Equals, containerIP)
c.Assert(ip.String(), check.Equals, containerIP)
// disconnect container from the network
dockerCmd(c, "network", "disconnect", "test", containerID)
nr = getNwResource(c, "test")
c.Assert(nr.Name, checker.Equals, "test")
c.Assert(len(nr.Containers), checker.Equals, 0)
c.Assert(nr.Name, check.Equals, "test")
c.Assert(len(nr.Containers), check.Equals, 0)
// check if network connect fails for inactive containers
dockerCmd(c, "stop", containerID)
@@ -233,13 +223,13 @@ func (s *DockerNetworkSuite) TestDockerNetworkInspect(c *check.C) {
assertNwIsAvailable(c, "br0")
nr := getNetworkResource(c, "br0")
c.Assert(nr.Driver, checker.Equals, "bridge")
c.Assert(nr.Scope, checker.Equals, "local")
c.Assert(nr.IPAM.Driver, checker.Equals, "default")
c.Assert(len(nr.IPAM.Config), checker.Equals, 1)
c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "172.28.0.0/16")
c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24")
c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254")
c.Assert(nr.Driver, check.Equals, "bridge")
c.Assert(nr.Scope, check.Equals, "local")
c.Assert(nr.IPAM.Driver, check.Equals, "default")
c.Assert(len(nr.IPAM.Config), check.Equals, 1)
c.Assert(nr.IPAM.Config[0].Subnet, check.Equals, "172.28.0.0/16")
c.Assert(nr.IPAM.Config[0].IPRange, check.Equals, "172.28.5.0/24")
c.Assert(nr.IPAM.Config[0].Gateway, check.Equals, "172.28.5.254")
dockerCmd(c, "network", "rm", "br0")
}
@@ -265,16 +255,3 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpamInvalidCombinations(c *check.C
c.Assert(err, check.NotNil)
dockerCmd(c, "network", "rm", "test0")
}
func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *check.C) {
dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "-o", "opt1=drv1", "-o", "opt2=drv2", "testopt")
assertNwIsAvailable(c, "testopt")
gopts := remoteDriverNetworkRequest.Options[netlabel.GenericData]
c.Assert(gopts, checker.NotNil)
opts, ok := gopts.(map[string]interface{})
c.Assert(ok, checker.Equals, true)
c.Assert(opts["opt1"], checker.Equals, "drv1")
c.Assert(opts["opt2"], checker.Equals, "drv2")
dockerCmd(c, "network", "rm", "testopt")
}
+30 -11
View File
@@ -4,7 +4,6 @@ import (
"fmt"
"strings"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -17,20 +16,30 @@ func (s *DockerSuite) TestPause(c *check.C) {
dockerCmd(c, "pause", name)
pausedContainers, err := getSliceOfPausedContainers()
c.Assert(err, checker.IsNil)
c.Assert(len(pausedContainers), checker.Equals, 1)
if err != nil {
c.Fatalf("error thrown while checking if containers were paused: %v", err)
}
if len(pausedContainers) != 1 {
c.Fatalf("there should be one paused container and not %d", len(pausedContainers))
}
dockerCmd(c, "unpause", name)
out, _ := dockerCmd(c, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
events := strings.Split(out, "\n")
c.Assert(len(events) > 1, checker.Equals, true)
if len(events) <= 1 {
c.Fatalf("Missing expected event")
}
pauseEvent := strings.Fields(events[len(events)-3])
unpauseEvent := strings.Fields(events[len(events)-2])
c.Assert(pauseEvent[len(pauseEvent)-1], checker.Equals, "pause")
c.Assert(unpauseEvent[len(unpauseEvent)-1], checker.Equals, "unpause")
if pauseEvent[len(pauseEvent)-1] != "pause" {
c.Fatalf("event should be pause, not %#v", pauseEvent)
}
if unpauseEvent[len(unpauseEvent)-1] != "unpause" {
c.Fatalf("event should be unpause, not %#v", unpauseEvent)
}
}
@@ -47,14 +56,20 @@ func (s *DockerSuite) TestPauseMultipleContainers(c *check.C) {
}
dockerCmd(c, append([]string{"pause"}, containers...)...)
pausedContainers, err := getSliceOfPausedContainers()
c.Assert(err, checker.IsNil)
c.Assert(len(pausedContainers), checker.Equals, len(containers))
if err != nil {
c.Fatalf("error thrown while checking if containers were paused: %v", err)
}
if len(pausedContainers) != len(containers) {
c.Fatalf("there should be %d paused container and not %d", len(containers), len(pausedContainers))
}
dockerCmd(c, append([]string{"unpause"}, containers...)...)
out, _ := dockerCmd(c, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
events := strings.Split(out, "\n")
c.Assert(len(events) > len(containers)*3-2, checker.Equals, true)
if len(events) <= len(containers)*3-2 {
c.Fatalf("Missing expected event")
}
pauseEvents := make([][]string, len(containers))
unpauseEvents := make([][]string, len(containers))
@@ -64,10 +79,14 @@ func (s *DockerSuite) TestPauseMultipleContainers(c *check.C) {
}
for _, pauseEvent := range pauseEvents {
c.Assert(pauseEvent[len(pauseEvent)-1], checker.Equals, "pause")
if pauseEvent[len(pauseEvent)-1] != "pause" {
c.Fatalf("event should be pause, not %#v", pauseEvent)
}
}
for _, unpauseEvent := range unpauseEvents {
c.Assert(unpauseEvent[len(unpauseEvent)-1], checker.Equals, "unpause")
if unpauseEvent[len(unpauseEvent)-1] != "unpause" {
c.Fatalf("event should be unpause, not %#v", unpauseEvent)
}
}
}
+78 -76
View File
@@ -7,7 +7,6 @@ import (
"sort"
"strings"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -19,16 +18,15 @@ func (s *DockerSuite) TestPortList(c *check.C) {
out, _ = dockerCmd(c, "port", firstID, "80")
err := assertPortList(c, out, []string{"0.0.0.0:9876"})
// Port list is not correct
c.Assert(err, checker.IsNil)
if !assertPortList(c, out, []string{"0.0.0.0:9876"}) {
c.Error("Port list is not correct")
}
out, _ = dockerCmd(c, "port", firstID)
err = assertPortList(c, out, []string{"80/tcp -> 0.0.0.0:9876"})
// Port list is not correct
c.Assert(err, checker.IsNil)
if !assertPortList(c, out, []string{"80/tcp -> 0.0.0.0:9876"}) {
c.Error("Port list is not correct")
}
dockerCmd(c, "rm", "-f", firstID)
// three port
@@ -41,19 +39,18 @@ func (s *DockerSuite) TestPortList(c *check.C) {
out, _ = dockerCmd(c, "port", ID, "80")
err = assertPortList(c, out, []string{"0.0.0.0:9876"})
// Port list is not correct
c.Assert(err, checker.IsNil)
if !assertPortList(c, out, []string{"0.0.0.0:9876"}) {
c.Error("Port list is not correct")
}
out, _ = dockerCmd(c, "port", ID)
err = assertPortList(c, out, []string{
if !assertPortList(c, out, []string{
"80/tcp -> 0.0.0.0:9876",
"81/tcp -> 0.0.0.0:9877",
"82/tcp -> 0.0.0.0:9878"})
// Port list is not correct
c.Assert(err, checker.IsNil)
"82/tcp -> 0.0.0.0:9878"}) {
c.Error("Port list is not correct")
}
dockerCmd(c, "rm", "-f", ID)
// more and one port mapped to the same container port
@@ -67,19 +64,19 @@ func (s *DockerSuite) TestPortList(c *check.C) {
out, _ = dockerCmd(c, "port", ID, "80")
err = assertPortList(c, out, []string{"0.0.0.0:9876", "0.0.0.0:9999"})
// Port list is not correct
c.Assert(err, checker.IsNil)
if !assertPortList(c, out, []string{"0.0.0.0:9876", "0.0.0.0:9999"}) {
c.Error("Port list is not correct")
}
out, _ = dockerCmd(c, "port", ID)
err = assertPortList(c, out, []string{
if !assertPortList(c, out, []string{
"80/tcp -> 0.0.0.0:9876",
"80/tcp -> 0.0.0.0:9999",
"81/tcp -> 0.0.0.0:9877",
"82/tcp -> 0.0.0.0:9878"})
// Port list is not correct
c.Assert(err, checker.IsNil)
"82/tcp -> 0.0.0.0:9878"}) {
c.Error("Port list is not correct\n", out)
}
dockerCmd(c, "rm", "-f", ID)
testRange := func() {
@@ -93,17 +90,19 @@ func (s *DockerSuite) TestPortList(c *check.C) {
out, _ = dockerCmd(c, "port", IDs[i])
err = assertPortList(c, out, []string{fmt.Sprintf("80/tcp -> 0.0.0.0:%d", 9090+i)})
// Port list is not correct
c.Assert(err, checker.IsNil)
if !assertPortList(c, out, []string{
fmt.Sprintf("80/tcp -> 0.0.0.0:%d", 9090+i)}) {
c.Error("Port list is not correct\n", out)
}
}
// test port range exhaustion
out, _, err = dockerCmdWithError("run", "-d",
out, _, err := dockerCmdWithError("run", "-d",
"-p", "9090-9092:80",
"busybox", "top")
// Exhausted port range did not return an error
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
if err == nil {
c.Errorf("Exhausted port range did not return an error. Out: %s", out)
}
for i := 0; i < 3; i++ {
dockerCmd(c, "rm", "-f", IDs[i])
@@ -115,11 +114,12 @@ func (s *DockerSuite) TestPortList(c *check.C) {
// test invalid port ranges
for _, invalidRange := range []string{"9090-9089:80", "9090-:80", "-9090:80"} {
out, _, err = dockerCmdWithError("run", "-d",
out, _, err := dockerCmdWithError("run", "-d",
"-p", invalidRange,
"busybox", "top")
// Port range should have returned an error
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
if err == nil {
c.Errorf("Port range should have returned an error. Out: %s", out)
}
}
// test host range:container range spec.
@@ -130,13 +130,13 @@ func (s *DockerSuite) TestPortList(c *check.C) {
out, _ = dockerCmd(c, "port", ID)
err = assertPortList(c, out, []string{
if !assertPortList(c, out, []string{
"80/tcp -> 0.0.0.0:9800",
"81/tcp -> 0.0.0.0:9801",
"82/tcp -> 0.0.0.0:9802",
"83/tcp -> 0.0.0.0:9803"})
// Port list is not correct
c.Assert(err, checker.IsNil)
"83/tcp -> 0.0.0.0:9803"}) {
c.Error("Port list is not correct\n", out)
}
dockerCmd(c, "rm", "-f", ID)
// test mixing protocols in same port range
@@ -148,29 +148,32 @@ func (s *DockerSuite) TestPortList(c *check.C) {
out, _ = dockerCmd(c, "port", ID)
err = assertPortList(c, out, []string{
if !assertPortList(c, out, []string{
"80/tcp -> 0.0.0.0:8000",
"80/udp -> 0.0.0.0:8000"})
// Port list is not correct
c.Assert(err, checker.IsNil)
"80/udp -> 0.0.0.0:8000"}) {
c.Error("Port list is not correct\n", out)
}
dockerCmd(c, "rm", "-f", ID)
}
func assertPortList(c *check.C, out string, expected []string) error {
func assertPortList(c *check.C, out string, expected []string) bool {
//lines := strings.Split(out, "\n")
lines := strings.Split(strings.Trim(out, "\n "), "\n")
if len(lines) != len(expected) {
return fmt.Errorf("different size lists %s, %d, %d", out, len(lines), len(expected))
c.Errorf("different size lists %s, %d, %d", out, len(lines), len(expected))
return false
}
sort.Strings(lines)
sort.Strings(expected)
for i := 0; i < len(expected); i++ {
if lines[i] != expected[i] {
return fmt.Errorf("|" + lines[i] + "!=" + expected[i] + "|")
c.Error("|" + lines[i] + "!=" + expected[i] + "|")
return false
}
}
return nil
return true
}
func stopRemoveContainer(id string, c *check.C) {
@@ -190,10 +193,9 @@ func (s *DockerSuite) TestUnpublishedPortsInPsOutput(c *check.C) {
unpPort1 := fmt.Sprintf("%d/tcp", port1)
unpPort2 := fmt.Sprintf("%d/tcp", port2)
out, _ := dockerCmd(c, "ps", "-n=1")
// Missing unpublished ports in docker ps output
c.Assert(out, checker.Contains, unpPort1)
// Missing unpublished ports in docker ps output
c.Assert(out, checker.Contains, unpPort2)
if !strings.Contains(out, unpPort1) || !strings.Contains(out, unpPort2) {
c.Errorf("Missing unpublished ports(s) (%s, %s) in docker ps output: %s", unpPort1, unpPort2, out)
}
// Run the container forcing to publish the exposed ports
dockerCmd(c, "run", "-d", "-P", expose1, expose2, "busybox", "sleep", "5")
@@ -202,10 +204,10 @@ func (s *DockerSuite) TestUnpublishedPortsInPsOutput(c *check.C) {
expBndRegx1 := regexp.MustCompile(`0.0.0.0:\d\d\d\d\d->` + unpPort1)
expBndRegx2 := regexp.MustCompile(`0.0.0.0:\d\d\d\d\d->` + unpPort2)
out, _ = dockerCmd(c, "ps", "-n=1")
// Cannot find expected port binding port (0.0.0.0:xxxxx->unpPort1) in docker ps output
c.Assert(expBndRegx1.MatchString(out), checker.Equals, true, check.Commentf("out: %s; unpPort1: %s", out, unpPort1))
// Cannot find expected port binding port (0.0.0.0:xxxxx->unpPort2) in docker ps output
c.Assert(expBndRegx2.MatchString(out), checker.Equals, true, check.Commentf("out: %s; unpPort2: %s", out, unpPort2))
if !expBndRegx1.MatchString(out) || !expBndRegx2.MatchString(out) {
c.Errorf("Cannot find expected port binding ports(s) (0.0.0.0:xxxxx->%s, 0.0.0.0:xxxxx->%s) in docker ps output:\n%s",
unpPort1, unpPort2, out)
}
// Run the container specifying explicit port bindings for the exposed ports
offset := 10000
@@ -218,11 +220,9 @@ func (s *DockerSuite) TestUnpublishedPortsInPsOutput(c *check.C) {
expBnd1 := fmt.Sprintf("0.0.0.0:%d->%s", offset+port1, unpPort1)
expBnd2 := fmt.Sprintf("0.0.0.0:%d->%s", offset+port2, unpPort2)
out, _ = dockerCmd(c, "ps", "-n=1")
// Cannot find expected port binding (expBnd1) in docker ps output
c.Assert(out, checker.Contains, expBnd1)
// Cannot find expected port binding (expBnd2) in docker ps output
c.Assert(out, checker.Contains, expBnd2)
if !strings.Contains(out, expBnd1) || !strings.Contains(out, expBnd2) {
c.Errorf("Cannot find expected port binding(s) (%s, %s) in docker ps output: %s", expBnd1, expBnd2, out)
}
// Remove container now otherwise it will interfeer with next test
stopRemoveContainer(id, c)
@@ -232,10 +232,9 @@ func (s *DockerSuite) TestUnpublishedPortsInPsOutput(c *check.C) {
// Check docker ps o/p for last created container reports the specified port mappings
out, _ = dockerCmd(c, "ps", "-n=1")
// Cannot find expected port binding (expBnd1) in docker ps output
c.Assert(out, checker.Contains, expBnd1)
// Cannot find expected port binding (expBnd2) in docker ps output
c.Assert(out, checker.Contains, expBnd2)
if !strings.Contains(out, expBnd1) || !strings.Contains(out, expBnd2) {
c.Errorf("Cannot find expected port binding(s) (%s, %s) in docker ps output: %s", expBnd1, expBnd2, out)
}
// Remove container now otherwise it will interfeer with next test
stopRemoveContainer(id, c)
@@ -244,10 +243,9 @@ func (s *DockerSuite) TestUnpublishedPortsInPsOutput(c *check.C) {
// Check docker ps o/p for last created container reports the specified unpublished port and port mapping
out, _ = dockerCmd(c, "ps", "-n=1")
// Missing unpublished exposed ports (unpPort1) in docker ps output
c.Assert(out, checker.Contains, unpPort1)
// Missing port binding (expBnd2) in docker ps output
c.Assert(out, checker.Contains, expBnd2)
if !strings.Contains(out, unpPort1) || !strings.Contains(out, expBnd2) {
c.Errorf("Missing unpublished ports or port binding (%s, %s) in docker ps output: %s", unpPort1, expBnd2, out)
}
}
func (s *DockerSuite) TestPortHostBinding(c *check.C) {
@@ -258,18 +256,19 @@ func (s *DockerSuite) TestPortHostBinding(c *check.C) {
out, _ = dockerCmd(c, "port", firstID, "80")
err := assertPortList(c, out, []string{"0.0.0.0:9876"})
// Port list is not correct
c.Assert(err, checker.IsNil)
if !assertPortList(c, out, []string{"0.0.0.0:9876"}) {
c.Error("Port list is not correct")
}
dockerCmd(c, "run", "--net=host", "busybox",
"nc", "localhost", "9876")
dockerCmd(c, "rm", "-f", firstID)
out, _, err = dockerCmdWithError("run", "--net=host", "busybox", "nc", "localhost", "9876")
// Port is still bound after the Container is removed
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
if _, _, err := dockerCmdWithError("run", "--net=host", "busybox",
"nc", "localhost", "9876"); err == nil {
c.Error("Port is still bound after the Container is removed")
}
}
func (s *DockerSuite) TestPortExposeHostBinding(c *check.C) {
@@ -281,15 +280,18 @@ func (s *DockerSuite) TestPortExposeHostBinding(c *check.C) {
out, _ = dockerCmd(c, "port", firstID, "80")
_, exposedPort, err := net.SplitHostPort(out)
c.Assert(err, checker.IsNil, check.Commentf("out: %s", out))
if err != nil {
c.Fatal(out, err)
}
dockerCmd(c, "run", "--net=host", "busybox",
"nc", "localhost", strings.TrimSpace(exposedPort))
dockerCmd(c, "rm", "-f", firstID)
out, _, err = dockerCmdWithError("run", "--net=host", "busybox",
"nc", "localhost", strings.TrimSpace(exposedPort))
// Port is still bound after the Container is removed
c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
if _, _, err = dockerCmdWithError("run", "--net=host", "busybox",
"nc", "localhost", strings.TrimSpace(exposedPort)); err == nil {
c.Error("Port is still bound after the Container is removed")
}
}
+54 -30
View File
@@ -4,7 +4,6 @@ import (
"strings"
"time"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -16,12 +15,16 @@ func (s *DockerSuite) TestRestartStoppedContainer(c *check.C) {
dockerCmd(c, "wait", cleanedContainerID)
out, _ = dockerCmd(c, "logs", cleanedContainerID)
c.Assert(out, checker.Equals, "foobar\n")
if out != "foobar\n" {
c.Errorf("container should've printed 'foobar'")
}
dockerCmd(c, "restart", cleanedContainerID)
out, _ = dockerCmd(c, "logs", cleanedContainerID)
c.Assert(out, checker.Equals, "foobar\nfoobar\n")
if out != "foobar\nfoobar\n" {
c.Errorf("container should've printed 'foobar' twice, got %v", out)
}
}
func (s *DockerSuite) TestRestartRunningContainer(c *check.C) {
@@ -30,18 +33,22 @@ func (s *DockerSuite) TestRestartRunningContainer(c *check.C) {
cleanedContainerID := strings.TrimSpace(out)
c.Assert(waitRun(cleanedContainerID), checker.IsNil)
c.Assert(waitRun(cleanedContainerID), check.IsNil)
out, _ = dockerCmd(c, "logs", cleanedContainerID)
c.Assert(out, checker.Equals, "foobar\n")
if out != "foobar\n" {
c.Errorf("container should've printed 'foobar'")
}
dockerCmd(c, "restart", "-t", "1", cleanedContainerID)
out, _ = dockerCmd(c, "logs", cleanedContainerID)
c.Assert(waitRun(cleanedContainerID), checker.IsNil)
c.Assert(waitRun(cleanedContainerID), check.IsNil)
c.Assert(out, checker.Equals, "foobar\nfoobar\n")
if out != "foobar\nfoobar\n" {
c.Errorf("container should've printed 'foobar' twice")
}
}
// Test that restarting a container with a volume does not create a new volume on restart. Regression test for #819.
@@ -51,21 +58,27 @@ func (s *DockerSuite) TestRestartWithVolumes(c *check.C) {
cleanedContainerID := strings.TrimSpace(out)
out, _ = dockerCmd(c, "inspect", "--format", "{{ len .Mounts }}", cleanedContainerID)
out = strings.Trim(out, " \n\r")
c.Assert(out, checker.Equals, "1")
if out = strings.Trim(out, " \n\r"); out != "1" {
c.Errorf("expect 1 volume received %s", out)
}
source, err := inspectMountSourceField(cleanedContainerID, "/test")
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
dockerCmd(c, "restart", cleanedContainerID)
out, _ = dockerCmd(c, "inspect", "--format", "{{ len .Mounts }}", cleanedContainerID)
out = strings.Trim(out, " \n\r")
c.Assert(out, checker.Equals, "1")
if out = strings.Trim(out, " \n\r"); out != "1" {
c.Errorf("expect 1 volume after restart received %s", out)
}
sourceAfterRestart, err := inspectMountSourceField(cleanedContainerID, "/test")
c.Assert(err, checker.IsNil)
c.Assert(source, checker.Equals, sourceAfterRestart)
c.Assert(err, check.IsNil)
if source != sourceAfterRestart {
c.Errorf("expected volume path: %s Actual path: %s", source, sourceAfterRestart)
}
}
func (s *DockerSuite) TestRestartPolicyNO(c *check.C) {
@@ -74,8 +87,10 @@ func (s *DockerSuite) TestRestartPolicyNO(c *check.C) {
id := strings.TrimSpace(string(out))
name, err := inspectField(id, "HostConfig.RestartPolicy.Name")
c.Assert(err, checker.IsNil)
c.Assert(name, checker.Equals, "no")
c.Assert(err, check.IsNil)
if name != "no" {
c.Fatalf("Container restart policy name is %s, expected %s", name, "no")
}
}
func (s *DockerSuite) TestRestartPolicyAlways(c *check.C) {
@@ -84,14 +99,18 @@ func (s *DockerSuite) TestRestartPolicyAlways(c *check.C) {
id := strings.TrimSpace(string(out))
name, err := inspectField(id, "HostConfig.RestartPolicy.Name")
c.Assert(err, checker.IsNil)
c.Assert(name, checker.Equals, "always")
c.Assert(err, check.IsNil)
if name != "always" {
c.Fatalf("Container restart policy name is %s, expected %s", name, "always")
}
MaximumRetryCount, err := inspectField(id, "HostConfig.RestartPolicy.MaximumRetryCount")
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
// MaximumRetryCount=0 if the restart policy is always
c.Assert(MaximumRetryCount, checker.Equals, "0")
if MaximumRetryCount != "0" {
c.Fatalf("Container Maximum Retry Count is %s, expected %s", MaximumRetryCount, "0")
}
}
func (s *DockerSuite) TestRestartPolicyOnFailure(c *check.C) {
@@ -100,8 +119,10 @@ func (s *DockerSuite) TestRestartPolicyOnFailure(c *check.C) {
id := strings.TrimSpace(string(out))
name, err := inspectField(id, "HostConfig.RestartPolicy.Name")
c.Assert(err, checker.IsNil)
c.Assert(name, checker.Equals, "on-failure")
c.Assert(err, check.IsNil)
if name != "on-failure" {
c.Fatalf("Container restart policy name is %s, expected %s", name, "on-failure")
}
}
@@ -112,15 +133,18 @@ func (s *DockerSuite) TestContainerRestartwithGoodContainer(c *check.C) {
out, _ := dockerCmd(c, "run", "-d", "--restart=on-failure:3", "busybox", "true")
id := strings.TrimSpace(string(out))
err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false false", 5*time.Second)
c.Assert(err, checker.IsNil)
if err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false false", 5*time.Second); err != nil {
c.Fatal(err)
}
count, err := inspectField(id, "RestartCount")
c.Assert(err, checker.IsNil)
c.Assert(count, checker.Equals, "0")
c.Assert(err, check.IsNil)
if count != "0" {
c.Fatalf("Container was restarted %s times, expected %d", count, 0)
}
MaximumRetryCount, err := inspectField(id, "HostConfig.RestartPolicy.MaximumRetryCount")
c.Assert(err, checker.IsNil)
c.Assert(MaximumRetryCount, checker.Equals, "3")
c.Assert(err, check.IsNil)
if MaximumRetryCount != "3" {
c.Fatalf("Container Maximum Retry Count is %s, expected %s", MaximumRetryCount, "3")
}
}
+26 -14
View File
@@ -4,7 +4,6 @@ import (
"os"
"strings"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -14,8 +13,9 @@ func (s *DockerSuite) TestRmContainerWithRemovedVolume(c *check.C) {
dockerCmd(c, "run", "--name", "losemyvolumes", "-v", "/tmp/testing:/test", "busybox", "true")
err := os.Remove("/tmp/testing")
c.Assert(err, check.IsNil)
if err := os.Remove("/tmp/testing"); err != nil {
c.Fatal(err)
}
dockerCmd(c, "rm", "-v", "losemyvolumes")
}
@@ -31,8 +31,9 @@ func (s *DockerSuite) TestRmRunningContainer(c *check.C) {
testRequires(c, DaemonIsLinux)
createRunningContainer(c, "foo")
_, _, err := dockerCmdWithError("rm", "foo")
c.Assert(err, checker.NotNil, check.Commentf("Expected error, can't rm a running container"))
if _, _, err := dockerCmdWithError("rm", "foo"); err == nil {
c.Fatalf("Expected error, can't rm a running container")
}
}
func (s *DockerSuite) TestRmForceRemoveRunningContainer(c *check.C) {
@@ -54,20 +55,31 @@ func (s *DockerSuite) TestRmContainerOrphaning(c *check.C) {
// build first dockerfile
img1, err := buildImage(img, dockerfile1, true)
c.Assert(err, check.IsNil, check.Commentf("Could not build image %s", img))
if err != nil {
c.Fatalf("Could not build image %s: %v", img, err)
}
// run container on first image
dockerCmd(c, "run", img)
if out, _, err := dockerCmdWithError("run", img); err != nil {
c.Fatalf("Could not run image %s: %v: %s", img, err, out)
}
// rebuild dockerfile with a small addition at the end
_, err = buildImage(img, dockerfile2, true)
c.Assert(err, check.IsNil, check.Commentf("Could not rebuild image %s", img))
if _, err := buildImage(img, dockerfile2, true); err != nil {
c.Fatalf("Could not rebuild image %s: %v", img, err)
}
// try to remove the image, should error out.
out, _, err := dockerCmdWithError("rmi", img)
c.Assert(err, check.NotNil, check.Commentf("Expected to error out removing the image, but succeeded: %s", out))
if out, _, err := dockerCmdWithError("rmi", img); err == nil {
c.Fatalf("Expected to error out removing the image, but succeeded: %s", out)
}
// check if we deleted the first image
out, _ = dockerCmd(c, "images", "-q", "--no-trunc")
c.Assert(out, checker.Contains, img1, check.Commentf("Orphaned container (could not find %q in docker images): %s", img1, out))
out, _, err := dockerCmdWithError("images", "-q", "--no-trunc")
if err != nil {
c.Fatalf("%v: %s", err, out)
}
if !strings.Contains(out, img1) {
c.Fatalf("Orphaned container (could not find %q in docker images): %s", img1, out)
}
}
func (s *DockerSuite) TestRmInvalidContainer(c *check.C) {
+146 -76
View File
@@ -5,7 +5,6 @@ import (
"os/exec"
"strings"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -14,21 +13,27 @@ func (s *DockerSuite) TestRmiWithContainerFails(c *check.C) {
errSubstr := "is using it"
// create a container
out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
out, _, err := dockerCmdWithError("run", "-d", "busybox", "true")
if err != nil {
c.Fatalf("failed to create a container: %s, %v", out, err)
}
cleanedContainerID := strings.TrimSpace(out)
// try to delete the image
out, _, err := dockerCmdWithError("rmi", "busybox")
// Container is using image, should not be able to rmi
c.Assert(err, checker.NotNil)
// Container is using image, error message should contain errSubstr
c.Assert(out, checker.Contains, errSubstr, check.Commentf("Container: %q", cleanedContainerID))
out, _, err = dockerCmdWithError("rmi", "busybox")
if err == nil {
c.Fatalf("Container %q is using image, should not be able to rmi: %q", cleanedContainerID, out)
}
if !strings.Contains(out, errSubstr) {
c.Fatalf("Container %q is using image, error message should contain %q: %v", cleanedContainerID, errSubstr, out)
}
// make sure it didn't delete the busybox name
images, _ := dockerCmd(c, "images")
// The name 'busybox' should not have been removed from images
c.Assert(images, checker.Contains, "busybox")
if !strings.Contains(images, "busybox") {
c.Fatalf("The name 'busybox' should not have been removed from images: %q", images)
}
}
func (s *DockerSuite) TestRmiTag(c *check.C) {
@@ -39,71 +44,97 @@ func (s *DockerSuite) TestRmiTag(c *check.C) {
dockerCmd(c, "tag", "busybox", "utest:5000/docker:tag3")
{
imagesAfter, _ := dockerCmd(c, "images", "-a")
c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+3, check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter))
if strings.Count(imagesAfter, "\n") != strings.Count(imagesBefore, "\n")+3 {
c.Fatalf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)
}
}
dockerCmd(c, "rmi", "utest/docker:tag2")
{
imagesAfter, _ := dockerCmd(c, "images", "-a")
c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+2, check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter))
if strings.Count(imagesAfter, "\n") != strings.Count(imagesBefore, "\n")+2 {
c.Fatalf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)
}
}
dockerCmd(c, "rmi", "utest:5000/docker:tag3")
{
imagesAfter, _ := dockerCmd(c, "images", "-a")
c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+1, check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter))
if strings.Count(imagesAfter, "\n") != strings.Count(imagesBefore, "\n")+1 {
c.Fatalf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)
}
}
dockerCmd(c, "rmi", "utest:tag1")
{
imagesAfter, _ := dockerCmd(c, "images", "-a")
c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n"), check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter))
if strings.Count(imagesAfter, "\n") != strings.Count(imagesBefore, "\n")+0 {
c.Fatalf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter)
}
}
}
func (s *DockerSuite) TestRmiImgIDMultipleTag(c *check.C) {
testRequires(c, DaemonIsLinux)
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir '/busybox-one'")
out, _, err := dockerCmdWithError("run", "-d", "busybox", "/bin/sh", "-c", "mkdir '/busybox-one'")
if err != nil {
c.Fatalf("failed to create a container:%s, %v", out, err)
}
containerID := strings.TrimSpace(out)
dockerCmd(c, "commit", containerID, "busybox-one")
out, _, err = dockerCmdWithError("commit", containerID, "busybox-one")
if err != nil {
c.Fatalf("failed to commit a new busybox-one:%s, %v", out, err)
}
imagesBefore, _ := dockerCmd(c, "images", "-a")
dockerCmd(c, "tag", "busybox-one", "busybox-one:tag1")
dockerCmd(c, "tag", "busybox-one", "busybox-one:tag2")
imagesAfter, _ := dockerCmd(c, "images", "-a")
// tag busybox to create 2 more images with same imageID
c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+2, check.Commentf("docker images shows: %q\n", imagesAfter))
if strings.Count(imagesAfter, "\n") != strings.Count(imagesBefore, "\n")+2 {
c.Fatalf("tag busybox to create 2 more images with same imageID; docker images shows: %q\n", imagesAfter)
}
imgID, err := inspectField("busybox-one:tag1", "Id")
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
// run a container with the image
out, _ = dockerCmd(c, "run", "-d", "busybox-one", "top")
out, _, err = dockerCmdWithError("run", "-d", "busybox-one", "top")
if err != nil {
c.Fatalf("failed to create a container:%s, %v", out, err)
}
containerID = strings.TrimSpace(out)
// first checkout without force it fails
out, _, err = dockerCmdWithError("rmi", imgID)
expected := fmt.Sprintf("conflict: unable to delete %s (cannot be forced) - image is being used by running container %s", imgID[:12], containerID[:12])
// rmi tagged in multiple repos should have failed without force
c.Assert(err, checker.NotNil)
c.Assert(out, checker.Contains, expected)
if err == nil || !strings.Contains(out, expected) {
c.Fatalf("rmi tagged in multiple repos should have failed without force: %s, %v, expected: %s", out, err, expected)
}
dockerCmd(c, "stop", containerID)
dockerCmd(c, "rmi", "-f", imgID)
imagesAfter, _ = dockerCmd(c, "images", "-a")
// rmi -f failed, image still exists
c.Assert(imagesAfter, checker.Not(checker.Contains), imgID[:12], check.Commentf("ImageID:%q; ImagesAfter: %q", imgID, imagesAfter))
if strings.Contains(imagesAfter, imgID[:12]) {
c.Fatalf("rmi -f %s failed, image still exists: %q\n\n", imgID, imagesAfter)
}
}
func (s *DockerSuite) TestRmiImgIDForce(c *check.C) {
testRequires(c, DaemonIsLinux)
out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir '/busybox-test'")
out, _, err := dockerCmdWithError("run", "-d", "busybox", "/bin/sh", "-c", "mkdir '/busybox-test'")
if err != nil {
c.Fatalf("failed to create a container:%s, %v", out, err)
}
containerID := strings.TrimSpace(out)
dockerCmd(c, "commit", containerID, "busybox-test")
out, _, err = dockerCmdWithError("commit", containerID, "busybox-test")
if err != nil {
c.Fatalf("failed to commit a new busybox-test:%s, %v", out, err)
}
imagesBefore, _ := dockerCmd(c, "images", "-a")
dockerCmd(c, "tag", "busybox-test", "utest:tag1")
@@ -112,23 +143,25 @@ func (s *DockerSuite) TestRmiImgIDForce(c *check.C) {
dockerCmd(c, "tag", "busybox-test", "utest:5000/docker:tag4")
{
imagesAfter, _ := dockerCmd(c, "images", "-a")
c.Assert(strings.Count(imagesAfter, "\n"), checker.Equals, strings.Count(imagesBefore, "\n")+4, check.Commentf("before: %q\n\nafter: %q\n", imagesBefore, imagesAfter))
if strings.Count(imagesAfter, "\n") != strings.Count(imagesBefore, "\n")+4 {
c.Fatalf("tag busybox to create 4 more images with same imageID; docker images shows: %q\n", imagesAfter)
}
}
imgID, err := inspectField("busybox-test", "Id")
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
// first checkout without force it fails
out, _, err = dockerCmdWithError("rmi", imgID)
// rmi tagged in multiple repos should have failed without force
c.Assert(err, checker.NotNil)
// rmi tagged in multiple repos should have failed without force
c.Assert(out, checker.Contains, "(must be forced) - image is referenced in one or more repositories", check.Commentf("out: %s; err: %v;", out, err))
if err == nil || !strings.Contains(out, "(must be forced) - image is referenced in one or more repositories") {
c.Fatalf("rmi tagged in multiple repos should have failed without force:%s, %v", out, err)
}
dockerCmd(c, "rmi", "-f", imgID)
{
imagesAfter, _ := dockerCmd(c, "images", "-a")
// rmi failed, image still exists
c.Assert(imagesAfter, checker.Not(checker.Contains), imgID[:12])
if strings.Contains(imagesAfter, imgID[:12]) {
c.Fatalf("rmi -f %s failed, image still exists: %q\n\n", imgID, imagesAfter)
}
}
}
@@ -137,16 +170,17 @@ func (s *DockerSuite) TestRmiImageIDForceWithRunningContainersAndMultipleTags(c
testRequires(c, DaemonIsLinux)
dockerfile := "FROM busybox\nRUN echo test 14116\n"
imgID, err := buildImage("test-14116", dockerfile, false)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
newTag := "newtag"
dockerCmd(c, "tag", imgID, newTag)
dockerCmd(c, "run", "-d", imgID, "top")
out, _, err := dockerCmdWithError("rmi", "-f", imgID)
// rmi -f should not delete image with running containers
c.Assert(err, checker.NotNil)
c.Assert(out, checker.Contains, "(cannot be forced) - image is being used by running container")
if err == nil || !strings.Contains(out, "(cannot be forced) - image is being used by running container") {
c.Log(out)
c.Fatalf("rmi -f should not delete image with running containers")
}
}
func (s *DockerSuite) TestRmiTagWithExistingContainers(c *check.C) {
@@ -154,12 +188,19 @@ func (s *DockerSuite) TestRmiTagWithExistingContainers(c *check.C) {
container := "test-delete-tag"
newtag := "busybox:newtag"
bb := "busybox:latest"
dockerCmd(c, "tag", bb, newtag)
dockerCmd(c, "run", "--name", container, bb, "/bin/true")
out, _ := dockerCmd(c, "rmi", newtag)
c.Assert(strings.Count(out, "Untagged: "), checker.Equals, 1)
if out, _, err := dockerCmdWithError("tag", bb, newtag); err != nil {
c.Fatalf("Could not tag busybox: %v: %s", err, out)
}
if out, _, err := dockerCmdWithError("run", "--name", container, bb, "/bin/true"); err != nil {
c.Fatalf("Could not run busybox: %v: %s", err, out)
}
out, _, err := dockerCmdWithError("rmi", newtag)
if err != nil {
c.Fatalf("Could not remove tag %s: %v: %s", newtag, err, out)
}
if d := strings.Count(out, "Untagged: "); d != 1 {
c.Fatalf("Expected 1 untagged entry got %d: %q", d, out)
}
}
func (s *DockerSuite) TestRmiForceWithExistingContainers(c *check.C) {
@@ -170,12 +211,17 @@ func (s *DockerSuite) TestRmiForceWithExistingContainers(c *check.C) {
cmd.Stdin = strings.NewReader(`FROM busybox
MAINTAINER foo`)
out, _, err := runCommandWithOutput(cmd)
c.Assert(err, checker.IsNil, check.Commentf("Could not build %s: %s", image, out))
if out, _, err := runCommandWithOutput(cmd); err != nil {
c.Fatalf("Could not build %s: %s, %v", image, out, err)
}
dockerCmd(c, "run", "--name", "test-force-rmi", image, "/bin/true")
if out, _, err := dockerCmdWithError("run", "--name", "test-force-rmi", image, "/bin/true"); err != nil {
c.Fatalf("Could not run container: %s, %v", out, err)
}
dockerCmd(c, "rmi", "-f", image)
if out, _, err := dockerCmdWithError("rmi", "-f", image); err != nil {
c.Fatalf("Could not remove image %s: %s, %v", image, out, err)
}
}
func (s *DockerSuite) TestRmiWithMultipleRepositories(c *check.C) {
@@ -183,32 +229,51 @@ func (s *DockerSuite) TestRmiWithMultipleRepositories(c *check.C) {
newRepo := "127.0.0.1:5000/busybox"
oldRepo := "busybox"
newTag := "busybox:test"
dockerCmd(c, "tag", oldRepo, newRepo)
out, _, err := dockerCmdWithError("tag", oldRepo, newRepo)
if err != nil {
c.Fatalf("Could not tag busybox: %v: %s", err, out)
}
dockerCmd(c, "run", "--name", "test", oldRepo, "touch", "/home/abcd")
out, _, err = dockerCmdWithError("run", "--name", "test", oldRepo, "touch", "/home/abcd")
if err != nil {
c.Fatalf("failed to run container: %v, output: %s", err, out)
}
dockerCmd(c, "commit", "test", newTag)
out, _, err = dockerCmdWithError("commit", "test", newTag)
if err != nil {
c.Fatalf("failed to commit container: %v, output: %s", err, out)
}
out, _ := dockerCmd(c, "rmi", newTag)
c.Assert(out, checker.Contains, "Untagged: "+newTag)
out, _, err = dockerCmdWithError("rmi", newTag)
if err != nil {
c.Fatalf("failed to remove image: %v, output: %s", err, out)
}
if !strings.Contains(out, "Untagged: "+newTag) {
c.Fatalf("Could not remove image %s: %s, %v", newTag, out, err)
}
}
func (s *DockerSuite) TestRmiBlank(c *check.C) {
testRequires(c, DaemonIsLinux)
// try to delete a blank image name
out, _, err := dockerCmdWithError("rmi", "")
// Should have failed to delete '' image
c.Assert(err, checker.NotNil)
// Wrong error message generated
c.Assert(out, checker.Not(checker.Contains), "no such id", check.Commentf("out: %s", out))
// Expected error message not generated
c.Assert(out, checker.Contains, "image name cannot be blank", check.Commentf("out: %s", out))
if err == nil {
c.Fatal("Should have failed to delete '' image")
}
if strings.Contains(out, "no such id") {
c.Fatalf("Wrong error message generated: %s", out)
}
if !strings.Contains(out, "image name cannot be blank") {
c.Fatalf("Expected error message not generated: %s", out)
}
out, _, err = dockerCmdWithError("rmi", " ")
// Should have failed to delete '' image
c.Assert(err, checker.NotNil)
// Expected error message not generated
c.Assert(out, checker.Contains, "no such id", check.Commentf("out: %s", out))
if err == nil {
c.Fatal("Should have failed to delete '' image")
}
if !strings.Contains(out, "no such id") {
c.Fatalf("Expected error message not generated: %s", out)
}
}
func (s *DockerSuite) TestRmiContainerImageNotFound(c *check.C) {
@@ -219,7 +284,7 @@ func (s *DockerSuite) TestRmiContainerImageNotFound(c *check.C) {
for i, name := range imageNames {
dockerfile := fmt.Sprintf("FROM busybox\nMAINTAINER %s\nRUN echo %s\n", name, name)
id, err := buildImage(name, dockerfile, false)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
imageIds[i] = id
}
@@ -232,9 +297,10 @@ func (s *DockerSuite) TestRmiContainerImageNotFound(c *check.C) {
// Try to remove the image of the running container and see if it fails as expected.
out, _, err := dockerCmdWithError("rmi", "-f", imageIds[0])
// The image of the running container should not be removed.
c.Assert(err, checker.NotNil)
c.Assert(out, checker.Contains, "image is being used by running container", check.Commentf("out: %s", out))
if err == nil || !strings.Contains(out, "image is being used by running container") {
c.Log(out)
c.Fatal("The image of the running container should not be removed.")
}
}
// #13422
@@ -249,7 +315,7 @@ RUN echo 1 #layer1
RUN echo 2 #layer2
`
_, err := buildImage(image, dockerfile, false)
c.Assert(err, checker.IsNil)
c.Assert(err, check.IsNil)
out, _ := dockerCmd(c, "history", "-q", image)
ids := strings.Split(out, "\n")
@@ -263,8 +329,10 @@ RUN echo 2 #layer2
// See if the "tmp2" can be untagged.
out, _ = dockerCmd(c, "rmi", newTag)
// Expected 1 untagged entry
c.Assert(strings.Count(out, "Untagged: "), checker.Equals, 1, check.Commentf("out: %s", out))
if d := strings.Count(out, "Untagged: "); d != 1 {
c.Log(out)
c.Fatalf("Expected 1 untagged entry got %d: %q", d, out)
}
// Now let's add the tag again and create a container based on it.
dockerCmd(c, "tag", idToTag, newTag)
@@ -274,13 +342,15 @@ RUN echo 2 #layer2
// At this point we have 2 containers, one based on layer2 and another based on layer0.
// Try to untag "tmp2" without the -f flag.
out, _, err = dockerCmdWithError("rmi", newTag)
// should not be untagged without the -f flag
c.Assert(err, checker.NotNil)
c.Assert(out, checker.Contains, cid[:12])
c.Assert(out, checker.Contains, "(must force)")
if err == nil || !strings.Contains(out, cid[:12]) || !strings.Contains(out, "(must force)") {
c.Log(out)
c.Fatalf("%q should not be untagged without the -f flag", newTag)
}
// Add the -f flag and test again.
out, _ = dockerCmd(c, "rmi", "-f", newTag)
// should be allowed to untag with the -f flag
c.Assert(out, checker.Contains, fmt.Sprintf("Untagged: %s:latest", newTag))
if !strings.Contains(out, fmt.Sprintf("Untagged: %s:latest", newTag)) {
c.Log(out)
c.Fatalf("%q should be allowed to untag with the -f flag", newTag)
}
}
+35 -5
View File
@@ -1197,7 +1197,7 @@ func (s *DockerSuite) TestRunNonRootUserResolvName(c *check.C) {
// uses the host's /etc/resolv.conf and does not have any dns options provided.
func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) {
// Not applicable on Windows as testing unix specific functionality
testRequires(c, SameHostDaemon, DaemonIsLinux, NativeExecDriver)
testRequires(c, SameHostDaemon, DaemonIsLinux)
tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\n")
tmpLocalhostResolvConf := []byte("nameserver 127.0.0.1")
@@ -3425,10 +3425,13 @@ func (s *DockerSuite) TestContainersInUserDefinedNetwork(c *check.C) {
dockerCmd(c, "run", "-d", "--net=testnetwork", "--name=first", "busybox", "top")
c.Assert(waitRun("first"), check.IsNil)
dockerCmd(c, "run", "-t", "--net=testnetwork", "--name=second", "busybox", "ping", "-c", "1", "first")
dockerCmd(c, "stop", "first")
dockerCmd(c, "stop", "second")
dockerCmd(c, "network", "rm", "testnetwork")
}
func (s *DockerSuite) TestContainersInMultipleNetworks(c *check.C) {
testRequires(c, DaemonIsLinux, NotUserNamespace, NativeExecDriver)
testRequires(c, DaemonIsLinux, NotUserNamespace)
// Create 2 networks using bridge driver
dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2")
@@ -3444,10 +3447,14 @@ func (s *DockerSuite) TestContainersInMultipleNetworks(c *check.C) {
dockerCmd(c, "network", "connect", "testnetwork2", "second")
// Check connectivity between containers
dockerCmd(c, "exec", "second", "ping", "-c", "1", "first.testnetwork2")
dockerCmd(c, "stop", "first")
dockerCmd(c, "stop", "second")
dockerCmd(c, "network", "rm", "testnetwork1")
dockerCmd(c, "network", "rm", "testnetwork2")
}
func (s *DockerSuite) TestContainersNetworkIsolation(c *check.C) {
testRequires(c, DaemonIsLinux, NotUserNamespace, NativeExecDriver)
testRequires(c, DaemonIsLinux, NotUserNamespace)
// Create 2 networks using bridge driver
dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2")
@@ -3471,6 +3478,11 @@ func (s *DockerSuite) TestContainersNetworkIsolation(c *check.C) {
// ping must fail again
_, _, err = dockerCmdWithError("exec", "first", "ping", "-c", "1", "second")
c.Assert(err, check.NotNil)
dockerCmd(c, "stop", "first")
dockerCmd(c, "stop", "second")
dockerCmd(c, "network", "rm", "testnetwork1")
dockerCmd(c, "network", "rm", "testnetwork2")
}
func (s *DockerSuite) TestNetworkRmWithActiveContainers(c *check.C) {
@@ -3489,14 +3501,17 @@ func (s *DockerSuite) TestNetworkRmWithActiveContainers(c *check.C) {
dockerCmd(c, "stop", "first")
_, _, err = dockerCmdWithError("network", "rm", "testnetwork1")
c.Assert(err, check.NotNil)
dockerCmd(c, "stop", "second")
// Network delete must succeed after all the connected containers are inactive
dockerCmd(c, "network", "rm", "testnetwork1")
}
func (s *DockerSuite) TestContainerRestartInMultipleNetworks(c *check.C) {
testRequires(c, DaemonIsLinux, NotUserNamespace, NativeExecDriver)
testRequires(c, DaemonIsLinux, NotUserNamespace)
// Create 2 networks using bridge driver
dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2")
// Run and connect containers to testnetwork1
dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top")
c.Assert(waitRun("first"), check.IsNil)
@@ -3521,6 +3536,11 @@ func (s *DockerSuite) TestContainerRestartInMultipleNetworks(c *check.C) {
dockerCmd(c, "start", "second")
dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1")
dockerCmd(c, "exec", "second", "ping", "-c", "1", "first.testnetwork2")
dockerCmd(c, "stop", "first")
dockerCmd(c, "stop", "second")
dockerCmd(c, "network", "rm", "testnetwork1")
dockerCmd(c, "network", "rm", "testnetwork2")
}
func (s *DockerSuite) TestContainerWithConflictingHostNetworks(c *check.C) {
@@ -3535,6 +3555,8 @@ func (s *DockerSuite) TestContainerWithConflictingHostNetworks(c *check.C) {
// Connecting to the user defined network must fail
_, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "first")
c.Assert(err, check.NotNil)
dockerCmd(c, "stop", "first")
dockerCmd(c, "network", "rm", "testnetwork1")
}
func (s *DockerSuite) TestContainerWithConflictingSharedNetwork(c *check.C) {
@@ -3552,6 +3574,10 @@ func (s *DockerSuite) TestContainerWithConflictingSharedNetwork(c *check.C) {
out, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "second")
c.Assert(err, check.NotNil)
c.Assert(out, checker.Contains, runconfig.ErrConflictSharedNetwork.Error())
dockerCmd(c, "stop", "first")
dockerCmd(c, "stop", "second")
dockerCmd(c, "network", "rm", "testnetwork1")
}
func (s *DockerSuite) TestContainerWithConflictingNoneNetwork(c *check.C) {
@@ -3574,6 +3600,10 @@ func (s *DockerSuite) TestContainerWithConflictingNoneNetwork(c *check.C) {
// Connect second container to none network. it must fail as well
_, _, err = dockerCmdWithError("network", "connect", "none", "second")
c.Assert(err, check.NotNil)
dockerCmd(c, "stop", "first")
dockerCmd(c, "stop", "second")
dockerCmd(c, "network", "rm", "testnetwork1")
}
// #11957 - stdin with no tty does not exit if stdin is not closed even though container exited
+4 -25
View File
@@ -17,7 +17,6 @@ import (
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/pkg/units"
"github.com/go-check/check"
"github.com/kr/pty"
)
@@ -273,10 +272,9 @@ func (s *DockerSuite) TestRunWithBlkioWeight(c *check.C) {
func (s *DockerSuite) TestRunWithBlkioInvalidWeight(c *check.C) {
testRequires(c, blkioWeight)
out, _, err := dockerCmdWithError("run", "--blkio-weight", "5", "busybox", "true")
c.Assert(err, check.NotNil, check.Commentf(out))
expected := "Range of blkio weight is from 10 to 1000"
c.Assert(out, checker.Contains, expected)
if _, _, err := dockerCmdWithError("run", "--blkio-weight", "5", "busybox", "true"); err == nil {
c.Fatalf("run with invalid blkio-weight should failed")
}
}
func (s *DockerSuite) TestRunOOMExitCode(c *check.C) {
@@ -421,7 +419,7 @@ func (s *DockerSuite) TestRunInvalidCpusetMemsFlagValue(c *check.C) {
}
func (s *DockerSuite) TestRunInvalidCPUShares(c *check.C) {
testRequires(c, cpuShare, NativeExecDriver)
testRequires(c, cpuShare)
out, _, err := dockerCmdWithError("run", "--cpu-shares", "1", "busybox", "echo", "test")
c.Assert(err, check.NotNil, check.Commentf(out))
expected := "The minimum allowed cpu-shares is 2"
@@ -437,22 +435,3 @@ func (s *DockerSuite) TestRunInvalidCPUShares(c *check.C) {
expected = "The maximum allowed cpu-shares is"
c.Assert(out, checker.Contains, expected)
}
func (s *DockerSuite) TestRunWithCorrectMemorySwapOnLXC(c *check.C) {
testRequires(c, memoryLimitSupport)
testRequires(c, swapMemorySupport)
testRequires(c, SameHostDaemon)
out, _ := dockerCmd(c, "run", "-d", "-m", "16m", "--memory-swap", "64m", "busybox", "top")
if _, err := os.Stat("/sys/fs/cgroup/memory/lxc"); err != nil {
c.Skip("Excecution driver must be LXC for this test")
}
id := strings.TrimSpace(out)
memorySwap, err := ioutil.ReadFile(fmt.Sprintf("/sys/fs/cgroup/memory/lxc/%s/memory.memsw.limit_in_bytes", id))
c.Assert(err, check.IsNil)
cgSwap, err := strconv.ParseInt(strings.TrimSpace(string(memorySwap)), 10, 64)
c.Assert(err, check.IsNil)
swap, err := units.RAMInBytes("64m")
c.Assert(err, check.IsNil)
c.Assert(cgSwap, check.Equals, swap)
}
+33 -12
View File
@@ -37,7 +37,9 @@ func makefile(contents string) (string, func(), error) {
// attempt to contact any v1 registry endpoints.
func (s *DockerRegistrySuite) TestV2Only(c *check.C) {
reg, err := newTestRegistry(c)
c.Assert(err, check.IsNil)
if err != nil {
c.Fatal(err.Error())
}
reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(404)
@@ -50,10 +52,14 @@ func (s *DockerRegistrySuite) TestV2Only(c *check.C) {
repoName := fmt.Sprintf("%s/busybox", reg.hostport)
err = s.d.Start("--insecure-registry", reg.hostport, "--disable-legacy-registry=true")
c.Assert(err, check.IsNil)
if err != nil {
c.Fatalf("Error starting daemon: %s", err.Error())
}
dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.hostport))
c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile"))
if err != nil {
c.Fatalf("Unable to create test dockerfile")
}
defer cleanup()
s.d.Cmd("build", "--file", dockerfileName, ".")
@@ -70,7 +76,9 @@ func (s *DockerRegistrySuite) TestV2Only(c *check.C) {
// login, push, pull, build & run
func (s *DockerRegistrySuite) TestV1(c *check.C) {
reg, err := newTestRegistry(c)
c.Assert(err, check.IsNil)
if err != nil {
c.Fatal(err.Error())
}
v2Pings := 0
reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) {
@@ -99,29 +107,42 @@ func (s *DockerRegistrySuite) TestV1(c *check.C) {
})
err = s.d.Start("--insecure-registry", reg.hostport, "--disable-legacy-registry=false")
c.Assert(err, check.IsNil)
if err != nil {
c.Fatalf("Error starting daemon: %s", err.Error())
}
dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.hostport))
c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile"))
if err != nil {
c.Fatalf("Unable to create test dockerfile")
}
defer cleanup()
s.d.Cmd("build", "--file", dockerfileName, ".")
c.Assert(v1Repo, check.Not(check.Equals), 0, check.Commentf("Expected v1 repository access after build"))
if v1Repo == 0 {
c.Errorf("Expected v1 repository access after build")
}
repoName := fmt.Sprintf("%s/busybox", reg.hostport)
s.d.Cmd("run", repoName)
c.Assert(v1Repo, check.Not(check.Equals), 1, check.Commentf("Expected v1 repository access after run"))
if v1Repo == 1 {
c.Errorf("Expected v1 repository access after run")
}
s.d.Cmd("login", "-u", "richard", "-p", "testtest", "-e", "testuser@testdomain.com", reg.hostport)
c.Assert(v1Logins, check.Not(check.Equals), 0, check.Commentf("Expected v1 login attempt"))
if v1Logins == 0 {
c.Errorf("Expected v1 login attempt")
}
s.d.Cmd("tag", "busybox", repoName)
s.d.Cmd("push", repoName)
c.Assert(v1Repo, check.Equals, 2)
c.Assert(v1Pings, check.Equals, 1)
if v1Repo != 2 || v1Pings != 1 {
c.Error("Not all endpoints contacted after push", v1Repo, v1Pings)
}
s.d.Cmd("pull", repoName)
c.Assert(v1Repo, check.Equals, 3, check.Commentf("Expected v1 repository access after pull"))
if v1Repo != 3 {
c.Errorf("Expected v1 repository access after pull")
}
}
+9 -4
View File
@@ -3,7 +3,6 @@ package main
import (
"strings"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
@@ -22,7 +21,9 @@ func (s *DockerSuite) TestVersionEnsureSucceeds(c *check.C) {
}
for k, v := range stringsToCheck {
c.Assert(strings.Count(out, k), checker.Equals, v, check.Commentf("The count of %v in %s does not match excepted", k, out))
if strings.Count(out, k) != v {
c.Errorf("%v expected %d instances found %d", k, v, strings.Count(out, k))
}
}
}
@@ -43,7 +44,9 @@ func testVersionPlatform(c *check.C, platform string) {
expected := "OS/Arch: " + platform
split := strings.Split(out, "\n")
c.Assert(len(split) >= 14, checker.Equals, true, check.Commentf("got %d lines from version", len(split)))
if len(split) < 14 { // To avoid invalid indexing in loop below
c.Errorf("got %d lines from version", len(split))
}
// Verify the second 'OS/Arch' matches the platform. Experimental has
// more lines of output than 'regular'
@@ -54,5 +57,7 @@ func testVersionPlatform(c *check.C, platform string) {
break
}
}
c.Assert(bFound, checker.Equals, true, check.Commentf("Could not find server '%s' in '%s'", expected, out))
if !bFound {
c.Errorf("Could not find server '%s' in '%s'", expected, out)
}
}
+55 -57
View File
@@ -57,15 +57,21 @@ type Daemon struct {
// The daemon will not automatically start.
func NewDaemon(c *check.C) *Daemon {
dest := os.Getenv("DEST")
c.Assert(dest, check.Not(check.Equals), "", check.Commentf("Please set the DEST environment variable"))
if dest == "" {
c.Fatal("Please set the DEST environment variable")
}
id := fmt.Sprintf("d%d", time.Now().UnixNano()%100000000)
dir := filepath.Join(dest, id)
daemonFolder, err := filepath.Abs(dir)
c.Assert(err, check.IsNil, check.Commentf("Could not make %q an absolute path", dir))
if err != nil {
c.Fatalf("Could not make %q an absolute path: %v", dir, err)
}
daemonRoot := filepath.Join(daemonFolder, "root")
c.Assert(os.MkdirAll(daemonRoot, 0755), check.IsNil, check.Commentf("Could not create daemon root %q", dir))
if err := os.MkdirAll(daemonRoot, 0755); err != nil {
c.Fatalf("Could not create daemon root %q: %v", dir, err)
}
userlandProxy := true
if env := os.Getenv("DOCKER_USERLANDPROXY"); env != "" {
@@ -90,7 +96,9 @@ func NewDaemon(c *check.C) *Daemon {
// You can specify additional daemon flags.
func (d *Daemon) Start(arg ...string) error {
dockerBinary, err := exec.LookPath(dockerBinary)
d.c.Assert(err, check.IsNil, check.Commentf("[%s] could not find docker binary in $PATH", d.id))
if err != nil {
d.c.Fatalf("[%s] could not find docker binary in $PATH: %v", d.id, err)
}
args := append(d.GlobalFlags,
d.Command,
@@ -128,7 +136,9 @@ func (d *Daemon) Start(arg ...string) error {
d.cmd = exec.Command(dockerBinary, args...)
d.logFile, err = os.OpenFile(filepath.Join(d.folder, "docker.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
d.c.Assert(err, check.IsNil, check.Commentf("[%s] Could not create %s/docker.log", d.id, d.folder))
if err != nil {
d.c.Fatalf("[%s] Could not create %s/docker.log: %v", d.id, d.folder, err)
}
d.cmd.Stdout = d.logFile
d.cmd.Stderr = d.logFile
@@ -177,7 +187,9 @@ func (d *Daemon) Start(arg ...string) error {
defer client.Close()
req, err := http.NewRequest("GET", "/_ping", nil)
d.c.Assert(err, check.IsNil, check.Commentf("[%s] could not create new request", d.id))
if err != nil {
d.c.Fatalf("[%s] could not create new request: %v", d.id, err)
}
resp, err := client.Do(req)
if err != nil {
@@ -494,42 +506,6 @@ func deleteAllContainers() error {
return nil
}
func deleteAllNetworks() error {
networks, err := getAllNetworks()
if err != nil {
return err
}
var errors []string
for _, n := range networks {
if n.Name != "bridge" {
status, b, err := sockRequest("DELETE", "/networks/"+n.Name, nil)
if err != nil {
errors = append(errors, err.Error())
continue
}
if status != http.StatusNoContent {
errors = append(errors, fmt.Sprintf("error deleting network %s: %s", n.Name, string(b)))
}
}
}
if len(errors) > 0 {
return fmt.Errorf(strings.Join(errors, "\n"))
}
return nil
}
func getAllNetworks() ([]types.NetworkResource, error) {
var networks []types.NetworkResource
_, b, err := sockRequest("GET", "/networks", nil)
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &networks); err != nil {
return nil, err
}
return networks, nil
}
func deleteAllVolumes() error {
volumes, err := getAllVolumes()
if err != nil {
@@ -742,7 +718,13 @@ func dockerCmdInDirWithTimeout(timeout time.Duration, path string, args ...strin
}
func findContainerIP(c *check.C, id string, vargs ...string) string {
out, _ := dockerCmd(c, "inspect", "--format='{{ .NetworkSettings.IPAddress }}'", id)
args := append(vargs, "inspect", "--format='{{ .NetworkSettings.IPAddress }}'", id)
cmd := exec.Command(dockerBinary, args...)
out, _, err := runCommandWithOutput(cmd)
if err != nil {
c.Fatal(err, out)
}
return strings.Trim(out, " \r\n'")
}
@@ -1294,23 +1276,30 @@ func newFakeGit(name string, files map[string]string, enforceLocalServer bool) (
// Write `content` to the file at path `dst`, creating it if necessary,
// as well as any missing directories.
// The file is truncated if it already exists.
// Fail the test when error occures.
// Call c.Fatal() at the first error.
func writeFile(dst, content string, c *check.C) {
// Create subdirectories if necessary
c.Assert(os.MkdirAll(path.Dir(dst), 0700), check.IsNil)
if err := os.MkdirAll(path.Dir(dst), 0700); err != nil {
c.Fatal(err)
}
f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
c.Assert(err, check.IsNil)
if err != nil {
c.Fatal(err)
}
defer f.Close()
// Write content (truncate if it exists)
_, err = io.Copy(f, strings.NewReader(content))
c.Assert(err, check.IsNil)
if _, err := io.Copy(f, strings.NewReader(content)); err != nil {
c.Fatal(err)
}
}
// Return the contents of file at path `src`.
// Fail the test when error occures.
// Call c.Fatal() at the first error (including if the file doesn't exist)
func readFile(src string, c *check.C) (content string) {
data, err := ioutil.ReadFile(src)
c.Assert(err, check.IsNil)
if err != nil {
c.Fatal(err)
}
return string(data)
}
@@ -1362,25 +1351,30 @@ func daemonTime(c *check.C) time.Time {
}
status, body, err := sockRequest("GET", "/info", nil)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, http.StatusOK)
c.Assert(err, check.IsNil)
type infoJSON struct {
SystemTime string
}
var info infoJSON
err = json.Unmarshal(body, &info)
c.Assert(err, check.IsNil, check.Commentf("unable to unmarshal GET /info response"))
if err = json.Unmarshal(body, &info); err != nil {
c.Fatalf("unable to unmarshal /info response: %v", err)
}
dt, err := time.Parse(time.RFC3339Nano, info.SystemTime)
c.Assert(err, check.IsNil, check.Commentf("invalid time format in GET /info response"))
if err != nil {
c.Fatal(err)
}
return dt
}
func setupRegistry(c *check.C) *testRegistryV2 {
testRequires(c, RegistryHosting)
reg, err := newTestRegistryV2(c)
c.Assert(err, check.IsNil)
if err != nil {
c.Fatal(err)
}
// Wait for registry to be ready to serve requests.
for i := 0; i != 5; i++ {
@@ -1390,14 +1384,18 @@ func setupRegistry(c *check.C) *testRegistryV2 {
time.Sleep(100 * time.Millisecond)
}
c.Assert(err, check.IsNil, check.Commentf("Timeout waiting for test registry to become available"))
if err != nil {
c.Fatal("Timeout waiting for test registry to become available")
}
return reg
}
func setupNotary(c *check.C) *testNotary {
testRequires(c, NotaryHosting)
ts, err := newTestNotary(c)
c.Assert(err, check.IsNil)
if err != nil {
c.Fatal(err)
}
return ts
}
+2 -2
View File
@@ -7,7 +7,7 @@ docker-build - Build a new image from the source code at PATH
# SYNOPSIS
**docker build**
[**--build-arg**[=*[]*]]
[**--cpu-shares**[=*0*]]
[**-c**|**--cpu-shares**[=*0*]]
[**--cgroup-parent**[=*CGROUP-PARENT*]]
[**--help**]
[**-f**|**--file**[=*PATH/Dockerfile*]]
@@ -90,7 +90,7 @@ set as the **URL**, the repository is cloned locally and then sent as the contex
**--memory-swap**=*MEMORY-SWAP*
Total memory (memory + swap), '-1' to disable swap.
**--cpu-shares**=*0*
**-c**, **--cpu-shares**=*0*
CPU shares (relative weight).
By default, all containers get the same proportion of CPU cycles.

Some files were not shown because too many files have changed in this diff Show More