Merge pull request #31140 from thaJeztah/1.13.2-cherry-picks

17.03 cherry picks
This commit is contained in:
Victor Vieux 2017-02-19 00:36:22 -08:00 committed by GitHub
commit 2a46799a87
23 changed files with 210 additions and 59 deletions

View File

@ -63,6 +63,8 @@ func GetHTTPErrorStatusCode(err error) int {
{"unauthorized", http.StatusUnauthorized},
{"hasn't been activated", http.StatusForbidden},
{"this node", http.StatusServiceUnavailable},
{"needs to be unlocked", http.StatusServiceUnavailable},
{"certificates have expired", http.StatusServiceUnavailable},
} {
if strings.Contains(errStr, status.keyword) {
statusCode = status.code

View File

@ -369,6 +369,11 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
version := httputils.VersionFromContext(ctx)
adjustCPUShares := versions.LessThan(version, "1.19")
// When using API 1.24 and under, the client is responsible for removing the container
if hostConfig != nil && versions.LessThan(version, "1.25") {
hostConfig.AutoRemove = false
}
ccr, err := s.backend.ContainerCreate(types.ContainerCreateConfig{
Name: name,
Config: config,

View File

@ -104,7 +104,8 @@ func MakeTarSumContext(tarStream io.Reader) (ModifiableContext, error) {
return nil, err
}
if err := chrootarchive.Untar(sum, root, nil); err != nil {
err = chrootarchive.Untar(sum, root, nil)
if err != nil {
return nil, err
}

View File

@ -74,9 +74,8 @@ func runRun(dockerCli *command.DockerCli, flags *pflag.FlagSet, opts *runOptions
cmdPath := "run"
var (
flAttach *opttypes.ListOpts
ErrConflictAttachDetach = fmt.Errorf("Conflicting options: -a and -d")
ErrConflictRestartPolicyAndAutoRemove = fmt.Errorf("Conflicting options: --restart and --rm")
flAttach *opttypes.ListOpts
ErrConflictAttachDetach = fmt.Errorf("Conflicting options: -a and -d")
)
config, hostConfig, networkingConfig, err := runconfigopts.Parse(flags, copts)
@ -87,9 +86,6 @@ func runRun(dockerCli *command.DockerCli, flags *pflag.FlagSet, opts *runOptions
return cli.StatusError{StatusCode: 125}
}
if hostConfig.AutoRemove && !hostConfig.RestartPolicy.IsNone() {
return ErrConflictRestartPolicyAndAutoRemove
}
if hostConfig.OomKillDisable != nil && *hostConfig.OomKillDisable && hostConfig.Memory == 0 {
fmt.Fprintf(stderr, "WARNING: Disabling the OOM killer on containers without setting a '-m/--memory' limit may be dangerous.\n")
}

View File

@ -145,8 +145,10 @@ func (c *containerStatsContext) Container() string {
func (c *containerStatsContext) Name() string {
c.AddHeader(nameHeader)
name := c.s.Name[1:]
return name
if len(c.s.Name) > 1 {
return c.s.Name[1:]
}
return "--"
}
func (c *containerStatsContext) ID() string {

View File

@ -69,6 +69,12 @@ func TestContainerStatsContextWrite(t *testing.T) {
`MEM USAGE / LIMIT
20 B / 20 B
-- / --
`,
},
{
Context{Format: "{{.Container}} {{.ID}} {{.Name}}"},
`container1 abcdef foo
container2 --
`,
},
{
@ -83,6 +89,8 @@ container2 --
stats := []StatsEntry{
{
Container: "container1",
ID: "abcdef",
Name: "/foo",
CPUPercentage: 20,
Memory: 20,
MemoryLimit: 20,

View File

@ -219,19 +219,27 @@ func convertServiceSecrets(
if gid == "" {
gid = "0"
}
mode := secret.Mode
if mode == nil {
mode = uint32Ptr(0444)
}
opts = append(opts, &types.SecretRequestOption{
Source: source,
Target: target,
UID: uid,
GID: gid,
Mode: os.FileMode(secret.Mode),
Mode: os.FileMode(*mode),
})
}
return servicecli.ParseSecrets(client, opts)
}
func uint32Ptr(value uint32) *uint32 {
return &value
}
func convertExtraHosts(extraHosts map[string]string) []string {
hosts := []string{}
for host, ip := range extraHosts {

View File

@ -199,7 +199,7 @@ type ServiceSecretConfig struct {
Target string
UID string
GID string
Mode uint32
Mode *uint32
}
// UlimitsConfig the ulimit configuration

View File

@ -7,6 +7,7 @@ import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/versions"
"golang.org/x/net/context"
)
@ -25,6 +26,11 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
return response, err
}
// When using API 1.24 and under, the client is responsible for removing the container
if hostConfig != nil && versions.LessThan(cli.ClientVersion(), "1.25") {
hostConfig.AutoRemove = false
}
query := url.Values{}
if containerName != "" {
query.Set("name", containerName)

View File

@ -74,3 +74,45 @@ func TestContainerCreateWithName(t *testing.T) {
t.Fatalf("expected `container_id`, got %s", r.ID)
}
}
// TestContainerCreateAutoRemove validates that a client using API 1.24 always disables AutoRemove. When using API 1.25
// or up, AutoRemove should not be disabled.
func TestContainerCreateAutoRemove(t *testing.T) {
autoRemoveValidator := func(expectedValue bool) func(req *http.Request) (*http.Response, error) {
return func(req *http.Request) (*http.Response, error) {
var config configWrapper
if err := json.NewDecoder(req.Body).Decode(&config); err != nil {
return nil, err
}
if config.HostConfig.AutoRemove != expectedValue {
return nil, fmt.Errorf("expected AutoRemove to be %v, got %v", expectedValue, config.HostConfig.AutoRemove)
}
b, err := json.Marshal(container.ContainerCreateCreatedBody{
ID: "container_id",
})
if err != nil {
return nil, err
}
return &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(bytes.NewReader(b)),
}, nil
}
}
client := &Client{
client: newMockClient(autoRemoveValidator(false)),
version: "1.24",
}
if _, err := client.ContainerCreate(context.Background(), nil, &container.HostConfig{AutoRemove: true}, nil, ""); err != nil {
t.Fatal(err)
}
client = &Client{
client: newMockClient(autoRemoveValidator(true)),
version: "1.25",
}
if _, err := client.ContainerCreate(context.Background(), nil, &container.HostConfig{AutoRemove: true}, nil, ""); err != nil {
t.Fatal(err)
}
}

View File

@ -28,7 +28,7 @@ import (
"github.com/docker/docker/pkg/loopback"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/go-units"
units "github.com/docker/go-units"
"github.com/opencontainers/runc/libcontainer/label"
)
@ -1713,9 +1713,9 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
// https://github.com/docker/docker/issues/4036
if supported := devicemapper.UdevSetSyncSupport(true); !supported {
if dockerversion.IAmStatic == "true" {
logrus.Error("devmapper: Udev sync is not supported. This will lead to data loss and unexpected behavior. Install a dynamic binary to use devicemapper or select a different storage driver. For more information, see https://docs.docker.com/engine/reference/commandline/daemon/#daemon-storage-driver-option")
logrus.Error("devmapper: Udev sync is not supported. This will lead to data loss and unexpected behavior. Install a dynamic binary to use devicemapper or select a different storage driver. For more information, see https://docs.docker.com/engine/reference/commandline/dockerd/#storage-driver-options")
} else {
logrus.Error("devmapper: Udev sync is not supported. This will lead to data loss and unexpected behavior. Install a more recent version of libdevmapper or select a different storage driver. For more information, see https://docs.docker.com/engine/reference/commandline/daemon/#daemon-storage-driver-option")
logrus.Error("devmapper: Udev sync is not supported. This will lead to data loss and unexpected behavior. Install a more recent version of libdevmapper or select a different storage driver. For more information, see https://docs.docker.com/engine/reference/commandline/dockerd/#storage-driver-options")
}
if !devices.overrideUdevSyncCheck {

View File

@ -31,6 +31,7 @@ import (
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/longpath"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/docker/pkg/system"
units "github.com/docker/go-units"
"golang.org/x/sys/windows"
)
@ -265,19 +266,35 @@ func (d *Driver) Remove(id string) error {
// it is a transient error. Retry until it succeeds.
var computeSystems []hcsshim.ContainerProperties
retryCount := 0
osv := system.GetOSVersion()
for {
// Get and terminate any template VMs that are currently using the layer
// Get and terminate any template VMs that are currently using the layer.
// Note: It is unfortunate that we end up in the graphdrivers Remove() call
// for both containers and images, but the logic for template VMs is only
// needed for images - specifically we are looking to see if a base layer
// is in use by a template VM as a result of having started a Hyper-V
// container at some point.
//
// We have a retry loop for ErrVmcomputeOperationInvalidState and
// ErrVmcomputeOperationAccessIsDenied as there is a race condition
// in RS1 and RS2 building during enumeration when a silo is going away
// for example under it, in HCS. AccessIsDenied added to fix 30278.
//
// TODO @jhowardmsft - For RS3, we can remove the retries. Also consider
// using platform APIs (if available) to get this more succinctly. Also
// consider enlighting the Remove() interface to have context of why
// the remove is being called - that could improve efficiency by not
// enumerating compute systems during a remove of a container as it's
// not required.
computeSystems, err = hcsshim.GetContainers(hcsshim.ComputeSystemQuery{})
if err != nil {
if err == hcsshim.ErrVmcomputeOperationInvalidState {
if retryCount >= 5 {
// If we are unable to get the list of containers
// go ahead and attempt to delete the layer anyway
// as it will most likely work.
if (osv.Build < 15139) &&
((err == hcsshim.ErrVmcomputeOperationInvalidState) || (err == hcsshim.ErrVmcomputeOperationAccessIsDenied)) {
if retryCount >= 500 {
break
}
retryCount++
time.Sleep(2 * time.Second)
time.Sleep(10 * time.Millisecond)
continue
}
return err

View File

@ -137,7 +137,11 @@ func tailFile(f io.ReadSeeker, logWatcher *logger.LogWatcher, tail int, since ti
if !since.IsZero() && msg.Timestamp.Before(since) {
continue
}
logWatcher.Msg <- msg
select {
case <-logWatcher.WatchClose():
return
case logWatcher.Msg <- msg:
}
}
}
@ -252,9 +256,12 @@ func followLogs(f *os.File, logWatcher *logger.LogWatcher, notifyRotate chan int
handleDecodeErr := func(err error) error {
if err == io.EOF {
for err := waitRead(); err != nil; {
for {
err := waitRead()
if err == nil {
break
}
if err == errRetry {
// retry the waitRead
continue
}
return err

View File

@ -61,6 +61,18 @@ func (daemon *Daemon) ContainerLogs(ctx context.Context, containerName string, c
Follow: follow,
}
logs := logReader.ReadLogs(readConfig)
// Close logWatcher on exit
defer func() {
logs.Close()
if cLog != container.LogDriver {
// Since the logger isn't cached in the container, which
// occurs if it is running, it must get explicitly closed
// here to avoid leaking it and any file handles it has.
if err := cLog.Close(); err != nil {
logrus.Errorf("Error closing logger: %v", err)
}
}
}()
wf := ioutils.NewWriteFlusher(config.OutStream)
defer wf.Close()
@ -81,19 +93,11 @@ func (daemon *Daemon) ContainerLogs(ctx context.Context, containerName string, c
logrus.Errorf("Error streaming logs: %v", err)
return nil
case <-ctx.Done():
logs.Close()
logrus.Debugf("logs: end stream, ctx is done: %v", ctx.Err())
return nil
case msg, ok := <-logs.Msg:
if !ok {
logrus.Debug("logs: end stream")
logs.Close()
if cLog != container.LogDriver {
// Since the logger isn't cached in the container, which occurs if it is running, it
// must get explicitly closed here to avoid leaking it and any file handles it has.
if err := cLog.Close(); err != nil {
logrus.Errorf("Error closing logger: %v", err)
}
}
return nil
}
logLine := msg.Line

View File

@ -33,7 +33,9 @@ func (daemon *Daemon) ContainerStats(ctx context.Context, prefixOrName string, c
// If the container is either not running or restarting and requires no stream, return an empty stats.
if (!container.IsRunning() || container.IsRestarting()) && !config.Stream {
return json.NewEncoder(config.OutStream).Encode(&types.Stats{})
return json.NewEncoder(config.OutStream).Encode(&types.StatsJSON{
Name: container.Name,
ID: container.ID})
}
outStream := config.OutStream

View File

@ -120,7 +120,14 @@ func (s *statsCollector) run() {
if err != nil {
if _, ok := err.(errNotRunning); !ok {
logrus.Errorf("collecting stats for %s: %v", pair.container.ID, err)
continue
}
// publish empty stats containing only name and ID if not running
pair.publisher.Publish(types.StatsJSON{
Name: pair.container.Name,
ID: pair.container.ID,
})
continue
}
// FIXME: move to containerd on Linux (not Windows)

View File

@ -531,6 +531,10 @@ func (s *DockerSuite) TestBuildCacheAdd(c *check.C) {
}
func (s *DockerSuite) TestBuildLastModified(c *check.C) {
// Temporary fix for #30890. TODO @jhowardmsft figure out what
// has changed in the master busybox image.
testRequires(c, DaemonIsLinux)
name := "testbuildlastmodified"
server, err := fakeStorage(map[string]string{
@ -3647,6 +3651,7 @@ RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1042:1043/10
}
}
// FIXME(vdemeester) rename this test (and probably "merge" it with the one below TestBuildEnvUsage2)
func (s *DockerSuite) TestBuildEnvUsage(c *check.C) {
// /docker/world/hello is not owned by the correct user
testRequires(c, NotUserNamespace)
@ -3685,6 +3690,7 @@ RUN [ "$ghi" = "def" ]
}
}
// FIXME(vdemeester) rename this test (and probably "merge" it with the one above TestBuildEnvUsage)
func (s *DockerSuite) TestBuildEnvUsage2(c *check.C) {
// /docker/world/hello is not owned by the correct user
testRequires(c, NotUserNamespace)
@ -4811,6 +4817,7 @@ CMD cat /foo/file`,
}
// FIXME(vdemeester) part of this should be unit test, other part should be clearer
func (s *DockerSuite) TestBuildRenamedDockerfile(c *check.C) {
ctx, err := fakeContext(`FROM busybox

View File

@ -157,3 +157,22 @@ func (s *DockerSuite) TestStatsAllNewContainersAdded(c *check.C) {
// ignore, done
}
}
func (s *DockerSuite) TestStatsFormatAll(c *check.C) {
// Windows does not support stats
testRequires(c, DaemonIsLinux)
dockerCmd(c, "run", "-d", "--name=RunningOne", "busybox", "top")
c.Assert(waitRun("RunningOne"), check.IsNil)
dockerCmd(c, "run", "-d", "--name=ExitedOne", "busybox", "top")
dockerCmd(c, "stop", "ExitedOne")
c.Assert(waitExited("ExitedOne", 5*time.Second), check.IsNil)
out, _ := dockerCmd(c, "stats", "--no-stream", "--format", "{{.Name}}")
c.Assert(out, checker.Contains, "RunningOne")
c.Assert(out, checker.Not(checker.Contains), "ExitedOne")
out, _ = dockerCmd(c, "stats", "--all", "--no-stream", "--format", "{{.Name}}")
c.Assert(out, checker.Contains, "RunningOne")
c.Assert(out, checker.Contains, "ExitedOne")
}

View File

@ -621,6 +621,10 @@ func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *c
Runtime: copts.runtime,
}
if copts.autoRemove && !hostConfig.RestartPolicy.IsNone() {
return nil, nil, nil, fmt.Errorf("Conflicting options: --restart and --rm")
}
// only set this value if the user provided the flag, else it should default to nil
if flags.Changed("init") {
hostConfig.Init = &copts.init

View File

@ -586,6 +586,14 @@ func TestParseRestartPolicy(t *testing.T) {
}
}
func TestParseRestartPolicyAutoRemove(t *testing.T) {
expected := "Conflicting options: --restart and --rm"
_, _, _, err := parseRun([]string{"--rm", "--restart=always", "img", "cmd"})
if err == nil || err.Error() != expected {
t.Fatalf("Expected error %v, but got none", expected)
}
}
func TestParseHealth(t *testing.T) {
checkOk := func(args ...string) *container.HealthConfig {
config, _, _, err := parseRun(args)

View File

@ -1,6 +1,6 @@
# the following lines are in sorted order, FYI
github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62
github.com/Microsoft/hcsshim v0.5.9
github.com/Microsoft/hcsshim v0.5.12
github.com/Microsoft/go-winio v0.3.8
github.com/Sirupsen/logrus v0.11.0
github.com/davecgh/go-spew 6d212800a42e8ab5c146b8ace3490ee17e5225f9

View File

@ -50,6 +50,10 @@ var (
// ErrProcNotFound is an error encountered when the the process cannot be found
ErrProcNotFound = syscall.Errno(0x7f)
// ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2
// builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3.
ErrVmcomputeOperationAccessIsDenied = syscall.Errno(0x5)
)
// ProcessError is an error encountered in HCS during an operation on a Process object

View File

@ -41,30 +41,32 @@ type HvRuntime struct {
// ContainerConfig is used as both the input of CreateContainer
// and to convert the parameters to JSON for passing onto the HCS
type ContainerConfig struct {
SystemType string // HCS requires this to be hard-coded to "Container"
Name string // Name of the container. We use the docker ID.
Owner string // The management platform that created this container
IsDummy bool // Used for development purposes.
VolumePath string `json:",omitempty"` // Windows volume path for scratch space. Used by Windows Server Containers only. Format \\?\\Volume{GUID}
IgnoreFlushesDuringBoot bool // Optimization hint for container startup in Windows
LayerFolderPath string `json:",omitempty"` // Where the layer folders are located. Used by Windows Server Containers only. Format %root%\windowsfilter\containerID
Layers []Layer // List of storage layers. Required for Windows Server and Hyper-V Containers. Format ID=GUID;Path=%root%\windowsfilter\layerID
Credentials string `json:",omitempty"` // Credentials information
ProcessorCount uint32 `json:",omitempty"` // Number of processors to assign to the container.
ProcessorWeight uint64 `json:",omitempty"` // CPU Shares 0..10000 on Windows; where 0 will be omitted and HCS will default.
ProcessorMaximum int64 `json:",omitempty"` // CPU maximum usage percent 1..100
StorageIOPSMaximum uint64 `json:",omitempty"` // Maximum Storage IOPS
StorageBandwidthMaximum uint64 `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second
StorageSandboxSize uint64 `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller
MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes
HostName string // Hostname
MappedDirectories []MappedDir // List of mapped directories (volumes/mounts)
SandboxPath string `json:",omitempty"` // Location of unmounted sandbox. Used by Hyper-V containers only. Format %root%\windowsfilter
HvPartition bool // True if it a Hyper-V Container
EndpointList []string // List of networking endpoints to be attached to container
HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM
Servicing bool // True if this container is for servicing
AllowUnqualifiedDNSQuery bool // True to allow unqualified DNS name resolution
SystemType string // HCS requires this to be hard-coded to "Container"
Name string // Name of the container. We use the docker ID.
Owner string // The management platform that created this container
IsDummy bool // Used for development purposes.
VolumePath string `json:",omitempty"` // Windows volume path for scratch space. Used by Windows Server Containers only. Format \\?\\Volume{GUID}
IgnoreFlushesDuringBoot bool // Optimization hint for container startup in Windows
LayerFolderPath string `json:",omitempty"` // Where the layer folders are located. Used by Windows Server Containers only. Format %root%\windowsfilter\containerID
Layers []Layer // List of storage layers. Required for Windows Server and Hyper-V Containers. Format ID=GUID;Path=%root%\windowsfilter\layerID
Credentials string `json:",omitempty"` // Credentials information
ProcessorCount uint32 `json:",omitempty"` // Number of processors to assign to the container.
ProcessorWeight uint64 `json:",omitempty"` // CPU Shares 0..10000 on Windows; where 0 will be omitted and HCS will default.
ProcessorMaximum int64 `json:",omitempty"` // CPU maximum usage percent 1..100
StorageIOPSMaximum uint64 `json:",omitempty"` // Maximum Storage IOPS
StorageBandwidthMaximum uint64 `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second
StorageSandboxSize uint64 `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller
MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes
HostName string // Hostname
MappedDirectories []MappedDir // List of mapped directories (volumes/mounts)
SandboxPath string `json:",omitempty"` // Location of unmounted sandbox. Used by Hyper-V containers only. Format %root%\windowsfilter
HvPartition bool // True if it a Hyper-V Container
EndpointList []string // List of networking endpoints to be attached to container
NetworkSharedContainerName string `json:",omitempty"` // Name (ID) of the container that we will share the network stack with.
HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM
Servicing bool // True if this container is for servicing
AllowUnqualifiedDNSQuery bool // True to allow unqualified DNS name resolution
DNSSearchList string `json:",omitempty"` // Comma seperated list of DNS suffixes to use for name resolution
}
type ComputeSystemQuery struct {