mirror of
https://github.com/clearlinux/docker.git
synced 2026-08-20 04:36:37 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 24a4d5767f | |||
| c156bd83c4 |
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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,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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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]" \
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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{}
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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**
|
||||
|
||||
@@ -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
@@ -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 .
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ func (s *DockerSuite) TearDownTest(c *check.C) {
|
||||
deleteAllContainers()
|
||||
deleteAllImages()
|
||||
deleteAllVolumes()
|
||||
deleteAllNetworks()
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user