Package init

This commit is contained in:
overweight 2019-09-30 10:37:25 -04:00
commit 6138d366d1
135 changed files with 21570 additions and 0 deletions

1
VERSION-openeuler Normal file
View File

@ -0,0 +1 @@
18.09.0.100

44
apply-patches Executable file
View File

@ -0,0 +1,44 @@
#!/bin/bash
# Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
# Description: This shell script is used to apply patches for the project
# Author: jingrui@huawei.com
# Create: 2019-03-02
set -ex
pkg=docker-ce-18.09.0
cwd=$PWD
src=$cwd/$pkg
tar -xzvf $pkg.tar.gz
cd $src
git init
git add .
git config user.name 'build'
git config user.email 'build@obs.com'
git commit -m 'init build'
cd $cwd
series=$cwd/series.conf
while IPF= read -r line
do
if [[ "$line" =~ ^patch* ]]; then
echo git apply $cwd/$line
cd $src && git apply $cwd/$line
fi
done <"$series"
cd $cwd
if [ "$1" == "selinux" ]; then
cp -rf $src/components/engine/contrib/selinux-euleros/docker-engine-selinux/* .
else
cp -rf $src/* .
cp -rf VERSION-openeuler $cwd/components/cli/
cp -rf VERSION-openeuler $cwd/components/engine/
fi
mv $src/.git $src/git

BIN
docker-ce-18.09.0.tar.gz Executable file

Binary file not shown.

View File

@ -0,0 +1,202 @@
Name: docker-engine
Version: 18.09.0
Release: 100
Summary: The open-source application container engine
Group: Tools/Docker
License: ASL 2.0
Source: %{name}.tar.gz
URL: https://mobyproject.org
%global is_systemd 1
%global debug_package %{nil}
# required packages for build
# most are already in the container (see contrib/builder/rpm/ARCH/generate.sh)
BuildRequires: pkgconfig(systemd) golang >= 1.8.3 go-md2man btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel
BuildRequires: libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel sqlite-devel systemd-devel
BuildRequires: tar containerd docker-runc docker-proxy
# required packages on install
Requires: /bin/sh iptables libcgroup tar xz device-mapper-libs >= 1.02.90-1 systemd-units
# conflicting packages
Provides: docker
Conflicts: docker-io
Conflicts: docker-engine-cs
%description
Docker is an open source project to build, ship and run any application as a
lightweight container.
Docker containers are both hardware-agnostic and platform-agnostic. This means
they can run anywhere, from your laptop to the largest EC2 compute instance and
everything in between - and they don't require you to use a particular
language, framework or packaging system. That makes them great building blocks
for deploying and scaling web apps, databases, and backend services without
depending on a particular stack or provider.
%prep
%autosetup -c -n %{name}
%build
./apply-patches
# build docker engine
WORKDIR=$(pwd)
GITCOMMIT=$(git rev-parse --short HEAD)
export VERSION=$(cat VERSION)
export DOCKER_GITCOMMIT=${GITCOMMIT}
export AUTO_GOPATH=1
export DOCKER_BUILDTAGS="pkcs11 seccomp selinux"
cd ${WORKDIR}/components/engine
./hack/make.sh dynbinary
# buid docker cli
cd ${WORKDIR}/components/cli
mkdir -p .gopath/src/github.com/docker
export GOPATH=`pwd`/.gopath
ln -sf `pwd` .gopath/src/github.com/docker/cli
ln -sf ${WORKDIR}/components/engine .gopath/src/github.com/docker/docker
cd .gopath/src/github.com/docker/cli
make dynbinary
# ./man/md2man-all.sh runs outside the build container (if at all), since we don't have go-md2man here
./man/md2man-all.sh -q
rm -rf .gopath
cd ${WORKDIR}
%check
./components/engine/bundles/dynbinary-daemon/dockerd -v
./components/cli/build/docker -v
%install
# install binary
install -d $RPM_BUILD_ROOT/%{_bindir}
install -p -m 755 components/engine/bundles/dynbinary-daemon/dockerd $RPM_BUILD_ROOT/%{_bindir}/dockerd
# install cli
install -p -m 755 components/cli/build/docker $RPM_BUILD_ROOT/%{_bindir}/docker
# install proxy
install -p -m 755 /usr/bin/docker-proxy $RPM_BUILD_ROOT/%{_bindir}/docker-proxy
# install containerd
install -p -m 755 /usr/bin/containerd $RPM_BUILD_ROOT/%{_bindir}/containerd
install -p -m 755 /usr/bin/containerd-shim $RPM_BUILD_ROOT/%{_bindir}/containerd-shim
# install runc
install -p -m 755 /usr/local/bin/runc $RPM_BUILD_ROOT/%{_bindir}/runc
# install udev rules
install -d $RPM_BUILD_ROOT/%{_sysconfdir}/udev/rules.d
install -p -m 644 components/engine/contrib/udev/80-docker.rules $RPM_BUILD_ROOT/%{_sysconfdir}/udev/rules.d/80-docker.rules
# add init scripts
install -d $RPM_BUILD_ROOT/etc/sysconfig
install -d $RPM_BUILD_ROOT/%{_initddir}
install -p -m 644 components/engine/contrib/init/sysvinit-redhat/docker.sysconfig $RPM_BUILD_ROOT/etc/sysconfig/docker
install -p -m 644 components/engine/contrib/init/sysvinit-redhat/docker-network $RPM_BUILD_ROOT/etc/sysconfig/docker-network
install -p -m 644 components/engine/contrib/init/sysvinit-redhat/docker-storage $RPM_BUILD_ROOT/etc/sysconfig/docker-storage
install -d $RPM_BUILD_ROOT/%{_unitdir}
install -p -m 644 components/engine/contrib/init/systemd/docker.service $RPM_BUILD_ROOT/%{_unitdir}/docker.service
# add bash, zsh, and fish completions
install -d $RPM_BUILD_ROOT/usr/share/bash-completion/completions
install -d $RPM_BUILD_ROOT/usr/share/zsh/vendor-completions
install -d $RPM_BUILD_ROOT/usr/share/fish/vendor_completions.d
install -p -m 644 components/cli/contrib/completion/bash/docker $RPM_BUILD_ROOT/usr/share/bash-completion/completions/docker
install -p -m 644 components/cli/contrib/completion/zsh/_docker $RPM_BUILD_ROOT/usr/share/zsh/vendor-completions/_docker
install -p -m 644 components/cli/contrib/completion/fish/docker.fish $RPM_BUILD_ROOT/usr/share/fish/vendor_completions.d/docker.fish
# install manpages
install -d %{buildroot}%{_mandir}/man1
install -p -m 644 components/cli/man/man1/*.1 $RPM_BUILD_ROOT/%{_mandir}/man1
install -d %{buildroot}%{_mandir}/man5
install -p -m 644 components/cli/man/man5/*.5 $RPM_BUILD_ROOT/%{_mandir}/man5
install -d %{buildroot}%{_mandir}/man8
install -p -m 644 components/cli/man/man8/*.8 $RPM_BUILD_ROOT/%{_mandir}/man8
# add vimfiles
install -d $RPM_BUILD_ROOT/usr/share/vim/vimfiles/doc
install -d $RPM_BUILD_ROOT/usr/share/vim/vimfiles/ftdetect
install -d $RPM_BUILD_ROOT/usr/share/vim/vimfiles/syntax
install -p -m 644 components/engine/contrib/syntax/vim/doc/dockerfile.txt $RPM_BUILD_ROOT/usr/share/vim/vimfiles/doc/dockerfile.txt
install -p -m 644 components/engine/contrib/syntax/vim/ftdetect/dockerfile.vim $RPM_BUILD_ROOT/usr/share/vim/vimfiles/ftdetect/dockerfile.vim
install -p -m 644 components/engine/contrib/syntax/vim/syntax/dockerfile.vim $RPM_BUILD_ROOT/usr/share/vim/vimfiles/syntax/dockerfile.vim
# add nano
install -d $RPM_BUILD_ROOT/usr/share/nano
install -p -m 644 components/engine/contrib/syntax/nano/Dockerfile.nanorc $RPM_BUILD_ROOT/usr/share/nano/Dockerfile.nanorc
# list files owned by the package here
%files
%doc components/engine/AUTHORS components/engine/CHANGELOG.md components/engine/CONTRIBUTING.md components/engine/LICENSE components/engine/MAINTAINERS components/engine/NOTICE components/engine/README.md
/%{_bindir}/docker
/%{_bindir}/dockerd
/%{_bindir}/containerd
/%{_bindir}/docker-proxy
/%{_bindir}/containerd-shim
/%{_bindir}/runc
/%{_sysconfdir}/udev/rules.d/80-docker.rules
%if 0%{?is_systemd}
/%{_unitdir}/docker.service
%else
/%{_initddir}/docker
%endif
/usr/share/bash-completion/completions/docker
/usr/share/zsh/vendor-completions/_docker
/usr/share/fish/vendor_completions.d/docker.fish
%doc
/%{_mandir}/man1/*
/%{_mandir}/man5/*
/%{_mandir}/man8/*
%config(noreplace,missingok) /etc/sysconfig/docker
%config(noreplace,missingok) /etc/sysconfig/docker-storage
%config(noreplace,missingok) /etc/sysconfig/docker-network
/usr/share/vim/vimfiles/doc/dockerfile.txt
/usr/share/vim/vimfiles/ftdetect/dockerfile.vim
/usr/share/vim/vimfiles/syntax/dockerfile.vim
/usr/share/nano/Dockerfile.nanorc
%post
if ! getent group docker > /dev/null; then
groupadd --system docker
fi
%if 0%{?is_systemd}
#%systemd_post docker
systemctl enable docker
systemctl start docker
%else
# This adds the proper /etc/rc*.d links for the script
/sbin/chkconfig --add docker
%endif
if ! getent group docker > /dev/null; then
groupadd --system docker
fi
%preun
%if 0%{?is_systemd}
%systemd_preun docker
%else
if [ $1 -eq 0 ] ; then
/sbin/service docker stop >/dev/null 2>&1
/sbin/chkconfig --del docker
fi
%endif
%postun
%if 0%{?is_systemd}
%systemd_postun_with_restart docker
%else
if [ "$1" -ge "1" ] ; then
/sbin/service docker condrestart >/dev/null 2>&1 || :
fi
%endif
%changelog

View File

@ -0,0 +1,616 @@
From 7e41c5cf67a5deaa542d3907a257adf6ae6c976b Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:07:09 +0800
Subject: [PATCH 001/111] pause: move pause function to docker
reason: The origin pause function has a long callstack from
docker->containerd->runc,it is waste a lot of time.
Now we move this function to docker, docker will update freeze
cgroup directly.
Change-Id: I8c26d5b4ed71fb30563db0d4e77167b5b68ccad9
Signed-off-by: Wentao Zhang <zhangwentao234@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/container/container.go | 1 +
components/engine/daemon/daemon.go | 53 ++++++
components/engine/daemon/freezer/cgroup_fs.go | 94 +++++++++
.../engine/daemon/freezer/cgroup_systemd.go | 59 ++++++
components/engine/daemon/freezer/freezer.go | 179 ++++++++++++++++++
components/engine/daemon/oci_linux.go | 1 +
components/engine/daemon/pause.go | 19 +-
components/engine/daemon/unpause.go | 17 +-
.../engine/libcontainerd/utils_linux.go | 25 +++
.../engine/libcontainerd/utils_windows.go | 7 +-
10 files changed, 449 insertions(+), 6 deletions(-)
create mode 100644 components/engine/daemon/freezer/cgroup_fs.go
create mode 100644 components/engine/daemon/freezer/cgroup_systemd.go
create mode 100644 components/engine/daemon/freezer/freezer.go
create mode 100644 components/engine/libcontainerd/utils_linux.go
diff --git a/components/engine/container/container.go b/components/engine/container/container.go
index 6a5907c34b..f74676f7ee 100644
--- a/components/engine/container/container.go
+++ b/components/engine/container/container.go
@@ -106,6 +106,7 @@ type Container struct {
// Fields here are specific to Windows
NetworkSharedContainerID string `json:"-"`
SharedEndpointList []string `json:"-"`
+ CgroupParent string
}
// NewBaseContainer creates a new container with its
diff --git a/components/engine/daemon/daemon.go b/components/engine/daemon/daemon.go
index a307863017..8d6b4d8546 100644
--- a/components/engine/daemon/daemon.go
+++ b/components/engine/daemon/daemon.go
@@ -35,6 +35,7 @@ import (
"github.com/docker/docker/daemon/discovery"
"github.com/docker/docker/daemon/events"
"github.com/docker/docker/daemon/exec"
+ "github.com/docker/docker/daemon/freezer"
"github.com/docker/docker/daemon/images"
"github.com/docker/docker/daemon/logger"
"github.com/docker/docker/daemon/network"
@@ -197,6 +198,53 @@ func (daemon *Daemon) NewResolveOptionsFunc() resolver.ResolveOptionsFunc {
}
}
+func (daemon *Daemon) updatePauseStatus(c *container.Container) error {
+ if !daemon.IsNativeRuntime(c.HostConfig.Runtime) {
+ return nil
+ }
+
+ // update docker pause status.
+ // for old container, CgroupParent may be empty.
+ if c.CgroupParent == "" {
+ spec, err := libcontainerd.LoadContainerSpec(filepath.Join(daemon.configStore.ExecRoot, "libcontainerd"), c.ID)
+ if err != nil {
+ return err
+ }
+ c.CgroupParent = spec.Linux.CgroupsPath
+ }
+
+ if !c.IsRunning() {
+ c.Paused = false
+ return nil
+ }
+
+ useSystemd := UsingSystemd(daemon.configStore)
+ freeze, err := freezer.New(c.ID, c.CgroupParent, useSystemd)
+ if err != nil {
+ return err
+ }
+
+ paused, err := freeze.IsPaused()
+ if err != nil {
+ return err
+ }
+ c.Paused = paused
+ return nil
+}
+
+func (daemon *Daemon) IsNativeRuntime(runtime string) bool {
+ // For the containers which created by old docker (do not support multi-runtime)
+ // c.HostConfig.Runtime may be empty. just use the default runtime.
+ if runtime == "" {
+ runtime = daemon.configStore.GetDefaultRuntimeName()
+ }
+ rt := daemon.configStore.GetRuntime(runtime)
+ if rt != nil && filepath.Base(rt.Path) == DefaultRuntimeBinary {
+ return true
+ }
+ return false
+}
+
func (daemon *Daemon) restore() error {
containers := make(map[string]*container.Container)
@@ -244,6 +292,11 @@ func (daemon *Daemon) restore() error {
delete(containers, id)
continue
}
+
+ if err := daemon.updatePauseStatus(c); err != nil {
+ logrus.Errorf("Failed to update pause status for container %s: %s", c.ID, err)
+ }
+
if err := daemon.Register(c); err != nil {
logrus.Errorf("Failed to register container %s: %s", c.ID, err)
delete(containers, id)
diff --git a/components/engine/daemon/freezer/cgroup_fs.go b/components/engine/daemon/freezer/cgroup_fs.go
new file mode 100644
index 0000000000..5822c3a659
--- /dev/null
+++ b/components/engine/daemon/freezer/cgroup_fs.go
@@ -0,0 +1,94 @@
+package freezer
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "sync"
+
+ "github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runc/libcontainer/configs"
+ "github.com/opencontainers/runc/libcontainer/utils"
+)
+
+// The absolute path to the root of the cgroup hierarchies.
+var cgroupRootLock sync.Mutex
+var cgroupRoot string
+
+func fsCgroupPath(subsystem string, c *configs.Cgroup) (string, error) {
+ rawRoot, err := getCgroupRoot()
+ if err != nil {
+ return "", err
+ }
+
+ if (c.Name != "" || c.Parent != "") && c.Path != "" {
+ return "", fmt.Errorf("cgroup: either Path or Name and Parent should be used")
+ }
+
+ // XXX: Do not remove this code. Path safety is important! -- cyphar
+ cgPath := utils.CleanPath(c.Path)
+ cgParent := utils.CleanPath(c.Parent)
+ cgName := utils.CleanPath(c.Name)
+
+ innerPath := cgPath
+ if innerPath == "" {
+ innerPath = filepath.Join(cgParent, cgName)
+ }
+
+ mnt, root, err := cgroups.FindCgroupMountpointAndRoot(subsystem)
+ // If we didn't mount the subsystem, there is no point we make the path.
+ if err != nil {
+ return "", err
+ }
+
+ // If the cgroup name/path is absolute do not look relative to the cgroup of the init process.
+ if filepath.IsAbs(innerPath) {
+ // Sometimes subsystems can be mounted together as 'cpu,cpuacct'.
+ return filepath.Join(rawRoot, filepath.Base(mnt), innerPath), nil
+ }
+
+ parentPath, err := parentPath(subsystem, mnt, root)
+ if err != nil {
+ return "", err
+ }
+
+ return filepath.Join(parentPath, innerPath), nil
+}
+
+func parentPath(subsystem, mountpoint, root string) (string, error) {
+ // Use GetThisCgroupDir instead of GetInitCgroupDir, because the creating
+ // process could in container and shared pid namespace with host, and
+ // /proc/1/cgroup could point to whole other world of cgroups.
+ initPath, err := cgroups.GetOwnCgroup(subsystem)
+ if err != nil {
+ return "", err
+ }
+ // This is needed for nested containers, because in /proc/self/cgroup we
+ // see pathes from host, which don't exist in container.
+ relDir, err := filepath.Rel(root, initPath)
+ if err != nil {
+ return "", err
+ }
+ return filepath.Join(mountpoint, relDir), nil
+}
+
+func getCgroupRoot() (string, error) {
+ cgroupRootLock.Lock()
+ defer cgroupRootLock.Unlock()
+
+ if cgroupRoot != "" {
+ return cgroupRoot, nil
+ }
+
+ root, err := cgroups.FindCgroupMountpointDir()
+ if err != nil {
+ return "", err
+ }
+
+ if _, err := os.Stat(root); err != nil {
+ return "", err
+ }
+
+ cgroupRoot = root
+ return cgroupRoot, nil
+}
diff --git a/components/engine/daemon/freezer/cgroup_systemd.go b/components/engine/daemon/freezer/cgroup_systemd.go
new file mode 100644
index 0000000000..4a05d04910
--- /dev/null
+++ b/components/engine/daemon/freezer/cgroup_systemd.go
@@ -0,0 +1,59 @@
+package freezer
+
+import (
+ "fmt"
+ "path/filepath"
+ "strings"
+
+ "github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runc/libcontainer/cgroups/systemd"
+ "github.com/opencontainers/runc/libcontainer/configs"
+)
+
+var (
+ systemdEnabledChecked = false
+ systemdEnabled = false
+)
+
+func SystemdEnabled() bool {
+ if systemdEnabledChecked {
+ return systemdEnabled
+ }
+ systemdEnabledChecked = true
+ systemdEnabled = systemd.UseSystemd()
+ return systemdEnabled
+}
+
+func systemdCgroupPath(subsystem string, c *configs.Cgroup) (string, error) {
+ mountpoint, err := cgroups.FindCgroupMountpoint(subsystem)
+ if err != nil {
+ return "", err
+ }
+
+ initPath, err := cgroups.GetInitCgroup(subsystem)
+ if err != nil {
+ return "", err
+ }
+ // if pid 1 is systemd 226 or later, it will be in init.scope, not the root
+ initPath = strings.TrimSuffix(filepath.Clean(initPath), "init.scope")
+
+ slice := "system.slice"
+ if c.Parent != "" {
+ slice = c.Parent
+ }
+
+ slice, err = systemd.ExpandSlice(slice)
+ if err != nil {
+ return "", err
+ }
+
+ return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil
+}
+
+func getUnitName(c *configs.Cgroup) string {
+ // by default, we create a scope unless the user explicitly asks for a slice.
+ if !strings.HasSuffix(c.Name, ".slice") {
+ return fmt.Sprintf("%s-%s.scope", c.ScopePrefix, c.Name)
+ }
+ return c.Name
+}
diff --git a/components/engine/daemon/freezer/freezer.go b/components/engine/daemon/freezer/freezer.go
new file mode 100644
index 0000000000..774f5c21ed
--- /dev/null
+++ b/components/engine/daemon/freezer/freezer.go
@@ -0,0 +1,179 @@
+package freezer
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/opencontainers/runc/libcontainer/configs"
+ "github.com/opencontainers/runc/libcontainer/utils"
+)
+
+// Freezer is the interface which could be used to pause/resume container,
+// And it could be used to get the real container paused status of a container too.
+type Freezer interface {
+ // Pause will set the container to pause state by writing freeze cgroup.
+ Pause() error
+
+ // Resume will set the container to running state by writing freeze cgroup.
+ Resume() error
+
+ // IsPaused will return if the container is paused or not by reading cgroup information.
+ IsPaused() (bool, error)
+}
+
+func writeFile(dir, file, data string) error {
+ // Normally dir should not be empty, one case is that cgroup subsystem
+ // is not mounted, we will get empty dir, and we want it fail here.
+ if dir == "" {
+ return fmt.Errorf("no such directory for %s", file)
+ }
+ if err := ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700); err != nil {
+ return fmt.Errorf("failed to write %v to %v: %v", data, file, err)
+ }
+ return nil
+}
+
+func readFile(dir, file string) (string, error) {
+ data, err := ioutil.ReadFile(filepath.Join(dir, file))
+ return string(data), err
+}
+
+// New will create a Freezer interface for caller
+func New(cid, cgroupParent string, useSystemdCgroup bool) (Freezer, error) {
+ if useSystemdCgroup && !SystemdEnabled() {
+ return nil, fmt.Errorf("systemd cgroup flag passed, but systemd support for managing cgroups is not available")
+ }
+ cgroupConfig, err := prepareCgroupConfig(cid, cgroupParent, useSystemdCgroup)
+ if err != nil {
+ return nil, err
+ }
+
+ return newFreezer(useSystemdCgroup, cgroupConfig)
+}
+
+func prepareCgroupConfig(cid, cgroupsPath string, useSystemdCgroup bool) (*configs.Cgroup, error) {
+ var myCgroupPath string
+ c := &configs.Cgroup{
+ Resources: &configs.Resources{},
+ }
+ if cgroupsPath != "" {
+ myCgroupPath = utils.CleanPath(cgroupsPath)
+ if useSystemdCgroup {
+ myCgroupPath = cgroupsPath
+ }
+ }
+
+ if useSystemdCgroup {
+ if myCgroupPath == "" {
+ c.Parent = "system.slice"
+ c.ScopePrefix = "runc"
+ c.Name = cid
+ } else {
+ // Parse the path from expected "slice:prefix:name"
+ // for e.g. "system.slice:docker:1234"
+ parts := strings.Split(myCgroupPath, ":")
+ if len(parts) != 3 {
+ return nil, fmt.Errorf("expected cgroupsPath to be of format \"slice:prefix:name\" for systemd cgroups")
+ }
+ c.Parent = parts[0]
+ c.ScopePrefix = parts[1]
+ c.Name = parts[2]
+ }
+ } else {
+ if myCgroupPath == "" {
+ c.Name = cid
+ }
+ c.Path = myCgroupPath
+ }
+ return c, nil
+}
+
+func newFreezer(useSystemdCgroup bool, cgroup *configs.Cgroup) (Freezer, error) {
+ var err error
+ var path string
+
+ if useSystemdCgroup {
+ path, err = systemdCgroupPath("freezer", cgroup)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ path, err = fsCgroupPath("freezer", cgroup)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return &freezer{path: path}, nil
+}
+
+type freezer struct {
+ sync.Mutex
+ path string
+}
+
+// Pause will set the container to pause state by writing freeze cgroup.
+func (f *freezer) Pause() error {
+ f.Lock()
+ defer f.Unlock()
+
+ if err := f.updateCgroup(string(configs.Frozen)); err != nil {
+ return err
+ }
+
+ tasks, err := readFile(f.path, "tasks")
+ if err != nil {
+ return fmt.Errorf("failed to check container cgroup task status: %v", err)
+ }
+
+ if strings.TrimSpace(tasks) == "" {
+ return fmt.Errorf("error: no tasks running in freeze cgroup")
+ }
+ return nil
+}
+
+// Resume will set the container to running state by writing freeze cgroup.
+func (f *freezer) Resume() error {
+ f.Lock()
+ defer f.Unlock()
+ return f.updateCgroup(string(configs.Thawed))
+}
+
+// IsPaused will return if the container is paused or not by reading cgroup information.
+func (f *freezer) IsPaused() (bool, error) {
+ f.Lock()
+ defer f.Unlock()
+
+ data, err := readFile(f.path, "freezer.state")
+ if err != nil {
+ // If freezer cgroup is not mounted, the container would just be not paused.
+ if os.IsNotExist(err) {
+ return false, nil
+ }
+ return false, fmt.Errorf("failed to check container status: %v", err)
+ }
+ return bytes.Equal(bytes.TrimSpace([]byte(data)), []byte("FROZEN")), nil
+}
+
+func (f *freezer) updateCgroup(state string) error {
+ if err := writeFile(f.path, "freezer.state", state); err != nil {
+ return err
+ }
+
+ for {
+ newState, err := readFile(f.path, "freezer.state")
+ if err != nil {
+ return err
+ }
+ if strings.TrimSpace(newState) == state {
+ break
+ }
+ time.Sleep(1 * time.Millisecond)
+ }
+ return nil
+}
diff --git a/components/engine/daemon/oci_linux.go b/components/engine/daemon/oci_linux.go
index 7611fc054d..864d22fbcb 100644
--- a/components/engine/daemon/oci_linux.go
+++ b/components/engine/daemon/oci_linux.go
@@ -711,6 +711,7 @@ func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, e
cgroupsPath = filepath.Join(parent, c.ID)
}
s.Linux.CgroupsPath = cgroupsPath
+ c.CgroupParent = cgroupsPath
if err := setResources(&s, c.HostConfig.Resources); err != nil {
return nil, fmt.Errorf("linux runtime spec resources: %v", err)
diff --git a/components/engine/daemon/pause.go b/components/engine/daemon/pause.go
index be6ec1b92a..972baa961f 100644
--- a/components/engine/daemon/pause.go
+++ b/components/engine/daemon/pause.go
@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/docker/docker/container"
+ "github.com/docker/docker/daemon/freezer"
"github.com/sirupsen/logrus"
)
@@ -38,8 +39,22 @@ func (daemon *Daemon) containerPause(container *container.Container) error {
return errContainerIsRestarting(container.ID)
}
- if err := daemon.containerd.Pause(context.Background(), container.ID); err != nil {
- return fmt.Errorf("Cannot pause container %s: %s", container.ID, err)
+ if daemon.IsNativeRuntime(container.HostConfig.Runtime) {
+ freezer, err := freezer.New(container.ID, container.CgroupParent, UsingSystemd(daemon.configStore))
+ if err != nil {
+ return fmt.Errorf("Failed to create freezer for container %s: %v", container.ID, err)
+ }
+
+ if err := freezer.Pause(); err != nil {
+ return fmt.Errorf("Cannot pause container %s: %v", container.ID, err)
+ }
+
+ container.Paused = true
+ daemon.LogContainerEvent(container, "pause")
+ } else {
+ if err := daemon.containerd.Pause(context.Background(), container.ID); err != nil {
+ return fmt.Errorf("Cannot pause container %s: %s", container.ID, err)
+ }
}
container.Paused = true
diff --git a/components/engine/daemon/unpause.go b/components/engine/daemon/unpause.go
index 27648ae72e..4a8225258f 100644
--- a/components/engine/daemon/unpause.go
+++ b/components/engine/daemon/unpause.go
@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/docker/docker/container"
+ "github.com/docker/docker/daemon/freezer"
"github.com/sirupsen/logrus"
)
@@ -27,8 +28,20 @@ func (daemon *Daemon) containerUnpause(container *container.Container) error {
return fmt.Errorf("Container %s is not paused", container.ID)
}
- if err := daemon.containerd.Resume(context.Background(), container.ID); err != nil {
- return fmt.Errorf("Cannot unpause container %s: %s", container.ID, err)
+ if daemon.IsNativeRuntime(container.HostConfig.Runtime) {
+ freezer, err := freezer.New(container.ID, container.CgroupParent, UsingSystemd(daemon.configStore))
+ if err != nil {
+ return fmt.Errorf("Failed to create freezer for container %s: %v", container.ID, err)
+ }
+ if err := freezer.Resume(); err != nil {
+ return fmt.Errorf("Cannot unpause container %s: %s", container.ID, err)
+ }
+ container.Paused = false
+ daemon.LogContainerEvent(container, "unpause")
+ } else {
+ if err := daemon.containerd.Resume(context.Background(), container.ID); err != nil {
+ return fmt.Errorf("Cannot unpause container %s: %s", container.ID, err)
+ }
}
container.Paused = false
diff --git a/components/engine/libcontainerd/utils_linux.go b/components/engine/libcontainerd/utils_linux.go
new file mode 100644
index 0000000000..f9b3e64db9
--- /dev/null
+++ b/components/engine/libcontainerd/utils_linux.go
@@ -0,0 +1,25 @@
+package libcontainerd
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "path/filepath"
+
+ "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+func LoadContainerSpec(stateDir, id string) (*specs.Spec, error) {
+ var spec specs.Spec
+ dir, err := filepath.Abs(stateDir)
+ if err != nil {
+ return nil, err
+ }
+ dt, err := ioutil.ReadFile(filepath.Join(dir, id, "config.json"))
+ if err != nil {
+ return nil, err
+ }
+ if err := json.Unmarshal(dt, &spec); err != nil {
+ return nil, err
+ }
+ return &spec, nil
+}
diff --git a/components/engine/libcontainerd/utils_windows.go b/components/engine/libcontainerd/utils_windows.go
index aabb9aeaaa..a8ba3629a3 100644
--- a/components/engine/libcontainerd/utils_windows.go
+++ b/components/engine/libcontainerd/utils_windows.go
@@ -1,6 +1,7 @@
package libcontainerd // import "github.com/docker/docker/libcontainerd"
import (
+ "fmt"
"strings"
opengcs "github.com/Microsoft/opengcs/client"
@@ -19,10 +20,12 @@ func setupEnvironmentVariables(a []string) map[string]string {
return r
}
+func LoadContainerSpec(stateDir, id string) (*specs.Spec, error) {
+ return nil, fmt.Errorf("not supported")
+}
+
// Apply for the LCOW option is a no-op.
func (s *LCOWOption) Apply(interface{}) error {
- return nil
-}
// debugGCS is a dirty hack for debugging for Linux Utility VMs. It simply
// runs a bunch of commands inside the UVM, but seriously aides in advanced debugging.
--
2.17.1

View File

@ -0,0 +1,76 @@
From fb74bc5ce2a510e38b9a8a83d4524876f1881759 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:11:25 +0800
Subject: [PATCH 002/111] pause: docker pause set timeout 30s
reason:fix docker pause in infinite loop case,when the process in D status
libcontainer: cgroups: Write freezer state after every state check
This commit ensures we write the expected freezer cgroup state after
every state check, in case the state check does not give the expected
result. This can happen when a new task is created and prevents the
whole cgroup to be FROZEN, leaving the state into FREEZING instead.
This patch prevents the case of an infinite loop to happen.
Cherry-pick from https://github.com/opencontainers/runc/pull/1610
Change-Id: Ib5355b9d928c491e120439780c1f03c18aa68b73
Signed-off-by: panwenxiang <panwenxiang@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/freezer/freezer.go | 37 +++++++++++++++------
1 file changed, 27 insertions(+), 10 deletions(-)
diff --git a/components/engine/daemon/freezer/freezer.go b/components/engine/daemon/freezer/freezer.go
index 774f5c21ed..cd8b3513d7 100644
--- a/components/engine/daemon/freezer/freezer.go
+++ b/components/engine/daemon/freezer/freezer.go
@@ -161,19 +161,36 @@ func (f *freezer) IsPaused() (bool, error) {
}
func (f *freezer) updateCgroup(state string) error {
- if err := writeFile(f.path, "freezer.state", state); err != nil {
- return err
+ curState, err := readFile(f.path, "freezer.state")
+ if err != nil {
+ return fmt.Errorf("read current state failed for %#v", err)
}
+ curState = strings.TrimSpace(curState)
+ timeout := time.After(30 * time.Second)
+ tick := time.Tick(1 * time.Millisecond)
for {
- newState, err := readFile(f.path, "freezer.state")
- if err != nil {
- return err
- }
- if strings.TrimSpace(newState) == state {
- break
+ select {
+ case <-timeout:
+ if err := writeFile(f.path, "freezer.state", curState); err != nil {
+ return fmt.Errorf("cannot write %s to freezer for %#v", curState, err)
+ }
+ return fmt.Errorf("update freezer cgroup timeout for 30s")
+ case <-tick:
+ // In case this loop does not exit because it doesn't get the expected
+ // state, let's write again this state, hoping it's going to be properly
+ // set this time. Otherwise, this loop could run infinitely, waiting for
+ // a state change that would never happen.
+ if err := writeFile(f.path, "freezer.state", state); err != nil {
+ return fmt.Errorf("cannot write freezer.state for %#v", err)
+ }
+ newState, err := readFile(f.path, "freezer.state")
+ if err != nil {
+ return err
+ }
+ if strings.TrimSpace(newState) == state {
+ return nil
+ }
}
- time.Sleep(1 * time.Millisecond)
}
- return nil
}
--
2.17.1

View File

@ -0,0 +1,50 @@
From 8a897fcad4bf6d2f4be05bb3075640d65e98ac8e Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:13:24 +0800
Subject: [PATCH 003/111] pause: fix integration testing faile about
`docker pause` status display
reason:fix integration testing faile about `docker pause` status display
Change-Id: I851b29171a33f5eb278800fb0f1e061bebb3745c
Signed-off-by: leizhongkai <leizhongkai@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/pause.go | 4 ++++
components/engine/daemon/unpause.go | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/components/engine/daemon/pause.go b/components/engine/daemon/pause.go
index 972baa961f..6f9d8b0f70 100644
--- a/components/engine/daemon/pause.go
+++ b/components/engine/daemon/pause.go
@@ -50,6 +50,10 @@ func (daemon *Daemon) containerPause(container *container.Container) error {
}
container.Paused = true
+ daemon.setStateCounter(container)
+ if err := container.CheckpointTo(daemon.containersReplica); err != nil {
+ return err
+ }
daemon.LogContainerEvent(container, "pause")
} else {
if err := daemon.containerd.Pause(context.Background(), container.ID); err != nil {
diff --git a/components/engine/daemon/unpause.go b/components/engine/daemon/unpause.go
index 4a8225258f..290d2b1d0c 100644
--- a/components/engine/daemon/unpause.go
+++ b/components/engine/daemon/unpause.go
@@ -37,6 +37,10 @@ func (daemon *Daemon) containerUnpause(container *container.Container) error {
return fmt.Errorf("Cannot unpause container %s: %s", container.ID, err)
}
container.Paused = false
+ daemon.setStateCounter(container)
+ if err := container.CheckpointTo(daemon.containersReplica); err != nil {
+ return err
+ }
daemon.LogContainerEvent(container, "unpause")
} else {
if err := daemon.containerd.Resume(context.Background(), container.ID); err != nil {
--
2.17.1

View File

@ -0,0 +1,398 @@
From a8f05692638bf50826ed9533f2a5282e2cde359d Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:13:41 +0800
Subject: [PATCH 004/111] prjquota: support set filesystem
quota if ext4 support project quota
reason:Support set filesystem quota if ext4 support project quota
Change-Id: I99d28f248e758837cbf8b615e673ee7d8e36be7b
Signed-off-by: Lei Jitang <leijitang@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/daemon_unix.go | 19 ++
.../daemon/graphdriver/overlay2/overlay.go | 10 +-
.../daemon/graphdriver/quota/projectquota.go | 176 +++++++++++++++---
.../daemon/graphdriver/vfs/quota_linux.go | 13 +-
4 files changed, 191 insertions(+), 27 deletions(-)
diff --git a/components/engine/daemon/daemon_unix.go b/components/engine/daemon/daemon_unix.go
index b69eede21c..1b35df4950 100644
--- a/components/engine/daemon/daemon_unix.go
+++ b/components/engine/daemon/daemon_unix.go
@@ -633,6 +633,25 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
}
}
+ if hostConfig.StorageOpt != nil && daemon.imageService.GraphDriverForOS(runtime.GOOS) == "overlay2" {
+ _, exist := hostConfig.StorageOpt["size"]
+ if exist {
+ status := daemon.imageService.LayerStoreStatus()[runtime.GOOS]
+ if status[0][0] == "Backing Filesystem" && status[0][1] == "extfs" {
+ if hostConfig.Privileged {
+ warnings = append(warnings, "filesystem quota for overlay2 over ext4 can't take affect with privileged container")
+ } else {
+ for _, cap := range hostConfig.CapAdd {
+ if cap == "SYS_RESOURCE" {
+ warnings = append(warnings, "filesystem quota for overlay2 over ext4 can't take affect with CAP_SYS_RESOURCE")
+ break
+ }
+ }
+ }
+ }
+ }
+ }
+
return warnings, nil
}
diff --git a/components/engine/daemon/graphdriver/overlay2/overlay.go b/components/engine/daemon/graphdriver/overlay2/overlay.go
index 6b3236f8f3..36ae182bcd 100644
--- a/components/engine/daemon/graphdriver/overlay2/overlay.go
+++ b/components/engine/daemon/graphdriver/overlay2/overlay.go
@@ -216,16 +216,16 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
d.naiveDiff = graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps)
- if backingFs == "xfs" {
- // Try to enable project quota support over xfs.
- if d.quotaCtl, err = quota.NewControl(home); err == nil {
+ if backingFs == "xfs" || backingFs == "extfs" {
+ // Try to enable project quota support over xfs and extfs.
+ if d.quotaCtl, err = quota.NewControl(home, backingFs); err == nil {
projectQuotaSupported = true
} else if opts.quota.Size > 0 {
return nil, fmt.Errorf("Storage option overlay2.size not supported. Filesystem does not support Project Quota: %v", err)
}
} else if opts.quota.Size > 0 {
// if xfs is not the backing fs then error out if the storage-opt overlay2.size is used.
- return nil, fmt.Errorf("Storage Option overlay2.size only supported for backingFS XFS. Found %v", backingFs)
+ return nil, fmt.Errorf("Storage Option overlay2.size only supported for backingFS XFS or ext4. Found %v", backingFs)
}
logger.Debugf("backingFs=%s, projectQuotaSupported=%v", backingFs, projectQuotaSupported)
@@ -341,7 +341,7 @@ func (d *Driver) Cleanup() error {
// file system.
func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
if opts != nil && len(opts.StorageOpt) != 0 && !projectQuotaSupported {
- return fmt.Errorf("--storage-opt is supported only for overlay over xfs with 'pquota' mount option")
+ return fmt.Errorf("--storage-opt is supported only for overlay over xfs or ext4 with 'pquota' mount option")
}
if opts == nil {
diff --git a/components/engine/daemon/graphdriver/quota/projectquota.go b/components/engine/daemon/graphdriver/quota/projectquota.go
index 93e85823af..7d879eb81d 100644
--- a/components/engine/daemon/graphdriver/quota/projectquota.go
+++ b/components/engine/daemon/graphdriver/quota/projectquota.go
@@ -38,8 +38,8 @@ struct fsxattr {
#ifndef PRJQUOTA
#define PRJQUOTA 2
#endif
-#ifndef XFS_PROJ_QUOTA
-#define XFS_PROJ_QUOTA 2
+#ifndef PROJ_QUOTA
+#define PROJ_QUOTA 2
#endif
#ifndef Q_XSETPQLIM
#define Q_XSETPQLIM QCMD(Q_XSETQLIM, PRJQUOTA)
@@ -49,6 +49,28 @@ struct fsxattr {
#endif
const int Q_XGETQSTAT_PRJQUOTA = QCMD(Q_XGETQSTAT, PRJQUOTA);
+
+#ifndef Q_XGETPQSTAT
+#define Q_XGETPQSTAT QCMD(Q_XGETQSTAT, PRJQUOTA)
+#endif
+
+#ifndef Q_SETPQUOTA
+#define Q_SETPQUOTA (unsigned int)QCMD(Q_SETQUOTA, PRJQUOTA)
+#endif
+
+#ifndef Q_GETPQUOTA
+#define Q_GETPQUOTA (unsigned int)QCMD(Q_GETQUOTA, PRJQUOTA)
+#endif
+
+#define PDQ_ACCT_BIT 4
+#define PDQ_ENFD_BIT 5
+
+#ifndef QUOTA_PDQ_ACCT
+#define QUOTA_PDQ_ACCT (1<<PDQ_ACCT_BIT)
+#endif
+#ifndef QUOTA_PDQ_ENFD
+#define QUOTA_PDQ_ENFD (1<<PDQ_ENFD_BIT)
+#endif
*/
import "C"
import (
@@ -56,6 +78,8 @@ import (
"io/ioutil"
"path"
"path/filepath"
+ "sync"
+ "syscall"
"unsafe"
rsystem "github.com/opencontainers/runc/libcontainer/system"
@@ -74,6 +98,17 @@ type Control struct {
backingFsBlockDev string
nextProjectID uint32
quotas map[string]uint32
+ quotaOps QuotafileOps
+ lock sync.Mutex
+}
+
+// QuotafileOps is a interface for quotafile operations
+type QuotafileOps interface {
+ // SetProjectQuota sets the project quota for project id on block device
+ SetProjectQuota(dev string, projectID uint32, quota Quota) error
+
+ // GetProjectQuota gets the project quota for project id on block device
+ GetProjectQuota(dev string, projectID uint32, quota *Quota) error
}
// NewControl - initialize project quota support.
@@ -98,7 +133,7 @@ type Control struct {
// on it. If that works, continue to scan existing containers to map allocated
// project ids.
//
-func NewControl(basePath string) (*Control, error) {
+func NewControl(basePath string, fs string) (*Control, error) {
//
// If we are running in a user namespace quota won't be supported for
// now since makeBackingFsDev() will try to mknod().
@@ -141,7 +176,28 @@ func NewControl(basePath string) (*Control, error) {
quota := Quota{
Size: 0,
}
- if err := setProjectQuota(backingFsBlockDev, minProjectID, quota); err != nil {
+ //
+ // Get the quota stat to check whether the system support project quota
+ //
+ stat, err := getQuotaStat(backingFsBlockDev)
+ if err != nil || stat != 2 {
+ if err != nil {
+ logrus.Warnf("Get quota stat failed with: %v", err)
+ }
+ return nil, fmt.Errorf("quota isn't supported on your system")
+ }
+
+ var quotaOps QuotafileOps
+
+ if fs == "xfs" {
+ quotaOps = new(XfsQuota)
+ } else if fs == "extfs" {
+ quotaOps = new(Ext4Quota)
+ } else {
+ return nil, fmt.Errorf("quota isn't supported for filesystem %q", fs)
+ }
+
+ if err := quotaOps.SetProjectQuota(backingFsBlockDev, minProjectID, quota); err != nil {
return nil, err
}
@@ -149,6 +205,7 @@ func NewControl(basePath string) (*Control, error) {
backingFsBlockDev: backingFsBlockDev,
nextProjectID: minProjectID + 1,
quotas: make(map[string]uint32),
+ quotaOps: quotaOps,
}
//
@@ -167,6 +224,7 @@ func NewControl(basePath string) (*Control, error) {
// for that project id
func (q *Control) SetQuota(targetPath string, quota Quota) error {
+ q.lock.Lock()
projectID, ok := q.quotas[targetPath]
if !ok {
projectID = q.nextProjectID
@@ -176,26 +234,32 @@ func (q *Control) SetQuota(targetPath string, quota Quota) error {
//
err := setProjectID(targetPath, projectID)
if err != nil {
+ q.lock.Lock()
return err
}
q.quotas[targetPath] = projectID
q.nextProjectID++
}
+ q.lock.Unlock()
//
// set the quota limit for the container's project id
//
logrus.Debugf("SetQuota(%s, %d): projectID=%d", targetPath, quota.Size, projectID)
- return setProjectQuota(q.backingFsBlockDev, projectID, quota)
+ return q.quotaOps.SetProjectQuota(q.backingFsBlockDev, projectID, quota)
}
-// setProjectQuota - set the quota for project id on xfs block device
-func setProjectQuota(backingFsBlockDev string, projectID uint32, quota Quota) error {
+// XfsQuota is a struct implements quota operations
+type XfsQuota struct {
+}
+
+// SetProjectQuota - set the quota for project id on xfs block device
+func (q *XfsQuota) SetProjectQuota(backingFsBlockDev string, projectID uint32, quota Quota) error {
var d C.fs_disk_quota_t
d.d_version = C.FS_DQUOT_VERSION
d.d_id = C.__u32(projectID)
- d.d_flags = C.XFS_PROJ_QUOTA
+ d.d_flags = C.PROJ_QUOTA
d.d_fieldmask = C.FS_DQ_BHARD | C.FS_DQ_BSOFT
d.d_blk_hardlimit = C.__u64(quota.Size / 512)
@@ -215,20 +279,11 @@ func setProjectQuota(backingFsBlockDev string, projectID uint32, quota Quota) er
return nil
}
-// GetQuota - get the quota limits of a directory that was configured with SetQuota
-func (q *Control) GetQuota(targetPath string, quota *Quota) error {
-
- projectID, ok := q.quotas[targetPath]
- if !ok {
- return fmt.Errorf("quota not found for path : %s", targetPath)
- }
-
- //
- // get the quota limit for the container's project id
- //
+// GetProjectQuota gets the project quota for projectID on dev
+func (q *XfsQuota) GetProjectQuota(backingFsBlockDev string, projectID uint32, quota *Quota) error {
var d C.fs_disk_quota_t
- var cs = C.CString(q.backingFsBlockDev)
+ var cs = C.CString(backingFsBlockDev)
defer C.free(unsafe.Pointer(cs))
_, _, errno := unix.Syscall6(unix.SYS_QUOTACTL, C.Q_XGETPQUOTA,
@@ -236,13 +291,92 @@ func (q *Control) GetQuota(targetPath string, quota *Quota) error {
uintptr(unsafe.Pointer(&d)), 0, 0)
if errno != 0 {
return fmt.Errorf("Failed to get quota limit for projid %d on %s: %v",
- projectID, q.backingFsBlockDev, errno.Error())
+ projectID, backingFsBlockDev, errno.Error())
}
quota.Size = uint64(d.d_blk_hardlimit) * 512
return nil
}
+// Ext4Quota is a struct implements quota operations
+type Ext4Quota struct {
+}
+
+// SetProjectQuota - set the quota for project id on ext4 block device
+func (q *Ext4Quota) SetProjectQuota(backingFsBlockDev string, projectID uint32, quota Quota) error {
+ var d C.struct_if_dqblk
+ d.dqb_bhardlimit = C.__u64(quota.Size / 1024)
+ d.dqb_bsoftlimit = d.dqb_bhardlimit
+ d.dqb_valid = C.QIF_LIMITS
+
+ var cs = C.CString(backingFsBlockDev)
+ defer C.free(unsafe.Pointer(cs))
+
+ _, _, errno := syscall.Syscall6(syscall.SYS_QUOTACTL, C.Q_SETPQUOTA,
+ uintptr(unsafe.Pointer(cs)), uintptr(C.__u32(projectID)),
+ uintptr(unsafe.Pointer(&d)), 0, 0)
+ if errno != 0 {
+ return fmt.Errorf("Failed to set quota limit for projid %d on %s: %v",
+ projectID, backingFsBlockDev, errno.Error())
+ }
+
+ return nil
+}
+
+func (q *Ext4Quota) GetProjectQuota(backingFsBlockDev string, projectID uint32, quota *Quota) error {
+ var d C.struct_if_dqblk
+ d.dqb_valid = C.QIF_USAGE
+
+ var cs = C.CString(backingFsBlockDev)
+ defer C.free(unsafe.Pointer(cs))
+
+ _, _, errno := syscall.Syscall6(syscall.SYS_QUOTACTL, C.Q_SETPQUOTA,
+ uintptr(unsafe.Pointer(cs)), uintptr(C.__u32(projectID)),
+ uintptr(unsafe.Pointer(&d)), 0, 0)
+ if errno != 0 {
+ return fmt.Errorf("Failed to get quota limit for projid %d on %s: %v",
+ projectID, backingFsBlockDev, errno.Error())
+ }
+
+ quota.Size = uint64(d.dqb_bhardlimit) * 1024
+
+ return nil
+}
+
+// getQuotaStat - get the quota stat
+// return 2 means quota is on
+func getQuotaStat(backingFsBlockDev string) (int, error) {
+ var info C.fs_quota_stat_t
+
+ var cs = C.CString(backingFsBlockDev)
+ defer C.free(unsafe.Pointer(cs))
+ _, _, errno := syscall.Syscall6(syscall.SYS_QUOTACTL, C.Q_XGETPQSTAT,
+ uintptr(unsafe.Pointer(cs)), 0,
+ uintptr(unsafe.Pointer(&info)), 0, 0)
+ if errno != 0 {
+ return -1, fmt.Errorf("Failed to get quota stat on %s: %v",
+ backingFsBlockDev, errno.Error())
+ }
+
+ return int((info.qs_flags&C.QUOTA_PDQ_ACCT)>>C.PDQ_ACCT_BIT + (info.qs_flags&C.QUOTA_PDQ_ENFD)>>C.PDQ_ENFD_BIT), nil
+}
+
+// GetQuota - get the quota limits of a directory that was configured with SetQuota
+func (q *Control) GetQuota(targetPath string, quota *Quota) error {
+ q.lock.Lock()
+ projectID, ok := q.quotas[targetPath]
+ q.lock.Unlock()
+ if !ok {
+ return fmt.Errorf("quota not found for path : %s", targetPath)
+ }
+
+ //
+ // get the quota limit for the container's project id
+ //
+
+ return q.quotaOps.GetProjectQuota(q.backingFsBlockDev, projectID, quota)
+}
+
// getProjectID - get the project id of path on xfs
func getProjectID(targetPath string) (uint32, error) {
dir, err := openDir(targetPath)
diff --git a/components/engine/daemon/graphdriver/vfs/quota_linux.go b/components/engine/daemon/graphdriver/vfs/quota_linux.go
index 0d5c3a7b98..bb2f571834 100644
--- a/components/engine/daemon/graphdriver/vfs/quota_linux.go
+++ b/components/engine/daemon/graphdriver/vfs/quota_linux.go
@@ -1,6 +1,7 @@
package vfs // import "github.com/docker/docker/daemon/graphdriver/vfs"
import (
+ "github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/daemon/graphdriver/quota"
"github.com/sirupsen/logrus"
)
@@ -10,7 +11,17 @@ type driverQuota struct {
}
func setupDriverQuota(driver *Driver) {
- if quotaCtl, err := quota.NewControl(driver.home); err == nil {
+ // Probe fs type before setting quota, now only supports xfs and extfs
+ fsMagic, err := graphdriver.GetFSMagic(driver.home)
+ if err != nil {
+ return
+ }
+ fsName, ok := graphdriver.FsNames[fsMagic]
+ if !ok {
+ return
+ }
+
+ if quotaCtl, err := quota.NewControl(driver.home, fsName); err == nil {
driver.quotaCtl = quotaCtl
} else if err != quota.ErrQuotaNotSupported {
logrus.Warnf("Unable to setup quota: %v\n", err)
--
2.17.1

View File

@ -0,0 +1,37 @@
From b5e205b8d1ea0a62ea8847dc5510a10c65a2573e Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:13:57 +0800
Subject: [PATCH 005/111] prjquota: fix few overlay2 quota problems
reason:fix few overlay2 quota problems
Change-Id: Id3a7915747c415d56684c291fb0498d04b762c8c
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/graphdriver/overlay2/overlay.go | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/components/engine/daemon/graphdriver/overlay2/overlay.go b/components/engine/daemon/graphdriver/overlay2/overlay.go
index 36ae182bcd..96f44ba9a1 100644
--- a/components/engine/daemon/graphdriver/overlay2/overlay.go
+++ b/components/engine/daemon/graphdriver/overlay2/overlay.go
@@ -455,6 +455,14 @@ func (d *Driver) parseStorageOpt(storageOpt map[string]string, driver *Driver) e
if err != nil {
return err
}
+ // deal with negative and super large number
+ if size < 0 {
+ return fmt.Errorf("Illegal storage size(%s): numerical result out of range", val)
+ }
+ // for overlay (0-1024) means no limit
+ if size < 1024 && size > 0 {
+ return fmt.Errorf("Illegal storage size:%d, 1024 at least", size)
+ }
driver.options.quota.Size = uint64(size)
default:
return fmt.Errorf("Unknown option %s", key)
--
2.17.1

View File

@ -0,0 +1,53 @@
From c5a18b46152c4c7016c0c2f0054e276a53f25e1f Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:14:09 +0800
Subject: [PATCH 006/111] prjquota: overlay2 quota control backward
compability
reason: In Euleros docker we support default quota control limit
for daemon with commit
docker: Add options to surport default limit for daemon
However in mainstream they have similar commit
35903110 Add overlay2.size daemon storage-opt
But mainstream uses different api `overlay2.size` compares with
`overlay2.basesize`, so adding this backward compability.
Change-Id: I36a548bd7f1ce6fab6cad24cfb49faa56f7a1fd1
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/graphdriver/overlay2/overlay.go | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/components/engine/daemon/graphdriver/overlay2/overlay.go b/components/engine/daemon/graphdriver/overlay2/overlay.go
index 96f44ba9a1..b969582eb3 100644
--- a/components/engine/daemon/graphdriver/overlay2/overlay.go
+++ b/components/engine/daemon/graphdriver/overlay2/overlay.go
@@ -248,6 +248,7 @@ func parseOptions(options []string) (*overlayOptions, error) {
return nil, err
}
case "overlay2.size":
+ case "overlay2.basesize":
size, err := units.RAMInBytes(val)
if err != nil {
return nil, err
@@ -394,12 +395,16 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
}
}()
- if opts != nil && len(opts.StorageOpt) > 0 {
+ if (opts != nil && len(opts.StorageOpt) > 0) || d.options.quota.Size > 0 {
driver := &Driver{}
if err := d.parseStorageOpt(opts.StorageOpt, driver); err != nil {
return err
}
+ if driver.options.quota.Size == 0 && d.options.quota.Size > 0 {
+ driver.options.quota.Size = d.options.quota.Size
+ }
+
if driver.options.quota.Size > 0 {
// Set container disk quota limit
if err := d.quotaCtl.SetQuota(dir, driver.options.quota); err != nil {
--
2.17.1

View File

@ -0,0 +1,319 @@
From 1e26a8c5d18eb93c2786eff9eeede77f3b8162df Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:14:23 +0800
Subject: [PATCH 007/111] filelimit: Add file fds limit
Change-Id: I4255fc648ad71dcba78fe38fae9d26454e2e41d8
Signed-off-by: yangshukui <yangshukui@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/cli/cli/command/container/opts.go | 3 +++
components/cli/contrib/completion/bash/docker | 1 +
components/cli/contrib/completion/zsh/_docker | 1 +
.../cli/docs/reference/commandline/create.md | 1 +
components/cli/docs/reference/commandline/run.md | 1 +
components/cli/man/docker-run.1.md | 4 ++++
.../vendor/github.com/docker/docker/api/Checklist | 1 +
.../docker/api/types/container/host_config.go | 1 +
.../engine/api/types/container/host_config.go | 1 +
components/engine/daemon/daemon_unix.go | 6 ++++++
components/engine/daemon/oci_linux.go | 3 +++
.../integration-cli/docker_cli_run_unix_test.go | 10 ++++++++++
.../integration-cli/requirements_unix_test.go | 4 ++++
components/engine/pkg/sysinfo/sysinfo.go | 6 ++++++
components/engine/pkg/sysinfo/sysinfo_linux.go | 15 +++++++++++++++
.../opencontainers/runtime-spec/Checklist | 1 +
.../runtime-spec/specs-go/config.go | 8 ++++++++
17 files changed, 67 insertions(+)
create mode 100644 components/cli/vendor/github.com/docker/docker/api/Checklist
create mode 100644 components/engine/vendor/github.com/opencontainers/runtime-spec/Checklist
diff --git a/components/cli/cli/command/container/opts.go b/components/cli/cli/command/container/opts.go
index 97906b6722..efb28a2cdf 100644
--- a/components/cli/cli/command/container/opts.go
+++ b/components/cli/cli/command/container/opts.go
@@ -100,6 +100,7 @@ type containerOptions struct {
ipv6Address string
ipcMode string
pidsLimit int64
+ filesLimit int64
restartPolicy string
readonlyRootfs bool
loggingDriver string
@@ -271,6 +272,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
flags.BoolVar(&copts.oomKillDisable, "oom-kill-disable", false, "Disable OOM Killer")
flags.IntVar(&copts.oomScoreAdj, "oom-score-adj", 0, "Tune host's OOM preferences (-1000 to 1000)")
flags.Int64Var(&copts.pidsLimit, "pids-limit", 0, "Tune container pids limit (set -1 for unlimited)")
+ flags.Int64Var(&copts.filesLimit, "files-limit", 0, "Tune container files limit (set -1 for unlimited)")
// Low-level execution (cgroups, namespaces, ...)
flags.StringVar(&copts.cgroupParent, "cgroup-parent", "", "Optional parent cgroup for the container")
@@ -531,6 +533,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
CPURealtimePeriod: copts.cpuRealtimePeriod,
CPURealtimeRuntime: copts.cpuRealtimeRuntime,
PidsLimit: copts.pidsLimit,
+ FilesLimit: copts.filesLimit,
BlkioWeight: copts.blkioWeight,
BlkioWeightDevice: copts.blkioWeightDevice.GetList(),
BlkioDeviceReadBps: copts.deviceReadBps.GetList(),
diff --git a/components/cli/contrib/completion/bash/docker b/components/cli/contrib/completion/bash/docker
index 44ac8f3e0e..2e2c8cb04f 100644
--- a/components/cli/contrib/completion/bash/docker
+++ b/components/cli/contrib/completion/bash/docker
@@ -1789,6 +1789,7 @@ _docker_container_run_and_create() {
--env -e
--env-file
--expose
+ --files-limit
--group-add
--health-cmd
--health-interval
diff --git a/components/cli/contrib/completion/zsh/_docker b/components/cli/contrib/completion/zsh/_docker
index 94f042204d..cbbdfdb798 100644
--- a/components/cli/contrib/completion/zsh/_docker
+++ b/components/cli/contrib/completion/zsh/_docker
@@ -621,6 +621,7 @@ __docker_container_subcommand() {
"($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)--files-limit[Tune container files limit (set -1 for max)]"
"($help)*--group=[Set one or more supplementary user groups for the container]:group:_groups"
"($help -h --hostname)"{-h=,--hostname=}"[Container host name]:hostname:_hosts"
"($help -i --interactive)"{-i,--interactive}"[Keep stdin open even if not attached]"
diff --git a/components/cli/docs/reference/commandline/create.md b/components/cli/docs/reference/commandline/create.md
index d585da40ae..5d888183b3 100644
--- a/components/cli/docs/reference/commandline/create.md
+++ b/components/cli/docs/reference/commandline/create.md
@@ -57,6 +57,7 @@ Options:
-e, --env value Set environment variables (default [])
--env-file value Read in a file of environment variables (default [])
--expose value Expose a port or a range of ports (default [])
+ --files-limit int Tune container files limit (set -1 for unlimited)
--group-add value Add additional groups to join (default [])
--health-cmd string Command to run to check health
--health-interval duration Time between running the check (ns|us|ms|s|m|h) (default 0s)
diff --git a/components/cli/docs/reference/commandline/run.md b/components/cli/docs/reference/commandline/run.md
index 08b9f18d68..21b4fdf261 100644
--- a/components/cli/docs/reference/commandline/run.md
+++ b/components/cli/docs/reference/commandline/run.md
@@ -61,6 +61,7 @@ Options:
-e, --env value Set environment variables (default [])
--env-file value Read in a file of environment variables (default [])
--expose value Expose a port or a range of ports (default [])
+ --files-limit int Tune container files limit (set -1 for unlimited)
--group-add value Add additional groups to join (default [])
--health-cmd string Command to run to check health
--health-interval duration Time between running the check (ns|us|ms|s|m|h) (default 0s)
diff --git a/components/cli/man/docker-run.1.md b/components/cli/man/docker-run.1.md
index e03377001d..41f501d5b9 100644
--- a/components/cli/man/docker-run.1.md
+++ b/components/cli/man/docker-run.1.md
@@ -39,6 +39,7 @@ docker-run - Run a command in a new container
[**--entrypoint**[=*ENTRYPOINT*]]
[**--env-file**[=*[]*]]
[**--expose**[=*[]*]]
+[**--files-limit**[=*FILES_LIMIT*]]
[**--group-add**[=*[]*]]
[**-h**|**--hostname**[=*HOSTNAME*]]
[**--help**]
@@ -315,6 +316,9 @@ that the container listens on the specified network ports at runtime. Docker
uses this information to interconnect containers using links and to set up port
redirection on the host system.
+**--files-limit**=""
+ Tune the container's files limit. Set `-1` to have max files for the container.
+
**--group-add**=[]
Add additional groups to run as
diff --git a/components/cli/vendor/github.com/docker/docker/api/Checklist b/components/cli/vendor/github.com/docker/docker/api/Checklist
new file mode 100644
index 0000000000..9594f235e4
--- /dev/null
+++ b/components/cli/vendor/github.com/docker/docker/api/Checklist
@@ -0,0 +1 @@
+Add FilesLimit to components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go for supporting --files-limit
diff --git a/components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go b/components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go
index 4ef26fa6c8..1565b5e091 100644
--- a/components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go
+++ b/components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go
@@ -334,6 +334,7 @@ type Resources struct {
MemorySwappiness *int64 // Tuning container memory swappiness behaviour
OomKillDisable *bool // Whether to disable OOM Killer or not
PidsLimit int64 // Setting pids limit for a container
+ FilesLimit int64 // Setting files limit for a container
Ulimits []*units.Ulimit // List of ulimits to be set in the container
// Applicable to Windows
diff --git a/components/engine/api/types/container/host_config.go b/components/engine/api/types/container/host_config.go
index 4ef26fa6c8..1565b5e091 100644
--- a/components/engine/api/types/container/host_config.go
+++ b/components/engine/api/types/container/host_config.go
@@ -334,6 +334,7 @@ type Resources struct {
MemorySwappiness *int64 // Tuning container memory swappiness behaviour
OomKillDisable *bool // Whether to disable OOM Killer or not
PidsLimit int64 // Setting pids limit for a container
+ FilesLimit int64 // Setting files limit for a container
Ulimits []*units.Ulimit // List of ulimits to be set in the container
// Applicable to Windows
diff --git a/components/engine/daemon/daemon_unix.go b/components/engine/daemon/daemon_unix.go
index 1b35df4950..138b8ac544 100644
--- a/components/engine/daemon/daemon_unix.go
+++ b/components/engine/daemon/daemon_unix.go
@@ -425,6 +425,12 @@ func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysi
resources.PidsLimit = 0
}
+ if resources.FilesLimit != 0 && !sysInfo.FilesLimit {
+ warnings = append(warnings, "Your kernel does not support files limit capabilities, files limit discarded.")
+ logrus.Warnf("Your kernel does not support files limit capabilities, files limit discarded.")
+ resources.FilesLimit = 0
+ }
+
// cpu subsystem checks and adjustments
if resources.NanoCPUs > 0 && resources.CPUPeriod > 0 {
return warnings, fmt.Errorf("Conflicting options: Nano CPUs and CPU Period cannot both be set")
diff --git a/components/engine/daemon/oci_linux.go b/components/engine/daemon/oci_linux.go
index 864d22fbcb..210d2ad3f6 100644
--- a/components/engine/daemon/oci_linux.go
+++ b/components/engine/daemon/oci_linux.go
@@ -70,6 +70,9 @@ func setResources(s *specs.Spec, r containertypes.Resources) error {
Pids: &specs.LinuxPids{
Limit: r.PidsLimit,
},
+ Files: &specs.Files{
+ Limit: &r.FilesLimit,
+ },
}
if s.Linux.Resources != nil && len(s.Linux.Resources.Devices) > 0 {
diff --git a/components/engine/integration-cli/docker_cli_run_unix_test.go b/components/engine/integration-cli/docker_cli_run_unix_test.go
index 5f782ee530..a618316d4b 100644
--- a/components/engine/integration-cli/docker_cli_run_unix_test.go
+++ b/components/engine/integration-cli/docker_cli_run_unix_test.go
@@ -1414,6 +1414,16 @@ func (s *DockerSuite) TestRunPIDsLimit(c *check.C) {
c.Assert(out, checker.Equals, "4", check.Commentf("setting the pids limit failed"))
}
+// TestRunFilesLimit makes sure the files cgroup is set with --files-limit
+func (s *DockerSuite) TestRunFilesLimit(c *check.C) {
+ testRequires(c, filesLimit)
+ file := "/sys/fs/cgroup/files/files.limit"
+ out, _ := dockerCmd(c, "run", "--name", "fileslimit", "--files-limit", "32", "busybox", "cat", file)
+ c.Assert(strings.TrimSpace(out), checker.Equals, "32")
+ out = inspectField(c, "fileslimit", "HostConfig.FilesLimit")
+ c.Assert(out, checker.Equals, "32", check.Commentf("setting the files limit failed"))
+}
+
func (s *DockerSuite) TestRunPrivilegedAllowedDevices(c *check.C) {
testRequires(c, DaemonIsLinux, NotUserNamespace)
diff --git a/components/engine/integration-cli/requirements_unix_test.go b/components/engine/integration-cli/requirements_unix_test.go
index 7c594f7db4..873c1fbfe2 100644
--- a/components/engine/integration-cli/requirements_unix_test.go
+++ b/components/engine/integration-cli/requirements_unix_test.go
@@ -37,6 +37,10 @@ func pidsLimit() bool {
return SysInfo.PidsLimit
}
+func filesLimit() bool {
+ return SysInfo.FilesLimit
+}
+
func kernelMemorySupport() bool {
return testEnv.DaemonInfo.KernelMemory
}
diff --git a/components/engine/pkg/sysinfo/sysinfo.go b/components/engine/pkg/sysinfo/sysinfo.go
index 0f327d5068..5d9320218c 100644
--- a/components/engine/pkg/sysinfo/sysinfo.go
+++ b/components/engine/pkg/sysinfo/sysinfo.go
@@ -15,6 +15,7 @@ type SysInfo struct {
cgroupBlkioInfo
cgroupCpusetInfo
cgroupPids
+ cgroupFiles
// Whether IPv4 forwarding is supported or not, if this was disabled, networking will not work
IPv4ForwardingDisabled bool
@@ -102,6 +103,11 @@ type cgroupPids struct {
PidsLimit bool
}
+type cgroupFiles struct {
+ // Whether Files Limit is supported or not
+ FilesLimit bool
+}
+
// IsCpusetCpusAvailable returns `true` if the provided string set is contained
// in cgroup's cpuset.cpus set, `false` otherwise.
// If error is not nil a parsing error occurred.
diff --git a/components/engine/pkg/sysinfo/sysinfo_linux.go b/components/engine/pkg/sysinfo/sysinfo_linux.go
index dde5be19bc..c0bf280412 100644
--- a/components/engine/pkg/sysinfo/sysinfo_linux.go
+++ b/components/engine/pkg/sysinfo/sysinfo_linux.go
@@ -40,6 +40,7 @@ func New(quiet bool) *SysInfo {
sysInfo.cgroupBlkioInfo = checkCgroupBlkioInfo(cgMounts, quiet)
sysInfo.cgroupCpusetInfo = checkCgroupCpusetInfo(cgMounts, quiet)
sysInfo.cgroupPids = checkCgroupPids(quiet)
+ sysInfo.cgroupFiles = checkCgroupFiles(quiet)
}
_, ok := cgMounts["devices"]
@@ -240,6 +241,20 @@ func checkCgroupPids(quiet bool) cgroupPids {
}
}
+// checkCgroupPids reads the files information from the pids cgroup mount point.
+func checkCgroupFiles(quiet bool) cgroupFiles {
+ _, err := cgroups.FindCgroupMountpoint("files")
+ if err != nil {
+ if !quiet {
+ logrus.Warn(err)
+ }
+ return cgroupFiles{}
+ }
+ return cgroupFiles{
+ FilesLimit: true,
+ }
+}
+
func cgroupEnabled(mountPoint, name string) bool {
_, err := os.Stat(path.Join(mountPoint, name))
return err == nil
diff --git a/components/engine/vendor/github.com/opencontainers/runtime-spec/Checklist b/components/engine/vendor/github.com/opencontainers/runtime-spec/Checklist
new file mode 100644
index 0000000000..5b7ba2fab9
--- /dev/null
+++ b/components/engine/vendor/github.com/opencontainers/runtime-spec/Checklist
@@ -0,0 +1 @@
+Add struct LinuxFiles to components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go for supporting --files-limit
diff --git a/components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
index f32698cab2..46049b3bfa 100644
--- a/components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
+++ b/components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
@@ -314,6 +314,12 @@ type LinuxPids struct {
Limit int64 `json:"limit"`
}
+// Files for Linux cgroup 'files' resource management (https://lwn.net/Articles/604129/)
+type Files struct {
+ // Maximum number of open files. Default is "no limit".
+ Limit *int64 `json:"limit,omitempty"`
+}
+
// LinuxNetwork identification and priority configuration
type LinuxNetwork struct {
// Set class identifier for container's network packets
@@ -340,6 +346,8 @@ type LinuxResources struct {
CPU *LinuxCPU `json:"cpu,omitempty"`
// Task resource restriction configuration.
Pids *LinuxPids `json:"pids,omitempty"`
+ // Files resource restriction configuration.
+ Files *Files `json:"files,omitempty"`
// BlockIO restriction configuration
BlockIO *LinuxBlockIO `json:"blockIO,omitempty"`
// Hugetlb limit (in bytes)
--
2.17.1

View File

@ -0,0 +1,104 @@
From 7a965f7491e5f60e27ce1f6c052aa139f80e0744 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:14:42 +0800
Subject: [PATCH 008/111] filelimit: Ignore host kernel whether suport
files limit when run a secure container
reason:Ignore host kernel whether suport files limit when run a secure
container.
Change-Id: Iabd2c54492465a8df53375206d5ff600d9da7f6e
Signed-off-by: yangshukui <yangshukui@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/container.go | 2 +-
components/engine/daemon/daemon_unix.go | 15 +++++++++------
components/engine/daemon/daemon_windows.go | 6 +++---
3 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/components/engine/daemon/container.go b/components/engine/daemon/container.go
index c8e2053970..bd96de2571 100644
--- a/components/engine/daemon/container.go
+++ b/components/engine/daemon/container.go
@@ -348,7 +348,7 @@ func (daemon *Daemon) verifyContainerSettings(platform string, hostConfig *conta
warnings []string
)
// Now do platform-specific verification
- if warnings, err = verifyPlatformContainerSettings(daemon, hostConfig, config, update); err != nil {
+ if warnings, err = daemon.verifyPlatformContainerSettings(hostConfig, config, update); err != nil {
return warnings, err
}
if hostConfig.NetworkMode.IsHost() && len(hostConfig.PortBindings) > 0 {
diff --git a/components/engine/daemon/daemon_unix.go b/components/engine/daemon/daemon_unix.go
index 138b8ac544..f4b75055f5 100644
--- a/components/engine/daemon/daemon_unix.go
+++ b/components/engine/daemon/daemon_unix.go
@@ -350,8 +350,9 @@ func adaptSharedNamespaceContainer(daemon containerGetter, hostConfig *container
}
}
-func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysinfo.SysInfo, update bool) ([]string, error) {
+func (daemon *Daemon) verifyContainerResources(hostConfig *containertypes.HostConfig, sysInfo *sysinfo.SysInfo, update bool) ([]string, error) {
warnings := []string{}
+ resources := &hostConfig.Resources
fixMemorySwappiness(resources)
// memory subsystem checks and adjustments
@@ -426,9 +427,11 @@ func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysi
}
if resources.FilesLimit != 0 && !sysInfo.FilesLimit {
- warnings = append(warnings, "Your kernel does not support files limit capabilities, files limit discarded.")
- logrus.Warnf("Your kernel does not support files limit capabilities, files limit discarded.")
- resources.FilesLimit = 0
+ if daemon.IsNativeRuntime(hostConfig.Runtime) {
+ warnings = append(warnings, "Your kernel does not support files limit capabilities, files limit discarded.")
+ logrus.Warnf("Your kernel does not support files limit capabilities, files limit discarded.")
+ resources.FilesLimit = 0
+ }
}
// cpu subsystem checks and adjustments
@@ -580,11 +583,11 @@ func UsingSystemd(config *config.Config) bool {
// verifyPlatformContainerSettings performs platform-specific validation of the
// hostconfig and config structures.
-func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
+func (daemon *Daemon) verifyPlatformContainerSettings(hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
var warnings []string
sysInfo := sysinfo.New(true)
- w, err := verifyContainerResources(&hostConfig.Resources, sysInfo, update)
+ w, err := daemon.verifyContainerResources(hostConfig, sysInfo, update)
// no matter err is nil or not, w could have data in itself.
warnings = append(warnings, w...)
diff --git a/components/engine/daemon/daemon_windows.go b/components/engine/daemon/daemon_windows.go
index 04d3de9924..4812236bc2 100644
--- a/components/engine/daemon/daemon_windows.go
+++ b/components/engine/daemon/daemon_windows.go
@@ -75,7 +75,7 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConf
return nil
}
-func verifyContainerResources(resources *containertypes.Resources, isHyperv bool) ([]string, error) {
+func (daemon *Daemon) verifyContainerResources(resources *containertypes.Resources, isHyperv bool) ([]string, error) {
warnings := []string{}
fixMemorySwappiness(resources)
if !isHyperv {
@@ -191,10 +191,10 @@ func verifyContainerResources(resources *containertypes.Resources, isHyperv bool
// verifyPlatformContainerSettings performs platform-specific validation of the
// hostconfig and config structures.
-func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
+func (daemon *Daemon) verifyPlatformContainerSettings(hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
warnings := []string{}
- hyperv := daemon.runAsHyperVContainer(hostConfig)
+ hyperv := daemon.daemon.runAsHyperVContainer(hostConfig)
if !hyperv && system.IsWindowsClient() && !system.IsIoTCore() {
// @engine maintainers. This block should not be removed. It partially enforces licensing
// restrictions on Windows. Ping @jhowardmsft if there are concerns or PRs to change this.
--
2.17.1

View File

@ -0,0 +1,128 @@
From c03a609c9bb837d8f361888460c7a605dc1219d6 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:15:11 +0800
Subject: [PATCH 009/111] healthycheck: add healthycheck in _ping &
add semaphore set info in docker info
reason: add healthycheck in _ping & add semaphore set info in docker info
Change-Id: I90b3def5fa8bcf0e21090471c43c6309e58c26aa
Signed-off-by: liruilin4 <liruilin4@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
.../api/server/router/system/backend.go | 1 +
.../api/server/router/system/system_routes.go | 2 ++
.../daemon/graphdriver/devmapper/driver.go | 7 ++++++
components/engine/daemon/info.go | 10 ++++++++
components/engine/utils/utils.go | 23 +++++++++++++++++++
5 files changed, 43 insertions(+)
create mode 100644 components/engine/utils/utils.go
diff --git a/components/engine/api/server/router/system/backend.go b/components/engine/api/server/router/system/backend.go
index f5d2d98101..2ba5ab774b 100644
--- a/components/engine/api/server/router/system/backend.go
+++ b/components/engine/api/server/router/system/backend.go
@@ -19,6 +19,7 @@ type Backend interface {
SubscribeToEvents(since, until time.Time, ef filters.Args) ([]events.Message, chan interface{})
UnsubscribeFromEvents(chan interface{})
AuthenticateToRegistry(ctx context.Context, authConfig *types.AuthConfig) (string, string, error)
+ HealthyCheck()
}
// ClusterBackend is all the methods that need to be implemented
diff --git a/components/engine/api/server/router/system/system_routes.go b/components/engine/api/server/router/system/system_routes.go
index a2ff692de3..f235acc657 100644
--- a/components/engine/api/server/router/system/system_routes.go
+++ b/components/engine/api/server/router/system/system_routes.go
@@ -31,6 +31,8 @@ func (s *systemRouter) pingHandler(ctx context.Context, w http.ResponseWriter, r
if bv := builderVersion; bv != "" {
w.Header().Set("Builder-Version", string(bv))
}
+
+ s.backend.HealthyCheck()
_, err := w.Write([]byte{'O', 'K'})
return err
}
diff --git a/components/engine/daemon/graphdriver/devmapper/driver.go b/components/engine/daemon/graphdriver/devmapper/driver.go
index 899b1f8670..623843f852 100644
--- a/components/engine/daemon/graphdriver/devmapper/driver.go
+++ b/components/engine/daemon/graphdriver/devmapper/driver.go
@@ -15,6 +15,7 @@ import (
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/locker"
"github.com/docker/docker/pkg/mount"
+ "github.com/docker/docker/utils"
"github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -101,6 +102,12 @@ func (d *Driver) Status() [][2]string {
if vStr, err := devicemapper.GetLibraryVersion(); err == nil {
status = append(status, [2]string{"Library Version", vStr})
}
+ usz, mni, err := utils.CheckSemSetStat()
+ status = append(status, [2]string{"Semaphore Set Used", fmt.Sprintf("%d", usz)})
+ status = append(status, [2]string{"Semaphore Set Total", fmt.Sprintf("%d", mni)})
+ if err != nil {
+ status = append(status, [2]string{"WARNING", fmt.Sprintf("%v", err)})
+ }
return status
}
diff --git a/components/engine/daemon/info.go b/components/engine/daemon/info.go
index bf84342b54..262719d9d1 100644
--- a/components/engine/daemon/info.go
+++ b/components/engine/daemon/info.go
@@ -20,6 +20,7 @@ import (
"github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/registry"
+ "github.com/docker/docker/utils"
"github.com/docker/go-connections/sockets"
"github.com/sirupsen/logrus"
)
@@ -256,3 +257,12 @@ func maskCredentials(rawURL string) string {
maskedURL := parsedURL.String()
return maskedURL
}
+
+func (daemon *Daemon) HealthyCheck() {
+ if daemon.imageService.GraphDriverForOS(runtime.GOOS) == "devicemapper" {
+ _, _, err := utils.CheckSemSetStat()
+ if err != nil {
+ logrus.Warn(err)
+ }
+ }
+}
diff --git a/components/engine/utils/utils.go b/components/engine/utils/utils.go
new file mode 100644
index 0000000000..75fd409399
--- /dev/null
+++ b/components/engine/utils/utils.go
@@ -0,0 +1,23 @@
+package utils
+
+/*
+#include <sys/types.h>
+#include <sys/sem.h>
+int mysemctl(int cmd, struct seminfo *p){
+ return semctl(0, 0, cmd, p);
+}
+*/
+import "C"
+import (
+ "fmt"
+)
+
+func CheckSemSetStat() (int, int, error) {
+ var seminfo *C.struct_seminfo = new(C.struct_seminfo)
+ C.mysemctl(C.SEM_INFO, seminfo)
+ var err error = nil
+ if seminfo.semusz == seminfo.semmni {
+ err = fmt.Errorf("system semaphore nums has attached limit: %d", int(seminfo.semusz))
+ }
+ return int(seminfo.semusz), int(seminfo.semmni), err
+}
--
2.17.1

View File

@ -0,0 +1,149 @@
From 961d5e98090e4725dca298dde8afb8df54f99f2e Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:15:25 +0800
Subject: [PATCH 010/111] annotation: add annotation into cli flag
reason: add annotation into cli flag
Change-Id: Ibca64819e6f390c70e8516a1462d8e465fcfe080
Signed-off-by: caihaomin <caihaomin@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/cli/cli/command/container/opts.go | 7 +++++
.../docker/api/types/container/config.go | 1 +
.../engine/api/types/container/config.go | 1 +
components/engine/api/types/types.go | 28 ++++++++++---------
components/engine/daemon/oci_linux.go | 1 +
5 files changed, 25 insertions(+), 13 deletions(-)
diff --git a/components/cli/cli/command/container/opts.go b/components/cli/cli/command/container/opts.go
index efb28a2cdf..af30dfcbf2 100644
--- a/components/cli/cli/command/container/opts.go
+++ b/components/cli/cli/command/container/opts.go
@@ -43,6 +43,7 @@ type containerOptions struct {
deviceWriteIOps opts.ThrottledeviceOpt
env opts.ListOpts
labels opts.ListOpts
+ annotation opts.ListOpts
deviceCgroupRules opts.ListOpts
devices opts.ListOpts
ulimits *opts.UlimitOpt
@@ -148,6 +149,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
groupAdd: opts.NewListOpts(nil),
labels: opts.NewListOpts(nil),
labelsFile: opts.NewListOpts(nil),
+ annotation: opts.NewListOpts(opts.ValidateEnv),
linkLocalIPs: opts.NewListOpts(nil),
links: opts.NewListOpts(opts.ValidateLink),
loggingOpts: opts.NewListOpts(nil),
@@ -173,6 +175,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
flags.BoolVarP(&copts.stdin, "interactive", "i", false, "Keep STDIN open even if not attached")
flags.VarP(&copts.labels, "label", "l", "Set meta data on a container")
flags.Var(&copts.labelsFile, "label-file", "Read in a line delimited file of labels")
+ flags.Var(&copts.annotation, "annotation", "Set annotations on a container")
flags.BoolVar(&copts.readonlyRootfs, "read-only", false, "Mount the container's root filesystem as read only")
flags.StringVar(&copts.restartPolicy, "restart", "no", "Restart policy to apply when a container exits")
flags.StringVar(&copts.stopSignal, "stop-signal", signal.DefaultStopSignal, "Signal to stop a container")
@@ -438,6 +441,9 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
return nil, err
}
+ // collect all the annotations for the container
+ annotations := copts.annotation.GetAll()
+
pidMode := container.PidMode(copts.pidMode)
if !pidMode.Valid() {
return nil, errors.Errorf("--pid: invalid PID mode")
@@ -568,6 +574,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
Entrypoint: entrypoint,
WorkingDir: copts.workingDir,
Labels: opts.ConvertKVStringsToMap(labels),
+ Annotations: opts.ConvertKVStringsToMap(annotations),
Healthcheck: healthConfig,
}
if flags.Changed("stop-signal") {
diff --git a/components/cli/vendor/github.com/docker/docker/api/types/container/config.go b/components/cli/vendor/github.com/docker/docker/api/types/container/config.go
index 89ad08c234..c28f0b101e 100644
--- a/components/cli/vendor/github.com/docker/docker/api/types/container/config.go
+++ b/components/cli/vendor/github.com/docker/docker/api/types/container/config.go
@@ -63,6 +63,7 @@ type Config struct {
MacAddress string `json:",omitempty"` // Mac Address of the container
OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile
Labels map[string]string // List of labels set to this container
+ Annotations map[string]string // List of annotations set to this container
StopSignal string `json:",omitempty"` // Signal to stop a container
StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container
Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
diff --git a/components/engine/api/types/container/config.go b/components/engine/api/types/container/config.go
index 89ad08c234..c28f0b101e 100644
--- a/components/engine/api/types/container/config.go
+++ b/components/engine/api/types/container/config.go
@@ -63,6 +63,7 @@ type Config struct {
MacAddress string `json:",omitempty"` // Mac Address of the container
OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile
Labels map[string]string // List of labels set to this container
+ Annotations map[string]string // List of annotations set to this container
StopSignal string `json:",omitempty"` // Signal to stop a container
StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container
Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
diff --git a/components/engine/api/types/types.go b/components/engine/api/types/types.go
index a8fae3ba32..959e9eb447 100644
--- a/components/engine/api/types/types.go
+++ b/components/engine/api/types/types.go
@@ -56,19 +56,20 @@ type ImageMetadata struct {
// Container contains response of Engine API:
// GET "/containers/json"
type Container struct {
- ID string `json:"Id"`
- Names []string
- Image string
- ImageID string
- Command string
- Created int64
- Ports []Port
- SizeRw int64 `json:",omitempty"`
- SizeRootFs int64 `json:",omitempty"`
- Labels map[string]string
- State string
- Status string
- HostConfig struct {
+ ID string `json:"Id"`
+ Names []string
+ Image string
+ ImageID string
+ Command string
+ Created int64
+ Ports []Port
+ SizeRw int64 `json:",omitempty"`
+ SizeRootFs int64 `json:",omitempty"`
+ Labels map[string]string
+ Annotaitons map[string]string
+ State string
+ Status string
+ HostConfig struct {
NetworkMode string `json:",omitempty"`
}
NetworkSettings *SummaryNetworkSettings
@@ -188,6 +189,7 @@ type Info struct {
NoProxy string
Name string
Labels []string
+ Annotations []string
ExperimentalBuild bool
ServerVersion string
ClusterStore string
diff --git a/components/engine/daemon/oci_linux.go b/components/engine/daemon/oci_linux.go
index 210d2ad3f6..5018b21f0d 100644
--- a/components/engine/daemon/oci_linux.go
+++ b/components/engine/daemon/oci_linux.go
@@ -846,6 +846,7 @@ func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, e
s.Process.NoNewPrivileges = c.NoNewPrivileges
s.Process.OOMScoreAdj = &c.HostConfig.OomScoreAdj
s.Linux.MountLabel = c.MountLabel
+ s.Annotations = c.Config.Annotations
// Set the masked and readonly paths with regard to the host config options if they are set.
if c.HostConfig.MaskedPaths != nil {
--
2.17.1

View File

@ -0,0 +1,288 @@
From 65c782bb9b0b159f5644395cb291b8741b4400f4 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:15:40 +0800
Subject: [PATCH 011/111] hookspec: Allow adding custom hooks
reason: Add new flag "--hook-spec" which accept a file containing custom hook
definitions, custom hooks will be appended to system hooks which means
docker will execute its own hook first(libnetwork prestart hook) to make
sure everything predefined is working normally, user custom programme
can be executed afterwards
One example hook spec file can be of format:
```
{
"prestart": [
{
"path": "/bin/ls",
"args": ["ls"],
"env": []
}
],
"poststart":[],
"poststop":[]
}
```
Change-Id: Iee6f4e5b56ebf0647304c08c2948d599356192e6
Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
Signed-off-by: xiadanni <xiadanni@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/cli/cli/command/container/opts.go | 3 ++
.../cli/docs/reference/commandline/create.md | 1 +
.../cli/docs/reference/commandline/run.md | 1 +
components/cli/man/docker-run.1.md | 28 +++++++++++++++++++
.../docker/api/types/container/host_config.go | 1 +
.../engine/api/types/container/host_config.go | 1 +
components/engine/container/container.go | 4 ++-
components/engine/daemon/container.go | 24 ++++++++++++++++
components/engine/daemon/daemon_unix.go | 16 +++++++++++
components/engine/daemon/oci_linux.go | 6 ++++
10 files changed, 84 insertions(+), 1 deletion(-)
diff --git a/components/cli/cli/command/container/opts.go b/components/cli/cli/command/container/opts.go
index af30dfcbf2..8e07aa77cb 100644
--- a/components/cli/cli/command/container/opts.go
+++ b/components/cli/cli/command/container/opts.go
@@ -111,6 +111,7 @@ type containerOptions struct {
stopTimeout int
isolation string
shmSize opts.MemBytes
+ hookSpec string
noHealthcheck bool
healthCmd string
healthInterval time.Duration
@@ -283,6 +284,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
flags.StringVar(&copts.isolation, "isolation", "", "Container isolation technology")
flags.StringVar(&copts.pidMode, "pid", "", "PID namespace to use")
flags.Var(&copts.shmSize, "shm-size", "Size of /dev/shm")
+ flags.StringVar(&copts.hookSpec, "hook-spec", "", "file containing hook definition(prestart, poststart, poststop)")
flags.StringVar(&copts.utsMode, "uts", "", "UTS namespace to use")
flags.StringVar(&copts.runtime, "runtime", "", "Runtime to use for this container")
@@ -619,6 +621,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
VolumeDriver: copts.volumeDriver,
Isolation: container.Isolation(copts.isolation),
ShmSize: copts.shmSize.Value(),
+ HookSpec: copts.hookSpec,
Resources: resources,
Tmpfs: tmpfs,
Sysctls: copts.sysctls.GetAll(),
diff --git a/components/cli/docs/reference/commandline/create.md b/components/cli/docs/reference/commandline/create.md
index 5d888183b3..34cb79a679 100644
--- a/components/cli/docs/reference/commandline/create.md
+++ b/components/cli/docs/reference/commandline/create.md
@@ -66,6 +66,7 @@ Options:
--health-start-period duration Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h) (default 0s)
--help Print usage
-h, --hostname string Container host name
+ --hook-spec File containing hook definition(prestart, poststart, poststop)
--init Run an init inside the container that forwards signals and reaps processes
-i, --interactive Keep STDIN open even if not attached
--io-maxbandwidth string Maximum IO bandwidth limit for the system drive (Windows only)
diff --git a/components/cli/docs/reference/commandline/run.md b/components/cli/docs/reference/commandline/run.md
index 21b4fdf261..1dc43ddcd9 100644
--- a/components/cli/docs/reference/commandline/run.md
+++ b/components/cli/docs/reference/commandline/run.md
@@ -70,6 +70,7 @@ Options:
--health-start-period duration Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h) (default 0s)
--help Print usage
-h, --hostname string Container host name
+ --hook-spec File containing hook definition(prestart, poststart, poststop)
--init Run an init inside the container that forwards signals and reaps processes
-i, --interactive Keep STDIN open even if not attached
--io-maxbandwidth string Maximum IO bandwidth limit for the system drive (Windows only)
diff --git a/components/cli/man/docker-run.1.md b/components/cli/man/docker-run.1.md
index 41f501d5b9..b0cbcd2e87 100644
--- a/components/cli/man/docker-run.1.md
+++ b/components/cli/man/docker-run.1.md
@@ -43,6 +43,7 @@ docker-run - Run a command in a new container
[**--group-add**[=*[]*]]
[**-h**|**--hostname**[=*HOSTNAME*]]
[**--help**]
+[**--hook-spec**[=*HOOKFILE*]]
[**--init**]
[**-i**|**--interactive**]
[**--ip**[=*IPv4-ADDRESS*]]
@@ -330,6 +331,33 @@ redirection on the host system.
**--help**
Print usage statement
+**--hook-spec**=""
+ Add custom hooks for container
+
+ With this flag, user can specify a file containing custom hook, an example hook file can be like this:
+
+```
+{
+ "prestart": [
+ {
+ "path": "/usr/libexec/oci/hooks.d/oci-systemd-hook",
+ "args": ["oci-systemd-hook", "prestart"],
+ "env": ["container=runc"]
+ }
+ ],
+ "poststop":[
+ {
+ "path": "/usr/libexec/oci/hooks.d/oci-systemd-hook",
+ "args": ["oci-systemd-hook", "poststop"],
+ "env": ["container=runc"]
+ }
+ ]
+}
+```
+
+ currently it supports three hooks: "prestart", "poststart", "poststop".
+ See OCI spec definition for more information about "hooks".
+
**--init**
Run an init inside the container that forwards signals and reaps processes
diff --git a/components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go b/components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go
index 1565b5e091..701cae55f1 100644
--- a/components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go
+++ b/components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go
@@ -395,6 +395,7 @@ type HostConfig struct {
// Applicable to Windows
ConsoleSize [2]uint // Initial console size (height,width)
Isolation Isolation // Isolation technology of the container (e.g. default, hyperv)
+ HookSpec string // specification file containing custom hook definition
// Contains container's resources (cgroups, ulimits)
Resources
diff --git a/components/engine/api/types/container/host_config.go b/components/engine/api/types/container/host_config.go
index 1565b5e091..701cae55f1 100644
--- a/components/engine/api/types/container/host_config.go
+++ b/components/engine/api/types/container/host_config.go
@@ -395,6 +395,7 @@ type HostConfig struct {
// Applicable to Windows
ConsoleSize [2]uint // Initial console size (height,width)
Isolation Isolation // Isolation technology of the container (e.g. default, hyperv)
+ HookSpec string // specification file containing custom hook definition
// Contains container's resources (cgroups, ulimits)
Resources
diff --git a/components/engine/container/container.go b/components/engine/container/container.go
index f74676f7ee..02adc2019a 100644
--- a/components/engine/container/container.go
+++ b/components/engine/container/container.go
@@ -38,6 +38,7 @@ import (
volumemounts "github.com/docker/docker/volume/mounts"
"github.com/docker/go-units"
agentexec "github.com/docker/swarmkit/agent/exec"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -93,6 +94,8 @@ type Container struct {
LogCopier *logger.Copier `json:"-"`
restartManager restartmanager.RestartManager
attachContext *attachContext
+ Hooks specs.Hooks
+ CgroupParent string
// Fields here are specific to Unix platforms
AppArmorProfile string
@@ -106,7 +109,6 @@ type Container struct {
// Fields here are specific to Windows
NetworkSharedContainerID string `json:"-"`
SharedEndpointList []string `json:"-"`
- CgroupParent string
}
// NewBaseContainer creates a new container with its
diff --git a/components/engine/daemon/container.go b/components/engine/daemon/container.go
index bd96de2571..8e68904b16 100644
--- a/components/engine/daemon/container.go
+++ b/components/engine/daemon/container.go
@@ -1,6 +1,7 @@
package daemon // import "github.com/docker/docker/daemon"
import (
+ "encoding/json"
"fmt"
"os"
"path"
@@ -224,11 +225,34 @@ func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *
return err
}
+ // register hooks to container
+ if err := daemon.registerHooks(container, hostConfig); err != nil {
+ return err
+ }
+
runconfig.SetDefaultNetModeIfBlank(hostConfig)
container.HostConfig = hostConfig
return container.CheckpointTo(daemon.containersReplica)
}
+
+func (daemon *Daemon) registerHooks(container *container.Container, hostConfig *containertypes.HostConfig) error {
+ if hostConfig.HookSpec == "" {
+ return nil
+ }
+ // the hook spec has already been sanitized, so no need for validation again
+ f, err := os.Open(hostConfig.HookSpec)
+ if err != nil {
+ return fmt.Errorf("open hook spec file error: %v", err)
+ }
+ defer f.Close()
+
+ if err = json.NewDecoder(f).Decode(&container.Hooks); err != nil {
+ return fmt.Errorf("malformed hook spec, is your spec file in json format? error: %v", err)
+ }
+ return nil
+}
+
// verifyContainerSettings performs validation of the hostconfig and config
// structures.
func (daemon *Daemon) verifyContainerSettings(platform string, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
diff --git a/components/engine/daemon/daemon_unix.go b/components/engine/daemon/daemon_unix.go
index f4b75055f5..ebf4e067fb 100644
--- a/components/engine/daemon/daemon_unix.go
+++ b/components/engine/daemon/daemon_unix.go
@@ -627,6 +627,22 @@ func (daemon *Daemon) verifyPlatformContainerSettings(hostConfig *containertypes
return warnings, fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
}
}
+
+ if hostConfig.HookSpec != "" {
+ hostConfig.HookSpec = filepath.Clean(hostConfig.HookSpec)
+ if !filepath.IsAbs(hostConfig.HookSpec) {
+ return warnings, fmt.Errorf("Hook spec file must be an absolute path")
+ }
+ fi, err := os.Stat(hostConfig.HookSpec)
+ if err != nil {
+ return warnings, fmt.Errorf("stat hook spec file failed: %v", err)
+ }
+ if !fi.Mode().IsRegular() {
+ return warnings, fmt.Errorf("Hook spec file must be a regular text file")
+ }
+ }
+
+
if hostConfig.Runtime == "" {
hostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName()
}
diff --git a/components/engine/daemon/oci_linux.go b/components/engine/daemon/oci_linux.go
index 5018b21f0d..884739c07e 100644
--- a/components/engine/daemon/oci_linux.go
+++ b/components/engine/daemon/oci_linux.go
@@ -818,6 +818,12 @@ func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, e
}
}
+ // apppend user custom hooks after system hooks
+ // make sure docker's predefined hooks are executed before custom hooks
+ s.Hooks.Prestart = append(s.Hooks.Prestart, c.Hooks.Prestart...)
+ s.Hooks.Poststart = append(s.Hooks.Poststart, c.Hooks.Poststart...)
+ s.Hooks.Poststop = append(s.Hooks.Poststop, c.Hooks.Poststop...)
+
if apparmor.IsEnabled() {
var appArmorProfile string
if c.AppArmorProfile != "" {
--
2.17.1

View File

@ -0,0 +1,82 @@
From e81d103000ae3213b91ed54410ddb20d911ddc1a Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:15:56 +0800
Subject: [PATCH 012/111] hookspec: Security enhancement for hooks
reason: Currently docker support running hooks with any path, this is insecure.
To solve this, we need to restrict path to specified path, e.g.
"/var/lib/docker/hooks" or "/var/lib/docker/1000.1000/hooks" if user
remap enabled for user ns.
Change-Id: I9cff78f1a1105dcb4bc0b00c8e6e715904dfb778
Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
Signed-off-by: xiadanni <xiadanni@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/container.go | 37 +++++++++++++++++++++++++++
components/engine/daemon/daemon.go | 1 +
2 files changed, 38 insertions(+)
diff --git a/components/engine/daemon/container.go b/components/engine/daemon/container.go
index 8e68904b16..0864443513 100644
--- a/components/engine/daemon/container.go
+++ b/components/engine/daemon/container.go
@@ -250,6 +250,43 @@ func (daemon *Daemon) registerHooks(container *container.Container, hostConfig *
if err = json.NewDecoder(f).Decode(&container.Hooks); err != nil {
return fmt.Errorf("malformed hook spec, is your spec file in json format? error: %v", err)
}
+
+ // hook path must be absolute and must be subdir of XXX
+ if err = daemon.validateHook(container); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (daemon *Daemon) validateHook(container *container.Container) error {
+ for _, v := range container.Hooks.Prestart {
+ if err := daemon.validateHookPath(v.Path); err != nil {
+ return err
+ }
+ }
+ for _, v := range container.Hooks.Poststart {
+ if err := daemon.validateHookPath(v.Path); err != nil {
+ return err
+ }
+ }
+ for _, v := range container.Hooks.Poststop {
+ if err := daemon.validateHookPath(v.Path); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (daemon *Daemon) validateHookPath(path string) error {
+ // hook path must be absolute and must be subdir of XXX
+ path = filepath.Clean(path)
+ if !filepath.IsAbs(path) {
+ return fmt.Errorf("Hook path %q must be an absolute path", path)
+ }
+
+ if !filepath.HasPrefix(path, daemon.hookStore) {
+ return fmt.Errorf("hook program must be put under %q", daemon.hookStore)
+ }
return nil
}
diff --git a/components/engine/daemon/daemon.go b/components/engine/daemon/daemon.go
index 8d6b4d8546..d1f3131c4f 100644
--- a/components/engine/daemon/daemon.go
+++ b/components/engine/daemon/daemon.go
@@ -95,6 +95,7 @@ type Daemon struct {
volumes *volumesservice.VolumesService
discoveryWatcher discovery.Reloader
root string
+ hookStore string
seccompEnabled bool
apparmorEnabled bool
shutdown bool
--
2.17.1

View File

@ -0,0 +1,31 @@
From e261cd646bd656db1eae5a3bcb4af59af3423a46 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:16:09 +0800
Subject: [PATCH 013/111] hookspec: Add bash completion for
--hook-spec
reason: Add bash completion for --hook-spec
Change-Id: Ic2cf226576a5437aa69b48edb73737c59f116ae8
Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
Signed-off-by: xiadanni <xiadanni@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/cli/contrib/completion/bash/docker | 1 +
1 file changed, 1 insertion(+)
diff --git a/components/cli/contrib/completion/bash/docker b/components/cli/contrib/completion/bash/docker
index 2e2c8cb04f..9012988075 100644
--- a/components/cli/contrib/completion/bash/docker
+++ b/components/cli/contrib/completion/bash/docker
@@ -1791,6 +1791,7 @@ _docker_container_run_and_create() {
--expose
--files-limit
--group-add
+ --hook-spec
--health-cmd
--health-interval
--health-retries
--
2.17.1

View File

@ -0,0 +1,367 @@
From d6725e951ee958b61af8c32d5c71d79d2e708432 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:16:48 +0800
Subject: [PATCH 014/111] hookspec: Add default hooks for all
containers
reason: Add new flag `--hook-spec` for daemon, so that we can specify one json
file containing hooks definition for all containers.
You can also add this into `/etc/docker/daemon.json` daemon config file:
```
{
"hook-spec": "/tmp/hookspec.json"
}
```
Change-Id: I9263d5a912daeb04621e7d2ec991204333c2b931
Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
Signed-off-by: xiadanni <xiadanni@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/cli/cli/command/system/info.go | 4 +
components/cli/contrib/completion/bash/docker | 1 +
.../cli/docs/reference/commandline/dockerd.md | 1 +
components/cli/man/dockerd.8.md | 25 ++++-
.../docker/docker/api/types/types.go | 1 +
components/engine/api/types/types.go | 1 +
components/engine/cmd/dockerd/config.go | 1 +
components/engine/daemon/config/config.go | 1 +
components/engine/daemon/container.go | 94 +++++++++++++++++--
components/engine/daemon/daemon.go | 7 ++
components/engine/daemon/info.go | 1 +
11 files changed, 126 insertions(+), 11 deletions(-)
diff --git a/components/cli/cli/command/system/info.go b/components/cli/cli/command/system/info.go
index 92fc2cd3e7..17ccc14aec 100644
--- a/components/cli/cli/command/system/info.go
+++ b/components/cli/cli/command/system/info.go
@@ -204,6 +204,10 @@ func prettyPrintInfo(dockerCli command.Cli, info types.Info) error {
}
fmt.Fprintln(dockerCli.Out(), "Live Restore Enabled:", info.LiveRestoreEnabled)
+ if info.HookSpec != "" {
+ fmt.Fprintf(dockerCli.Out(), "Default hook spec file: %s", info.HookSpec)
+ }
+
if info.ProductLicense != "" {
fmt.Fprintln(dockerCli.Out(), "Product License:", info.ProductLicense)
}
diff --git a/components/cli/contrib/completion/bash/docker b/components/cli/contrib/completion/bash/docker
index 9012988075..64f7fe08dd 100644
--- a/components/cli/contrib/completion/bash/docker
+++ b/components/cli/contrib/completion/bash/docker
@@ -2274,6 +2274,7 @@ _docker_daemon() {
--fixed-cidr
--fixed-cidr-v6
--group -G
+ --hook-spec
--init-path
--insecure-registry
--ip
diff --git a/components/cli/docs/reference/commandline/dockerd.md b/components/cli/docs/reference/commandline/dockerd.md
index 4b50b78b19..bbf6908af3 100644
--- a/components/cli/docs/reference/commandline/dockerd.md
+++ b/components/cli/docs/reference/commandline/dockerd.md
@@ -53,6 +53,7 @@ Options:
--fixed-cidr-v6 string IPv6 subnet for fixed IPs
-G, --group string Group for the unix socket (default "docker")
--help Print usage
+ --hook-spec Default hook spec file applied to all containers
-H, --host list Daemon socket(s) to connect to (default [])
--icc Enable inter-container communication (default true)
--init Run an init in the container to forward signals and reap processes
diff --git a/components/cli/man/dockerd.8.md b/components/cli/man/dockerd.8.md
index 0224035970..d075080e78 100644
--- a/components/cli/man/dockerd.8.md
+++ b/components/cli/man/dockerd.8.md
@@ -38,6 +38,7 @@ dockerd - Enable daemon mode
[**-G**|**--group**[=*docker*]]
[**-H**|**--host**[=*[]*]]
[**--help**]
+[**--hook-spec**[=*HOOKFILE*]]
[**--icc**[=*true*]]
[**--init**[=*false*]]
[**--init-path**[=*""*]]
@@ -239,7 +240,29 @@ unix://[/path/to/socket] to use.
**--help**
Print usage statement
-
+
+**--hook-spec**=""
+ Add default hooks for all containers.
+
+ With this flag, user can specify a file containing custom hook, an example hook file can be like this:
+
+ ```
+ {
+ "prestart": [
+ {
+ "path": "/var/lib/docker/hooks/myhook",
+ "args": ["myhook", "prestart"],
+ "env": ["container=runc"]
+ }
+ ]
+ }
+ ```
+
+ Then all the containers will run the default hook `myhook` when start.
+
+ currently it supports three hooks: "prestart", "poststart", "poststop".
+ See OCI spec definition for more information about "hooks".
+
**--icc**=*true*|*false*
Allow unrestricted inter\-container and Docker daemon host communication. If
disabled, containers can still be linked together using the **--link** option
diff --git a/components/cli/vendor/github.com/docker/docker/api/types/types.go b/components/cli/vendor/github.com/docker/docker/api/types/types.go
index a8fae3ba32..2fb6c5478b 100644
--- a/components/cli/vendor/github.com/docker/docker/api/types/types.go
+++ b/components/cli/vendor/github.com/docker/docker/api/types/types.go
@@ -192,6 +192,7 @@ type Info struct {
ServerVersion string
ClusterStore string
ClusterAdvertise string
+ HookSpec string
Runtimes map[string]Runtime
DefaultRuntime string
Swarm swarm.Info
diff --git a/components/engine/api/types/types.go b/components/engine/api/types/types.go
index 959e9eb447..820d513cbb 100644
--- a/components/engine/api/types/types.go
+++ b/components/engine/api/types/types.go
@@ -194,6 +194,7 @@ type Info struct {
ServerVersion string
ClusterStore string
ClusterAdvertise string
+ HookSpec string
Runtimes map[string]Runtime
DefaultRuntime string
Swarm swarm.Info
diff --git a/components/engine/cmd/dockerd/config.go b/components/engine/cmd/dockerd/config.go
index 2c8ed8edb4..6f62b97da8 100644
--- a/components/engine/cmd/dockerd/config.go
+++ b/components/engine/cmd/dockerd/config.go
@@ -56,6 +56,7 @@ func installCommonConfigFlags(conf *config.Config, flags *pflag.FlagSet) {
flags.StringVar(&conf.ClusterAdvertise, "cluster-advertise", "", "Address or interface name to advertise")
flags.StringVar(&conf.ClusterStore, "cluster-store", "", "URL of the distributed storage backend")
flags.Var(opts.NewNamedMapOpts("cluster-store-opts", conf.ClusterOpts, nil), "cluster-store-opt", "Set cluster store options")
+ flags.StringVar(&conf.HookSpec, "hook-spec", "", "Default hook spec file applied to all containers")
flags.StringVar(&conf.CorsHeaders, "api-cors-header", "", "Set CORS headers in the Engine API")
flags.IntVar(&maxConcurrentDownloads, "max-concurrent-downloads", config.DefaultMaxConcurrentDownloads, "Set the max concurrent downloads for each pull")
flags.IntVar(&maxConcurrentUploads, "max-concurrent-uploads", config.DefaultMaxConcurrentUploads, "Set the max concurrent uploads for each push")
diff --git a/components/engine/daemon/config/config.go b/components/engine/daemon/config/config.go
index 8b2c844a57..2141ce8c54 100644
--- a/components/engine/daemon/config/config.go
+++ b/components/engine/daemon/config/config.go
@@ -124,6 +124,7 @@ type CommonConfig struct {
ExecOptions []string `json:"exec-opts,omitempty"`
GraphDriver string `json:"storage-driver,omitempty"`
GraphOptions []string `json:"storage-opts,omitempty"`
+ HookSpec string `json:"hook-spec,omitempty"`
Labels []string `json:"labels,omitempty"`
Mtu int `json:"mtu,omitempty"`
NetworkDiagnosticPort int `json:"network-diagnostic-port,omitempty"`
diff --git a/components/engine/daemon/container.go b/components/engine/daemon/container.go
index 0864443513..8f9f6baf25 100644
--- a/components/engine/daemon/container.go
+++ b/components/engine/daemon/container.go
@@ -13,16 +13,19 @@ import (
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/docker/container"
+ "github.com/docker/docker/daemon/config"
"github.com/docker/docker/daemon/network"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/image"
"github.com/docker/docker/opts"
+ "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/pkg/truncindex"
"github.com/docker/docker/runconfig"
volumemounts "github.com/docker/docker/volume/mounts"
"github.com/docker/go-connections/nat"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
)
@@ -226,7 +229,7 @@ func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *
}
// register hooks to container
- if err := daemon.registerHooks(container, hostConfig); err != nil {
+ if err := daemon.registerHooks(container, hostConfig.HookSpec); err != nil {
return err
}
@@ -235,41 +238,112 @@ func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *
return container.CheckpointTo(daemon.containersReplica)
}
+func (daemon *Daemon) sanitizeHookSpec(spec string) (string, error) {
+ if spec != "" {
+ spec = filepath.Clean(spec)
+ if !filepath.IsAbs(spec) {
+ return "", fmt.Errorf("hook spec file must be an absolute path")
+ }
+ fi, err := os.Stat(spec)
+ if err != nil {
+ return "", fmt.Errorf("stat hook spec file failed: %v", err)
+ }
+ if !fi.Mode().IsRegular() {
+ return "", fmt.Errorf("hook spec file must be a regular text file")
+ }
+ }
+ return spec, nil
+}
+
+func (daemon *Daemon) initHooks(config *config.Config, rootIdentity idtools.Identity) error {
+ // create hook store dir
+ var err error
+ hookDir := filepath.Join(config.Root, "hooks")
+ if err = idtools.MkdirAllAndChown(hookDir, 0700, rootIdentity); err != nil && !os.IsExist(err) {
+ return err
+ }
+ daemon.hookStore = hookDir
+
+ if config.HookSpec, err = daemon.sanitizeHookSpec(config.HookSpec); err != nil {
+ return err
+ }
+
+ // setup default hooks
+ if err := daemon.registerDaemonHooks(config.HookSpec); err != nil {
+ return err
+ }
+
+ return nil
+}
-func (daemon *Daemon) registerHooks(container *container.Container, hostConfig *containertypes.HostConfig) error {
- if hostConfig.HookSpec == "" {
+func (daemon *Daemon) registerDaemonHooks(hookspec string) error {
+ if hookspec == "" {
return nil
}
+
// the hook spec has already been sanitized, so no need for validation again
- f, err := os.Open(hostConfig.HookSpec)
+ f, err := os.Open(hookspec)
if err != nil {
return fmt.Errorf("open hook spec file error: %v", err)
}
defer f.Close()
- if err = json.NewDecoder(f).Decode(&container.Hooks); err != nil {
+ if err = json.NewDecoder(f).Decode(&daemon.Hooks); err != nil {
return fmt.Errorf("malformed hook spec, is your spec file in json format? error: %v", err)
}
// hook path must be absolute and must be subdir of XXX
- if err = daemon.validateHook(container); err != nil {
+ if err = daemon.validateHook(&daemon.Hooks); err != nil {
return err
}
+
+ return nil
+}
+
+func (daemon *Daemon) registerHooks(container *container.Container, hookspec string) error {
+ container.Hooks.Prestart = append(container.Hooks.Prestart, daemon.Hooks.Prestart...)
+ container.Hooks.Poststart = append(container.Hooks.Poststart, daemon.Hooks.Poststart...)
+ container.Hooks.Poststop = append(container.Hooks.Poststop, daemon.Hooks.Poststop...)
+ if hookspec == "" {
+ return nil
+ }
+
+ // the hook spec has already been sanitized, so no need for validation again
+ f, err := os.Open(hookspec)
+ if err != nil {
+ return fmt.Errorf("open hook spec file error: %v", err)
+ }
+ defer f.Close()
+
+ var hooks specs.Hooks
+ if err = json.NewDecoder(f).Decode(&hooks); err != nil {
+ return fmt.Errorf("malformed hook spec, is your spec file in json format? error: %v", err)
+ }
+
+ container.Hooks.Prestart = append(container.Hooks.Prestart, hooks.Prestart...)
+ container.Hooks.Poststart = append(container.Hooks.Poststart, hooks.Poststart...)
+ container.Hooks.Poststop = append(container.Hooks.Poststop, hooks.Poststop...)
+
+ // hook path must be absolute and must be subdir of XXX
+ if err = daemon.validateHook(&container.Hooks); err != nil {
+ return err
+ }
+
return nil
}
-func (daemon *Daemon) validateHook(container *container.Container) error {
- for _, v := range container.Hooks.Prestart {
+func (daemon *Daemon) validateHook(hooks *specs.Hooks) error {
+ for _, v := range hooks.Prestart {
if err := daemon.validateHookPath(v.Path); err != nil {
return err
}
}
- for _, v := range container.Hooks.Poststart {
+ for _, v := range hooks.Poststart {
if err := daemon.validateHookPath(v.Path); err != nil {
return err
}
}
- for _, v := range container.Hooks.Poststop {
+ for _, v := range hooks.Poststop {
if err := daemon.validateHookPath(v.Path); err != nil {
return err
}
diff --git a/components/engine/daemon/daemon.go b/components/engine/daemon/daemon.go
index d1f3131c4f..f7635f27cc 100644
--- a/components/engine/daemon/daemon.go
+++ b/components/engine/daemon/daemon.go
@@ -67,6 +67,7 @@ import (
"github.com/docker/libnetwork"
"github.com/docker/libnetwork/cluster"
nwconfig "github.com/docker/libnetwork/config"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)
@@ -109,6 +110,7 @@ type Daemon struct {
containerdCli *containerd.Client
containerd libcontainerd.Client
defaultIsolation containertypes.Isolation // Default isolation mode on Windows
+ Hooks specs.Hooks
clusterProvider cluster.Provider
cluster Cluster
genericResources []swarm.GenericResource
@@ -997,6 +999,11 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
return nil, errors.New("Devices cgroup isn't mounted")
}
+ // setup hooks environment
+ if err := d.initHooks(config, rootIDs); err != nil {
+ return nil, fmt.Errorf("Failed to register default hooks: %v", err)
+ }
+
d.ID = trustKey.PublicKey().KeyID()
d.repository = daemonRepo
d.containers = container.NewMemoryStore()
diff --git a/components/engine/daemon/info.go b/components/engine/daemon/info.go
index 262719d9d1..523a396643 100644
--- a/components/engine/daemon/info.go
+++ b/components/engine/daemon/info.go
@@ -67,6 +67,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
HTTPSProxy: maskCredentials(sockets.GetProxyEnv("https_proxy")),
NoProxy: sockets.GetProxyEnv("no_proxy"),
LiveRestoreEnabled: daemon.configStore.LiveRestoreEnabled,
+ HookSpec: daemon.configStore.HookSpec,
Isolation: daemon.defaultIsolation,
}
--
2.17.1

View File

@ -0,0 +1,72 @@
From a6c5e3824b6b8d3a443e1a14136360cc73779296 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:17:06 +0800
Subject: [PATCH 015/111] hookspec: add limit of hook spec file
reason: add limit of hook spec file, to prevent docker daemon OOM.
Change-Id: I11afebf163de3c401ed4f9b8f30c403f1d15de77
Signed-off-by: xiadanni <xiadanni@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/container.go | 8 ++++++++
components/engine/daemon/daemon_unix.go | 15 ++-------------
2 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/components/engine/daemon/container.go b/components/engine/daemon/container.go
index 8f9f6baf25..a8cb950f44 100644
--- a/components/engine/daemon/container.go
+++ b/components/engine/daemon/container.go
@@ -30,6 +30,11 @@ import (
"github.com/pkg/errors"
)
+const (
+ // hook spec file size limit (in bytes)
+ hookSpecSizeLimit = (10 * 1024 * 1024)
+)
+
// GetContainer looks for a container using the provided information, which could be
// one of the following inputs from the caller:
// - A full container ID, which will exact match a container in daemon's list
@@ -251,6 +256,9 @@ func (daemon *Daemon) sanitizeHookSpec(spec string) (string, error) {
if !fi.Mode().IsRegular() {
return "", fmt.Errorf("hook spec file must be a regular text file")
}
+ if fi.Size() > hookSpecSizeLimit {
+ return "", fmt.Errorf("Hook spec file size must not exceed %d bytes", hookSpecSizeLimit)
+ }
}
return spec, nil
}
diff --git a/components/engine/daemon/daemon_unix.go b/components/engine/daemon/daemon_unix.go
index ebf4e067fb..5b390d2db1 100644
--- a/components/engine/daemon/daemon_unix.go
+++ b/components/engine/daemon/daemon_unix.go
@@ -628,21 +628,10 @@ func (daemon *Daemon) verifyPlatformContainerSettings(hostConfig *containertypes
}
}
- if hostConfig.HookSpec != "" {
- hostConfig.HookSpec = filepath.Clean(hostConfig.HookSpec)
- if !filepath.IsAbs(hostConfig.HookSpec) {
- return warnings, fmt.Errorf("Hook spec file must be an absolute path")
- }
- fi, err := os.Stat(hostConfig.HookSpec)
- if err != nil {
- return warnings, fmt.Errorf("stat hook spec file failed: %v", err)
- }
- if !fi.Mode().IsRegular() {
- return warnings, fmt.Errorf("Hook spec file must be a regular text file")
- }
+ if hostConfig.HookSpec, err = daemon.sanitizeHookSpec(hostConfig.HookSpec); err != nil {
+ return warnings, err
}
-
if hostConfig.Runtime == "" {
hostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName()
}
--
2.17.1

View File

@ -0,0 +1,31 @@
From 8dd367f460008bbe1715117610b1eb48cb5b20bf Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:17:23 +0800
Subject: [PATCH 016/111] hookspec: fix hooks nil pointer dereference
reason: merge containerd and runc into one version for docker-1.11.2 and
docker-17.06
Change-Id: I1b0899cf18f2734bb205026b3094f1a3264a695e
Signed-off-by: jingrui <jingrui@huawei.com>
Signed-off-by: xiadanni <xiadanni@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/oci/defaults.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/components/engine/oci/defaults.go b/components/engine/oci/defaults.go
index 992157b0f5..5e17ea3f38 100644
--- a/components/engine/oci/defaults.go
+++ b/components/engine/oci/defaults.go
@@ -66,6 +66,7 @@ func DefaultLinuxSpec() specs.Spec {
},
},
Root: &specs.Root{},
+ Hooks: &specs.Hooks{},
}
s.Mounts = []specs.Mount{
{
--
2.17.1

View File

@ -0,0 +1,45 @@
From fe67259fd158b8193db31fad83f2dc3d3d3bc5c4 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:17:38 +0800
Subject: [PATCH 017/111] hookspec: canonicalize hook path before
validation
reason:hook programs must put under hook directory, but if we refer
them with a symbolic link path in hookspecs, docker daemon refuse
to run. so we just canonicalize path first before check.
Change-Id: I68d3757f26d7df05eb048e686368eca061cb06a9
Signed-off-by: zhangyuyun <zhangyuyun@huawei.com>
Signed-off-by: xiadanni <xiadanni@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/container.go | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/components/engine/daemon/container.go b/components/engine/daemon/container.go
index a8cb950f44..06a19bb4c8 100644
--- a/components/engine/daemon/container.go
+++ b/components/engine/daemon/container.go
@@ -366,8 +366,17 @@ func (daemon *Daemon) validateHookPath(path string) error {
return fmt.Errorf("Hook path %q must be an absolute path", path)
}
- if !filepath.HasPrefix(path, daemon.hookStore) {
- return fmt.Errorf("hook program must be put under %q", daemon.hookStore)
+ realPath, err := filepath.EvalSymlinks(path)
+ if err != nil {
+ if !strings.Contains(err.Error(), "no such file or directory") {
+ return fmt.Errorf("failed to canonicalise path for %s: %s", path, err)
+ }
+ // for backward compatibility
+ realPath = path
+ }
+
+ if !filepath.HasPrefix(realPath, daemon.hookStore) {
+ return fmt.Errorf("hook path %q isn't right, hook program must be put under %q", path, daemon.hookStore)
}
return nil
}
--
2.17.1

View File

@ -0,0 +1,362 @@
From 6a9e68763da72ebc0b9a7e45cd08ce57fe11998f Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:21:56 +0800
Subject: [PATCH 018/111] dfx/trylock: add trylock and trylocktimeout
for docker inspect
reason:In order to avoid deadlocks, add trylock and trylocktimeout
for docker inspect commmand. The -t/--time is a parameter of
docker inspect command, set by user, and the default value
is 120s.
Change-Id: Ie30ff28941624cc595e2a30d453d6f90b265d803
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
.../cli/cli/command/container/inspect.go | 4 +-
components/cli/cli/command/system/inspect.go | 12 ++--
.../github.com/docker/docker/client/Checklist | 1 +
.../docker/docker/client/container_inspect.go | 4 +-
.../docker/docker/client/interface.go | 2 +-
.../api/server/router/container/backend.go | 2 +-
.../api/server/router/container/inspect.go | 4 +-
components/engine/container/state.go | 4 +-
.../engine/daemon/cluster/executor/backend.go | 2 +-
.../cluster/executor/container/adapter.go | 3 +-
components/engine/daemon/inspect.go | 12 ++--
components/engine/pkg/trylock/mutex.go | 61 +++++++++++++++++++
12 files changed, 93 insertions(+), 18 deletions(-)
create mode 100644 components/cli/vendor/github.com/docker/docker/client/Checklist
create mode 100644 components/engine/pkg/trylock/mutex.go
diff --git a/components/cli/cli/command/container/inspect.go b/components/cli/cli/command/container/inspect.go
index 4f50e2a080..b77994e896 100644
--- a/components/cli/cli/command/container/inspect.go
+++ b/components/cli/cli/command/container/inspect.go
@@ -13,6 +13,7 @@ type inspectOptions struct {
format string
size bool
refs []string
+ time int
}
// newInspectCommand creates a new cobra.Command for `docker container inspect`
@@ -32,6 +33,7 @@ func newInspectCommand(dockerCli command.Cli) *cobra.Command {
flags := cmd.Flags()
flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template")
flags.BoolVarP(&opts.size, "size", "s", false, "Display total file sizes")
+ flags.IntVarP(&opts.time, "time", "t", 120, "Seconds to wait for inspect timeout")
return cmd
}
@@ -41,7 +43,7 @@ func runInspect(dockerCli command.Cli, opts inspectOptions) error {
ctx := context.Background()
getRefFunc := func(ref string) (interface{}, []byte, error) {
- return client.ContainerInspectWithRaw(ctx, ref, opts.size)
+ return client.ContainerInspectWithRaw(ctx, ref, opts.size, opts.time)
}
return inspect.Inspect(dockerCli.Out(), opts.refs, opts.format, getRefFunc)
}
diff --git a/components/cli/cli/command/system/inspect.go b/components/cli/cli/command/system/inspect.go
index b49b4b33d3..248f9caad2 100644
--- a/components/cli/cli/command/system/inspect.go
+++ b/components/cli/cli/command/system/inspect.go
@@ -19,6 +19,7 @@ type inspectOptions struct {
inspectType string
size bool
ids []string
+ time int
}
// NewInspectCommand creates a new cobra.Command for `docker inspect`
@@ -39,6 +40,7 @@ func NewInspectCommand(dockerCli command.Cli) *cobra.Command {
flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template")
flags.StringVar(&opts.inspectType, "type", "", "Return JSON for specified type")
flags.BoolVarP(&opts.size, "size", "s", false, "Display total file sizes if the type is container")
+ flags.IntVarP(&opts.time, "time", "t", 120, "Seconds to wait for inspect timeout")
return cmd
}
@@ -47,16 +49,16 @@ func runInspect(dockerCli command.Cli, opts inspectOptions) error {
var elementSearcher inspect.GetRefFunc
switch opts.inspectType {
case "", "container", "image", "node", "network", "service", "volume", "task", "plugin", "secret":
- elementSearcher = inspectAll(context.Background(), dockerCli, opts.size, opts.inspectType)
+ elementSearcher = inspectAll(context.Background(), dockerCli, opts.size, opts.inspectType, opts.time)
default:
return errors.Errorf("%q is not a valid value for --type", opts.inspectType)
}
return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, elementSearcher)
}
-func inspectContainers(ctx context.Context, dockerCli command.Cli, getSize bool) inspect.GetRefFunc {
+func inspectContainers(ctx context.Context, dockerCli command.Cli, getSize bool, timeout int) inspect.GetRefFunc {
return func(ref string) (interface{}, []byte, error) {
- return dockerCli.Client().ContainerInspectWithRaw(ctx, ref, getSize)
+ return dockerCli.Client().ContainerInspectWithRaw(ctx, ref, getSize, timeout)
}
}
@@ -109,7 +111,7 @@ func inspectSecret(ctx context.Context, dockerCli command.Cli) inspect.GetRefFun
}
}
-func inspectAll(ctx context.Context, dockerCli command.Cli, getSize bool, typeConstraint string) inspect.GetRefFunc {
+func inspectAll(ctx context.Context, dockerCli command.Cli, getSize bool, typeConstraint string, timeout int) inspect.GetRefFunc {
var inspectAutodetect = []struct {
objectType string
isSizeSupported bool
@@ -119,7 +121,7 @@ func inspectAll(ctx context.Context, dockerCli command.Cli, getSize bool, typeCo
{
objectType: "container",
isSizeSupported: true,
- objectInspector: inspectContainers(ctx, dockerCli, getSize),
+ objectInspector: inspectContainers(ctx, dockerCli, getSize, timeout),
},
{
objectType: "image",
diff --git a/components/cli/vendor/github.com/docker/docker/client/Checklist b/components/cli/vendor/github.com/docker/docker/client/Checklist
new file mode 100644
index 0000000000..9b1682dc41
--- /dev/null
+++ b/components/cli/vendor/github.com/docker/docker/client/Checklist
@@ -0,0 +1 @@
+Add trylcok and trylocktimeout for docker inspect commmand.
diff --git a/components/cli/vendor/github.com/docker/docker/client/container_inspect.go b/components/cli/vendor/github.com/docker/docker/client/container_inspect.go
index f453064cf8..b8573fd40b 100644
--- a/components/cli/vendor/github.com/docker/docker/client/container_inspect.go
+++ b/components/cli/vendor/github.com/docker/docker/client/container_inspect.go
@@ -6,6 +6,7 @@ import (
"encoding/json"
"io/ioutil"
"net/url"
+ "strconv"
"github.com/docker/docker/api/types"
)
@@ -27,7 +28,7 @@ func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (ty
}
// ContainerInspectWithRaw returns the container information and its raw representation.
-func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID string, getSize bool) (types.ContainerJSON, []byte, error) {
+func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID string, getSize bool, timeout int) (types.ContainerJSON, []byte, error) {
if containerID == "" {
return types.ContainerJSON{}, nil, objectNotFoundError{object: "container", id: containerID}
}
@@ -35,6 +36,7 @@ func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID stri
if getSize {
query.Set("size", "1")
}
+ query.Set("t", strconv.Itoa(timeout))
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil)
if err != nil {
return types.ContainerJSON{}, nil, wrapResponseError(err, serverResp, "container", containerID)
diff --git a/components/cli/vendor/github.com/docker/docker/client/interface.go b/components/cli/vendor/github.com/docker/docker/client/interface.go
index d190f8e58d..b2d5d7bb72 100644
--- a/components/cli/vendor/github.com/docker/docker/client/interface.go
+++ b/components/cli/vendor/github.com/docker/docker/client/interface.go
@@ -56,7 +56,7 @@ type ContainerAPIClient interface {
ContainerExecStart(ctx context.Context, execID string, config types.ExecStartCheck) error
ContainerExport(ctx context.Context, container string) (io.ReadCloser, error)
ContainerInspect(ctx context.Context, container string) (types.ContainerJSON, error)
- ContainerInspectWithRaw(ctx context.Context, container string, getSize bool) (types.ContainerJSON, []byte, error)
+ ContainerInspectWithRaw(ctx context.Context, container string, getSize bool, timeout int) (types.ContainerJSON, []byte, error)
ContainerKill(ctx context.Context, container, signal string) error
ContainerList(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error)
ContainerLogs(ctx context.Context, container string, options types.ContainerLogsOptions) (io.ReadCloser, error)
diff --git a/components/engine/api/server/router/container/backend.go b/components/engine/api/server/router/container/backend.go
index 75ea1d82b7..88fbe71a88 100644
--- a/components/engine/api/server/router/container/backend.go
+++ b/components/engine/api/server/router/container/backend.go
@@ -49,7 +49,7 @@ type stateBackend interface {
// monitorBackend includes functions to implement to provide containers monitoring functionality.
type monitorBackend interface {
ContainerChanges(name string) ([]archive.Change, error)
- ContainerInspect(name string, size bool, version string) (interface{}, error)
+ ContainerInspect(name string, size bool, version string, timeout int) (interface{}, error)
ContainerLogs(ctx context.Context, name string, config *types.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
ContainerStats(ctx context.Context, name string, config *backend.ContainerStatsConfig) error
ContainerTop(name string, psArgs string) (*container.ContainerTopOKBody, error)
diff --git a/components/engine/api/server/router/container/inspect.go b/components/engine/api/server/router/container/inspect.go
index 5c78d15bc9..cb6eb50251 100644
--- a/components/engine/api/server/router/container/inspect.go
+++ b/components/engine/api/server/router/container/inspect.go
@@ -3,6 +3,7 @@ package container // import "github.com/docker/docker/api/server/router/containe
import (
"context"
"net/http"
+ "strconv"
"github.com/docker/docker/api/server/httputils"
)
@@ -12,7 +13,8 @@ func (s *containerRouter) getContainersByName(ctx context.Context, w http.Respon
displaySize := httputils.BoolValue(r, "size")
version := httputils.VersionFromContext(ctx)
- json, err := s.backend.ContainerInspect(vars["name"], displaySize, version)
+ timeout, _ := strconv.Atoi(r.Form.Get("t"))
+ json, err := s.backend.ContainerInspect(vars["name"], displaySize, version, timeout)
if err != nil {
return err
}
diff --git a/components/engine/container/state.go b/components/engine/container/state.go
index 7c2a1ec81c..91ea30a76e 100644
--- a/components/engine/container/state.go
+++ b/components/engine/container/state.go
@@ -4,10 +4,10 @@ import (
"context"
"errors"
"fmt"
- "sync"
"time"
"github.com/docker/docker/api/types"
+ "github.com/docker/docker/pkg/trylock"
"github.com/docker/go-units"
)
@@ -15,7 +15,7 @@ import (
// set the state. Container has an embed, which allows all of the
// functions defined against State to run against Container.
type State struct {
- sync.Mutex
+ trylock.TryMutex
// Note that `Running` and `Paused` are not mutually exclusive:
// When pausing a container (on Linux), the cgroups freezer is used to suspend
// all processes in the container. Freezing the process requires the process to
diff --git a/components/engine/daemon/cluster/executor/backend.go b/components/engine/daemon/cluster/executor/backend.go
index cfbc86ce36..c9ff4503bc 100644
--- a/components/engine/daemon/cluster/executor/backend.go
+++ b/components/engine/daemon/cluster/executor/backend.go
@@ -41,7 +41,7 @@ type Backend interface {
ActivateContainerServiceBinding(containerName string) error
DeactivateContainerServiceBinding(containerName string) error
UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error
- ContainerInspectCurrent(name string, size bool) (*types.ContainerJSON, error)
+ ContainerInspectCurrent(name string, size bool, timeout int) (*types.ContainerJSON, error)
ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)
ContainerRm(name string, config *types.ContainerRmConfig) error
ContainerKill(name string, sig uint64) error
diff --git a/components/engine/daemon/cluster/executor/container/adapter.go b/components/engine/daemon/cluster/executor/container/adapter.go
index 720b8447fc..3743cb6418 100644
--- a/components/engine/daemon/cluster/executor/container/adapter.go
+++ b/components/engine/daemon/cluster/executor/container/adapter.go
@@ -351,7 +351,8 @@ func (c *containerAdapter) start(ctx context.Context) error {
}
func (c *containerAdapter) inspect(ctx context.Context) (types.ContainerJSON, error) {
- cs, err := c.backend.ContainerInspectCurrent(c.container.name(), false)
+ timeout := -1
+ cs, err := c.backend.ContainerInspectCurrent(c.container.name(), false, timeout)
if ctx.Err() != nil {
return types.ContainerJSON{}, ctx.Err()
}
diff --git a/components/engine/daemon/inspect.go b/components/engine/daemon/inspect.go
index 45a2154254..be8f6eff71 100644
--- a/components/engine/daemon/inspect.go
+++ b/components/engine/daemon/inspect.go
@@ -19,25 +19,29 @@ import (
// ContainerInspect returns low-level information about a
// container. Returns an error if the container cannot be found, or if
// there is an error getting the data.
-func (daemon *Daemon) ContainerInspect(name string, size bool, version string) (interface{}, error) {
+func (daemon *Daemon) ContainerInspect(name string, size bool, version string, timeout int) (interface{}, error) {
switch {
case versions.LessThan(version, "1.20"):
return daemon.containerInspectPre120(name)
case versions.Equal(version, "1.20"):
return daemon.containerInspect120(name)
}
- return daemon.ContainerInspectCurrent(name, size)
+ return daemon.ContainerInspectCurrent(name, size, timeout)
}
// ContainerInspectCurrent returns low-level information about a
// container in a most recent api version.
-func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.ContainerJSON, error) {
+func (daemon *Daemon) ContainerInspectCurrent(name string, size bool, timeout int) (*types.ContainerJSON, error) {
container, err := daemon.GetContainer(name)
if err != nil {
return nil, err
}
- container.Lock()
+ // The unit of timeout is seconds, and the unit of frequency is milliseconds.
+ lockTimeoutSuccess := container.TryLockTimeout(timeout, 100)
+ if lockTimeoutSuccess == false {
+ return nil, fmt.Errorf("Container %s inspect failed due to trylock timeout for %ds.", name, timeout)
+ }
base, err := daemon.getInspectData(container)
if err != nil {
diff --git a/components/engine/pkg/trylock/mutex.go b/components/engine/pkg/trylock/mutex.go
new file mode 100644
index 0000000000..18b3c3cca7
--- /dev/null
+++ b/components/engine/pkg/trylock/mutex.go
@@ -0,0 +1,61 @@
+package trylock
+
+import (
+ "sync"
+ "sync/atomic"
+ "time"
+ "unsafe"
+)
+
+const mutexLocked = 1 << iota
+
+// Mutex is simple sync.Mutex + ability to try to Lock.
+type TryMutex struct {
+ in sync.Mutex
+}
+
+// Lock locks m.
+// If the lock is already in use, the calling goroutine
+// blocks until the mutex is available.
+func (m *TryMutex) Lock() {
+ m.in.Lock()
+}
+
+// Unlock unlocks m.
+// It is a run-time error if m is not locked on entry to Unlock.
+//
+// A locked Mutex is not associated with a particular goroutine.
+// It is allowed for one goroutine to lock a Mutex and then
+// arrange for another goroutine to unlock it.
+func (m *TryMutex) Unlock() {
+ m.in.Unlock()
+}
+
+// TryLock tries to lock m. It returns true in case of success, false otherwise.
+func (m *TryMutex) TryLock() bool {
+ return atomic.CompareAndSwapInt32((*int32)(unsafe.Pointer(&m.in)), 0, mutexLocked)
+}
+
+// TryLockTimeout tries to lock m at a certain frequency for a certain period of time.
+// It returns true in case of success, false otherwise.
+func (m *TryMutex) TryLockTimeout(timeout int, frequency int) bool {
+ if timeout <= 0 {
+ m.Lock()
+ return true
+ } else {
+ timer := time.After(time.Second * time.Duration(timeout))
+ result := false
+ for {
+ select {
+ case <-timer:
+ return result
+ default:
+ }
+ result = atomic.CompareAndSwapInt32((*int32)(unsafe.Pointer(&m.in)), 0, mutexLocked)
+ if result {
+ return result
+ }
+ time.Sleep(time.Millisecond * time.Duration(frequency))
+ }
+ }
+}
--
2.17.1

View File

@ -0,0 +1,31 @@
From 9e05ad46f060ab47559cd1566a95ec579fbc08ac Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:18:35 +0800
Subject: [PATCH 019/111] dfx: print container name and id when create
done
reason:print container name and id when create done
Change-Id: I62932133c2a28e24adb54a40d16e2792a0772185
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/create.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/components/engine/daemon/create.go b/components/engine/daemon/create.go
index 1afb1bebea..565e9dc022 100644
--- a/components/engine/daemon/create.go
+++ b/components/engine/daemon/create.go
@@ -74,6 +74,7 @@ func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, manage
return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, err
}
containerActions.WithValues("create").UpdateSince(start)
+ logrus.Infof("Container create done(Name: %s ID: %s)", container.Name, container.ID)
return containertypes.ContainerCreateCreatedBody{ID: container.ID, Warnings: warnings}, nil
}
--
2.17.1

View File

@ -0,0 +1,441 @@
From b555ed1bb121b0740665fb0db9f7fea3b339f98c Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:22:22 +0800
Subject: [PATCH 020/111] cleanup: remove redundant files in
graphdriver and mount dir
reason:remove redundant files in graphdriver and mount dir
Change-Id: Ie75b78ac1e288d2c909dcd446636d16b1dd60363
Signed-off-by: yangshukui <yangshukui@huawei.com>
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/daemon.go | 28 ++++++-
.../engine/daemon/graphdriver/aufs/aufs.go | 5 ++
.../engine/daemon/graphdriver/btrfs/btrfs.go | 5 ++
.../daemon/graphdriver/devmapper/driver.go | 5 ++
.../engine/daemon/graphdriver/driver.go | 2 +
.../daemon/graphdriver/overlay/overlay.go | 5 ++
.../daemon/graphdriver/overlay2/overlay.go | 19 +++++
components/engine/daemon/graphdriver/proxy.go | 5 ++
.../engine/daemon/graphdriver/vfs/driver.go | 5 ++
.../engine/daemon/graphdriver/zfs/zfs.go | 5 ++
components/engine/daemon/images/service.go | 4 +
.../engine/distribution/xfer/download_test.go | 4 +
components/engine/layer/layer.go | 1 +
components/engine/layer/layer_store.go | 73 +++++++++++++++++++
components/engine/pkg/ioutils/fswriters.go | 36 +++++++++
components/engine/reference/store.go | 1 +
16 files changed, 201 insertions(+), 2 deletions(-)
diff --git a/components/engine/daemon/daemon.go b/components/engine/daemon/daemon.go
index f7635f27cc..4546587369 100644
--- a/components/engine/daemon/daemon.go
+++ b/components/engine/daemon/daemon.go
@@ -262,7 +262,15 @@ func (daemon *Daemon) restore() error {
id := v.Name()
container, err := daemon.load(id)
if err != nil {
- logrus.Errorf("Failed to load container %v: %v", id, err)
+ logrus.Errorf("Failed to load container %v: %v. Try to remove it", id, err)
+ cdir := filepath.Join(daemon.repository, id)
+ // to make sure we are not in fd exhausted state
+ if !strings.Contains(err.Error(), "too many open files") {
+ logrus.Warnf("remove invalid container data: %s", cdir)
+ if err := system.EnsureRemoveAll(cdir); err != nil {
+ logrus.Warnf("remove %s error: %v", cdir, err)
+ }
+ }
continue
}
if !system.IsOSSupported(container.OS) {
@@ -274,7 +282,12 @@ func (daemon *Daemon) restore() error {
if (container.Driver == "" && currentDriverForContainerOS == "aufs") || container.Driver == currentDriverForContainerOS {
rwlayer, err := daemon.imageService.GetLayerByID(container.ID, container.OS)
if err != nil {
- logrus.Errorf("Failed to load container mount %v: %v", id, err)
+ logrus.Errorf("Failed to load container mount %v: %v. Try to remove it", id, err)
+ cdir := filepath.Join(daemon.repository, id)
+ logrus.Warnf("remove invalid container data: %s", cdir)
+ if err := system.EnsureRemoveAll(cdir); err != nil {
+ logrus.Warnf("remove %s error: %v", cdir, err)
+ }
continue
}
container.RWLayer = rwlayer
@@ -472,6 +485,17 @@ func (daemon *Daemon) restore() error {
}(c)
}
wg.Wait()
+
+ containerIDs := make(map[string]struct{})
+ for cid, _ := range containers {
+ containerIDs[cid] = struct{}{}
+ }
+
+ err = daemon.imageService.LayerStoreForOS(runtime.GOOS).CleanupRedundant(containerIDs)
+ if err != nil {
+ logrus.Errorf("cleanup redundant IDs in layerStore failed %s", err)
+ }
+
daemon.netController, err = daemon.initNetworkController(daemon.configStore, activeSandboxes)
if err != nil {
return fmt.Errorf("Error initializing network controller: %v", err)
diff --git a/components/engine/daemon/graphdriver/aufs/aufs.go b/components/engine/daemon/graphdriver/aufs/aufs.go
index 114aa9a615..303138d48a 100644
--- a/components/engine/daemon/graphdriver/aufs/aufs.go
+++ b/components/engine/daemon/graphdriver/aufs/aufs.go
@@ -230,6 +230,11 @@ func (a *Driver) Exists(id string) bool {
return true
}
+// GetAll not implemented
+func (a *Driver) GetAll() []string {
+ return []string{}
+}
+
// CreateReadWrite creates a layer that is writable for use as a container
// file system.
func (a *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
diff --git a/components/engine/daemon/graphdriver/btrfs/btrfs.go b/components/engine/daemon/graphdriver/btrfs/btrfs.go
index 7ce7edef36..d04ce10be9 100644
--- a/components/engine/daemon/graphdriver/btrfs/btrfs.go
+++ b/components/engine/daemon/graphdriver/btrfs/btrfs.go
@@ -167,6 +167,11 @@ func (d *Driver) GetMetadata(id string) (map[string]string, error) {
return nil, nil
}
+// GetAll not implemented
+func (a *Driver) GetAll() []string {
+ return []string{}
+}
+
// Cleanup unmounts the home directory.
func (d *Driver) Cleanup() error {
err := d.subvolDisableQuota()
diff --git a/components/engine/daemon/graphdriver/devmapper/driver.go b/components/engine/daemon/graphdriver/devmapper/driver.go
index 623843f852..a56b26bc8f 100644
--- a/components/engine/daemon/graphdriver/devmapper/driver.go
+++ b/components/engine/daemon/graphdriver/devmapper/driver.go
@@ -126,6 +126,11 @@ func (d *Driver) GetMetadata(id string) (map[string]string, error) {
return metadata, nil
}
+// GetAll not implemented
+func (a *Driver) GetAll() []string {
+ return []string{}
+}
+
// Cleanup unmounts a device.
func (d *Driver) Cleanup() error {
err := d.DeviceSet.Shutdown(d.home)
diff --git a/components/engine/daemon/graphdriver/driver.go b/components/engine/daemon/graphdriver/driver.go
index a9e1957393..672257a9b5 100644
--- a/components/engine/daemon/graphdriver/driver.go
+++ b/components/engine/daemon/graphdriver/driver.go
@@ -78,6 +78,8 @@ type ProtoDriver interface {
// held by the driver, e.g., unmounting all layered filesystems
// known to this driver.
Cleanup() error
+ // GetAll returns all the mountid exists in this driver
+ GetAll() []string
}
// DiffDriver is the interface to use to implement graph diffs
diff --git a/components/engine/daemon/graphdriver/overlay/overlay.go b/components/engine/daemon/graphdriver/overlay/overlay.go
index 08c05e192f..d59a6dfc83 100644
--- a/components/engine/daemon/graphdriver/overlay/overlay.go
+++ b/components/engine/daemon/graphdriver/overlay/overlay.go
@@ -264,6 +264,11 @@ func (d *Driver) GetMetadata(id string) (map[string]string, error) {
return metadata, nil
}
+// GetAll not implemented
+func (a *Driver) GetAll() []string {
+ return []string{}
+}
+
// Cleanup any state created by overlay which should be cleaned when daemon
// is being shutdown. For now, we just have to unmount the bind mounted
// we had created.
diff --git a/components/engine/daemon/graphdriver/overlay2/overlay.go b/components/engine/daemon/graphdriver/overlay2/overlay.go
index b969582eb3..7290616bae 100644
--- a/components/engine/daemon/graphdriver/overlay2/overlay.go
+++ b/components/engine/daemon/graphdriver/overlay2/overlay.go
@@ -507,6 +507,25 @@ func (d *Driver) dir(id string) string {
return path.Join(d.home, id)
}
+func (d *Driver) GetAll() []string {
+ var ids []string
+
+ fs, err := ioutil.ReadDir(d.home)
+ if err != nil {
+ logrus.Errorf("open directory(%s) failed: %s", d.home, err)
+ return ids
+ }
+
+ for _, f := range fs {
+ if len(f.Name()) >= 64 {
+ ids = append(ids, f.Name())
+ }
+ }
+
+ return ids
+
+}
+
func (d *Driver) getLowerDirs(id string) ([]string, error) {
var lowersArray []string
lowers, err := ioutil.ReadFile(path.Join(d.dir(id), lowerFile))
diff --git a/components/engine/daemon/graphdriver/proxy.go b/components/engine/daemon/graphdriver/proxy.go
index cb350d8074..6c132d40a8 100644
--- a/components/engine/daemon/graphdriver/proxy.go
+++ b/components/engine/daemon/graphdriver/proxy.go
@@ -91,6 +91,11 @@ func (d *graphDriverProxy) Capabilities() Capabilities {
return d.caps
}
+// GetAll not implemented
+func (d *graphDriverProxy) GetAll() []string {
+ return []string{}
+}
+
func (d *graphDriverProxy) CreateReadWrite(id, parent string, opts *CreateOpts) error {
return d.create("GraphDriver.CreateReadWrite", id, parent, opts)
}
diff --git a/components/engine/daemon/graphdriver/vfs/driver.go b/components/engine/daemon/graphdriver/vfs/driver.go
index 33e6bf6cc9..8c2947d9ee 100644
--- a/components/engine/daemon/graphdriver/vfs/driver.go
+++ b/components/engine/daemon/graphdriver/vfs/driver.go
@@ -64,6 +64,11 @@ func (d *Driver) GetMetadata(id string) (map[string]string, error) {
return nil, nil
}
+// GetAll not implemented
+func (a *Driver) GetAll() []string {
+ return []string{}
+}
+
// Cleanup is used to implement graphdriver.ProtoDriver. There is no cleanup required for this driver.
func (d *Driver) Cleanup() error {
return nil
diff --git a/components/engine/daemon/graphdriver/zfs/zfs.go b/components/engine/daemon/graphdriver/zfs/zfs.go
index 8a798778d2..e1e2d0d823 100644
--- a/components/engine/daemon/graphdriver/zfs/zfs.go
+++ b/components/engine/daemon/graphdriver/zfs/zfs.go
@@ -227,6 +227,11 @@ func (d *Driver) GetMetadata(id string) (map[string]string, error) {
}, nil
}
+// GetAll not implemented
+func (a *Driver) GetAll() []string {
+ return []string{}
+}
+
func (d *Driver) cloneFilesystem(name, parentName string) error {
snapshotName := fmt.Sprintf("%d", time.Now().Nanosecond())
parentDataset := zfs.Dataset{Name: parentName}
diff --git a/components/engine/daemon/images/service.go b/components/engine/daemon/images/service.go
index e8df5cb649..8d187e2603 100644
--- a/components/engine/daemon/images/service.go
+++ b/components/engine/daemon/images/service.go
@@ -177,6 +177,10 @@ func (i *ImageService) GraphDriverForOS(os string) string {
return i.layerStores[os].DriverName()
}
+func (i *ImageService) LayerStoreForOS(os string) layer.Store {
+ return i.layerStores[os]
+}
+
// ReleaseLayer releases a layer allowing it to be removed
// called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport()
func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer, containerOS string) error {
diff --git a/components/engine/distribution/xfer/download_test.go b/components/engine/distribution/xfer/download_test.go
index 4ab3705af6..91153591ed 100644
--- a/components/engine/distribution/xfer/download_test.go
+++ b/components/engine/distribution/xfer/download_test.go
@@ -150,6 +150,10 @@ func (ls *mockLayerStore) DriverStatus() [][2]string {
return [][2]string{}
}
+func (ls *mockLayerStore) CleanupRedundant(cids map[string]struct{}) error {
+ return nil
+}
+
func (ls *mockLayerStore) DriverName() string {
return "mock"
}
diff --git a/components/engine/layer/layer.go b/components/engine/layer/layer.go
index d0c7fa8608..425006854d 100644
--- a/components/engine/layer/layer.go
+++ b/components/engine/layer/layer.go
@@ -193,6 +193,7 @@ type Store interface {
Cleanup() error
DriverStatus() [][2]string
DriverName() string
+ CleanupRedundant(map[string]struct{}) error
}
// DescribableStore represents a layer store capable of storing
diff --git a/components/engine/layer/layer_store.go b/components/engine/layer/layer_store.go
index bc3e8719fc..6a568e9d9b 100644
--- a/components/engine/layer/layer_store.go
+++ b/components/engine/layer/layer_store.go
@@ -5,6 +5,7 @@ import (
"fmt"
"io"
"io/ioutil"
+ "strings"
"sync"
"github.com/docker/distribution"
@@ -460,6 +461,78 @@ func (ls *layerStore) releaseLayer(l *roLayer) ([]Metadata, error) {
}
}
+// CleanupRedundant will cleanup useless dirs in image/mount and driver
+func (ls *layerStore) CleanupRedundant(cs map[string]struct{}) error {
+ cids, err := ls.getAndCleanCacheIDs(cs)
+ if err != nil {
+ return fmt.Errorf("get cacheIDs failed: %s", err)
+ }
+
+ ids := ls.driver.GetAll()
+
+ for _, id := range ids {
+ if _, ok := cids[id]; !ok {
+ logrus.Warnf("remove redundant cacheID: %s", id)
+ ls.driver.Remove(id)
+ }
+ }
+ return nil
+}
+
+func (ls *layerStore) getAndCleanCacheIDs(cs map[string]struct{}) (map[string]struct{}, error) {
+ cids := make(map[string]struct{})
+
+ ids, mountids, err := ls.store.List()
+ if err != nil {
+ return cids, fmt.Errorf("failed to get mount list from store: %s", err)
+ }
+
+ for _, id := range ids {
+ cid, err := ls.store.GetCacheID(id)
+ if err != nil {
+ logrus.Errorf("failed to get cache id for %s: %s", id, err)
+ // just return if we are not in fd exhausted state
+ if strings.Contains(err.Error(), "too many open files") {
+ return cids, err
+ }
+ continue
+ }
+ cids[cid] = struct{}{}
+ }
+
+ for _, mid := range mountids {
+ // if mid not exist in current container list, just remove it
+ if _, ok := cs[mid]; !ok {
+ logrus.Warnf("remove redundant mountID: %s", mid)
+ ls.store.RemoveMount(mid)
+ continue
+ }
+ mountID, err := ls.store.GetMountID(mid)
+ if err != nil {
+ logrus.Errorf("failed to get mount id for %s: %s", mid, err)
+ // just return if we are not in fd exhausted state
+ if strings.Contains(err.Error(), "too many open files") {
+ return cids, err
+ }
+ } else {
+ cids[mountID] = struct{}{}
+ }
+
+ initID, err := ls.store.GetInitID(mid)
+ if err != nil {
+ logrus.Errorf("failed to get init id for %s: %s", mid, err)
+ // just return if we are not in fd exhausted state
+ if strings.Contains(err.Error(), "too many open files") {
+ return cids, err
+ }
+ continue
+ }
+ cids[initID] = struct{}{}
+ }
+
+ return cids, nil
+}
+
func (ls *layerStore) Release(l Layer) ([]Metadata, error) {
ls.layerL.Lock()
defer ls.layerL.Unlock()
diff --git a/components/engine/pkg/ioutils/fswriters.go b/components/engine/pkg/ioutils/fswriters.go
index 534d66ac26..093f11ad8e 100644
--- a/components/engine/pkg/ioutils/fswriters.go
+++ b/components/engine/pkg/ioutils/fswriters.go
@@ -5,6 +5,9 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "strings"
+
+ "github.com/sirupsen/logrus"
)
// NewAtomicFileWriter returns WriteCloser so that writing to it writes to a
@@ -27,6 +30,39 @@ func NewAtomicFileWriter(filename string, perm os.FileMode) (io.WriteCloser, err
}, nil
}
+func CleanupTmpFilesRecursive(rootDir string) {
+ var removals []string
+ filepath.Walk(rootDir, func(path string, f os.FileInfo, err error) error {
+ if strings.HasPrefix(f.Name(), ".tmp-") {
+ removals = append(removals, path)
+ }
+ return nil
+ })
+
+ for _, r := range removals {
+ os.RemoveAll(r)
+ }
+}
+
+// CleanupAtomicFile cleanup redundant atomic files
+func CleanupAtomicFile(filename string) error {
+ baseName := ".tmp-" + filepath.Base(filename)
+ dir := filepath.Dir(filename)
+ fs, err := ioutil.ReadDir(dir)
+ if err != nil {
+ logrus.Errorf("open directory(%s) failed: %s", dir, err)
+ return err
+ }
+
+ for _, f := range fs {
+ if strings.Contains(f.Name(), baseName) {
+ logrus.Warnf("Remove temporary file: %s", filepath.Join(dir, f.Name()))
+ os.RemoveAll(filepath.Join(dir, f.Name()))
+ }
+ }
+ return nil
+}
+
// AtomicWriteFile atomically writes data to a file named by filename.
func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error {
f, err := NewAtomicFileWriter(filename, perm)
diff --git a/components/engine/reference/store.go b/components/engine/reference/store.go
index b01051bf58..e54f772b5e 100644
--- a/components/engine/reference/store.go
+++ b/components/engine/reference/store.go
@@ -81,6 +81,7 @@ func NewReferenceStore(jsonPath string) (Store, error) {
Repositories: make(map[string]repository),
referencesByIDCache: make(map[digest.Digest]map[string]reference.Named),
}
+ ioutils.CleanupAtomicFile(abspath)
// Load the json file if it exists, otherwise create it.
if err := store.reload(); os.IsNotExist(err) {
if err := store.save(); err != nil {
--
2.17.1

View File

@ -0,0 +1,125 @@
From 79b46d05b185bf8df96cabb2a121186cd2f121c3 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:22:35 +0800
Subject: [PATCH 021/111] umask: support specify umask
reason: support specify umask.
Umask can be 0022 or 0027(default) by specify umask when
start container by command `docker create/run` or start
daemon by command `dockerd`. For example:
$ dockerd --annotation native.umask=normal
$ dockerd --annotation native.umask=secure
$ docker run --exec-opt native.umask=normal
$ docker run --exec-opt native.umask=secure
`normal` reparent umask is 0022, `secure`
reparent umask is 0027.
Change-Id: Iba07a884b733b411e5268d7ecaa22b9aa327ac3c
Signed-off-by: wangfengtu <wangfengtu@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/create.go | 21 +++++++++++++++-
components/engine/daemon/daemon_unix.go | 33 +++++++++++++++++++++++++
2 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/components/engine/daemon/create.go b/components/engine/daemon/create.go
index 565e9dc022..fa000c2208 100644
--- a/components/engine/daemon/create.go
+++ b/components/engine/daemon/create.go
@@ -79,6 +79,22 @@ func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, manage
return containertypes.ContainerCreateCreatedBody{ID: container.ID, Warnings: warnings}, nil
}
+func (daemon *Daemon) setUmask(c *containertypes.Config) error {
+ // Use option native.umask passed by command create/run if specified,
+ // otherwise use daemon's native.umask option.
+ if val, ok := c.Annotations["native.umask"]; ok {
+ if val != umaskNormal && val != umaskSecure {
+ return fmt.Errorf("native.umask option %s not supported", val)
+ }
+ } else if UsingNormalUmask(daemon.configStore) {
+ c.Annotations["native.umask"] = umaskNormal
+ } else {
+ c.Annotations["native.umask"] = umaskSecure
+ }
+
+ return nil
+}
+
// Create creates a new container from the given configuration with a given name.
func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (retC *container.Container, retErr error) {
var (
@@ -162,8 +178,11 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
}
container.RWLayer = rwLayer
- rootIDs := daemon.idMapping.RootPair()
+ if err := daemon.setUmask(params.Config); err != nil {
+ return nil, err
+ }
+ rootIDs := daemon.idMapping.RootPair()
if err := idtools.MkdirAndChown(container.Root, 0700, rootIDs); err != nil {
return nil, err
}
diff --git a/components/engine/daemon/daemon_unix.go b/components/engine/daemon/daemon_unix.go
index 5b390d2db1..8ffdd0009a 100644
--- a/components/engine/daemon/daemon_unix.go
+++ b/components/engine/daemon/daemon_unix.go
@@ -77,6 +77,10 @@ const (
// DefaultRuntimeName is the default runtime to be used by
// containerd if none is specified
DefaultRuntimeName = "runc"
+
+ // constant for umasks in containers. normal: 0022, secure(default): 0027
+ umaskNormal = "normal"
+ umaskSecure = "secure"
)
type containerGetter interface {
@@ -581,6 +585,32 @@ func UsingSystemd(config *config.Config) bool {
return getCD(config) == cgroupSystemdDriver
}
+// getUmask gets the raw value of the native.umask option, if set.
+func getUmask(config *config.Config) string {
+ for _, option := range config.ExecOptions {
+ key, val, err := parsers.ParseKeyValueOpt(option)
+ if err != nil || !strings.EqualFold(key, "native.umask") {
+ continue
+ }
+ return val
+ }
+ return ""
+}
+
+// VerifyNativeUmask validates native.umask
+func VerifyNativeUmask(config *config.Config) error {
+ umask := getUmask(config)
+ if umask == "" || umask == umaskNormal || umask == umaskSecure {
+ return nil
+ }
+ return fmt.Errorf("native.umask option %s not supported", umask)
+}
+
+// UsingNormalUmask returns true if cli option includes native.umask=normal
+func UsingNormalUmask(config *config.Config) bool {
+ return getUmask(config) == umaskNormal
+}
+
// verifyPlatformContainerSettings performs platform-specific validation of the
// hostconfig and config structures.
func (daemon *Daemon) verifyPlatformContainerSettings(hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
@@ -737,6 +767,9 @@ func verifyDaemonSettings(conf *config.Config) error {
return fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
}
}
+ if err := VerifyNativeUmask(conf); err != nil {
+ return err
+ }
if conf.DefaultRuntime == "" {
conf.DefaultRuntime = config.StockRuntimeName
--
2.17.1

View File

@ -0,0 +1,42 @@
From 412b8a34a2aa40ddf6f9b507142c4793922cedf5 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 11:22:46 +0800
Subject: [PATCH 022/111] umask: fix nil pointer on c.Annotations in
setUmask
reason: c.Annotations should be check before using in setUmask().
When "/create" request is sent via restful api, the c.Annotations
is nil, so **nil map** happens in setUmask.
Change-Id: Idafa2d8d1f54c1ebc34a6380d64c1cd7efad0266
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/create.go | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/components/engine/daemon/create.go b/components/engine/daemon/create.go
index fa000c2208..b57b01eacc 100644
--- a/components/engine/daemon/create.go
+++ b/components/engine/daemon/create.go
@@ -86,10 +86,15 @@ func (daemon *Daemon) setUmask(c *containertypes.Config) error {
if val != umaskNormal && val != umaskSecure {
return fmt.Errorf("native.umask option %s not supported", val)
}
- } else if UsingNormalUmask(daemon.configStore) {
- c.Annotations["native.umask"] = umaskNormal
} else {
- c.Annotations["native.umask"] = umaskSecure
+ if c.Annotations == nil {
+ c.Annotations = make(map[string]string)
+ }
+ if UsingNormalUmask(daemon.configStore) {
+ c.Annotations["native.umask"] = umaskNormal
+ } else {
+ c.Annotations["native.umask"] = umaskSecure
+ }
}
return nil
--
2.17.1

View File

@ -0,0 +1,65 @@
From d864d32460063a25ef5a408c596b40555a062646 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 15:02:39 +0800
Subject: [PATCH 023/111] prjquota: fix syscall bugs in projectquota
reason: fix syscall bugs in projectquota, which is introduced
when cherry-picked.
Change-Id: I4496f2b8fcdcd16eb34584b435a9ef9434639cee
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
.../engine/daemon/graphdriver/quota/projectquota.go | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/components/engine/daemon/graphdriver/quota/projectquota.go b/components/engine/daemon/graphdriver/quota/projectquota.go
index 7d879eb81d..7f2fa2fe70 100644
--- a/components/engine/daemon/graphdriver/quota/projectquota.go
+++ b/components/engine/daemon/graphdriver/quota/projectquota.go
@@ -79,7 +79,6 @@ import (
"path"
"path/filepath"
"sync"
- "syscall"
"unsafe"
rsystem "github.com/opencontainers/runc/libcontainer/system"
@@ -234,7 +233,7 @@ func (q *Control) SetQuota(targetPath string, quota Quota) error {
//
err := setProjectID(targetPath, projectID)
if err != nil {
- q.lock.Lock()
+ q.lock.Unlock()
return err
}
@@ -312,7 +311,7 @@ func (q *Ext4Quota) SetProjectQuota(backingFsBlockDev string, projectID uint32,
var cs = C.CString(backingFsBlockDev)
defer C.free(unsafe.Pointer(cs))
- _, _, errno := syscall.Syscall6(syscall.SYS_QUOTACTL, C.Q_SETPQUOTA,
+ _, _, errno := unix.Syscall6(unix.SYS_QUOTACTL, C.Q_SETPQUOTA,
uintptr(unsafe.Pointer(cs)), uintptr(C.__u32(projectID)),
uintptr(unsafe.Pointer(&d)), 0, 0)
if errno != 0 {
@@ -330,7 +329,7 @@ func (q *Ext4Quota) GetProjectQuota(backingFsBlockDev string, projectID uint32,
var cs = C.CString(backingFsBlockDev)
defer C.free(unsafe.Pointer(cs))
- _, _, errno := syscall.Syscall6(syscall.SYS_QUOTACTL, C.Q_SETPQUOTA,
+ _, _, errno := unix.Syscall6(unix.SYS_QUOTACTL, C.Q_GETPQUOTA,
uintptr(unsafe.Pointer(cs)), uintptr(C.__u32(projectID)),
uintptr(unsafe.Pointer(&d)), 0, 0)
if errno != 0 {
@@ -350,7 +349,7 @@ func getQuotaStat(backingFsBlockDev string) (int, error) {
var cs = C.CString(backingFsBlockDev)
defer C.free(unsafe.Pointer(cs))
- _, _, errno := syscall.Syscall6(syscall.SYS_QUOTACTL, C.Q_XGETPQSTAT,
+ _, _, errno := unix.Syscall6(unix.SYS_QUOTACTL, C.Q_XGETPQSTAT,
uintptr(unsafe.Pointer(cs)), 0,
uintptr(unsafe.Pointer(&info)), 0, 0)
if errno != 0 {
--
2.17.1

View File

@ -0,0 +1,51 @@
From 3de51170031133bcd8d6aefe022d3fd26287c8c0 Mon Sep 17 00:00:00 2001
From: leizhongkai <leizhongkai@huawei.com>
Date: Sat, 19 Jan 2019 16:45:43 +0800
Subject: [PATCH 024/111] runtime-spec: Compatibility modifications
for runc-1.0.0-rc3 about `struct LinuxBlockIO`
reason:Compatibility modifications for runc-1.0.0-rc3 about `struct LinuxBlockIO`
Change-Id: If2389709d4639b5e9d61a9b853a8f220ef6e3884
Signed-off-by: leizhongkai <leizhongkai@huawei.com>
---
.../runtime-spec/specs-go/config.go | 18 +++++++++---------
2 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
index 46049b3bfa..aab7b8a098 100644
--- a/components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
+++ b/components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
@@ -256,20 +256,20 @@ type LinuxThrottleDevice struct {
// LinuxBlockIO for Linux cgroup 'blkio' resource management
type LinuxBlockIO struct {
- // Specifies per cgroup weight
- Weight *uint16 `json:"weight,omitempty"`
- // Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, CFQ scheduler only
- LeafWeight *uint16 `json:"leafWeight,omitempty"`
+ // Specifies per cgroup weight, range is from 10 to 1000
+ Weight *uint16 `json:"blkioWeight,omitempty"`
+ // Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only
+ LeafWeight *uint16 `json:"blkioLeafWeight,omitempty"`
// Weight per cgroup per device, can override BlkioWeight
- WeightDevice []LinuxWeightDevice `json:"weightDevice,omitempty"`
+ WeightDevice []LinuxWeightDevice `json:"blkioWeightDevice,omitempty"`
// IO read rate limit per cgroup per device, bytes per second
- ThrottleReadBpsDevice []LinuxThrottleDevice `json:"throttleReadBpsDevice,omitempty"`
+ ThrottleReadBpsDevice []LinuxThrottleDevice `json:"blkioThrottleReadBpsDevice,omitempty"`
// IO write rate limit per cgroup per device, bytes per second
- ThrottleWriteBpsDevice []LinuxThrottleDevice `json:"throttleWriteBpsDevice,omitempty"`
+ ThrottleWriteBpsDevice []LinuxThrottleDevice `json:"blkioThrottleWriteBpsDevice,omitempty"`
// IO read rate limit per cgroup per device, IO per second
- ThrottleReadIOPSDevice []LinuxThrottleDevice `json:"throttleReadIOPSDevice,omitempty"`
+ ThrottleReadIOPSDevice []LinuxThrottleDevice `json:"blkioThrottleReadIOPSDevice,omitempty"`
// IO write rate limit per cgroup per device, IO per second
- ThrottleWriteIOPSDevice []LinuxThrottleDevice `json:"throttleWriteIOPSDevice,omitempty"`
+ ThrottleWriteIOPSDevice []LinuxThrottleDevice `json:"blkioThrottleWriteIOPSDevice,omitempty"`
}
// LinuxMemory for Linux cgroup 'memory' resource management
--
2.17.1

View File

@ -0,0 +1,44 @@
From d0625f253c9cfd62e043f1799b9f9c2a0e2fdb21 Mon Sep 17 00:00:00 2001
From: caihaomin <caihaomin@huawei.com>
Date: Sun, 20 Jan 2019 13:59:45 +0800
Subject: [PATCH 025/111] resource-limit: enable unlimited usage of
memory compoents
reason:enable unlimited usage of memory compoents
Change-Id: I24871d1b2ef1fe20277d5e5c721d1297fa5fd6cf
Signed-off-by: caihaomin <caihaomin@huawei.com>
---
components/engine/container/container_unix.go | 2 +-
components/engine/daemon/update_linux.go | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/components/engine/container/container_unix.go b/components/engine/container/container_unix.go
index ed664f3eec..5a21b8c483 100644
--- a/components/engine/container/container_unix.go
+++ b/components/engine/container/container_unix.go
@@ -323,7 +323,7 @@ func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfi
if resources.Memory != 0 {
// if memory limit smaller than already set memoryswap limit and doesn't
// update the memoryswap limit, then error out.
- if resources.Memory > cResources.MemorySwap && resources.MemorySwap == 0 {
+ if cResources.MemorySwap > 0 && resources.Memory > cResources.MemorySwap && resources.MemorySwap == 0 {
return conflictingUpdateOptions("Memory limit should be smaller than already set memoryswap limit, update the memoryswap at the same time")
}
cResources.Memory = resources.Memory
diff --git a/components/engine/daemon/update_linux.go b/components/engine/daemon/update_linux.go
index 6a307eabc5..1a6f070b82 100644
--- a/components/engine/daemon/update_linux.go
+++ b/components/engine/daemon/update_linux.go
@@ -46,7 +46,7 @@ func toContainerdResources(resources container.Resources) *libcontainerd.Resourc
Kernel: &resources.KernelMemory,
}
- if resources.MemorySwap > 0 {
+ if resources.MemorySwap != 0 {
r.Memory.Swap = &resources.MemorySwap
}
--
2.17.1

View File

@ -0,0 +1,37 @@
From 0ff4db1fc19ecb6f9dedfaa8d0645a638bb7ab20 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Sat, 19 Jan 2019 17:53:59 +0800
Subject: [PATCH 026/111] prjquota: use dockerd quota size when
docker not specifies
reason: if docker run not specifies quota size but dockerd has default
size, we should use the default value in dockerd.
EulerOS docker 1.11.2 and 17.06 has the same logic. But now, if docker
create/run not give --storage-opt, it will panic during parseStorageOpt, so
updating the handling logic.
Change-Id: I52141c7f1caf5a2a4cbd9c00fbe709f09f7a412b
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
.../engine/daemon/graphdriver/overlay2/overlay.go | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/components/engine/daemon/graphdriver/overlay2/overlay.go b/components/engine/daemon/graphdriver/overlay2/overlay.go
index 7290616bae..722d65b11a 100644
--- a/components/engine/daemon/graphdriver/overlay2/overlay.go
+++ b/components/engine/daemon/graphdriver/overlay2/overlay.go
@@ -406,6 +406,11 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
return err
}
}
+ } else if d.options.quota.Size > 0 {
+ // docker run not specified quota size, but dockerd does, so limits it also
+ if err := d.quotaCtl.SetQuota(dir, d.options.quota); err != nil {
+ return err
+ }
}
if err := idtools.MkdirAndChown(path.Join(dir, "diff"), 0755, root); err != nil {
--
2.17.1

View File

@ -0,0 +1,30 @@
From 5370b3b9f2f4adfc10bbc3db5903b1a23e13f6c2 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 9 Jan 2019 00:37:17 +0800
Subject: [PATCH 027/111] oci: add files_panic_enable to masked path
reason: cherry-pick commits to docker-18.09
reason:add files_panic_enable to masked path
Change-Id: I3d6fb04a1063f64ad52e40cb5debf21c301d829c
Signed-off-by: xiadanni <xiadanni@huawei.com>
---
components/engine/oci/defaults.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/components/engine/oci/defaults.go b/components/engine/oci/defaults.go
index 5e17ea3f38..e39140b47f 100644
--- a/components/engine/oci/defaults.go
+++ b/components/engine/oci/defaults.go
@@ -123,6 +123,7 @@ func DefaultLinuxSpec() specs.Spec {
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
+ "/proc/files_panic_enable",
"/sys/firmware",
},
ReadonlyPaths: []string{
--
2.17.1

View File

@ -0,0 +1,34 @@
From f81a87edbeb1ddc58d48d36c963f76f0ed6cc04f Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 9 Jan 2019 00:40:29 +0800
Subject: [PATCH 028/111] oci: add fdenable fdstat and fdthreshold to
masked path
reason: cherry-pick commits to docker-18.09
reason:add fdenable fdstat and fdthreshold to masked path
Change-Id: I7b39a4ad9b989ef4b8185e386aa70c2d638efcd9
Signed-off-by: caihaomin <caihaomin@huawei.com>
Signed-off-by: xiadanni <xiadanni@huawei.com>
---
components/engine/oci/defaults.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/components/engine/oci/defaults.go b/components/engine/oci/defaults.go
index e39140b47f..de0088c4bb 100644
--- a/components/engine/oci/defaults.go
+++ b/components/engine/oci/defaults.go
@@ -124,6 +124,9 @@ func DefaultLinuxSpec() specs.Spec {
"/proc/sched_debug",
"/proc/scsi",
"/proc/files_panic_enable",
+ "/proc/fdthreshold",
+ "/proc/fdstat",
+ "/proc/fdenable",
"/sys/firmware",
},
ReadonlyPaths: []string{
--
2.17.1

View File

@ -0,0 +1,43 @@
From fe4522af7f1c5dadfeaf8513dd584c66854d612b Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 9 Jan 2019 00:43:55 +0800
Subject: [PATCH 029/111] oci: add oom_extend to proc masked path
reason: cherry-pick commits to docker-18.09
reason:add oom_extend to proc masked path
Change-Id: I4b9c3dd94b6d68d753e9aad0879949b310fe7180
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
Signed-off-by: Haomin <caihaomin@huawei.com>
Signed-off-by: xiadanni <xiadanni@huawei.com>
---
components/engine/oci/defaults.go | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/components/engine/oci/defaults.go b/components/engine/oci/defaults.go
index de0088c4bb..74d3fdb2d8 100644
--- a/components/engine/oci/defaults.go
+++ b/components/engine/oci/defaults.go
@@ -116,6 +116,7 @@ func DefaultLinuxSpec() specs.Spec {
s.Linux = &specs.Linux{
MaskedPaths: []string{
"/proc/acpi",
+ "/proc/config.gz",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
@@ -127,6 +128,10 @@ func DefaultLinuxSpec() specs.Spec {
"/proc/fdthreshold",
"/proc/fdstat",
"/proc/fdenable",
+ "/proc/signo",
+ "/proc/sig_catch",
+ "/proc/kbox",
+ "/proc/oom_extend",
"/sys/firmware",
},
ReadonlyPaths: []string{
--
2.17.1

View File

@ -0,0 +1,34 @@
From 1e9ad6a48e283bcc9850fb1439bf0be6be805010 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 9 Jan 2019 00:49:35 +0800
Subject: [PATCH 030/111] restart: fix docker stats blocked while
docker daemon restart
reason: cherry-pick commits to docker-18.09
change closeChan channel from non-buffered channel to 2-buffered channel,
because non-blocked channel will be blocked while docker daemon restart
Change-Id: Ica5dbefc85e463836b55e5d96da522a64a259f64
Signed-off-by: jiangpengfei9 <jiangpengfei9@huawei.com>
Signed-off-by: xiadanni <xiadanni@huawei.com>
---
components/cli/cli/command/container/stats.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/components/cli/cli/command/container/stats.go b/components/cli/cli/command/container/stats.go
index 4efcb19e65..1f9e1b8556 100644
--- a/components/cli/cli/command/container/stats.go
+++ b/components/cli/cli/command/container/stats.go
@@ -53,7 +53,7 @@ func NewStatsCommand(dockerCli command.Cli) *cobra.Command {
// nolint: gocyclo
func runStats(dockerCli command.Cli, opts *statsOptions) error {
showAll := len(opts.containers) == 0
- closeChan := make(chan error)
+ closeChan := make(chan error, 2)
ctx := context.Background()
--
2.17.1

View File

@ -0,0 +1,66 @@
From 6da7401bff6b59e59f04323fcf2f88115f38ede8 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 9 Jan 2019 16:33:11 +0800
Subject: [PATCH 031/111] restart: Incase deadlock when kill the docker
CLI and restart
reason: cherry-pick commits to docker-18.09
the docker daemon is in created stage and last long time, then kill
the docker cli and restart docker at the same time, the restart stage will trylock,
because the created stage already locked.
cherry-pick from 1.11.2: 3082432
the testcase testCE_container_resourced_cpuiso_ABN.023.sh
current_dir=$(cd `dirname $0` && pwd)
source ${COMMON_DIR}/commonlib.sh
source ${current_dir}/../common/container_resourced_commonlib.sh
resource_managerd_env
work_dir=`mktemp -d /tmp/testCE_container_resourced_cpuiso_ABN_005.XXXX`
bind_cpu=1
resource_pid=`ps axu |grep resource-managerd |grep -v grep|awk '{print $2}'`
service container-resourced stop
service container-resourced start & kill -9 $!
container_id=`timeout 10 docker run -itd --hook-spec /etc/docker/resource-hook.json --cpuset-cpus $bind_cpu -e ISOLATION_CORES=$bind_cpu $ubuntu_image bash &`
timeout 10 docker restart $container_id
fn_check_result_noeq $? 0
resource_managerd_env
docker restart $container_id
fn_check_result $? 0
test_cpuset $container_id
docker rm -f $container_id
rm -rf $work_dir
kill_resource_managerd
exit $exit_flag
Conflicts:
daemon/restart.go
Change-Id: I571f109dc07a7e76df40c544008a97cd497ef8bb
Signed-off-by: panwenxiang <panwenxiang@huawei.com>
Signed-off-by: lixiang172 <lixiang172@huawei.com>
---
components/engine/daemon/restart.go | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/components/engine/daemon/restart.go b/components/engine/daemon/restart.go
index 0f06dea267..bae665f76b 100644
--- a/components/engine/daemon/restart.go
+++ b/components/engine/daemon/restart.go
@@ -41,7 +41,10 @@ func (daemon *Daemon) containerRestart(container *container.Container, seconds i
defer daemon.Unmount(container)
}
- if container.IsRunning() {
+ if container.RemovalInProgress || container.Dead {
+ return fmt.Errorf("can't restart a container which is dead or marked for removal")
+ }
+ if container.Running {
// set AutoRemove flag to false before stop so the container won't be
// removed during restart process
autoRemove := container.HostConfig.AutoRemove
--
2.17.1

View File

@ -0,0 +1,254 @@
From e22807e3972f1c168e596fa95a97e2730024824c Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 3 Jan 2019 10:20:44 +0800
Subject: [PATCH 032/111] devmapper: Add udev event time out to fix
docker stuck on udev wait
reason: cherry-pick commits to docker-18.09
Add udev event time out to fix docker stuck on udev wait
Change-Id: I47505140699c0a51f37f4127b761f2a99930466d
Signed-off-by: jingrui <jingrui@huawei.com>
---
.../daemon/graphdriver/devmapper/deviceset.go | 28 ++++++---
.../engine/pkg/devicemapper/devmapper.go | 57 +++++++++++++------
.../pkg/devicemapper/devmapper_wrapper.go | 5 ++
3 files changed, 66 insertions(+), 24 deletions(-)
diff --git a/components/engine/daemon/graphdriver/devmapper/deviceset.go b/components/engine/daemon/graphdriver/devmapper/deviceset.go
index 5dc01d71d9..af53cf83e6 100644
--- a/components/engine/daemon/graphdriver/devmapper/deviceset.go
+++ b/components/engine/daemon/graphdriver/devmapper/deviceset.go
@@ -35,13 +35,16 @@ import (
)
var (
- defaultDataLoopbackSize int64 = 100 * 1024 * 1024 * 1024
- defaultMetaDataLoopbackSize int64 = 2 * 1024 * 1024 * 1024
- defaultBaseFsSize uint64 = 10 * 1024 * 1024 * 1024
- defaultThinpBlockSize uint32 = 128 // 64K = 128 512b sectors
- defaultUdevSyncOverride = false
- maxDeviceID = 0xffffff // 24 bit, pool limit
- deviceIDMapSz = (maxDeviceID + 1) / 8
+ defaultDataLoopbackSize int64 = 100 * 1024 * 1024 * 1024
+ defaultMetaDataLoopbackSize int64 = 2 * 1024 * 1024 * 1024
+ defaultBaseFsSize uint64 = 10 * 1024 * 1024 * 1024
+ defaultThinpBlockSize uint32 = 128 // 64K = 128 512b sectors
+ defaultUdevSyncOverride = false
+ maxDeviceID = 0xffffff // 24 bit, pool limit
+ deviceIDMapSz = (maxDeviceID + 1) / 8
+ // The default timeout is 30s from `man systemd-udevd`, we use 35
+ // just to make sure the timeout really happened in systemd-udevd
+ defaultUdevWaitTimeout = 35
driverDeferredRemovalSupport = false
enableDeferredRemoval = false
enableDeferredDeletion = false
@@ -2059,7 +2062,9 @@ func (devices *DeviceSet) issueDiscard(info *devInfo) error {
// Should be called with devices.Lock() held.
func (devices *DeviceSet) deleteDevice(info *devInfo, syncDelete bool) error {
if devices.doBlkDiscard {
- devices.issueDiscard(info)
+ if err := devices.issueDiscard(info); err != nil {
+ return err
+ }
}
// Try to deactivate device in case it is active.
@@ -2651,6 +2656,7 @@ func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps [
foundBlkDiscard := false
var lvmSetupConfig directLVMConfig
+ udevWaitTimeout := int64(defaultUdevWaitTimeout)
for _, option := range options {
key, val, err := parsers.ParseKeyValueOpt(option)
if err != nil {
@@ -2800,10 +2806,16 @@ func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps [
devicemapper.LogInit(devicemapper.DefaultLogger{
Level: int(level),
})
+ case "dm.udev_wait_timeout":
+ udevWaitTimeout, err = strconv.ParseInt(val, 10, 32)
+ if err != nil {
+ return nil, err
+ }
default:
return nil, fmt.Errorf("devmapper: Unknown option %s", key)
}
}
+ devicemapper.SetUdevWaitTimtout(udevWaitTimeout)
if err := validateLVMConfig(lvmSetupConfig); err != nil {
return nil, err
diff --git a/components/engine/pkg/devicemapper/devmapper.go b/components/engine/pkg/devicemapper/devmapper.go
index 63243637a7..b384a27f8f 100644
--- a/components/engine/pkg/devicemapper/devmapper.go
+++ b/components/engine/pkg/devicemapper/devmapper.go
@@ -7,6 +7,7 @@ import (
"fmt"
"os"
"runtime"
+ "time"
"unsafe"
"github.com/sirupsen/logrus"
@@ -59,6 +60,7 @@ var (
ErrNilCookie = errors.New("cookie ptr can't be nil")
ErrGetBlockSize = errors.New("Can't get block size")
ErrUdevWait = errors.New("wait on udev cookie failed")
+ ErrUdevWaitTimeout = errors.New("wait on udev cookie time out")
ErrSetDevDir = errors.New("dm_set_dev_dir failed")
ErrGetLibraryVersion = errors.New("dm_get_library_version failed")
ErrCreateRemoveTask = errors.New("Can't create task of type deviceRemove")
@@ -71,10 +73,11 @@ var (
)
var (
- dmSawBusy bool
- dmSawExist bool
- dmSawEnxio bool // No Such Device or Address
- dmSawEnoData bool // No data available
+ dmSawBusy bool
+ dmSawExist bool
+ dmSawEnxio bool // No Such Device or Address
+ dmSawEnoData bool // No data available
+ dmUdevWaitTimeout int64
)
type (
@@ -256,13 +259,36 @@ func (t *Task) getNextTarget(next unsafe.Pointer) (nextPtr unsafe.Pointer, start
// UdevWait waits for any processes that are waiting for udev to complete the specified cookie.
func UdevWait(cookie *uint) error {
- if res := DmUdevWait(*cookie); res != 1 {
- logrus.Debugf("devicemapper: Failed to wait on udev cookie %d, %d", *cookie, res)
- return ErrUdevWait
+ chError := make(chan error)
+ go func() {
+ if res := DmUdevWait(*cookie); res != 1 {
+ logrus.Debugf("Failed to wait on udev cookie %d", *cookie)
+ chError <- ErrUdevWait
+ }
+ chError <- nil
+ }()
+ select {
+ case err := <-chError:
+ return err
+ case <-time.After(time.Second * time.Duration(dmUdevWaitTimeout)):
+ logrus.Errorf("Failed to wait on udev cookie %d: timeout %v", *cookie, dmUdevWaitTimeout)
+ if res := DmUdevComplete(*cookie); res != 1 {
+ // This is bad to return here
+ logrus.Errorf("Failed to complete udev cookie %d on udev wait timeout", *cookie)
+ return ErrUdevWaitTimeout
+ }
+ // wait DmUdevWait return after DmUdevComplete
+ <-chError
+ return ErrUdevWaitTimeout
}
return nil
}
+// SetUdevWaitTimtout sets udev wait timeout
+func SetUdevWaitTimtout(t int64) {
+ dmUdevWaitTimeout = t
+}
+
// SetDevDir sets the dev folder for the device mapper library (usually /dev).
func SetDevDir(dir string) error {
if res := DmSetDevDir(dir); res != 1 {
@@ -319,11 +345,11 @@ func RemoveDevice(name string) error {
if err := task.setCookie(cookie, 0); err != nil {
return fmt.Errorf("devicemapper: Can not set cookie: %s", err)
}
- defer UdevWait(cookie)
dmSawBusy = false // reset before the task is run
dmSawEnxio = false
if err = task.run(); err != nil {
+ UdevWait(cookie)
if dmSawBusy {
return ErrBusy
}
@@ -333,7 +359,7 @@ func RemoveDevice(name string) error {
return fmt.Errorf("devicemapper: Error running RemoveDevice %s", err)
}
- return nil
+ return UdevWait(cookie)
}
// RemoveDeviceDeferred is a useful helper for cleaning up a device, but deferred.
@@ -470,13 +496,13 @@ func CreatePool(poolName string, dataFile, metadataFile *os.File, poolBlockSize
if err := task.setCookie(cookie, flags); err != nil {
return fmt.Errorf("devicemapper: Can't set cookie %s", err)
}
- defer UdevWait(cookie)
if err := task.run(); err != nil {
+ UdevWait(cookie)
return fmt.Errorf("devicemapper: Error running deviceCreate (CreatePool) %s", err)
}
- return nil
+ return UdevWait(cookie)
}
// ReloadPool is the programmatic example of "dmsetup reload".
@@ -656,13 +682,13 @@ func ResumeDevice(name string) error {
if err := task.setCookie(cookie, 0); err != nil {
return fmt.Errorf("devicemapper: Can't set cookie %s", err)
}
- defer UdevWait(cookie)
if err := task.run(); err != nil {
+ UdevWait(cookie)
return fmt.Errorf("devicemapper: Error running deviceResume %s", err)
}
- return nil
+ return UdevWait(cookie)
}
// CreateDevice creates a device with the specified poolName with the specified device id.
@@ -760,13 +786,12 @@ func activateDevice(poolName string, name string, deviceID int, size uint64, ext
return fmt.Errorf("devicemapper: Can't set cookie %s", err)
}
- defer UdevWait(cookie)
-
if err := task.run(); err != nil {
+ UdevWait(cookie)
return fmt.Errorf("devicemapper: Error running deviceCreate (ActivateDevice) %s", err)
}
- return nil
+ return UdevWait(cookie)
}
// CreateSnapDeviceRaw creates a snapshot device. Caller needs to suspend and resume the origin device if it is active.
diff --git a/components/engine/pkg/devicemapper/devmapper_wrapper.go b/components/engine/pkg/devicemapper/devmapper_wrapper.go
index 0b88f49695..77cd674a09 100644
--- a/components/engine/pkg/devicemapper/devmapper_wrapper.go
+++ b/components/engine/pkg/devicemapper/devmapper_wrapper.go
@@ -77,6 +77,7 @@ var (
DmTaskSetRo = dmTaskSetRoFct
DmTaskSetSector = dmTaskSetSectorFct
DmUdevWait = dmUdevWaitFct
+ DmUdevComplete = dmUdevCompleteFct
DmUdevSetSyncSupport = dmUdevSetSyncSupportFct
DmUdevGetSyncSupport = dmUdevGetSyncSupportFct
DmCookieSupported = dmCookieSupportedFct
@@ -227,6 +228,10 @@ func dmUdevWaitFct(cookie uint) int {
return int(C.dm_udev_wait(C.uint32_t(cookie)))
}
+func dmUdevCompleteFct(cookie uint) int {
+ return int(C.dm_udev_complete(C.uint32_t(cookie)))
+}
+
func dmCookieSupportedFct() int {
return int(C.dm_cookie_supported())
}
--
2.17.1

View File

@ -0,0 +1,224 @@
From 72f9e0c4d0d907a036d25c9dfeea9c0baddddc3e Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 3 Jan 2019 10:37:50 +0800
Subject: [PATCH 033/111] devmapper: Fix devicemapper issue: power off
the VM while loading a image, couldn't load it after VM bootup
reason: cherry-pick commits to docker-18.09
cherry-pick from 28991928c4 | * Fix devicemapper issue: power off the VM while
loading a image, couldn't load it after VM bootup
Issue Description:
While running loading image test, power off or restart the VM, and then
there are
some chances that we can not load the image. And "Error running
deviceCreate (createSnapDevice) dm_task_run failed" will be reported.
Reproduce Steps:
> 1. run `docker load -i xxx.tar`
> 2. virsh restart VM; # restart the VM.
> 3. After startup, run `docker load -i xxx.tar`, will fail to import
> the image
Analysis:
From syslog, we found that docker was executing "Umount Device" then VM
powered restart. And found
two failure reasons:
> 1. Rollback operation only remove the device on DM thin pool, not
> remove the device in memory
> 2. TransactionData or metadata not flushed to Disk.
Solution:
> 1. Rollback operation for DM, should remove the devices cache in DM
> driver.
> 2. When restore layers and images, check whether the device exists in
> graphdriver.
If desen't, remove the layer( and the metadata) and do not load the
image.
Issue link:
#203
Signed-off-by: Wentao Zhang <zhangwentao234@huawei.com>
Conflicts:
image/store.go
layer/layer_store.go
Change-Id: If3bfbf0d0ed8f950cfd5934fc25fac892481275c
Signed-off-by: jingrui <jingrui@huawei.com>
---
.../daemon/graphdriver/devmapper/deviceset.go | 38 +++++++------------
components/engine/image/store.go | 3 +-
components/engine/layer/layer_store.go | 15 +++++++-
3 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/components/engine/daemon/graphdriver/devmapper/deviceset.go b/components/engine/daemon/graphdriver/devmapper/deviceset.go
index af53cf83e6..0675b2eacd 100644
--- a/components/engine/daemon/graphdriver/devmapper/deviceset.go
+++ b/components/engine/daemon/graphdriver/devmapper/deviceset.go
@@ -6,7 +6,6 @@ import (
"bufio"
"encoding/json"
"fmt"
- "io"
"io/ioutil"
"os"
"os/exec"
@@ -23,6 +22,7 @@ import (
"github.com/docker/docker/pkg/devicemapper"
"github.com/docker/docker/pkg/dmesg"
"github.com/docker/docker/pkg/idtools"
+ "github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/loopback"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/parsers"
@@ -306,6 +306,10 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
return filename, nil
}
+func (devices *DeviceSet) removeDeviceMap(hash string) {
+ delete(devices.Devices, hash)
+}
+
func (devices *DeviceSet) allocateTransactionID() uint64 {
devices.OpenTransactionID = devices.TransactionID + 1
return devices.OpenTransactionID
@@ -328,28 +332,9 @@ func (devices *DeviceSet) removeMetadata(info *devInfo) error {
// Given json data and file path, write it to disk
func (devices *DeviceSet) writeMetaFile(jsonData []byte, filePath string) error {
- tmpFile, err := ioutil.TempFile(devices.metadataDir(), ".tmp")
- if err != nil {
- return fmt.Errorf("devmapper: Error creating metadata file: %s", err)
- }
-
- n, err := tmpFile.Write(jsonData)
- if err != nil {
- return fmt.Errorf("devmapper: Error writing metadata to %s: %s", tmpFile.Name(), err)
- }
- if n < len(jsonData) {
- return io.ErrShortWrite
+ if err := ioutils.AtomicWriteFile(filePath, jsonData, 0600); err != nil {
+ return fmt.Errorf("devmapper: Error writing metadata to %s: %s", filePath, err)
}
- if err := tmpFile.Sync(); err != nil {
- return fmt.Errorf("devmapper: Error syncing metadata file %s: %s", tmpFile.Name(), err)
- }
- if err := tmpFile.Close(); err != nil {
- return fmt.Errorf("devmapper: Error closing metadata file %s: %s", tmpFile.Name(), err)
- }
- if err := os.Rename(tmpFile.Name(), filePath); err != nil {
- return fmt.Errorf("devmapper: Error committing metadata file %s: %s", tmpFile.Name(), err)
- }
-
return nil
}
@@ -483,7 +468,7 @@ func (devices *DeviceSet) unregisterDevice(hash string) error {
Hash: hash,
}
- delete(devices.Devices, hash)
+ devices.removeDeviceMap(hash)
if err := devices.removeMetadata(info); err != nil {
logrus.WithField("storage-driver", "devicemapper").Debugf("Error removing metadata: %s", err)
@@ -509,7 +494,7 @@ func (devices *DeviceSet) registerDevice(id int, hash string, size uint64, trans
if err := devices.saveMetadata(info); err != nil {
// Try to remove unused device
- delete(devices.Devices, hash)
+ devices.removeDeviceMap(hash)
return nil, err
}
@@ -1173,7 +1158,7 @@ func (devices *DeviceSet) checkGrowBaseDeviceFS(info *devInfo) error {
if err := devices.saveMetadata(info); err != nil {
// Try to remove unused device
- delete(devices.Devices, info.Hash)
+ devices.removeDeviceMap(info.Hash)
return err
}
@@ -1401,6 +1386,8 @@ func (devices *DeviceSet) rollbackTransaction() error {
devices.markDeviceIDFree(devices.DeviceID)
}
+ devices.removeDeviceMap(dinfo.Hash)
+
if err := devices.removeTransactionMetaData(); err != nil {
logger.Errorf("Unable to remove transaction meta file %s: %s", devices.transactionMetaFile(), err)
}
@@ -1482,6 +1469,7 @@ func (devices *DeviceSet) closeTransaction() error {
logrus.WithField("storage-driver", "devicemapper").Debug("Failed to close Transaction")
return err
}
+
return nil
}
diff --git a/components/engine/image/store.go b/components/engine/image/store.go
index 1a8a8a2451..b078a2627a 100644
--- a/components/engine/image/store.go
+++ b/components/engine/image/store.go
@@ -81,8 +81,9 @@ func (is *store) restore() error {
}
l, err = is.lss[img.OperatingSystem()].Get(chainID)
if err != nil {
+ logrus.Errorf("layer does not exist, not restoring image %v, %v, %s", dgst, chainID, img.OperatingSystem())
+ // If the layer doesn't exist, return nil to ignore this image.
if err == layer.ErrLayerDoesNotExist {
- logrus.Errorf("layer does not exist, not restoring image %v, %v, %s", dgst, chainID, img.OperatingSystem())
return nil
}
return err
diff --git a/components/engine/layer/layer_store.go b/components/engine/layer/layer_store.go
index 6a568e9d9b..351f787b87 100644
--- a/components/engine/layer/layer_store.go
+++ b/components/engine/layer/layer_store.go
@@ -105,7 +105,7 @@ func newStoreFromGraphDriver(root string, driver graphdriver.Driver, os string)
for _, id := range ids {
l, err := ls.loadLayer(id)
if err != nil {
- logrus.Debugf("Failed to load layer %s: %s", id, err)
+ logrus.Warnf("Failed to load layer %s: %s", id, err)
continue
}
if l.parent != nil {
@@ -126,11 +126,17 @@ func (ls *layerStore) Driver() graphdriver.Driver {
return ls.driver
}
-func (ls *layerStore) loadLayer(layer ChainID) (*roLayer, error) {
+func (ls *layerStore) loadLayer(layer ChainID) (l *roLayer, err error) {
cl, ok := ls.layerMap[layer]
if ok {
return cl, nil
}
+ defer func() {
+ // If failed to load the layer, remove the layer metadata.
+ if err != nil {
+ ls.store.Remove(layer)
+ }
+ }()
diff, err := ls.store.GetDiffID(layer)
if err != nil {
@@ -147,6 +153,11 @@ func (ls *layerStore) loadLayer(layer ChainID) (*roLayer, error) {
return nil, fmt.Errorf("failed to get cache id for %s: %s", layer, err)
}
+ // Check whether the layer exists in graphdriver here.
+ if exist := ls.driver.Exists(cacheID); !exist {
+ return nil, fmt.Errorf("cacheID %s for layer %s does not exists in graphdriver", cacheID, layer)
+ }
+
parent, err := ls.store.GetParent(layer)
if err != nil {
return nil, fmt.Errorf("failed to get parent for %s: %s", layer, err)
--
2.17.1

View File

@ -0,0 +1,42 @@
From 2e0fda9de03efe4f399a35c52cac2444b5518709 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 9 Jan 2019 16:43:39 +0800
Subject: [PATCH 035/111] restart: reject to restart container when
removing it
reason: cherry-pick commits to docker-18.09
concurrence of restart and remove a container may cause
that container info is still saved in memdb while container is actually
already removed.
cherry-pick from 1.11.2: f7eeafa
Conflicts:
daemon/restart.go
Change-Id: Ic9be384c908f49697c87f6b51ffcb1968f38d6cc
Signed-off-by: liruilin4 <liruilin4@huawei.com>
Signed-off-by: lixiang172 <lixiang172@huawei.com>
---
components/engine/daemon/restart.go | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/components/engine/daemon/restart.go b/components/engine/daemon/restart.go
index bae665f76b..2c441de873 100644
--- a/components/engine/daemon/restart.go
+++ b/components/engine/daemon/restart.go
@@ -55,6 +55,11 @@ func (daemon *Daemon) containerRestart(container *container.Container, seconds i
container.HostConfig.AutoRemove = autoRemove
// containerStop will write HostConfig to disk, we shall restore AutoRemove
// in disk too
+ // if rm running concurrently, the container may be already removed now. we should not
+ // save it to disk
+ if container.RemovalInProgress || container.Dead {
+ return fmt.Errorf("can't restart a container which is dead or marked for removal")
+ }
if toDiskErr := daemon.checkpointAndSave(container); toDiskErr != nil {
logrus.Errorf("Write container to disk error: %v", toDiskErr)
}
--
2.17.1

View File

@ -0,0 +1,41 @@
From af5045eb5d9cc84afeace447e2bf3e1571866f4d Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 9 Jan 2019 16:52:39 +0800
Subject: [PATCH 036/111] restart: do not reset container restartCount
on boot
reason: cherry-pick commits to docker-18.09
when daemon restart, container's RestartCount will be reseted to 0
this is cherry-picked from docker
commit:3bffccc719bf8237ce78af8b88aaa7757f43795a
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
cherry-pick from 1.11.2: d5292e3
Conflicts:
daemon/daemon.go
Change-Id: I2276e9d075b593b74e4b17c0f8e48a2dec3e6f4c
Signed-off-by: xueshaojia <xueshaojia@huawei.com>
Signed-off-by: lixiang172 <lixiang172@huawei.com>
---
components/engine/daemon/daemon.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/components/engine/daemon/daemon.go b/components/engine/daemon/daemon.go
index 4546587369..a058688dd3 100644
--- a/components/engine/daemon/daemon.go
+++ b/components/engine/daemon/daemon.go
@@ -532,7 +532,7 @@ func (daemon *Daemon) restore() error {
// Make sure networks are available before starting
daemon.waitForNetworks(c)
- if err := daemon.containerStart(c, "", "", true); err != nil {
+ if err := daemon.containerStart(c, "", "", false); err != nil {
logrus.Errorf("Failed to start container %s: %s", c.ID, err)
}
close(chNotify)
--
2.17.1

View File

@ -0,0 +1,50 @@
From 5f82c47f5f08655e325610a9430a4e891c71857a Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 3 Jan 2019 13:58:17 +0800
Subject: [PATCH 037/111] config: Add --liver-restore to OPTIION to
enable live restore by default
reason: cherry-pick commits to docker-18.09
this commit copy latest file from docker-1.11.2
cherry-pick from
c9846ccea8 | * Add --liver-restore to OPTIION to enable live restore by
default
Change-Id: I9c52a81d1bb06f2abb090bbd048cbf2dbc44956a
Signed-off-by: Lei Jitang <leijitang@huawei.com>
Signed-off-by: jingrui <jingrui@huawei.com>
---
.../init/sysvinit-redhat/docker.sysconfig | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/components/engine/contrib/init/sysvinit-redhat/docker.sysconfig b/components/engine/contrib/init/sysvinit-redhat/docker.sysconfig
index 0864b3d77f..234acad1dd 100644
--- a/components/engine/contrib/init/sysvinit-redhat/docker.sysconfig
+++ b/components/engine/contrib/init/sysvinit-redhat/docker.sysconfig
@@ -1,7 +1,16 @@
# /etc/sysconfig/docker
-#
-# Other arguments to pass to the docker daemon process
-# These will be parsed by the sysv initscript and appended
-# to the arguments list passed to docker daemon
-other_args=""
+# Modify these options if you want to change the way the docker daemon runs
+OPTIONS='--live-restore'
+
+DOCKER_CERT_PATH=/etc/docker
+
+# If you have a registry secured with https but do not have proper certs
+# distributed, you can tell docker to not look for full authorization by
+# adding the registry to the INSECURE_REGISTRY line and uncommenting it.
+# INSECURE_REGISTRY='--insecure-registry'
+
+# Location used for temporary files, such as those created by
+# docker load and build operations. Default is /var/lib/docker/tmp
+# Can be overridden by setting the following environment variable.
+# DOCKER_TMPDIR=/var/tmp
--
2.17.1

View File

@ -0,0 +1,44 @@
From 42da0fd120db6f5b34c523212b54b88e8837efa6 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 3 Jan 2019 14:09:59 +0800
Subject: [PATCH 038/111] devmapper: devicemapper: ignore error when
remove a device which does not exist
reason: cherry-pick commits to docker-18.09
cherry-pick from
e91268fda7 | * devicemapper: ignore error when remove a device which
does not exist
Conflicts:
daemon/graphdriver/devmapper/deviceset.go
pkg/devicemapper/devmapper.go
Change-Id: Ia1d33d78e4d7000c6e4bd54ec203800a0234cae5
Signed-off-by: Liu Hua <sdu.liu@huawei.com>
Signed-off-by: jingrui <jingrui@huawei.com>
---
.../engine/daemon/graphdriver/devmapper/deviceset.go | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/components/engine/daemon/graphdriver/devmapper/deviceset.go b/components/engine/daemon/graphdriver/devmapper/deviceset.go
index 0675b2eacd..be48d92e8d 100644
--- a/components/engine/daemon/graphdriver/devmapper/deviceset.go
+++ b/components/engine/daemon/graphdriver/devmapper/deviceset.go
@@ -2137,6 +2137,13 @@ func (devices *DeviceSet) deactivateDeviceMode(info *devInfo, deferredRemove boo
if deferredRemove {
err = devicemapper.RemoveDeviceDeferred(info.Name())
+ if err != nil {
+ if err == devicemapper.ErrEnxio {
+ logrus.Warnf("devmapper: device %s has gone", info.Name())
+ return nil
+ }
+ return err
+ }
} else {
err = devices.removeDevice(info.Name())
}
--
2.17.1

View File

@ -0,0 +1,361 @@
From 49a3cd1ceb6956bd7787135a7938543d64d30638 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 3 Jan 2019 14:02:32 +0800
Subject: [PATCH 039/111] restart: -- Remove redundant Mounts when
start docker daemon
reason: cherry-pick commits to docker-18.09
merge from
b192ce147d * Remove redundant Mounts when start docker daemon
8b031c9488 * devicemapper: remove redundant mountpoint when docker
restart
9a3c14633e * Revert "devicemapper: remove redundant mountpoint when
docker restart"
7bbda93537 * devicemapper: remove redundant mountpoint when docker
restart
0be4e475d7 * remove redundant containers/xxx/shm mountpoint
d4adbe2bf7 * Remove redundant overlay2 mountpoints
---
Remove redundant Mounts when start docker daemon
Signed-off-by: yangshukui <yangshukui@huawei.com>
---
devicemapper: remove redundant mountpoint when docker restart
Modify the regexp patterns in `getIdPatterns` in order to match
`/var/lib/docker/devicemapper/mnt/xxx-init`.
Fix #254
Signed-off-by: Yuanhong Peng <pengyuanhong@huawei.com>
---
Revert "devicemapper: remove redundant mountpoint when docker restart"
With this commit, daemon will restart with error:
```
level=error msg="devmapper: Error unmounting device
0019325b1b09c75da1c9c97dcffdc024498d318b2c148e4ebe67b1cda4ac446e:
devmapper: Unknown device
0019325b1b09c75da1c9c97dcffdc024498d318b2c148e4ebe67b1cda4ac446e"
```
Here, the redundant device is `xxx-init` not `xxx`.
This reverts commit 8b031c9488236a9a808be7aed4cce69786dec010.
Signed-off-by: Yuanhong Peng <pengyuanhong@huawei.com>
---
devicemapper: remove redundant mountpoint when docker restart
Modify the regexp patterns in `getIdPatterns` in order to match
`/var/lib/docker/devicemapper/mnt/xxx-init`.
Fix #254
Signed-off-by: Yuanhong Peng <pengyuanhong@huawei.com>
---
remove redundant containers/xxx/shm mountpoint
fix problems caused by killing docker daemon when running a container
once restarted, docker ps shows container in created status but failed
to rm it with `container/xxx/shm device or resource busy`
Signed-off-by: Deng Guangxing <dengguangxing@huawei.com>
---
Remove redundant overlay2 mountpoints
Modify the regexp patterns in `getIdPatterns` in order to match
/var/lib/docker/overlay2/xxx/merged.
Signed-off-by: Yuanhong Peng <pengyuanhong@huawei.com>
---
Signed-off-by: jingrui <jingrui@huawei.com>
Change-Id: I4859d9cca731477fc64be6772d8c4b89a000f1b5
---
components/engine/daemon/daemon.go | 6 +
components/engine/daemon/daemon_unix.go | 132 ++++++++++++++++++
components/engine/daemon/daemon_unix_test.go | 29 ++++
components/engine/daemon/daemon_windows.go | 4 +
components/engine/daemon/images/service.go | 4 +
.../engine/distribution/xfer/download_test.go | 4 +
components/engine/layer/layer.go | 1 +
components/engine/layer/layer_store.go | 4 +
8 files changed, 184 insertions(+)
diff --git a/components/engine/daemon/daemon.go b/components/engine/daemon/daemon.go
index a058688dd3..b207709f7c 100644
--- a/components/engine/daemon/daemon.go
+++ b/components/engine/daemon/daemon.go
@@ -486,6 +486,12 @@ func (daemon *Daemon) restore() error {
}
wg.Wait()
+ err = daemon.removeRedundantMounts(containers)
+ if err != nil {
+ // just print error info
+ logrus.Errorf("removeRedundantMounts failed %v", err)
+ }
+
containerIDs := make(map[string]struct{})
for cid, _ := range containers {
containerIDs[cid] = struct{}{}
diff --git a/components/engine/daemon/daemon_unix.go b/components/engine/daemon/daemon_unix.go
index 8ffdd0009a..d4a32a0b25 100644
--- a/components/engine/daemon/daemon_unix.go
+++ b/components/engine/daemon/daemon_unix.go
@@ -10,6 +10,7 @@ import (
"net"
"os"
"path/filepath"
+ "regexp"
"runtime"
"runtime/debug"
"strconv"
@@ -1587,3 +1588,134 @@ func (daemon *Daemon) setupSeccompProfile() error {
}
return nil
}
+
+func getIdPatterns(id string) (regexps []*regexp.Regexp) {
+ var patterns []string
+ if id == "" {
+ id = "(?P<id>[0-9a-f]{64})"
+ }
+ patterns = append(patterns, "aufs/mnt/"+id+"(-init)?"+"$", "overlay/"+id+"(-init)?"+"/merged$", "overlay2/"+id+"(-init)?"+"/merged$", "zfs/graph/"+id+"(-init)?"+"$", "devicemapper/mnt/"+id+"(-init)?"+"$")
+ for _, p := range patterns {
+ r, err := regexp.Compile(p)
+ if err == nil {
+ regexps = append(regexps, r)
+ }
+ }
+ return
+}
+
+func getContainerMountId(path string) (bool, string) {
+ regs := getIdPatterns("")
+ for _, reg := range regs {
+ ret := reg.FindStringSubmatch(path)
+ if len(ret) == 3 {
+ if ret[2] == "" {
+ return false, ret[1]
+ } else {
+ return true, ret[1]
+ }
+ }
+ }
+ return false, ""
+}
+
+func isContainerMount(path string) (bool, string) {
+ var regs []*regexp.Regexp
+ var patterns []string
+ var id = "(?P<id>[0-9a-f]{64})"
+
+ // TODO: fill in patterns with other mounts info
+ patterns = append(patterns, "containers/"+id+"/shm$")
+ for _, p := range patterns {
+ r, err := regexp.Compile(p)
+ if err == nil {
+ regs = append(regs, r)
+ }
+ }
+
+ for _, reg := range regs {
+ ret := reg.FindStringSubmatch(path)
+ if len(ret) == 2 {
+ return true, ret[1]
+ }
+ }
+ return false, ""
+}
+
+func (daemon *Daemon) removeRedundantMounts(containers map[string]*container.Container) error {
+ var (
+ isShmMount, isInitdev bool
+ id string
+ redundantMounts = map[string]bool{}
+ )
+
+ // Get redundant Mounts
+ f, err := os.Open("/proc/self/mountinfo")
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ activeContainers := map[string]string{}
+ for _, c := range containers {
+ if c.IsRunning() && !c.IsRestarting() {
+ activeContainers[c.ID] = c.ID
+ if mountid, err := daemon.imageService.GetLayerMountID(c.ID, c.OS); err == nil {
+ activeContainers[mountid] = c.ID
+ logrus.Debugf("removeRedundantMounts, mountid %s, containerID %s\n", mountid, c.ID)
+ }
+ }
+ }
+ root := filepath.Join(daemon.root, daemon.imageService.GraphDriverForOS(runtime.GOOS))
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ text := scanner.Text()
+ fields := strings.Split(text, " ")
+ if len(fields) < 5 {
+ return fmt.Errorf("%s", "/proc/self/mountinfo format err")
+ }
+ path := fields[4]
+ if !strings.HasPrefix(path, daemon.root) || path == root {
+ continue
+ }
+
+ isShmMount, id = isContainerMount(path)
+ if !isShmMount {
+ isInitdev, id = getContainerMountId(path)
+ }
+ if id == "" {
+ continue
+ }
+
+ if _, ok := activeContainers[id]; !ok {
+ if isShmMount {
+ redundantMounts[path] = true
+ } else {
+ if isInitdev {
+ id = fmt.Sprintf("%s-init", id)
+ }
+ redundantMounts[id] = false
+ }
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ return err
+ }
+
+ // Remove redundant Mounts
+ for path, shm := range redundantMounts {
+ var (
+ err error
+ )
+ logrus.Debugf("Umount legacy mountpoint [%s]", path)
+ if shm {
+ err = mount.Unmount(path)
+ } else {
+ err = daemon.imageService.DriverPut(runtime.GOOS, path)
+ }
+ if err != nil {
+ logrus.Debugf("Umount legacy mountpoint: %s failed with %s", path, err)
+ }
+ }
+ return err
+}
diff --git a/components/engine/daemon/daemon_unix_test.go b/components/engine/daemon/daemon_unix_test.go
index 36c6030988..d9bba54a93 100644
--- a/components/engine/daemon/daemon_unix_test.go
+++ b/components/engine/daemon/daemon_unix_test.go
@@ -266,3 +266,32 @@ func TestNetworkOptions(t *testing.T) {
t.Fatal("Expected networkOptions error, got nil")
}
}
+
+func TestGetContainerMountId(t *testing.T) {
+ id := "56e143922c405419a38b23bfbccc92284f35525e3f2ad7011ea904501ccd1219"
+
+ id1 := getContainerMountId("/var/lib/docker/aufs/mnt/" + id)
+ if id1 != id {
+ t.Fatalf("Expected container mount id [%s], but got [%s]", id, id1)
+ }
+
+ id1 = getContainerMountId("/var/lib/docker/devicemapper/mnt/" + id)
+ if id1 != id {
+ t.Fatalf("Expected container mount id [%s], but got [%s]", id, id1)
+ }
+
+ id1 = getContainerMountId("/var/lib/docker/overlay/" + id + "/merged")
+ if id1 != id {
+ t.Fatalf("Expected container mount id [%s], but got [%s]", id, id1)
+ }
+
+ id1 = getContainerMountId("/var/lib/docker/zfs/graph/" + id)
+ if id1 != id {
+ t.Fatalf("Expected container mount id [%s], but got [%s]", id, id1)
+ }
+
+ id1 = getContainerMountId("/var/lib/docker/devicemapper_err/mnt" + id)
+ if id1 != "" {
+ t.Fatalf("Expected a empty container mount id, but got [%s]", id1)
+ }
+}
diff --git a/components/engine/daemon/daemon_windows.go b/components/engine/daemon/daemon_windows.go
index 4812236bc2..9d895b3dfa 100644
--- a/components/engine/daemon/daemon_windows.go
+++ b/components/engine/daemon/daemon_windows.go
@@ -657,3 +657,7 @@ func (daemon *Daemon) initRuntimes(_ map[string]types.Runtime) error {
func setupResolvConf(config *config.Config) {
}
+
+func (daemon *Daemon) removeRedundantMounts(containers map[string]*container.Container) error {
+ return nil
+}
diff --git a/components/engine/daemon/images/service.go b/components/engine/daemon/images/service.go
index 8d187e2603..e43a4c6651 100644
--- a/components/engine/daemon/images/service.go
+++ b/components/engine/daemon/images/service.go
@@ -193,6 +193,10 @@ func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer, containerOS string) e
return nil
}
+func (i *ImageService) DriverPut(os string, path string) error {
+ return i.layerStores[os].DriverPut(path)
+}
+
// LayerDiskUsage returns the number of bytes used by layer stores
// called from disk_usage.go
func (i *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) {
diff --git a/components/engine/distribution/xfer/download_test.go b/components/engine/distribution/xfer/download_test.go
index 91153591ed..c4c4aefba9 100644
--- a/components/engine/distribution/xfer/download_test.go
+++ b/components/engine/distribution/xfer/download_test.go
@@ -146,6 +146,10 @@ func (ls *mockLayerStore) Cleanup() error {
return nil
}
+func (ls *mockLayerStore) DriverPut(id string) error {
+ return nil
+}
+
func (ls *mockLayerStore) DriverStatus() [][2]string {
return [][2]string{}
}
diff --git a/components/engine/layer/layer.go b/components/engine/layer/layer.go
index 425006854d..cb13c98d0b 100644
--- a/components/engine/layer/layer.go
+++ b/components/engine/layer/layer.go
@@ -191,6 +191,7 @@ type Store interface {
ReleaseRWLayer(RWLayer) ([]Metadata, error)
Cleanup() error
+ DriverPut(id string) error
DriverStatus() [][2]string
DriverName() string
CleanupRedundant(map[string]struct{}) error
diff --git a/components/engine/layer/layer_store.go b/components/engine/layer/layer_store.go
index 351f787b87..5decb0bdce 100644
--- a/components/engine/layer/layer_store.go
+++ b/components/engine/layer/layer_store.go
@@ -807,6 +807,10 @@ func (ls *layerStore) Cleanup() error {
return ls.driver.Cleanup()
}
+func (ls *layerStore) DriverPut(id string) error {
+ return ls.driver.Put(id)
+}
+
func (ls *layerStore) DriverStatus() [][2]string {
return ls.driver.Status()
}
--
2.17.1

View File

@ -0,0 +1,166 @@
From 9df99e9c4b27a3ccfae5f9b5b285784aeaaf1ac9 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Mon, 7 Jan 2019 13:36:04 +0800
Subject: [PATCH 040/111] devmapper: devicemapper: add API
GetDeviceList
reason: cherry-pick commits to docker-18.09
cherry-pick from 58fa445402 * devicemapper: add API GetDeviceList
Change-Id: Ia52611b75f12179bbe2e718e1b8575f0825d5dd7
Signed-off-by: Wang Long <long.wanglong@huawei.com>
Signed-off-by: jingrui <jingrui@huawei.com>
---
.../engine/pkg/devicemapper/devmapper.go | 21 ++++++
.../pkg/devicemapper/devmapper_wrapper.go | 67 +++++++++++++++++++
2 files changed, 88 insertions(+)
diff --git a/components/engine/pkg/devicemapper/devmapper.go b/components/engine/pkg/devicemapper/devmapper.go
index b384a27f8f..06ddc3e96b 100644
--- a/components/engine/pkg/devicemapper/devmapper.go
+++ b/components/engine/pkg/devicemapper/devmapper.go
@@ -55,6 +55,7 @@ var (
ErrTaskGetDeps = errors.New("dm_task_get_deps failed")
ErrTaskGetInfo = errors.New("dm_task_get_info failed")
ErrTaskGetDriverVersion = errors.New("dm_task_get_driver_version failed")
+ ErrTaskGetNames = errors.New("dm_task_get_names failed")
ErrTaskDeferredRemove = errors.New("dm_task_deferred_remove failed")
ErrTaskSetCookie = errors.New("dm_task_set_cookie failed")
ErrNilCookie = errors.New("cookie ptr can't be nil")
@@ -241,6 +242,14 @@ func (t *Task) getInfoWithDeferred() (*Info, error) {
return info, nil
}
+func (t *Task) getDeviceList() ([]string, error) {
+ res := DmTaskGetNames(t.unmanaged)
+ if res == nil {
+ return nil, ErrTaskGetNames
+ }
+ return res, nil
+}
+
func (t *Task) getDriverVersion() (string, error) {
res := DmTaskGetDriverVersion(t.unmanaged)
if res == "" {
@@ -569,6 +578,18 @@ func GetInfoWithDeferred(name string) (*Info, error) {
return task.getInfoWithDeferred()
}
+// GetDevices get all device name
+func GetDeviceList() ([]string, error) {
+ task := TaskCreate(deviceList)
+ if task == nil {
+ return nil, fmt.Errorf("devicemapper: Can't create deviceList task")
+ }
+ if err := task.run(); err != nil {
+ return nil, err
+ }
+ return task.getDeviceList()
+}
+
// GetDriverVersion is the programmatic example of "dmsetup version".
// It outputs version information of the driver.
func GetDriverVersion() (string, error) {
diff --git a/components/engine/pkg/devicemapper/devmapper_wrapper.go b/components/engine/pkg/devicemapper/devmapper_wrapper.go
index 77cd674a09..3b00a3b54b 100644
--- a/components/engine/pkg/devicemapper/devmapper_wrapper.go
+++ b/components/engine/pkg/devicemapper/devmapper_wrapper.go
@@ -6,6 +6,9 @@ package devicemapper // import "github.com/docker/docker/pkg/devicemapper"
#define _GNU_SOURCE
#include <libdevmapper.h>
#include <linux/fs.h> // FIXME: present only for BLKGETSIZE64, maybe we can remove it?
+#include <string.h>
+#include <stdlib.h>
+
// FIXME: Can't we find a way to do the logging in pure Go?
extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
@@ -32,6 +35,51 @@ static void log_with_errno_init()
{
dm_log_with_errno_init(log_cb);
}
+
+// FIXME: how to use dm_task_get_names directly
+static char **local_dm_task_get_names(struct dm_task *dmt, unsigned int *size) {
+ struct dm_names *ns, *ns1;
+ unsigned next = 0;
+ char **result;
+ int i = 0;
+
+ if (!(ns = dm_task_get_names(dmt)))
+ return NULL;
+
+ // No devices found
+ if (!ns->dev)
+ return NULL;
+
+ // calucate the total devices
+ ns1 = ns;
+ *size = 0;
+ do {
+ ns1 = (struct dm_names *)((char *) ns1 + next);
+ (*size)++;
+ next = ns1->next;
+ } while (next);
+
+ result = malloc(sizeof(char *)* (*size));
+ if (!result)
+ return NULL;
+
+ next = 0;
+ do {
+ ns = (struct dm_names *)((char *) ns + next);
+ result[i++] = strdup(ns->name);
+ next = ns->next;
+ } while (next);
+
+ return result;
+}
+
+void free_devices_names(char **names, unsigned int size) {
+ int i;
+
+ for (i = 0; i < size; i++)
+ free(names[i]);
+ free(names);
+}
*/
import "C"
@@ -69,6 +117,7 @@ var (
DmTaskGetDeps = dmTaskGetDepsFct
DmTaskGetInfo = dmTaskGetInfoFct
DmTaskGetDriverVersion = dmTaskGetDriverVersionFct
+ DmTaskGetNames = dmTaskGetNamesFct
DmTaskRun = dmTaskRunFct
DmTaskSetAddNode = dmTaskSetAddNodeFct
DmTaskSetCookie = dmTaskSetCookieFct
@@ -190,6 +239,24 @@ func dmTaskGetInfoFct(task *cdmTask, info *Info) int {
return int(C.dm_task_get_info((*C.struct_dm_task)(task), &Cinfo))
}
+func dmTaskGetNamesFct(task *cdmTask) []string {
+ var res []string
+ var names []*C.char
+ len := C.uint(0)
+ Cnames := C.local_dm_task_get_names((*C.struct_dm_task)(task), &len)
+ defer C.free_devices_names(Cnames, len)
+
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&names))
+ hdr.Cap = int(len)
+ hdr.Len = int(len)
+ hdr.Data = uintptr(unsafe.Pointer(Cnames))
+
+ for _, name := range names {
+ res = append(res, C.GoString(name))
+ }
+ return res
+}
+
func dmTaskGetDriverVersionFct(task *cdmTask) string {
buffer := C.malloc(128)
defer C.free(buffer)
--
2.17.1

View File

@ -0,0 +1,69 @@
From 544b5be235f9a34a5c75a936549bf6d6f2280339 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 3 Jan 2019 15:22:26 +0800
Subject: [PATCH 041/111] devmapper: devmapper: remove broken device
when start daemon
reason: cherry-pick commits to docker-18.09
cherry-pick from
6104c8e237 | * devmapper: remove broken device when start daemon
When use `kill -9 docker-daemon-pid` to stop docker, It may casue that
the status of devicemapper devices inconsisitent. eg, we can see the
device info use `dmsetup status` command, but the device does not exist
in `/dev/mapper` directory.
At next time docker start, it will start failed or load container
failed.
This patch add a check when docker start in `initDevmapper` function.
First, we find all devmapper devices in the system. Then If the device
name has a prefix with `docker-{major}:{minor}-{inode}` and the length
is equal to zero, we use `devicemapper.RemoveDevice` remove the device.
Change-Id: I7eccf4e9539751d615b953abf94951b7e94153d1
Signed-off-by: Wang Long <long.wanglong@huawei.com>
Signed-off-by: jingrui <jingrui@huawei.com>
---
.../daemon/graphdriver/devmapper/deviceset.go | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/components/engine/daemon/graphdriver/devmapper/deviceset.go b/components/engine/daemon/graphdriver/devmapper/deviceset.go
index be48d92e8d..b3e142e2ba 100644
--- a/components/engine/daemon/graphdriver/devmapper/deviceset.go
+++ b/components/engine/daemon/graphdriver/devmapper/deviceset.go
@@ -1732,6 +1732,29 @@ func (devices *DeviceSet) initDevmapper(doInit bool) (retErr error) {
devices.devicePrefix = fmt.Sprintf("docker-%d:%d-%d", major(st.Dev), minor(st.Dev), st.Ino)
logger.Debugf("Generated prefix: %s", devices.devicePrefix)
+ deviceNames, err := devicemapper.GetDeviceList()
+ if err != nil {
+ logrus.Debugf("devmapper: Failed to get device list: %s", err)
+ }
+
+ for _, name := range deviceNames {
+ if !strings.HasPrefix(name, devices.devicePrefix) {
+ continue
+ }
+ _, length, _, _, err := devicemapper.GetStatus(name)
+ if err != nil {
+ logrus.Warnf("devmapper: get device status(%s): %s", name, err)
+ continue
+ }
+ // remove broken device
+ if length == 0 {
+ if err := devicemapper.RemoveDevice(name); err != nil {
+ logrus.Warnf("devmapper: remove broken device(%s): %s", name, err)
+ }
+ logrus.Debugf("devmapper: remove broken device: %s", name)
+ }
+ }
+
// Check for the existence of the thin-pool device
poolExists, err := devices.thinPoolExists(devices.getPoolName())
if err != nil {
--
2.17.1

View File

@ -0,0 +1,137 @@
From 50c51324293064e12e99da9dfbb3554ab1255f51 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 3 Jan 2019 15:30:42 +0800
Subject: [PATCH 042/111] oci: Cannot join own pid/ipc namespace
reason: cherry-pick commits to docker-18.09
Change-Id: I34a0d97a4196d509d80d20f262f3fbac555e0745
Signed-off-by: Yuanhong Peng <pengyuanhong@huawei.com>
Signed-off-by: jingrui <jingrui@huawei.com>
---
.../daemon/container_operations_unix.go | 20 +++++++++-----
components/engine/daemon/oci_linux.go | 2 +-
.../integration-cli/docker_cli_run_test.go | 27 +++++++++++++++++++
3 files changed, 42 insertions(+), 7 deletions(-)
diff --git a/components/engine/daemon/container_operations_unix.go b/components/engine/daemon/container_operations_unix.go
index 9953c7f3fd..2cc2b2e3cd 100644
--- a/components/engine/daemon/container_operations_unix.go
+++ b/components/engine/daemon/container_operations_unix.go
@@ -58,13 +58,17 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s
return env, nil
}
-func (daemon *Daemon) getIpcContainer(id string) (*container.Container, error) {
- errMsg := "can't join IPC of container " + id
+func (daemon *Daemon) getIpcContainer(cc *container.Container) (*container.Container, error) {
+ containerID := cc.HostConfig.IpcMode.Container()
+ errMsg := "can't join IPC of container " + containerID
// Check the container exists
- container, err := daemon.GetContainer(id)
+ container, err := daemon.GetContainer(containerID)
if err != nil {
return nil, errors.Wrap(err, errMsg)
}
+ if container.ID == cc.ID {
+ return nil, fmt.Errorf("cannot join own ipc namespace")
+ }
// Check the container is running and not restarting
if err := daemon.checkContainer(container, containerIsRunning, containerIsNotRestarting); err != nil {
return nil, errors.Wrap(err, errMsg)
@@ -81,12 +85,16 @@ func (daemon *Daemon) getIpcContainer(id string) (*container.Container, error) {
return container, nil
}
-func (daemon *Daemon) getPidContainer(container *container.Container) (*container.Container, error) {
- containerID := container.HostConfig.PidMode.Container()
+func (daemon *Daemon) getPidContainer(cc *container.Container) (*container.Container, error) {
+ containerID := cc.HostConfig.PidMode.Container()
container, err := daemon.GetContainer(containerID)
if err != nil {
return nil, errors.Wrapf(err, "cannot join PID of a non running container: %s", containerID)
}
+ if container.ID == cc.ID {
+ return nil, fmt.Errorf("cannot join own pid namespace")
+ }
+
return container, daemon.checkContainer(container, containerIsRunning, containerIsNotRestarting)
}
@@ -109,7 +117,7 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
switch {
case ipcMode.IsContainer():
- ic, err := daemon.getIpcContainer(ipcMode.Container())
+ ic, err := daemon.getIpcContainer(c)
if err != nil {
return err
}
diff --git a/components/engine/daemon/oci_linux.go b/components/engine/daemon/oci_linux.go
index 884739c07e..f5270bd545 100644
--- a/components/engine/daemon/oci_linux.go
+++ b/components/engine/daemon/oci_linux.go
@@ -256,7 +256,7 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error
switch {
case ipcMode.IsContainer():
ns := specs.LinuxNamespace{Type: "ipc"}
- ic, err := daemon.getIpcContainer(ipcMode.Container())
+ ic, err := daemon.getIpcContainer(c)
if err != nil {
return err
}
diff --git a/components/engine/integration-cli/docker_cli_run_test.go b/components/engine/integration-cli/docker_cli_run_test.go
index 4f55c05aeb..4a137c6159 100644
--- a/components/engine/integration-cli/docker_cli_run_test.go
+++ b/components/engine/integration-cli/docker_cli_run_test.go
@@ -2323,6 +2323,15 @@ func (s *DockerSuite) TestRunModeIpcContainerNotExists(c *check.C) {
}
}
+func (s *DockerSuite) TestJoinOwnIpcNamespace(c *check.C) {
+ // Not applicable on Windows as uses Unix-specific capabilities
+ testRequires(c, DaemonIsLinux, NotUserNamespace)
+ _, _, err := dockerCmdWithError("run", "-d", "--name", "testipc", "--ipc", "container:testipc", "busybox", "top")
+ if err == nil {
+ c.Fatalf("Join own ipc namespace is not permitted")
+ }
+}
+
func (s *DockerSuite) TestRunModeIpcContainerNotRunning(c *check.C) {
// Not applicable on Windows as uses Unix-specific capabilities
testRequires(c, SameHostDaemon, DaemonIsLinux)
@@ -2383,6 +2392,15 @@ func (s *DockerSuite) TestRunModePIDContainerNotRunning(c *check.C) {
}
}
+func (s *DockerSuite) TestJoinOwnPidNamespace(c *check.C) {
+ // Not applicable on Windows as uses Unix-specific capabilities
+ testRequires(c, DaemonIsLinux)
+ _, _, err := dockerCmdWithError("run", "-d", "--name", "testpid", "--pid", "container:testpid", "busybox", "top")
+ if err == nil {
+ c.Fatalf("Join own pid namespace is not permitted")
+ }
+}
+
func (s *DockerSuite) TestRunMountShmMqueueFromHost(c *check.C) {
// Not applicable on Windows as uses Unix-specific capabilities
testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
@@ -2621,6 +2639,15 @@ func (s *DockerSuite) TestRunNetContainerWhichHost(c *check.C) {
}
}
+func (s *DockerSuite) TestJoinOwnNetNamespace(c *check.C) {
+ // Not applicable on Windows as uses Unix-specific capabilities
+ testRequires(c, DaemonIsLinux, NotUserNamespace)
+ _, _, err := dockerCmdWithError("run", "-d", "--name", "testnet", "--net", "container:testnet", "busybox", "top")
+ if err == nil {
+ c.Fatalf("Join own net namespace is not permitted")
+ }
+}
+
func (s *DockerSuite) TestRunAllowPortRangeThroughPublish(c *check.C) {
// TODO Windows. This may be possible to enable in the future. However,
// Windows does not currently support --expose, or populate the network
--
2.17.1

View File

@ -0,0 +1,81 @@
From f70a2648621ab1463299eabecda8e8c7584831c3 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 3 Jan 2019 16:01:36 +0800
Subject: [PATCH 043/111] docker: Make sure the pid exist in pidfile
is docker
reason: cherry-pick commits to docker-18.09.
cherry-pick from
b4714e3321 | * Make sure the pid exist in pidfile is docker
Because of the recycling of used PIDs policy in kernel,
it could be possible that the process died with pidfile existing
and when the process boot next time, the pid in pidfile has been assigned
to another process, this would make the process can't be boot again without
removing the pidfile manually.
Change-Id: I237566682716733174900cd4dc76ce74ff9f4195
Signed-off-by: Lei Jitang <leijitang@huawei.com>
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/pkg/pidfile/pidfile.go | 30 +++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/components/engine/pkg/pidfile/pidfile.go b/components/engine/pkg/pidfile/pidfile.go
index 0617a89e5f..485c00138b 100644
--- a/components/engine/pkg/pidfile/pidfile.go
+++ b/components/engine/pkg/pidfile/pidfile.go
@@ -4,6 +4,7 @@
package pidfile // import "github.com/docker/docker/pkg/pidfile"
import (
+ "bufio"
"fmt"
"io/ioutil"
"os"
@@ -19,12 +20,39 @@ type PIDFile struct {
path string
}
+// isSameApplication check whether the pid exist in pidfile
+// is the the same application we are going to run.
+func isSameApplication(pid int) (bool, error) {
+ path := filepath.Join("/proc", strconv.Itoa(pid), "status")
+ file, err := os.Open(path)
+ if err != nil {
+ return false, err
+ }
+ defer file.Close()
+ sc := bufio.NewScanner(file)
+ for sc.Scan() {
+ lens := strings.Split(sc.Text(), ":")
+ if len(lens) == 2 && strings.TrimSpace(lens[0]) == "Name" {
+ if strings.TrimSpace(lens[1]) == os.Args[0] {
+ return true, nil
+ }
+ return false, nil
+ }
+ }
+ if err := sc.Err(); err != nil {
+ return false, err
+ }
+ return false, nil
+}
+
func checkPIDFileAlreadyExists(path string) error {
if pidByte, err := ioutil.ReadFile(path); err == nil {
pidString := strings.TrimSpace(string(pidByte))
if pid, err := strconv.Atoi(pidString); err == nil {
if processExists(pid) {
- return fmt.Errorf("pid file found, ensure docker is not running or delete %s", path)
+ if same, err := isSameApplication(pid); same || (err != nil && !os.IsNotExist(err)) {
+ return fmt.Errorf("pid file found, ensure docker is not running or delete %s", path)
+ }
}
}
}
--
2.17.1

View File

@ -0,0 +1,99 @@
From 75d53c469ea6115db0386155262565a8aa15556d Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 3 Jan 2019 16:04:37 +0800
Subject: [PATCH 044/111] plugin: Fix plugin security bug caused by
unchecked plugin name
reason: cherry-pick commits to docker-18.09
cherry-pick from 48c9622f82 | * plugin,bugfix: Fix plugin security bug
caused by unchecked plugin name
Docker may activate plugins outside plugin directory if plugin name
contains string like "../../". This patch fix this bug by checking the
combined plugin path before use it.
fix issue docker/docker#268
Change-Id: Icff8b24e50fc92721149267bc8c29a8652046d8a
Signed-off-by: majiuyue <majiuyue@huawei.com>
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/pkg/plugins/discovery.go | 27 ++++++++++++++++------
components/engine/pkg/plugins/plugins.go | 2 +-
2 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/components/engine/pkg/plugins/discovery.go b/components/engine/pkg/plugins/discovery.go
index 4b79bd29ad..51f1d8ebea 100644
--- a/components/engine/pkg/plugins/discovery.go
+++ b/components/engine/pkg/plugins/discovery.go
@@ -14,6 +14,8 @@ import (
)
var (
+ // ErrForbidden plugin sock/spec outside allowed location
+ ErrForbidden = errors.New("plugin outside allowed location")
// ErrNotFound plugin not found
ErrNotFound = errors.New("plugin not found")
socketsPath = "/run/docker/plugins"
@@ -82,7 +84,10 @@ func Scan() ([]string, error) {
// Plugin returns the plugin registered with the given name (or returns an error).
func (l *localRegistry) Plugin(name string) (*Plugin, error) {
- socketpaths := pluginPaths(socketsPath, name, ".sock")
+ socketpaths, err := pluginPaths(socketsPath, name, ".sock")
+ if err != nil {
+ return nil, ErrForbidden
+ }
for _, p := range socketpaths {
if fi, err := os.Stat(p); err == nil && fi.Mode()&os.ModeSocket != 0 {
@@ -92,8 +97,10 @@ func (l *localRegistry) Plugin(name string) (*Plugin, error) {
var txtspecpaths []string
for _, p := range specsPaths {
- txtspecpaths = append(txtspecpaths, pluginPaths(p, name, ".spec")...)
- txtspecpaths = append(txtspecpaths, pluginPaths(p, name, ".json")...)
+ for _, ext := range []string{".spec", ".json"} {
+ paths, _ := pluginPaths(p, name, ext)
+ txtspecpaths = append(txtspecpaths, paths...)
+ }
}
for _, p := range txtspecpaths {
@@ -146,9 +153,15 @@ func readPluginJSONInfo(name, path string) (*Plugin, error) {
return &p, nil
}
-func pluginPaths(base, name, ext string) []string {
- return []string{
- filepath.Join(base, name+ext),
- filepath.Join(base, name, name+ext),
+func pluginPaths(base, name, ext string) ([]string, error) {
+ paths := []string{
+ filepath.Clean(filepath.Join(base, name+ext)),
+ filepath.Clean(filepath.Join(base, name, name+ext)),
+ }
+ for _, p := range paths {
+ if !strings.HasPrefix(p, base) {
+ return nil, ErrForbidden
+ }
}
+ return paths, nil
}
diff --git a/components/engine/pkg/plugins/plugins.go b/components/engine/pkg/plugins/plugins.go
index 6962079df9..8a6fbeda29 100644
--- a/components/engine/pkg/plugins/plugins.go
+++ b/components/engine/pkg/plugins/plugins.go
@@ -208,7 +208,7 @@ func loadWithRetry(name string, retry bool) (*Plugin, error) {
for {
pl, err := registry.Plugin(name)
if err != nil {
- if !retry {
+ if !retry || err == ErrForbidden {
return nil, err
}
--
2.17.1

View File

@ -0,0 +1,122 @@
From d2901f9efd4b1b26c995ea1c61663a14bc9c55d6 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 3 Jan 2019 16:25:23 +0800
Subject: [PATCH 045/111] overlay: safely remove overlay layer
directory
reason: cherry-pick commits to docker-18.09
merge from
0af3bf355a * safely remove overlay layer directory
e2b1d6827b * docker: add link string validation
---
safely remove overlay layer directory
do not recover link if the format is illegal
do not remove illegal link string
Signed-off-by: Deng Guangxing <dengguangxing@huawei.com>
---
docker: add link string validation
validate link string with restrict reqirements, not just stringLen.
Shukui Yang
Signed-off-by: Deng Guangxing <dengguangxing@huawei.com>
Signed-off-by: yangshukui <yangshukui@huawei.com>
Change-Id: Ie4f47b942c7e89bd6632d310c1cb34533ed5726b
Signed-off-by: jingrui <jingrui@huawei.com>
---
.../daemon/graphdriver/overlay2/overlay.go | 30 +++++++++++++++++--
.../daemon/graphdriver/overlay2/randomid.go | 7 +++++
2 files changed, 34 insertions(+), 3 deletions(-)
diff --git a/components/engine/daemon/graphdriver/overlay2/overlay.go b/components/engine/daemon/graphdriver/overlay2/overlay.go
index 722d65b11a..773d5232cc 100644
--- a/components/engine/daemon/graphdriver/overlay2/overlay.go
+++ b/components/engine/daemon/graphdriver/overlay2/overlay.go
@@ -419,6 +419,10 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
}
lid := generateID(idLength)
+ if !verifyID(lid, idLength) {
+ // this should never happen
+ return fmt.Errorf("[overlay2], generated link string(%s) illegal", lid)
+ }
if err := os.Symlink(path.Join("..", id, "diff"), path.Join(d.home, linkDir, lid)); err != nil {
return err
}
@@ -491,6 +495,9 @@ func (d *Driver) getLower(parent string) (string, error) {
if err != nil {
return "", err
}
+ if !verifyID(string(parentLink), idLength) {
+ return "", fmt.Errorf("illegal link string: %s", parentLink)
+ }
lowers := []string{path.Join(linkDir, string(parentLink))}
parentLower, err := ioutil.ReadFile(path.Join(parentDir, lowerFile))
@@ -570,7 +577,7 @@ func (d *Driver) Remove(id string) error {
dir := d.dir(id)
lid, err := ioutil.ReadFile(path.Join(dir, "link"))
if err == nil {
- if len(lid) == 0 {
+ if !verifyID(string(lid), idLength) {
logrus.WithField("storage-driver", "overlay2").Errorf("refusing to remove empty link for layer %v", id)
} else if err := os.RemoveAll(path.Join(d.home, linkDir, string(lid))); err != nil {
logrus.WithField("storage-driver", "overlay2").Debugf("Failed to remove link: %v", err)
@@ -703,8 +710,25 @@ func (d *Driver) Put(id string) error {
// Exists checks to see if the id is already mounted.
func (d *Driver) Exists(id string) bool {
- _, err := os.Stat(d.dir(id))
- return err == nil
+ _, rerr := os.Stat(d.dir(id))
+ if rerr == nil {
+ lstr, err := ioutil.ReadFile(path.Join(d.dir(id), "link"))
+ // link is valid
+ if err == nil && verifyID(string(lstr), idLength) {
+ // check symlink
+ _, rerr = os.Stat(path.Join(d.home, linkDir, string(lstr)))
+ if rerr != nil {
+ os.RemoveAll(path.Join(d.home, linkDir, string(lstr)))
+
+ logrus.Infof("[overlay2]: symlink (%s) is missing, create a new one", lstr)
+ if rerr = os.Symlink(path.Join("..", id, "diff"), path.Join(d.home, linkDir, string(lstr))); rerr != nil {
+ return false
+ }
+ }
+ return true
+ }
+ }
+ return false
}
// isParent determines whether the given parent is the direct parent of the
diff --git a/components/engine/daemon/graphdriver/overlay2/randomid.go b/components/engine/daemon/graphdriver/overlay2/randomid.go
index 842c06127f..933d9fccb6 100644
--- a/components/engine/daemon/graphdriver/overlay2/randomid.go
+++ b/components/engine/daemon/graphdriver/overlay2/randomid.go
@@ -8,6 +8,7 @@ import (
"fmt"
"io"
"os"
+ "regexp"
"syscall"
"time"
@@ -79,3 +80,9 @@ func retryOnError(err error) bool {
return false
}
+
+func verifyID(id string, l int) bool {
+ regstr := fmt.Sprintf("^[A-Z0-9]{%d}$", l)
+ rgxp := regexp.MustCompile(regstr)
+ return rgxp.MatchString(id)
+}
--
2.17.1

View File

@ -0,0 +1,57 @@
From 024a67b1d7ccfa85bba14318cd4fbbe78ecc8b7e Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 10 Jan 2019 00:17:01 +0800
Subject: [PATCH 046/111] debug: add more error info when dial
docker.sock fail
reason: cherry-pick commits to docker-18.09
add more error info when dial docker.sock fail
cherry-pick from 1.11.2: 91c7491
Change-Id: I3c7219d44be752ecde92479f03c0e2cee3ccb4a0
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
Signed-off-by: xiadanni <xiadanni@huawei.com>
---
components/engine/client/request.go | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/components/engine/client/request.go b/components/engine/client/request.go
index a19d62aa52..855b84d6ac 100644
--- a/components/engine/client/request.go
+++ b/components/engine/client/request.go
@@ -10,6 +10,7 @@ import (
"net"
"net/http"
"net/url"
+ "regexp"
"os"
"strings"
@@ -156,11 +157,19 @@ func (cli *Client) doRequest(ctx context.Context, req *http.Request) (serverResp
if err, ok := err.(net.Error); ok {
if err.Timeout() {
- return serverResp, ErrorConnectionFailed(cli.host)
+ return serverResp, fmt.Errorf("Cannot connect to the Docker daemon failed for timeout.")
}
if !err.Temporary() {
- if strings.Contains(err.Error(), "connection refused") || strings.Contains(err.Error(), "dial unix") {
- return serverResp, ErrorConnectionFailed(cli.host)
+ if strings.Contains(err.Error(), "dial unix") {
+ var err2 error
+ r, rerr := regexp.Compile("dial unix.*")
+ if rerr != nil {
+ err2 = fmt.Errorf("Cannot connect to the Docker daemon failed for dial unix.")
+ } else {
+ rbytes := r.Find([]byte(err.Error()))
+ err2 = fmt.Errorf("Cannot connect to the Docker daemon failed for %s", string(rbytes))
+ }
+ return serverResp, err2
}
}
}
--
2.17.1

View File

@ -0,0 +1,59 @@
From 8483caa076b11f33e9a4c578b8aefce127468e66 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Fri, 11 Jan 2019 12:18:27 +0800
Subject: [PATCH 047/111] docker: fix panic slice bounds out of range
reason: fix panic
panic: runtime error: slice bounds out of range
goroutine 1 [running]:
github.com/docker/docker/daemon.parseInitVersion(0xc4209da600, 0x22, 0x22, 0x600, 0xc4209da600, 0x22, 0x28, 0x0)
/go/src/github.com/docker/docker/daemon/info_unix.go:163 +0x3ce
github.com/docker/docker/daemon.(*Daemon).fillPlatformInfo(0xc4206e21e0, 0xc42009cc00, 0xc42081d220)
/go/src/github.com/docker/docker/daemon/info_unix.go:68 +0x115f
github.com/docker/docker/daemon.(*Daemon).SystemInfo(0xc4206e21e0, 0x0, 0x0, 0xc42020d3c0)
/go/src/github.com/docker/docker/daemon/info.go:75 +0x7e8
github.com/docker/docker/daemon.NewDaemon(0x55b515ace080, 0xc4201ab400, 0xc4207c5400, 0xc4207602d0, 0x0, 0x0, 0x0)
/go/src/github.com/docker/docker/daemon/daemon.go:1080 +0x2c87
main.(*DaemonCli).start(0xc420727260, 0xc42016f6e0, 0x0, 0x0)
/go/src/github.com/docker/docker/cmd/dockerd/daemon.go:180 +0x74f
main.runDaemon(0xc42016f6e0, 0xc420194600, 0x0)
/go/src/github.com/docker/docker/cmd/dockerd/docker_unix.go:7 +0x47
main.newDaemonCommand.func1(0xc42076d680, 0xc420190d80, 0x0, 0x8, 0x0, 0x0)
/go/src/github.com/docker/docker/cmd/dockerd/docker.go:29 +0x5d
github.com/docker/docker/vendor/github.com/spf13/cobra.(*Command).execute(0xc42076d680, 0xc42003a0a0, 0x8, 0x8, 0xc42076d680, 0xc42003a0a0)
/go/src/github.com/docker/docker/vendor/github.com/spf13/cobra/command.go:762 +0x46a
github.com/docker/docker/vendor/github.com/spf13/cobra.(*Command).ExecuteC(0xc42076d680, 0x55b515aa3350, 0x55b51565f0c0, 0x55b515aa3360)
/go/src/github.com/docker/docker/vendor/github.com/spf13/cobra/command.go:852 +0x30c
github.com/docker/docker/vendor/github.com/spf13/cobra.(*Command).Execute(0xc42076d680, 0xc42000e020, 0x55b5138f336f)
/go/src/github.com/docker/docker/vendor/github.com/spf13/cobra/command.go:800 +0x2d
main.main()
/go/src/github.com/docker/docker/cmd/dockerd/docker.go:70 +0xa2
Change-Id: Iafadb0c9215e1840c084637ebc96f5ef4d004cbd
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/daemon/info_unix.go | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/components/engine/daemon/info_unix.go b/components/engine/daemon/info_unix.go
index 55b6c6e79b..c53804edec 100644
--- a/components/engine/daemon/info_unix.go
+++ b/components/engine/daemon/info_unix.go
@@ -160,7 +160,11 @@ func parseInitVersion(v string) (types.Commit, error) {
gitParts := strings.Split(parts[1], ".")
if len(gitParts) == 2 && gitParts[0] == "git" {
version.ID = gitParts[1]
- version.Expected = dockerversion.InitCommitID[0:len(version.ID)]
+ n := len(dockerversion.InitCommitID)
+ if n > len(version.ID) {
+ n = len(version.ID)
+ }
+ version.Expected = dockerversion.InitCommitID[0:n]
}
}
if version.ID == "" && strings.HasPrefix(parts[0], "tini version ") {
--
2.17.1

View File

@ -0,0 +1,36 @@
From 7eb6d78447ed19a19c57331cb63e58097d29caeb Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Tue, 8 Jan 2019 18:19:16 +0800
Subject: [PATCH 048/111] docker: check metadata when load layer
reason:check metadata when load layer
Cherry-pick from docker 1.11.2:
- 41795d7 check metadata when load layer
Change-Id: Ia1734172a33d0ebe29ddb4b76d207da2981a137a
Signed-off-by: Liu Hua <sdu.liu@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/engine/layer/layer_store.go | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/components/engine/layer/layer_store.go b/components/engine/layer/layer_store.go
index 5decb0bdce..f22e9c666c 100644
--- a/components/engine/layer/layer_store.go
+++ b/components/engine/layer/layer_store.go
@@ -193,6 +193,11 @@ func (ls *layerStore) loadLayer(layer ChainID) (l *roLayer, err error) {
return nil, err
}
cl.parent = p
+ } else {
+ _, err := ls.driver.GetMetadata(cacheID)
+ if err != nil {
+ return nil, fmt.Errorf("cacheID %s for layer %s does not have metadata ", cacheID, layer)
+ }
}
ls.layerMap[cl.chainID] = cl
--
2.17.1

View File

@ -0,0 +1,81 @@
From 652be7c8c259c25adaed10f6f121a7d18283daa0 Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Tue, 8 Jan 2019 19:08:25 +0800
Subject: [PATCH 049/111] cleanup: cleanup useless netns file in
/var/run/docker/netns
reason:killing daemon would left useless netns file.
try to clean them up during daemon restore according to
activesandboxes
cherrt-pick from docker 1.11.2:
- e657d09 cleanup useless netns file in /var/run/docker/netns
Change-Id: I4bfff028a1ad2df9a42456b9f181db87d63c7cd7
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
.../docker/libnetwork/controller.go | 2 ++
.../docker/libnetwork/osl/namespace_linux.go | 33 +++++++++++++++++++
2 files changed, 35 insertions(+)
diff --git a/components/engine/vendor/github.com/docker/libnetwork/controller.go b/components/engine/vendor/github.com/docker/libnetwork/controller.go
index 2896011dbf..95013d31d3 100644
--- a/components/engine/vendor/github.com/docker/libnetwork/controller.go
+++ b/components/engine/vendor/github.com/docker/libnetwork/controller.go
@@ -247,6 +247,8 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
c.sandboxCleanup(c.cfg.ActiveSandboxes)
c.cleanupLocalEndpoints()
c.networkCleanup()
+ osl.NetnsFileCleanup(c.cfg.ActiveSandboxes)
+
if err := c.startExternalKeyListener(); err != nil {
return nil, err
diff --git a/components/engine/vendor/github.com/docker/libnetwork/osl/namespace_linux.go b/components/engine/vendor/github.com/docker/libnetwork/osl/namespace_linux.go
index bfc5d31a53..f97b286bcd 100644
--- a/components/engine/vendor/github.com/docker/libnetwork/osl/namespace_linux.go
+++ b/components/engine/vendor/github.com/docker/libnetwork/osl/namespace_linux.go
@@ -586,6 +586,39 @@ func (n *networkNamespace) Restore(ifsopt map[string][]IfaceOption, routes []*ty
return nil
}
+func NetnsFileCleanup(activeSandboxes map[string]interface{}) {
+ maxLen := 12
+ dir, err := ioutil.ReadDir(prefix)
+ if err != nil {
+ logrus.Warnf("failed to open %s for netns cleanup: %s", prefix, err)
+ return
+ }
+
+ activeSandboxesMap := make(map[string]string)
+ // shorten active sandboxes id to 12 char
+ for ac, _ := range activeSandboxes {
+ shortid := ac[:maxLen]
+ activeSandboxesMap[shortid] = shortid
+ }
+
+ for _, v := range dir {
+ id := v.Name()
+ // skip if id length is not 12, like default
+ if len(id) != maxLen {
+ continue
+ }
+
+ if _, ok := activeSandboxesMap[id]; !ok {
+ path := filepath.Join(prefix, id)
+ // cleanup netns file if not active
+ syscall.Unmount(path, syscall.MNT_DETACH)
+ if err := os.Remove(path); err != nil {
+ logrus.Warnf("Failed to cleanup netns file %s: %s", path, err)
+ }
+ }
+ }
+}
+
// Checks whether IPv6 needs to be enabled/disabled on the loopback interface
func (n *networkNamespace) checkLoV6() {
var (
--
2.17.1

View File

@ -0,0 +1,39 @@
From 415f93f45004d4082d3a7bcfdee122b584cd2e57 Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Tue, 8 Jan 2019 19:34:41 +0800
Subject: [PATCH 050/111] volume: Make v.opts to nil if opts.json is
null
reason:Make v.opts to nil if opts.json is null
cherry-pick from docker 1.11.2:
- 1b9344b Make v.opts to nil if opts.json is null
Change-Id: I59d6ebb41cbb908d72beb4f9f6c645cb7ae2c4ba
Signed-off-by: Lei Jitang <leijitang@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/engine/volume/local/local.go | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/components/engine/volume/local/local.go b/components/engine/volume/local/local.go
index 7190de9ed6..2e865815a9 100644
--- a/components/engine/volume/local/local.go
+++ b/components/engine/volume/local/local.go
@@ -89,6 +89,13 @@ func New(scope string, rootIdentity idtools.Identity) (*Root, error) {
v.opts = &opts
}
+ // For the local volumes created without options,
+ // the opts.json is null, so all the value in v.opts is null
+ // We should make v.opts to nil to avoid v.mount
+ if v.opts != nil && v.opts.MountType == "" && v.opts.MountOpts == "" && v.opts.MountDevice == "" {
+ v.opts = nil
+ }
+
// unmount anything that may still be mounted (for example, from an unclean shutdown)
mount.Unmount(v.path)
}
--
2.17.1

View File

@ -0,0 +1,102 @@
From 1fe0a4bfad5d7fa418f4e726211f4f037e59cfee Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Tue, 8 Jan 2019 19:47:28 +0800
Subject: [PATCH 051/111] docker: fix panic when load maliciously
image
reason:fix oom panic when load maliciously modified image with
huge size manifest files
cherry-pick from docker 1.11.2:
- bbe29c3 fix panic when load maliciously image
Change-Id: I2525e492fac31c33d3ba7275c95b570322a05025
Signed-off-by: leizhongkai <leizhongkai@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/engine/image/tarexport/load.go | 28 +++++++++++++++++++
.../engine/image/tarexport/tarexport.go | 1 +
2 files changed, 29 insertions(+)
diff --git a/components/engine/image/tarexport/load.go b/components/engine/image/tarexport/load.go
index 786214383e..b9f8f7e3ac 100644
--- a/components/engine/image/tarexport/load.go
+++ b/components/engine/image/tarexport/load.go
@@ -49,6 +49,11 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool)
if err != nil {
return err
}
+
+ if err = checkJsonFileSize(manifestPath); err != nil {
+ return err
+ }
+
manifestFile, err := os.Open(manifestPath)
if err != nil {
if os.IsNotExist(err) {
@@ -72,6 +77,9 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool)
if err != nil {
return err
}
+ if err = checkJsonFileSize(configPath); err != nil {
+ return err
+ }
config, err := ioutil.ReadFile(configPath)
if err != nil {
return err
@@ -246,6 +254,11 @@ func (l *tarexporter) legacyLoad(tmpDir string, outStream io.Writer, progressOut
if err != nil {
return err
}
+
+ if err = checkJsonFileSize(repositoriesPath); err != nil {
+ return err
+ }
+
repositoriesFile, err := os.Open(repositoriesPath)
if err != nil {
return err
@@ -286,6 +299,9 @@ func (l *tarexporter) legacyLoadImage(oldID, sourceDir string, loadedMap map[str
if err != nil {
return err
}
+ if err = checkJsonFileSize(configPath); err != nil {
+ return err
+ }
imageJSON, err := ioutil.ReadFile(configPath)
if err != nil {
logrus.Debugf("Error reading json: %v", err)
@@ -413,6 +429,18 @@ func checkValidParent(img, parent *image.Image) bool {
return true
}
+func checkJsonFileSize(path string) error {
+ fileInfo, err := os.Stat(path)
+ if err != nil {
+ return err
+ }
+ fileSize := fileInfo.Size()
+ if fileSize > maxJsonFileSize {
+ return fmt.Errorf("%s is too large", filepath.Base(path))
+ }
+ return nil
+}
+
func checkCompatibleOS(imageOS string) error {
// always compatible if the images OS matches the host OS; also match an empty image OS
if imageOS == runtime.GOOS || imageOS == "" {
diff --git a/components/engine/image/tarexport/tarexport.go b/components/engine/image/tarexport/tarexport.go
index beff668cd8..f23fe6f8bb 100644
--- a/components/engine/image/tarexport/tarexport.go
+++ b/components/engine/image/tarexport/tarexport.go
@@ -13,6 +13,7 @@ const (
legacyConfigFileName = "json"
legacyVersionFileName = "VERSION"
legacyRepositoriesFileName = "repositories"
+ maxJsonFileSize = (10 * 1024 * 1024)
)
type manifestItem struct {
--
2.17.1

View File

@ -0,0 +1,194 @@
From 568c9501d56ccff1806253f9e2289fdd5c002231 Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Thu, 17 Jan 2019 20:03:14 +0800
Subject: [PATCH 052/111] docker: Lock the RWLayer while
committing/exporting
reason:Add a rw mutex to `mountLayer/roLayer/emptyLayer` and introduce
new methods `RLockRWLayer()` and `RUnlockRWLayer()` to `RWLayer`.
Now the rw layer of the container would be locked to block removal of
that layer.
Cherry-pick from docker 1.11.2:
- 2923a77c Lock the RWLayer while committing/exporting
Change-Id: I11d6dcb60a23fe3516cebaed36d19aabaa863769
Signed-off-by: Yuanhong Peng <pengyuanhong@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/engine/daemon/commit.go | 2 ++
components/engine/daemon/export.go | 2 ++
components/engine/layer/empty.go | 13 ++++++++++++-
components/engine/layer/layer.go | 7 +++++++
components/engine/layer/layer_store.go | 2 ++
components/engine/layer/mounted_layer.go | 10 ++++++++++
components/engine/layer/ro_layer.go | 10 ++++++++++
7 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/components/engine/daemon/commit.go b/components/engine/daemon/commit.go
index 0f6f440514..fc7d2782ef 100644
--- a/components/engine/daemon/commit.go
+++ b/components/engine/daemon/commit.go
@@ -155,6 +155,8 @@ func (daemon *Daemon) CreateImageFromContainer(name string, c *backend.CreateIma
return "", err
}
+ container.RWLayer.RLockRWLayer()
+ defer container.RWLayer.RUnlockRWLayer()
id, err := daemon.imageService.CommitImage(backend.CommitConfig{
Author: c.Author,
Comment: c.Comment,
diff --git a/components/engine/daemon/export.go b/components/engine/daemon/export.go
index 27bc35967d..ebd2d75f40 100644
--- a/components/engine/daemon/export.go
+++ b/components/engine/daemon/export.go
@@ -34,6 +34,8 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
return errdefs.Conflict(err)
}
+ container.RWLayer.RLockRWLayer()
+ defer container.RWLayer.RUnlockRWLayer()
data, err := daemon.containerExport(container)
if err != nil {
return fmt.Errorf("Error exporting container %s: %v", name, err)
diff --git a/components/engine/layer/empty.go b/components/engine/layer/empty.go
index c81c702140..16a49a7abd 100644
--- a/components/engine/layer/empty.go
+++ b/components/engine/layer/empty.go
@@ -6,13 +6,16 @@ import (
"fmt"
"io"
"io/ioutil"
+ "sync"
)
// DigestSHA256EmptyTar is the canonical sha256 digest of empty tar file -
// (1024 NULL bytes)
const DigestSHA256EmptyTar = DiffID("sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef")
-type emptyLayer struct{}
+type emptyLayer struct {
+ sync.RWMutex
+}
// EmptyLayer is a layer that corresponds to empty tar.
var EmptyLayer = &emptyLayer{}
@@ -55,6 +58,14 @@ func (el *emptyLayer) Metadata() (map[string]string, error) {
return make(map[string]string), nil
}
+func (el *emptyLayer) RLockRWLayer() {
+ el.RLock()
+}
+
+func (el *emptyLayer) RUnlockRWLayer() {
+ el.RUnlock()
+}
+
// IsEmpty returns true if the layer is an EmptyLayer
func IsEmpty(diffID DiffID) bool {
return diffID == DigestSHA256EmptyTar
diff --git a/components/engine/layer/layer.go b/components/engine/layer/layer.go
index cb13c98d0b..e35a13135b 100644
--- a/components/engine/layer/layer.go
+++ b/components/engine/layer/layer.go
@@ -145,6 +145,13 @@ type RWLayer interface {
// Metadata returns the low level metadata for the mutable layer
Metadata() (map[string]string, error)
+
+ // RLockRWLayer locks the RWLayer to block unmounting/removal
+ // of that layer
+ RLockRWLayer()
+
+ // RUnlockRWLayer unlocks the RWLayer
+ RUnlockRWLayer()
}
// Metadata holds information about a
diff --git a/components/engine/layer/layer_store.go b/components/engine/layer/layer_store.go
index f22e9c666c..7c80a29645 100644
--- a/components/engine/layer/layer_store.go
+++ b/components/engine/layer/layer_store.go
@@ -666,6 +666,8 @@ func (ls *layerStore) ReleaseRWLayer(l RWLayer) ([]Metadata, error) {
return []Metadata{}, nil
}
+ m.Lock()
+ defer m.Unlock()
if err := m.deleteReference(l); err != nil {
return nil, err
}
diff --git a/components/engine/layer/mounted_layer.go b/components/engine/layer/mounted_layer.go
index d6858c662c..66711d6cf7 100644
--- a/components/engine/layer/mounted_layer.go
+++ b/components/engine/layer/mounted_layer.go
@@ -2,6 +2,7 @@ package layer // import "github.com/docker/docker/layer"
import (
"io"
+ "sync"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
@@ -16,6 +17,7 @@ type mountedLayer struct {
layerStore *layerStore
references map[RWLayer]*referencedRWLayer
+ sync.RWMutex
}
func (ml *mountedLayer) cacheParent() string {
@@ -58,6 +60,14 @@ func (ml *mountedLayer) Metadata() (map[string]string, error) {
return ml.layerStore.driver.GetMetadata(ml.mountID)
}
+func (ml *mountedLayer) RLockRWLayer() {
+ ml.RLock()
+}
+
+func (ml *mountedLayer) RUnlockRWLayer() {
+ ml.RUnlock()
+}
+
func (ml *mountedLayer) getReference() RWLayer {
ref := &referencedRWLayer{
mountedLayer: ml,
diff --git a/components/engine/layer/ro_layer.go b/components/engine/layer/ro_layer.go
index 3555e8b027..59bcf17d18 100644
--- a/components/engine/layer/ro_layer.go
+++ b/components/engine/layer/ro_layer.go
@@ -3,6 +3,7 @@ package layer // import "github.com/docker/docker/layer"
import (
"fmt"
"io"
+ "sync"
"github.com/docker/distribution"
"github.com/opencontainers/go-digest"
@@ -19,6 +20,7 @@ type roLayer struct {
referenceCount int
references map[Layer]struct{}
+ sync.RWMutex
}
// TarStream for roLayer guarantees that the data that is produced is the exact
@@ -92,6 +94,14 @@ func (rl *roLayer) Metadata() (map[string]string, error) {
return rl.layerStore.driver.GetMetadata(rl.cacheID)
}
+func (rl *roLayer) RLockRWLayer() {
+ rl.RLock()
+}
+
+func (rl *roLayer) RUnlockRWLayer() {
+ rl.RUnlock()
+}
+
type referencedCacheLayer struct {
*roLayer
}
--
2.17.1

View File

@ -0,0 +1,46 @@
From 2afc35ae4a34d70007bccb971d1f074574a3e282 Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Thu, 17 Jan 2019 20:13:18 +0800
Subject: [PATCH 053/111] docker: remove init layer when no space to
create RW layer
reason:remove init layer when no space to create RW layer
Cherry-pick from docker 1.11.2:
- 24d00cf remove init layer when no space to create RW layer
Change-Id: I3ef9fa1073c12242f5f56997883fe831d9497a9a
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/engine/layer/layer_store.go | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/components/engine/layer/layer_store.go b/components/engine/layer/layer_store.go
index 7c80a29645..20c0195b79 100644
--- a/components/engine/layer/layer_store.go
+++ b/components/engine/layer/layer_store.go
@@ -598,6 +598,20 @@ func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWL
// Release parent chain if error
defer func() {
if err != nil {
+ m.Lock()
+ if err := ls.driver.Remove(m.mountID); err != nil {
+ logrus.Errorf("Error removing mounted layer during create rw layer %s: %s", m.name, err)
+ }
+ if m.initID != "" {
+ if err := ls.driver.Remove(m.initID); err != nil {
+ logrus.Errorf("Error removing init layer during create rw layer %s: %s", m.name, err)
+ }
+ }
+ if err := ls.store.RemoveMount(m.name); err != nil {
+ logrus.Errorf("Error removing mount metadata during create rw layer %s: %s", m.name, err)
+ }
+ m.Unlock()
+
ls.layerL.Lock()
ls.releaseLayer(p)
ls.layerL.Unlock()
--
2.17.1

View File

@ -0,0 +1,78 @@
From 1fb61b2addb6043e8403a613b4229c20070f8bfe Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Fri, 18 Jan 2019 17:38:47 +0800
Subject: [PATCH 054/111] docker: remove init layer if fails in
initMount
reason:remove init layer if fails in initMount
Cherry-pick from docker 1.11.2:
- 673c733 remove init layer if fails in initMount
during initMount, operation could fails after device
created, it should be removed during rollback
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
-------
- 424970f fix metadata file deleted mistakely
fix devicemapper metadata file "base" be deleted mistakely
Signed-off-by: leizhongkai <leizhongkai@huawei.com>
Change-Id: Ieb40a8cfd3272abf28bfb046d77ecb61aea02bfa
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/engine/layer/layer_store.go | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/components/engine/layer/layer_store.go b/components/engine/layer/layer_store.go
index 20c0195b79..cbb1ee4a19 100644
--- a/components/engine/layer/layer_store.go
+++ b/components/engine/layer/layer_store.go
@@ -599,16 +599,16 @@ func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWL
defer func() {
if err != nil {
m.Lock()
- if err := ls.driver.Remove(m.mountID); err != nil {
- logrus.Errorf("Error removing mounted layer during create rw layer %s: %s", m.name, err)
+ if deferErr := ls.driver.Remove(m.mountID); deferErr != nil {
+ logrus.Errorf("Error removing mounted layer during create rw layer %s: %s", m.name, deferErr)
}
if m.initID != "" {
- if err := ls.driver.Remove(m.initID); err != nil {
- logrus.Errorf("Error removing init layer during create rw layer %s: %s", m.name, err)
+ if deferErr := ls.driver.Remove(m.initID); deferErr != nil {
+ logrus.Errorf("Error removing init layer during create rw layer %s: %s", m.name, deferErr)
}
}
- if err := ls.store.RemoveMount(m.name); err != nil {
- logrus.Errorf("Error removing mount metadata during create rw layer %s: %s", m.name, err)
+ if deferErr := ls.store.RemoveMount(m.name); deferErr != nil {
+ logrus.Errorf("Error removing mount metadata during create rw layer %s: %s", m.name, deferErr)
}
m.Unlock()
@@ -743,7 +743,7 @@ func (ls *layerStore) saveMount(mount *mountedLayer) error {
return nil
}
-func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit, storageOpt map[string]string) (string, error) {
+func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit, storageOpt map[string]string) (id string, err error) {
// Use "<graph-id>-init" to maintain compatibility with graph drivers
// which are expecting this layer with this special name. If all
// graph drivers can be updated to not rely on knowing about this layer
@@ -758,6 +758,14 @@ func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc Mou
if err := ls.driver.CreateReadWrite(initID, parent, createOpts); err != nil {
return "", err
}
+ defer func() {
+ if err != nil {
+ if deferErr := ls.driver.Remove(initID); deferErr != nil {
+ logrus.Errorf("Error removing init layer during init mount %s: %s", initID, deferErr)
+ }
+ }
+ }()
+
p, err := ls.driver.Get(initID, "")
if err != nil {
return "", err
--
2.17.1

View File

@ -0,0 +1,84 @@
From 04094d4f0ca583bf2a3eccc390515840ad322853 Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Thu, 17 Jan 2019 20:45:45 +0800
Subject: [PATCH 055/111] docker: range checking for memory and
memory.swap
reason:range checking for memory and memory.swap, avoid overflow
Cherry-pick from docker 1.11.2:
- 3dd33a7 range checking for memory and memory.swap
Change-Id: I1736627a3f847decd36117f307a4919707908b32
Signed-off-by: stella <zhangyu235@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/cli/vendor/github.com/docker/go-units/size.go | 4 ++++
components/engine/daemon/daemon_unix.go | 5 ++++-
.../engine/vendor/github.com/docker/go-units/Checklist | 1 +
components/engine/vendor/github.com/docker/go-units/size.go | 4 ++++
4 files changed, 13 insertions(+), 1 deletion(-)
create mode 100644 components/engine/vendor/github.com/docker/go-units/Checklist
diff --git a/components/cli/vendor/github.com/docker/go-units/size.go b/components/cli/vendor/github.com/docker/go-units/size.go
index 85f6ab0715..2b47b662ba 100644
--- a/components/cli/vendor/github.com/docker/go-units/size.go
+++ b/components/cli/vendor/github.com/docker/go-units/size.go
@@ -104,5 +104,9 @@ func parseSize(sizeStr string, uMap unitMap) (int64, error) {
size *= float64(mul)
}
+ if int64(size) < 0 {
+ return -1, fmt.Errorf("%s converted to int64 overflowed!", sizeStr)
+ }
+
return int64(size), nil
}
diff --git a/components/engine/daemon/daemon_unix.go b/components/engine/daemon/daemon_unix.go
index d4a32a0b25..e48dfcd1ef 100644
--- a/components/engine/daemon/daemon_unix.go
+++ b/components/engine/daemon/daemon_unix.go
@@ -65,7 +65,7 @@ const (
linuxMinCPUShares = 2
linuxMaxCPUShares = 262144
platformSupported = true
- // It's not kernel limit, we want this 4M limit to supply a reasonable functional container
+ // It's not kernel limit, we want this 4MB limit to supply a reasonable functional container
linuxMinMemory = 4194304
// constants for remapped root settings
defaultIDSpecifier = "default"
@@ -293,6 +293,9 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConf
if hostConfig.Memory > 0 && hostConfig.MemorySwap == 0 {
// By default, MemorySwap is set to twice the size of Memory.
hostConfig.MemorySwap = hostConfig.Memory * 2
+ if hostConfig.MemorySwap < 0 {
+ return fmt.Errorf("invalid memory swap! The memory swap is double of memory, and should be less than the maximum of int64.")
+ }
}
if hostConfig.ShmSize == 0 {
hostConfig.ShmSize = config.DefaultShmSize
diff --git a/components/engine/vendor/github.com/docker/go-units/Checklist b/components/engine/vendor/github.com/docker/go-units/Checklist
new file mode 100644
index 0000000000..6b3f1461e8
--- /dev/null
+++ b/components/engine/vendor/github.com/docker/go-units/Checklist
@@ -0,0 +1 @@
+add value range checking when converting units
\ No newline at end of file
diff --git a/components/engine/vendor/github.com/docker/go-units/size.go b/components/engine/vendor/github.com/docker/go-units/size.go
index 85f6ab0715..2b47b662ba 100644
--- a/components/engine/vendor/github.com/docker/go-units/size.go
+++ b/components/engine/vendor/github.com/docker/go-units/size.go
@@ -104,5 +104,9 @@ func parseSize(sizeStr string, uMap unitMap) (int64, error) {
size *= float64(mul)
}
+ if int64(size) < 0 {
+ return -1, fmt.Errorf("%s converted to int64 overflowed!", sizeStr)
+ }
+
return int64(size), nil
}
--
2.17.1

View File

@ -0,0 +1,132 @@
From e894ad0fa1c84d1a01afc47ccc52c3556121bbcd Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Tue, 8 Jan 2019 20:17:21 +0800
Subject: [PATCH 056/111] docker: check cpuset.cpu and cpuset.mem
reason:check cpuset.cpu and cpuset.mem
cherry-pick from docker 1.11.2:
- 1c769f0 check cpuset.cpu and cpuset.mem
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
-----
- 782f78f check cpuset.cpu and cpuset.mem
Signed-off-by: wangyi45 <wangyi45@huawei.com>
Change-Id: If21cad2023d737d03ba3d4a83e62d11fb2297945
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/engine/daemon/daemon_unix.go | 2 +
components/engine/pkg/sysinfo/sysinfo.go | 64 +++++++++++++++++++++++-
2 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/components/engine/daemon/daemon_unix.go b/components/engine/daemon/daemon_unix.go
index e48dfcd1ef..b20c66e27b 100644
--- a/components/engine/daemon/daemon_unix.go
+++ b/components/engine/daemon/daemon_unix.go
@@ -499,6 +499,7 @@ func (daemon *Daemon) verifyContainerResources(hostConfig *containertypes.HostCo
}
cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(resources.CpusetCpus)
if err != nil {
+ logrus.Errorf("Checking cpuset.cpus got %#v", err.Error())
return warnings, errors.Wrapf(err, "Invalid value %s for cpuset cpus", resources.CpusetCpus)
}
if !cpusAvailable {
@@ -506,6 +507,7 @@ func (daemon *Daemon) verifyContainerResources(hostConfig *containertypes.HostCo
}
memsAvailable, err := sysInfo.IsCpusetMemsAvailable(resources.CpusetMems)
if err != nil {
+ logrus.Errorf("Checking cpuset.mems got %#v", err.Error())
return warnings, errors.Wrapf(err, "Invalid value %s for cpuset mems", resources.CpusetMems)
}
if !memsAvailable {
diff --git a/components/engine/pkg/sysinfo/sysinfo.go b/components/engine/pkg/sysinfo/sysinfo.go
index 5d9320218c..7ea1be5daf 100644
--- a/components/engine/pkg/sysinfo/sysinfo.go
+++ b/components/engine/pkg/sysinfo/sysinfo.go
@@ -1,6 +1,12 @@
package sysinfo // import "github.com/docker/docker/pkg/sysinfo"
-import "github.com/docker/docker/pkg/parsers"
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/docker/docker/pkg/parsers"
+)
// SysInfo stores information about which features a kernel supports.
// TODO Windows: Factor out platform specific capabilities.
@@ -123,6 +129,13 @@ func (c cgroupCpusetInfo) IsCpusetMemsAvailable(provided string) (bool, error) {
}
func isCpusetListAvailable(provided, available string) (bool, error) {
+ if err := checkCPU(provided, available); err != nil {
+ if strings.Contains(err.Error(), "invalid format") {
+ return false, err
+ }
+ return false, nil
+ }
+
parsedAvailable, err := parsers.ParseUintList(available)
if err != nil {
return false, err
@@ -147,6 +160,55 @@ func isCpusetListAvailable(provided, available string) (bool, error) {
return true, nil
}
+func checkCPU(provided, available string) error {
+ if provided == "" {
+ return nil
+ }
+
+ maxAvailable, err := maxCPU(available)
+ if err != nil {
+ return err
+ }
+
+ maxRequest, err := maxCPU(provided)
+ if err != nil {
+ return err
+ }
+
+ if maxRequest > maxAvailable {
+ return fmt.Errorf("invalid maxRequest is %d, max available: %d", maxRequest, maxAvailable)
+ }
+
+ return nil
+}
+
+func maxCPU(cores string) (int, error) {
+ var max int
+ split := strings.Split(cores, ",")
+ errInvalidFormat := fmt.Errorf("invalid format: %s", cores)
+ for _, r := range split {
+ if !strings.Contains(r, "-") {
+ v, err := strconv.Atoi(r)
+ if err != nil {
+ return max, errInvalidFormat
+ }
+ if v > max {
+ max = v
+ }
+ } else {
+ split := strings.SplitN(r, "-", 2)
+ end, err := strconv.Atoi(split[1])
+ if err != nil {
+ return max, errInvalidFormat
+ }
+ if end > max {
+ max = end
+ }
+ }
+ }
+ return max, nil
+}
+
// Returns bit count of 1, used by NumCPU
func popcnt(x uint64) (n byte) {
x -= (x >> 1) & 0x5555555555555555
--
2.17.1

View File

@ -0,0 +1,55 @@
From 241fc5d726e63e995d3518b734e18efff76284ac Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Fri, 18 Jan 2019 11:07:06 +0800
Subject: [PATCH 057/111] docker: Ignore ToDisk error in StateChanged
reason:If container is started normally, but failed to save
state to disk due to error "no space left on device",
then container can not be stopped, because container's
infomation in libcontainerd is cleaned up when error
occurred(so it can not process event 'exit').
We can ignore ToDisk error in StateChanged, it only
change status of container. Status is correct if docker
daemon not restart, because right status exists in memory.
If docker daemon restart, it will restore these status
using status of containerd, so status is also correct.
This fix can break consistency of status in memory and
disk, but considering there is no space in disk, it is
not a big problem in this situation. Status in disk can
recover if disk have space and if ToDisk is written
again(for example, status changed).
Fix issuse #322
Cherry-pick from docker 1.11.2:
- 5eb9015 Ignore ToDisk error in StateChanged
Change-Id: Ifbdbffac06d1d739b03ea13962fb2d1fde7b5b3e
Signed-off-by: Fengtu Wang <wangfengtu@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/engine/daemon/monitor.go | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/components/engine/daemon/monitor.go b/components/engine/daemon/monitor.go
index 9b4452d7ef..807cdcaa89 100644
--- a/components/engine/daemon/monitor.go
+++ b/components/engine/daemon/monitor.go
@@ -154,7 +154,11 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerd.EventType, ei libc
daemon.initHealthMonitor(c)
if err := c.CheckpointTo(daemon.containersReplica); err != nil {
- return err
+ // If return err, container can not be stopped, see issue #322 for detail.
+ // Ignore error is safe, because if daemon not restart, status in memory is
+ // correct, and if daemon restart, it will restore status using status in
+ // containerd, so status in memory is also correct.
+ logrus.Debugf("Set status %v to disk failed: %v", e, err)
}
daemon.LogContainerEvent(c, "start")
}
--
2.17.1

View File

@ -0,0 +1,35 @@
From ee64a0b5fd645d1765b0c50cbaab76c17bab9b28 Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Fri, 18 Jan 2019 14:46:21 +0800
Subject: [PATCH 058/111] cleanup: cleanup incompleted device while
docker startup
cleanup incompleted device while docker startup
Change-Id: I9a9a96c655b61ac132fa7ed101dc9953c1bb613d
Signed-off-by: Wentao Zhang <zhangwentao234@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/engine/daemon/graphdriver/devmapper/deviceset.go | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/components/engine/daemon/graphdriver/devmapper/deviceset.go b/components/engine/daemon/graphdriver/devmapper/deviceset.go
index b3e142e2ba..f4dc589c6e 100644
--- a/components/engine/daemon/graphdriver/devmapper/deviceset.go
+++ b/components/engine/daemon/graphdriver/devmapper/deviceset.go
@@ -1753,6 +1753,12 @@ func (devices *DeviceSet) initDevmapper(doInit bool) (retErr error) {
}
logrus.Debugf("devmapper: remove broken device: %s", name)
}
+ if _, err := os.Stat(filepath.Join("/dev/mapper/", name)); err != nil {
+ if err := devicemapper.RemoveDevice(name); err != nil {
+ logrus.Warnf("devmapper: remove incompelete device(%s): %v", name, err)
+ }
+ logrus.Debugf("devmapper: remove incompelete device: %s", name)
+ }
}
// Check for the existence of the thin-pool device
--
2.17.1

View File

@ -0,0 +1,110 @@
From ef238d650231f8346078536b6133f147df11283a Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Fri, 18 Jan 2019 19:21:39 +0800
Subject: [PATCH 059/111] overlay2: avoid middle state while removing
images under overlay2
reason:avoid middle state while removing images under overlay2
kill -9 daemon while rmi images may cause some inconsistent state
of that image
if image symlink is removed but the id directory remained. daemon
restart and load again, the images look fine but create container
with it will error out:
`docker: Error response from daemon: error creating overlay
mount to /var/lib/docker/overlay2/xxx-init/merged:
no such file or directory`
This patch move symlink removal after directory removal, and check
link file state while daemon restore, to clean up stale links.
Change-Id: I44328bc2261c9ec73bcdcbed3d741e569cd4a834
Signed-off-by: Deng Guangxing <dengguangxing@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
.../daemon/graphdriver/overlay2/overlay.go | 40 ++++++++++++++++---
1 file changed, 34 insertions(+), 6 deletions(-)
diff --git a/components/engine/daemon/graphdriver/overlay2/overlay.go b/components/engine/daemon/graphdriver/overlay2/overlay.go
index 773d5232cc..cf8993e9f3 100644
--- a/components/engine/daemon/graphdriver/overlay2/overlay.go
+++ b/components/engine/daemon/graphdriver/overlay2/overlay.go
@@ -229,6 +229,8 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, fmt.Errorf("Storage Option overlay2.size only supported for backingFS XFS or ext4. Found %v", backingFs)
}
+ d.cleanupLinkDir()
+
// figure out whether "index=off" option is recognized by the kernel
_, err = os.Stat("/sys/module/overlay/parameters/index")
switch {
@@ -245,6 +247,19 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return d, nil
}
+func (d *Driver) cleanupLinkDir() {
+ filepath.Walk(path.Join(d.home, linkDir), func(path string, f os.FileInfo, err error) error {
+ if _, serr := filepath.EvalSymlinks(path); serr != nil {
+ logrus.Warnf("[overlay2]: remove invalid symlink: %s", path)
+ os.RemoveAll(path)
+ }
+ // always return nil, to walk all the symlink
+ return nil
+ })
+
+ return
+}
+
func parseOptions(options []string) (*overlayOptions, error) {
o := &overlayOptions{}
for _, option := range options {
@@ -575,8 +590,11 @@ func (d *Driver) Remove(id string) error {
d.locker.Lock(id)
defer d.locker.Unlock(id)
dir := d.dir(id)
- lid, err := ioutil.ReadFile(path.Join(dir, "link"))
- if err == nil {
+ lid, lerr := ioutil.ReadFile(path.Join(dir, "link"))
+ if err := system.EnsureRemoveAll(dir); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ if lerr == nil {
if !verifyID(string(lid), idLength) {
logrus.WithField("storage-driver", "overlay2").Errorf("refusing to remove empty link for layer %v", id)
} else if err := os.RemoveAll(path.Join(d.home, linkDir, string(lid))); err != nil {
@@ -568,9 +586,6 @@ func (d *Driver) Remove(id string) error {
}
}
- if err := system.EnsureRemoveAll(dir); err != nil && !os.IsNotExist(err) {
- return err
- }
return nil
}
@@ -710,7 +725,20 @@ func (d *Driver) Put(id string) error {
// Exists checks to see if the id is already mounted.
func (d *Driver) Exists(id string) bool {
- _, rerr := os.Stat(d.dir(id))
+ var rerr error
+ defer func() {
+ if rerr != nil {
+ logrus.Warnf("layer(%s) not exist: %s", id, rerr)
+ d.Remove(id)
+ }
+ }()
+
+ // check if the id directory exist and is valid
+ // check if link file exist and get link string from it
+ // check if symlink file exist
+ // if symlink not exist, create a new one and update link file
+ // any steps failed ,we will return false and remove this id layer
+ _, rerr = os.Stat(d.dir(id))
if rerr == nil {
lstr, err := ioutil.ReadFile(path.Join(d.dir(id), "link"))
// link is valid
--
2.17.1

View File

@ -0,0 +1,90 @@
From 42d1e785f2343323822db35966412fdcfce87989 Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Fri, 18 Jan 2019 15:55:51 +0800
Subject: [PATCH 060/111] debug: Add check when execute docker {cp,
export, diff}
reason:If a container is in Dead or RemovalInProgress state,it should return err for tip.
Cherry-pick from docker 1.11.2:
- 903a5de Add check when execute docker {cp, export, diff}
Change-Id: Idf441bf7d194cc61c618c20c0e6ef8b339e81191
Signed-off-by: yangshukui <yangshukui@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/engine/daemon/archive.go | 13 +++++++++++++
components/engine/daemon/changes.go | 5 +++++
2 files changed, 18 insertions(+)
diff --git a/components/engine/daemon/archive.go b/components/engine/daemon/archive.go
index 9c7971b56e..f1b715d9ae 100644
--- a/components/engine/daemon/archive.go
+++ b/components/engine/daemon/archive.go
@@ -1,6 +1,7 @@
package daemon // import "github.com/docker/docker/daemon"
import (
+ "fmt"
"io"
"os"
"strings"
@@ -77,6 +78,10 @@ func (daemon *Daemon) ContainerStatPath(name string, path string) (stat *types.C
return nil, err
}
+ if container.RemovalInProgress || container.Dead {
+ return nil, fmt.Errorf("can't stat file from a container which is dead or marked for removal")
+ }
+
// Make sure an online file-system operation is permitted.
if err := daemon.isOnlineFSOperationPermitted(container); err != nil {
return nil, errdefs.System(err)
@@ -102,6 +107,10 @@ func (daemon *Daemon) ContainerArchivePath(name string, path string) (content io
return nil, nil, err
}
+ if container.RemovalInProgress || container.Dead {
+ return nil, nil, fmt.Errorf("can't copy file from a container which is dead or marked for removal")
+ }
+
// Make sure an online file-system operation is permitted.
if err := daemon.isOnlineFSOperationPermitted(container); err != nil {
return nil, nil, errdefs.System(err)
@@ -130,6 +139,10 @@ func (daemon *Daemon) ContainerExtractToDir(name, path string, copyUIDGID, noOve
return err
}
+ if container.RemovalInProgress || container.Dead {
+ return fmt.Errorf("can't copy to a container which is dead or marked for removal")
+ }
+
// Make sure an online file-system operation is permitted.
if err := daemon.isOnlineFSOperationPermitted(container); err != nil {
return errdefs.System(err)
diff --git a/components/engine/daemon/changes.go b/components/engine/daemon/changes.go
index 70b3f6b943..55575a96bd 100644
--- a/components/engine/daemon/changes.go
+++ b/components/engine/daemon/changes.go
@@ -6,6 +6,7 @@ import (
"time"
"github.com/docker/docker/pkg/archive"
+ "fmt"
)
// ContainerChanges returns a list of container fs changes
@@ -16,6 +17,10 @@ func (daemon *Daemon) ContainerChanges(name string) ([]archive.Change, error) {
return nil, err
}
+ if container.RemovalInProgress || container.Dead {
+ return nil, fmt.Errorf("can't diff a container which is dead or marked for removal")
+ }
+
if runtime.GOOS == "windows" && container.IsRunning() {
return nil, errors.New("Windows does not support diff of a running container")
}
--
2.17.1

View File

@ -0,0 +1,54 @@
From 3b24c397492b921ce00f9786c8f6dd22cf2bb420 Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Fri, 18 Jan 2019 21:31:47 +0800
Subject: [PATCH 061/111] docker: check seccomp file size(max:10M)
before read into memory
reason:when seccomp file size is not limited, docker may result in memory OOM
Cherry-pick from docker 1.11.2:
- 3660784 check seccomp file size(max:10M) before read into memory
Change-Id: I6289b2e84e5aaf6d876e689c842f9d18acaf6814
Signed-off-by: xueshaojia <xueshaojia@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/cli/cli/command/container/opts.go | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/components/cli/cli/command/container/opts.go b/components/cli/cli/command/container/opts.go
index 8e07aa77cb..cbbc110f9c 100644
--- a/components/cli/cli/command/container/opts.go
+++ b/components/cli/cli/command/container/opts.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
+ "os"
"path"
"regexp"
"strconv"
@@ -27,6 +28,8 @@ var (
deviceCgroupRuleRegexp = regexp.MustCompile(`^[acb] ([0-9]+|\*):([0-9]+|\*) [rwm]{1,3}$`)
)
+const seccompFileMaxSize = 10 * 1024 * 1024
+
// containerOptions is a data object with all the options for creating a container
type containerOptions struct {
attach opts.ListOpts
@@ -726,6 +729,11 @@ func parseSecurityOpts(securityOpts []string) ([]string, error) {
}
}
if con[0] == "seccomp" && con[1] != "unconfined" {
+ if fileInfo, err := os.Stat(con[1]); err != nil {
+ return securityOpts, fmt.Errorf("stat seccomp profile (%s) failed: %v", con[1], err)
+ } else if fileInfo.Size() > seccompFileMaxSize {
+ return securityOpts, fmt.Errorf("stat seccomp profile (%s) failed: size exceed limit %dM", con[1], seccompFileMaxSize/1024/1024)
+ }
f, err := ioutil.ReadFile(con[1])
if err != nil {
return securityOpts, errors.Errorf("opening seccomp profile (%s) failed: %v", con[1], err)
--
2.17.1

View File

@ -0,0 +1,87 @@
From e065d6675c95e37144284f2ee5af3f7e326f9efe Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Fri, 18 Jan 2019 22:11:29 +0800
Subject: [PATCH 062/111] docker: check file size before reading
"envfile" and "labelfile", in case OOM
reason:check file size before reading "envfile" and "labelfile", in case OOM
Cherry-pick from docker 1.11.2:
- 931660a check file size before reading "envfile" and "labelfile", in case OOM
Change-Id: I32bc7951565d0e6e720cf7d9f1d53f8709ebc8b3
Signed-off-by: panwenxiang <panwenxiang@huawei.com>
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/cli/cli/command/container/opts.go | 28 +++++++++++++++++---
1 file changed, 25 insertions(+), 3 deletions(-)
diff --git a/components/cli/cli/command/container/opts.go b/components/cli/cli/command/container/opts.go
index cbbc110f9c..a1bf2be79a 100644
--- a/components/cli/cli/command/container/opts.go
+++ b/components/cli/cli/command/container/opts.go
@@ -28,7 +28,7 @@ var (
deviceCgroupRuleRegexp = regexp.MustCompile(`^[acb] ([0-9]+|\*):([0-9]+|\*) [rwm]{1,3}$`)
)
-const seccompFileMaxSize = 10 * 1024 * 1024
+const fileMaxSize = 10 * 1024 * 1024
// containerOptions is a data object with all the options for creating a container
type containerOptions struct {
@@ -435,12 +435,20 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
}
// collect all the environment variables for the container
+ err = checkFileSizeValid(copts.envFile.GetAll())
+ if err != nil {
+ return nil, err
+ }
envVariables, err := opts.ReadKVEnvStrings(copts.envFile.GetAll(), copts.env.GetAll())
if err != nil {
return nil, err
}
// collect all the labels for the container
+ err = checkFileSizeValid(copts.envFile.GetAll())
+ if err != nil {
+ return nil, err
+ }
labels, err := opts.ReadKVStrings(copts.labelsFile.GetAll(), copts.labels.GetAll())
if err != nil {
return nil, err
@@ -692,6 +700,20 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
}, nil
}
+// check file size
+func checkFileSizeValid(files []string) error {
+ for _, ef := range files {
+ fileInfo, err := os.Stat(ef)
+ if err != nil {
+ return err
+ }
+ if fileInfo.Size() > fileMaxSize {
+ return fmt.Errorf("check (%s) file size is %d, size exceed limit %d ", ef, fileInfo.Size(), fileMaxSize)
+ }
+ }
+ return nil
+}
+
func parsePortOpts(publishOpts []string) ([]string, error) {
optsList := []string{}
for _, publish := range publishOpts {
@@ -731,8 +753,8 @@ func parseSecurityOpts(securityOpts []string) ([]string, error) {
if con[0] == "seccomp" && con[1] != "unconfined" {
if fileInfo, err := os.Stat(con[1]); err != nil {
return securityOpts, fmt.Errorf("stat seccomp profile (%s) failed: %v", con[1], err)
- } else if fileInfo.Size() > seccompFileMaxSize {
- return securityOpts, fmt.Errorf("stat seccomp profile (%s) failed: size exceed limit %dM", con[1], seccompFileMaxSize/1024/1024)
+ } else if fileInfo.Size() > fileMaxSize {
+ return securityOpts, fmt.Errorf("stat seccomp profile (%s) failed: size exceed limit %dM", con[1], fileMaxSize/1024/1024)
}
f, err := ioutil.ReadFile(con[1])
if err != nil {
--
2.17.1

View File

@ -0,0 +1,38 @@
From a683efcf5e14acdd40574edeaed6b293b0536867 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Tue, 15 Jan 2019 10:16:25 +0800
Subject: [PATCH 063/111] test: fix umask make file mode failed
reason: set umask to 0022 make sure test added file's mode match expect.
Change-Id: I258d3d999c82041a16851f438f556746e6477ebf
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/internal/test/fakecontext/context.go | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/components/engine/internal/test/fakecontext/context.go b/components/engine/internal/test/fakecontext/context.go
index 8b11da207e..24f326b864 100644
--- a/components/engine/internal/test/fakecontext/context.go
+++ b/components/engine/internal/test/fakecontext/context.go
@@ -6,6 +6,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "syscall"
"github.com/docker/docker/internal/test"
"github.com/docker/docker/pkg/archive"
@@ -96,6 +97,9 @@ func (f *Fake) Add(file, content string) error {
}
func (f *Fake) addFile(file string, content []byte) error {
+ mask := syscall.Umask(0022)
+ defer syscall.Umask(mask)
+
fp := filepath.Join(f.Dir, filepath.FromSlash(file))
dirpath := filepath.Dir(fp)
if dirpath != "." {
--
2.17.1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
From 634d7c920176c726b8d32d8aee50c8073f4892a3 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Sun, 20 Jan 2019 15:35:57 +0800
Subject: [PATCH 068/111] pause: fix docker stop stuck on paused
container
reason: docker-18.09 support docker stop while container is paused.
ref 7aed75f09c * Allow stopping of paused container.
now docker function is moved to docker, so we still have to check
container paused status.
Change-Id: I60731c76808abb5a76daf96c2aba656d73a87e96
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/daemon/kill.go | 5 +++++
components/engine/daemon/unpause.go | 5 +++++
2 files changed, 10 insertions(+)
diff --git a/components/engine/daemon/kill.go b/components/engine/daemon/kill.go
index 3e6457e952..5b2e497604 100644
--- a/components/engine/daemon/kill.go
+++ b/components/engine/daemon/kill.go
@@ -66,6 +66,11 @@ func (daemon *Daemon) killWithSignal(container *containerpkg.Container, sig int)
daemon.stopHealthchecks(container)
+ // We could unpause the container for them rather than returning this error
+ if container.Paused {
+ return fmt.Errorf("Container %s is paused. Unpause the container before stopping or killing", container.ID)
+ }
+
if !container.Running {
return errNotRunning(container.ID)
}
diff --git a/components/engine/daemon/unpause.go b/components/engine/daemon/unpause.go
index 290d2b1d0c..2d3c056566 100644
--- a/components/engine/daemon/unpause.go
+++ b/components/engine/daemon/unpause.go
@@ -23,6 +23,11 @@ func (daemon *Daemon) containerUnpause(container *container.Container) error {
container.Lock()
defer container.Unlock()
+ // We cannot unpause the container which is not running
+ if !container.Running {
+ return fmt.Errorf("Container %s is not running", container.ID)
+ }
+
// We cannot unpause the container which is not paused
if !container.Paused {
return fmt.Errorf("Container %s is not paused", container.ID)
--
2.17.1

View File

@ -0,0 +1,108 @@
From a6db97d2574d509b2077236ff48d70c3469a042e Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Sun, 20 Jan 2019 16:39:08 +0800
Subject: [PATCH 069/111] pause: fix log pause/unpause event twice
reason: fix pause/unpause log event twice
Change-Id: If136d713afd37806256500d4760d0a344f7c5d92
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/daemon/monitor.go | 36 ++++++++++++++++++-----------
components/engine/daemon/pause.go | 7 ------
components/engine/daemon/unpause.go | 6 -----
3 files changed, 22 insertions(+), 27 deletions(-)
diff --git a/components/engine/daemon/monitor.go b/components/engine/daemon/monitor.go
index 807cdcaa89..51159eb76d 100644
--- a/components/engine/daemon/monitor.go
+++ b/components/engine/daemon/monitor.go
@@ -167,28 +167,36 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerd.EventType, ei libc
c.Lock()
defer c.Unlock()
- if !c.Paused {
- c.Paused = true
- daemon.setStateCounter(c)
- daemon.updateHealthMonitor(c)
- if err := c.CheckpointTo(daemon.containersReplica); err != nil {
- return err
+ if daemon.IsNativeRuntime(c.HostConfig.Runtime) {
+ logrus.Infof("Pause is moved to docker, skip.")
+ } else {
+ if !c.Paused {
+ c.Paused = true
+ daemon.setStateCounter(c)
+ daemon.updateHealthMonitor(c)
+ if err := c.CheckpointTo(daemon.containersReplica); err != nil {
+ return err
+ }
+ daemon.LogContainerEvent(c, "pause")
}
- daemon.LogContainerEvent(c, "pause")
}
case libcontainerd.EventResumed:
c.Lock()
defer c.Unlock()
- if c.Paused {
- c.Paused = false
- daemon.setStateCounter(c)
- daemon.updateHealthMonitor(c)
+ if daemon.IsNativeRuntime(c.HostConfig.Runtime) {
+ logrus.Infof("Pause is moved to docker, skip.")
+ } else {
+ if c.Paused {
+ c.Paused = false
+ daemon.setStateCounter(c)
+ daemon.updateHealthMonitor(c)
- if err := c.CheckpointTo(daemon.containersReplica); err != nil {
- return err
+ if err := c.CheckpointTo(daemon.containersReplica); err != nil {
+ return err
+ }
+ daemon.LogContainerEvent(c, "unpause")
}
- daemon.LogContainerEvent(c, "unpause")
}
}
return nil
diff --git a/components/engine/daemon/pause.go b/components/engine/daemon/pause.go
index 6f9d8b0f70..494aa326d9 100644
--- a/components/engine/daemon/pause.go
+++ b/components/engine/daemon/pause.go
@@ -48,13 +48,6 @@ func (daemon *Daemon) containerPause(container *container.Container) error {
if err := freezer.Pause(); err != nil {
return fmt.Errorf("Cannot pause container %s: %v", container.ID, err)
}
-
- container.Paused = true
- daemon.setStateCounter(container)
- if err := container.CheckpointTo(daemon.containersReplica); err != nil {
- return err
- }
- daemon.LogContainerEvent(container, "pause")
} else {
if err := daemon.containerd.Pause(context.Background(), container.ID); err != nil {
return fmt.Errorf("Cannot pause container %s: %s", container.ID, err)
diff --git a/components/engine/daemon/unpause.go b/components/engine/daemon/unpause.go
index 2d3c056566..a75589b888 100644
--- a/components/engine/daemon/unpause.go
+++ b/components/engine/daemon/unpause.go
@@ -41,12 +41,6 @@ func (daemon *Daemon) containerUnpause(container *container.Container) error {
if err := freezer.Resume(); err != nil {
return fmt.Errorf("Cannot unpause container %s: %s", container.ID, err)
}
- container.Paused = false
- daemon.setStateCounter(container)
- if err := container.CheckpointTo(daemon.containersReplica); err != nil {
- return err
- }
- daemon.LogContainerEvent(container, "unpause")
} else {
if err := daemon.containerd.Resume(context.Background(), container.ID); err != nil {
return fmt.Errorf("Cannot unpause container %s: %s", container.ID, err)
--
2.17.1

View File

@ -0,0 +1,39 @@
From 1bb39edbf403bf31aaece61510b43d9a6e781f7d Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Mon, 21 Jan 2019 17:57:03 +0800
Subject: [PATCH 070/111] test: fix umask make syscall-test failed
reason: set umask 0022 make sure add file's mode to image syscall-test
as exepected, so user has permission to exec.
Change-Id: Iaad1bc328c81b77aa630bcb9f974aeee3a50ecbf
Signed-off-by: jingrui <jingrui@huawei.com>
---
.../engine/integration-cli/fixtures_linux_daemon_test.go | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/components/engine/integration-cli/fixtures_linux_daemon_test.go b/components/engine/integration-cli/fixtures_linux_daemon_test.go
index 2387a9ebee..7be3c8b185 100644
--- a/components/engine/integration-cli/fixtures_linux_daemon_test.go
+++ b/components/engine/integration-cli/fixtures_linux_daemon_test.go
@@ -9,6 +9,7 @@ import (
"runtime"
"strings"
"sync"
+ "syscall"
"github.com/docker/docker/integration-cli/checker"
"github.com/docker/docker/internal/test/fixtures/load"
@@ -28,6 +29,9 @@ var ensureSyscallTestOnce sync.Once
func ensureSyscallTest(c *check.C) {
var doIt bool
+ mask := syscall.Umask(0022)
+ defer syscall.Umask(mask)
+
ensureSyscallTestOnce.Do(func() {
doIt = true
})
--
2.17.1

View File

@ -0,0 +1,44 @@
From 6a40d11a3bc9be18cb50fb86099ff52a6d459335 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Mon, 21 Jan 2019 18:57:43 +0800
Subject: [PATCH 071/111] devmapper: Increace udev wait timeout to
185s
reason: cherry-pick commits to docker-18.09
cherry-pick e89615bd40c32f95d095c17efaf5258b15543080 from docker-1.11.2
The default time out of latest systemd-udevd on RTOS and EulerOS
is 180s, we use 185s. Even if the time out of systemd-udevd is 30s,
set 185s on docker side is also safe, it will just take a longer time
to return when time out really happen, we should make sure the timeout
on docker side is bigger than the timeout on systemd-udevd.
Signed-off-by: Lei Jitang <leijitang@huawei.com>
Change-Id: I05d722f22a0c7728ae1bbe23ab67c567d1694b67
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/daemon/graphdriver/devmapper/deviceset.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/components/engine/daemon/graphdriver/devmapper/deviceset.go b/components/engine/daemon/graphdriver/devmapper/deviceset.go
index f4dc589c6e..f5c0b044c4 100644
--- a/components/engine/daemon/graphdriver/devmapper/deviceset.go
+++ b/components/engine/daemon/graphdriver/devmapper/deviceset.go
@@ -42,9 +42,9 @@ var (
defaultUdevSyncOverride = false
maxDeviceID = 0xffffff // 24 bit, pool limit
deviceIDMapSz = (maxDeviceID + 1) / 8
- // The default timeout is 30s from `man systemd-udevd`, we use 35
- // just to make sure the timeout really happened in systemd-udevd
- defaultUdevWaitTimeout = 35
+ // The default timeout for latest systemd on RTOS and EulerOS is 180s
+ // we use 185s to make sure the timeout really happened.
+ defaultUdevWaitTimeout = 185
driverDeferredRemovalSupport = false
enableDeferredRemoval = false
enableDeferredDeletion = false
--
2.17.1

View File

@ -0,0 +1,36 @@
From 59d4dd7fdb0c33dc4c3be2330606ec7724cb368c Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Fri, 11 Jan 2019 17:16:21 +0800
Subject: [PATCH 072/111] pause: fix test can not stop paused
container failed
reason: pause function moved to docker and does not support stop paused
container. return error message when stop a paused container.
Change-Id: Ia7b15877980088cdb4eaf9f7e3dd86667df0157b
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/integration/container/pause_test.go | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/components/engine/integration/container/pause_test.go b/components/engine/integration/container/pause_test.go
index 8dd2d784b7..da274c89ce 100644
--- a/components/engine/integration/container/pause_test.go
+++ b/components/engine/integration/container/pause_test.go
@@ -79,9 +79,10 @@ func TestPauseStopPausedContainer(t *testing.T) {
assert.NilError(t, err)
err = client.ContainerStop(ctx, cID, nil)
- assert.NilError(t, err)
-
- poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
+ // assert.NilError(t, err)
+ // poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
+ assert.Check(t, is.ErrorContains(err, "is paused"))
+ client.ContainerUnpause(ctx, cID)
}
func getEventActions(t *testing.T, messages <-chan events.Message, errs <-chan error) []string {
--
2.17.1

View File

@ -0,0 +1,68 @@
From 67f1bfcb1df53fcfc044927eda37f0f8b45498dc Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Mon, 21 Jan 2019 22:25:42 +0800
Subject: [PATCH 073/111] service: update docker.service with old
revision
reason: use docker.service as the same one used in Euleros docker
1.11.2 and 17.06
Change-Id: I3deb3f3a24d837c98e535550545fd49ea0822629
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
.../contrib/init/systemd/docker.service | 28 ++++++++-----------
1 file changed, 11 insertions(+), 17 deletions(-)
diff --git a/components/engine/contrib/init/systemd/docker.service b/components/engine/contrib/init/systemd/docker.service
index 517463172b..26c0fe648b 100644
--- a/components/engine/contrib/init/systemd/docker.service
+++ b/components/engine/contrib/init/systemd/docker.service
@@ -1,34 +1,28 @@
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
-After=network-online.target docker.socket firewalld.service
+After=network-online.target firewalld.service
Wants=network-online.target
-Requires=docker.socket
[Service]
Type=notify
-# the default is not to use systemd for cgroups because the delegate issues still
-# exists and systemd currently does not support the cgroup feature set required
-# for containers run by docker
-ExecStart=/usr/bin/dockerd -H fd://
+EnvironmentFile=-/etc/sysconfig/docker
+EnvironmentFile=-/etc/sysconfig/docker-storage
+EnvironmentFile=-/etc/sysconfig/docker-network
+Environment=GOTRACEBACK=crash
+
+ExecStart=/usr/bin/dockerd $OPTIONS \
+ $DOCKER_STORAGE_OPTIONS \
+ $DOCKER_NETWORK_OPTIONS \
+ $INSECURE_REGISTRY
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=1048576
-# Having non-zero Limit*s causes performance problems due to accounting overhead
-# in the kernel. We recommend using cgroups to do container-local accounting.
-LimitNPROC=infinity
+LimitNPROC=1048576
LimitCORE=infinity
-# Uncomment TasksMax if your systemd version supports it.
-# Only systemd 226 and above support this version.
-#TasksMax=infinity
-TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
-# restart the docker process if it exits prematurely
-Restart=on-failure
-StartLimitBurst=3
-StartLimitInterval=60s
[Install]
WantedBy=multi-user.target
--
2.17.1

View File

@ -0,0 +1,199 @@
From 22f9a89d9ddcb03aa5b00dc9ad4372f776c5f73b Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Mon, 21 Jan 2019 23:05:47 +0800
Subject: [PATCH 076/111] version: add EulerVersion
reason: Add EulerVersion and update-version.sh
Cherry-pick from 17.06 for
- 030513895 Add EulerVersion
- 102ee9ddc docker-17: add update-version tool for obs build
Change-Id: I95c9b98bd35e243ce1074fa7dd0d477bdf7dcee9
Signed-off-by: Lei Jitang <leijitang@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/cli/cli/command/system/version.go | 4 ++++
components/cli/cli/version.go | 1 +
components/cli/docker.Makefile | 3 ++-
components/cli/scripts/build/.variables | 2 ++
.../github.com/docker/docker/api/types/types.go | 1 +
components/engine/api/types/types.go | 1 +
components/engine/daemon/info.go | 3 ++-
components/engine/dockerversion/version_lib.go | 1 +
components/engine/hack/make.sh | 1 +
components/engine/hack/make/.go-autogen | 1 +
13 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/components/cli/cli/command/system/version.go b/components/cli/cli/command/system/version.go
index 7593b11b81..c13d135ae4 100644
--- a/components/cli/cli/command/system/version.go
+++ b/components/cli/cli/command/system/version.go
@@ -23,6 +23,7 @@ import (
var versionTemplate = `{{with .Client -}}
Client:{{if ne .Platform.Name ""}} {{.Platform.Name}}{{end}}
Version: {{.Version}}
+ EulerVersion: {{.EulerVersion}}
API version: {{.APIVersion}}{{if ne .APIVersion .DefaultAPIVersion}} (downgraded from {{.DefaultAPIVersion}}){{end}}
Go version: {{.GoVersion}}
Git commit: {{.GitCommit}}
@@ -38,6 +39,7 @@ Server:{{if ne .Platform.Name ""}} {{.Platform.Name}}{{end}}
{{$component.Name}}:
{{- if eq $component.Name "Engine" }}
Version: {{.Version}}
+ EulerVersion: {{index .Details "EulerVersion"}}
API version: {{index .Details "ApiVersion"}} (minimum version {{index .Details "MinAPIVersion"}})
Go version: {{index .Details "GoVersion"}}
Git commit: {{index .Details "GitCommit"}}
@@ -69,6 +71,7 @@ type clientVersion struct {
Platform struct{ Name string } `json:",omitempty"`
Version string
+ EulerVersion string
APIVersion string `json:"ApiVersion"`
DefaultAPIVersion string `json:"DefaultAPIVersion,omitempty"`
GitCommit string
@@ -135,6 +138,7 @@ func runVersion(dockerCli command.Cli, opts *versionOptions) error {
Client: clientVersion{
Platform: struct{ Name string }{cli.PlatformName},
Version: cli.Version,
+ EulerVersion: cli.EulerVersion,
APIVersion: dockerCli.Client().ClientVersion(),
DefaultAPIVersion: dockerCli.DefaultVersion(),
GoVersion: runtime.Version(),
diff --git a/components/cli/cli/version.go b/components/cli/cli/version.go
index c4120b9585..eeab90cad2 100644
--- a/components/cli/cli/version.go
+++ b/components/cli/cli/version.go
@@ -5,6 +5,7 @@ package cli
var (
PlatformName = ""
Version = "unknown-version"
+ EulerVersion = "unkonwn-version"
GitCommit = "unknown-commit"
BuildTime = "unknown-buildtime"
)
diff --git a/components/cli/docker.Makefile b/components/cli/docker.Makefile
index 28819997bc..3284d8ce0a 100644
--- a/components/cli/docker.Makefile
+++ b/components/cli/docker.Makefile
@@ -12,7 +12,8 @@ VALIDATE_IMAGE_NAME = docker-cli-shell-validate$(IMAGE_TAG)
E2E_IMAGE_NAME = docker-cli-e2e$(IMAGE_TAG)
MOUNTS = -v "$(CURDIR)":/go/src/github.com/docker/cli
VERSION = $(shell cat VERSION)
-ENVVARS = -e VERSION=$(VERSION) -e GITCOMMIT -e PLATFORM
+GITCOMMIT = $(shell git rev-parse --short HEAD 2> /dev/null || true)
+ENVVARS = -e VERSION=$(VERSION) -e GITCOMMIT=$(GITCOMMIT) -e PLATFORM
# build docker image (dockerfiles/Dockerfile.build)
.PHONY: build_docker_image
diff --git a/components/cli/scripts/build/.variables b/components/cli/scripts/build/.variables
index 208f44c316..d50403266e 100755
--- a/components/cli/scripts/build/.variables
+++ b/components/cli/scripts/build/.variables
@@ -3,6 +3,7 @@ set -eu
PLATFORM=${PLATFORM:-}
VERSION=${VERSION:-"unknown-version"}
+EULERVERSION=${EULERVERSION:-$(cat VERSION-EULER)}
GITCOMMIT=${GITCOMMIT:-$(git rev-parse --short HEAD 2> /dev/null || true)}
BUILDTIME=${BUILDTIME:-$(date --utc --rfc-3339 ns 2> /dev/null | sed -e 's/ /T/')}
@@ -17,6 +18,7 @@ export LDFLAGS="\
-X \"github.com/docker/cli/cli.GitCommit=${GITCOMMIT}\" \
-X \"github.com/docker/cli/cli.BuildTime=${BUILDTIME}\" \
-X \"github.com/docker/cli/cli.Version=${VERSION}\" \
+ -X \"github.com/docker/cli/cli.EulerVersion=${EULERVERSION}\" \
${LDFLAGS:-} \
"
diff --git a/components/cli/vendor/github.com/docker/docker/api/types/types.go b/components/cli/vendor/github.com/docker/docker/api/types/types.go
index 2fb6c5478b..56f556cad7 100644
--- a/components/cli/vendor/github.com/docker/docker/api/types/types.go
+++ b/components/cli/vendor/github.com/docker/docker/api/types/types.go
@@ -124,6 +124,7 @@ type Version struct {
// The following fields are deprecated, they relate to the Engine component and are kept for backwards compatibility
Version string
+ EulerVersion string
APIVersion string `json:"ApiVersion"`
MinAPIVersion string `json:"MinAPIVersion,omitempty"`
GitCommit string
diff --git a/components/engine/api/types/types.go b/components/engine/api/types/types.go
index 820d513cbb..78e97daf98 100644
--- a/components/engine/api/types/types.go
+++ b/components/engine/api/types/types.go
@@ -125,6 +125,7 @@ type Version struct {
// The following fields are deprecated, they relate to the Engine component and are kept for backwards compatibility
Version string
+ EulerVersion string
APIVersion string `json:"ApiVersion"`
MinAPIVersion string `json:"MinAPIVersion,omitempty"`
GitCommit string
diff --git a/components/engine/daemon/info.go b/components/engine/daemon/info.go
index 523a396643..4acad11b70 100644
--- a/components/engine/daemon/info.go
+++ b/components/engine/daemon/info.go
@@ -85,13 +85,13 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
// SystemVersion returns version information about the daemon.
func (daemon *Daemon) SystemVersion() types.Version {
kernelVersion := kernelVersion()
-
v := types.Version{
Components: []types.ComponentVersion{
{
Name: "Engine",
Version: dockerversion.Version,
Details: map[string]string{
+ "EulerVersion": dockerversion.EulerVersion,
"GitCommit": dockerversion.GitCommit,
"ApiVersion": api.DefaultVersion,
"MinAPIVersion": api.MinVersion,
@@ -107,6 +107,7 @@ func (daemon *Daemon) SystemVersion() types.Version {
// Populate deprecated fields for older clients
Version: dockerversion.Version,
+ EulerVersion: dockerversion.EulerVersion,
GitCommit: dockerversion.GitCommit,
APIVersion: api.DefaultVersion,
MinAPIVersion: api.MinVersion,
diff --git a/components/engine/dockerversion/version_lib.go b/components/engine/dockerversion/version_lib.go
index 5d9b3fdd2b..84b1339b5b 100644
--- a/components/engine/dockerversion/version_lib.go
+++ b/components/engine/dockerversion/version_lib.go
@@ -8,6 +8,7 @@ package dockerversion // import "github.com/docker/docker/dockerversion"
const (
GitCommit = "library-import"
Version = "library-import"
+ EulerVersion = "library-import"
BuildTime = "library-import"
IAmStatic = "library-import"
InitCommitID = "library-import"
diff --git a/components/engine/hack/make.sh b/components/engine/hack/make.sh
index 2f4ece3cdb..fa87d9110f 100755
--- a/components/engine/hack/make.sh
+++ b/components/engine/hack/make.sh
@@ -65,6 +65,7 @@ DEFAULT_BUNDLES=(
cross
)
+VERSION_EULER=$(< ./VERSION-EULER)
VERSION=${VERSION:-dev}
! BUILDTIME=$(date -u -d "@${SOURCE_DATE_EPOCH:-$(date +%s)}" --rfc-3339 ns 2> /dev/null | sed -e 's/ /T/')
if [ "$DOCKER_GITCOMMIT" ]; then
diff --git a/components/engine/hack/make/.go-autogen b/components/engine/hack/make/.go-autogen
index ea8a32ff5d..99d45e9cb8 100644
--- a/components/engine/hack/make/.go-autogen
+++ b/components/engine/hack/make/.go-autogen
@@ -17,6 +17,7 @@ package dockerversion
const (
GitCommit string = "$GITCOMMIT"
Version string = "$VERSION"
+ EulerVersion string = "$VERSION_EULER"
BuildTime string = "$BUILDTIME"
IAmStatic string = "${IAMSTATIC:-true}"
PlatformName string = "${PLATFORM}"
--
2.17.1

View File

@ -0,0 +1,32 @@
From be262686615a41b7377e5e19c9aae2a1d71cb4fb Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Tue, 22 Jan 2019 17:20:38 +0800
Subject: [PATCH 077/111] image: fix file not exist for check file
size
reason: check file size should support file not exist.
Change-Id: Iae3b8d4f477d6cfc51ba71a185a598687f8393a2
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/image/tarexport/load.go | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/components/engine/image/tarexport/load.go b/components/engine/image/tarexport/load.go
index b9f8f7e3ac..34574129f1 100644
--- a/components/engine/image/tarexport/load.go
+++ b/components/engine/image/tarexport/load.go
@@ -432,6 +432,10 @@ func checkValidParent(img, parent *image.Image) bool {
func checkJsonFileSize(path string) error {
fileInfo, err := os.Stat(path)
if err != nil {
+ // path can not exist.
+ if os.IsNotExist(err) {
+ return nil
+ }
return err
}
fileSize := fileInfo.Size()
--
2.17.1

View File

@ -0,0 +1,53 @@
From bcd276b5b62e1b5ff46eadad71417de076797ec8 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Tue, 22 Jan 2019 17:26:35 +0800
Subject: [PATCH 078/111] spec: add missing sysconfigs to rpm
reason: add missing sysconfigs to rpm, including
- /etc/sysconfig/docker
- /etc/sysconfig/docker-network
- /etc/sysconfig/docker-storage
Partly cherry-pick from 17.06 780e079a
Change-Id: I7a31bc6d99bab6c6a7a60988bc66db2d48f6ca4b
Signed-off-by: Lei Jitang <leijitang@huawei.com>
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
.../contrib/init/sysvinit-redhat/docker-network | 2 ++
.../contrib/init/sysvinit-redhat/docker-storage | 14 ++++++++++++++
5 files changed, 27 insertions(+), 4 deletions(-)
create mode 100644 components/engine/contrib/init/sysvinit-redhat/docker-network
create mode 100644 components/engine/contrib/init/sysvinit-redhat/docker-storage
diff --git a/components/engine/contrib/init/sysvinit-redhat/docker-network b/components/engine/contrib/init/sysvinit-redhat/docker-network
new file mode 100644
index 0000000000..048d1582ec
--- /dev/null
+++ b/components/engine/contrib/init/sysvinit-redhat/docker-network
@@ -0,0 +1,2 @@
+# /etc/sysconfig/docker-network
+DOCKER_NETWORK_OPTIONS=
diff --git a/components/engine/contrib/init/sysvinit-redhat/docker-storage b/components/engine/contrib/init/sysvinit-redhat/docker-storage
new file mode 100644
index 0000000000..3dc16542ff
--- /dev/null
+++ b/components/engine/contrib/init/sysvinit-redhat/docker-storage
@@ -0,0 +1,14 @@
+# This file may be automatically generated by an installation program.
+
+# By default, Docker uses a loopback-mounted sparse file in
+# /var/lib/docker. The loopback makes it slower, and there are some
+# restrictive defaults, such as 100GB max storage.
+
+# If your installation did not set a custom storage for Docker, you
+# may do it below.
+
+# Example: Use a custom pair of raw logical volumes (one for metadata,
+# one for data).
+# DOCKER_STORAGE_OPTIONS = --storage-opt dm.metadatadev=/dev/mylogvol/my-docker-metadata --storage-opt dm.datadev=/dev/mylogvol/my-docker-data
+
+DOCKER_STORAGE_OPTIONS=
--
2.17.1

View File

@ -0,0 +1,39 @@
From 1564b7d772b69da0ba7f6814af2fc094def9d2fd Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 23 Jan 2019 11:07:12 +0800
Subject: [PATCH 079/111] rwlayer: fix deadlock for docker
commit/export
reason: this commit avoid deadlock while del reference count.
Change-Id: I2627752ed38c7bb9d789f4604acd43d130bcb926
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/layer/layer_store.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/components/engine/layer/layer_store.go b/components/engine/layer/layer_store.go
index cbb1ee4a19..553b098dfd 100644
--- a/components/engine/layer/layer_store.go
+++ b/components/engine/layer/layer_store.go
@@ -680,8 +680,6 @@ func (ls *layerStore) ReleaseRWLayer(l RWLayer) ([]Metadata, error) {
return []Metadata{}, nil
}
- m.Lock()
- defer m.Unlock()
if err := m.deleteReference(l); err != nil {
return nil, err
}
@@ -690,6 +688,8 @@ func (ls *layerStore) ReleaseRWLayer(l RWLayer) ([]Metadata, error) {
return []Metadata{}, nil
}
+ m.Lock()
+ defer m.Unlock()
if err := ls.driver.Remove(m.mountID); err != nil {
logrus.Errorf("Error removing mounted layer %s: %s", m.name, err)
m.retakeReference(l)
--
2.17.1

View File

@ -0,0 +1,51 @@
From c1b7332e8f531e53062c740a16f953cd37661d30 Mon Sep 17 00:00:00 2001
From: leizhongkai <leizhongkai@huawei.com>
Date: Thu, 24 Jan 2019 20:24:08 +0800
Subject: [PATCH 081/111] runtime-spec: revert the modify of runtime
spec
reason:revert the modify of runtime spec,make the compatibility in runc
Change-Id: Ia294a169ff15c860c7db3b7a9ab14cecb605cfef
Signed-off-by: leizhongkai <leizhongkai@huawei.com>
---
.../runtime-spec/specs-go/config.go | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
index aab7b8a098..46049b3bfa 100644
--- a/components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
+++ b/components/engine/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
@@ -256,20 +256,20 @@ type LinuxThrottleDevice struct {
// LinuxBlockIO for Linux cgroup 'blkio' resource management
type LinuxBlockIO struct {
- // Specifies per cgroup weight, range is from 10 to 1000
- Weight *uint16 `json:"blkioWeight,omitempty"`
- // Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only
- LeafWeight *uint16 `json:"blkioLeafWeight,omitempty"`
+ // Specifies per cgroup weight
+ Weight *uint16 `json:"weight,omitempty"`
+ // Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, CFQ scheduler only
+ LeafWeight *uint16 `json:"leafWeight,omitempty"`
// Weight per cgroup per device, can override BlkioWeight
- WeightDevice []LinuxWeightDevice `json:"blkioWeightDevice,omitempty"`
+ WeightDevice []LinuxWeightDevice `json:"weightDevice,omitempty"`
// IO read rate limit per cgroup per device, bytes per second
- ThrottleReadBpsDevice []LinuxThrottleDevice `json:"blkioThrottleReadBpsDevice,omitempty"`
+ ThrottleReadBpsDevice []LinuxThrottleDevice `json:"throttleReadBpsDevice,omitempty"`
// IO write rate limit per cgroup per device, bytes per second
- ThrottleWriteBpsDevice []LinuxThrottleDevice `json:"blkioThrottleWriteBpsDevice,omitempty"`
+ ThrottleWriteBpsDevice []LinuxThrottleDevice `json:"throttleWriteBpsDevice,omitempty"`
// IO read rate limit per cgroup per device, IO per second
- ThrottleReadIOPSDevice []LinuxThrottleDevice `json:"blkioThrottleReadIOPSDevice,omitempty"`
+ ThrottleReadIOPSDevice []LinuxThrottleDevice `json:"throttleReadIOPSDevice,omitempty"`
// IO write rate limit per cgroup per device, IO per second
- ThrottleWriteIOPSDevice []LinuxThrottleDevice `json:"blkioThrottleWriteIOPSDevice,omitempty"`
+ ThrottleWriteIOPSDevice []LinuxThrottleDevice `json:"throttleWriteIOPSDevice,omitempty"`
}
// LinuxMemory for Linux cgroup 'memory' resource management
--
2.17.1

View File

@ -0,0 +1,32 @@
From 3e2f675c4e55a73e9ac2ae7b6c0dfca8d37dd9d8 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 24 Jan 2019 16:20:24 +0800
Subject: [PATCH 083/111] test: fix start paused container
reason: please unpause before start.
Change-Id: I435ab7e5cfe4aaed8c6c4e502ca64b0c65fff6a5
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/integration-cli/docker_cli_daemon_test.go | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/components/engine/integration-cli/docker_cli_daemon_test.go b/components/engine/integration-cli/docker_cli_daemon_test.go
index d3cd5f1676..02c42c22e2 100644
--- a/components/engine/integration-cli/docker_cli_daemon_test.go
+++ b/components/engine/integration-cli/docker_cli_daemon_test.go
@@ -1627,9 +1627,8 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithPausedContainer(c *check.C) {
case <-time.After(5 * time.Second):
c.Fatal("Waiting on start a container timed out")
case err := <-errchan:
- if err != nil {
- c.Fatal(err)
- }
+ c.Assert(err, check.NotNil, check.Commentf("cannot start a paused container"))
+ s.d.Cmd("unpause", "test")
}
}
--
2.17.1

View File

@ -0,0 +1,47 @@
From c6edc1d912211c8b35df6c28033fb577a899573e Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 24 Jan 2019 16:28:45 +0800
Subject: [PATCH 084/111] test: skip pause test with ctr
reason: pause managed by docker only
Change-Id: I8aae73e4ab1e0bf9ed639495aa112469ac3630d9
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/integration-cli/docker_cli_daemon_test.go | 3 ++-
components/engine/integration-cli/requirements_test.go | 5 +++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/components/engine/integration-cli/docker_cli_daemon_test.go b/components/engine/integration-cli/docker_cli_daemon_test.go
index 02c42c22e2..467edb04b4 100644
--- a/components/engine/integration-cli/docker_cli_daemon_test.go
+++ b/components/engine/integration-cli/docker_cli_daemon_test.go
@@ -2049,7 +2049,8 @@ func (s *DockerDaemonSuite) TestCleanupMountsAfterDaemonCrash(c *check.C) {
// TestDaemonRestartWithUnpausedRunningContainer requires live restore of running containers.
func (s *DockerDaemonSuite) TestDaemonRestartWithUnpausedRunningContainer(t *check.C) {
- testRequires(t, DaemonIsLinux)
+ testRequires(t, DaemonIsLinux, SupportCtr)
+
s.d.StartWithBusybox(t, "--live-restore")
cid, err := s.d.Cmd("run", "-d", "--name", "test", "busybox", "top")
diff --git a/components/engine/integration-cli/requirements_test.go b/components/engine/integration-cli/requirements_test.go
index 28be59cd2c..4647ce8ccc 100644
--- a/components/engine/integration-cli/requirements_test.go
+++ b/components/engine/integration-cli/requirements_test.go
@@ -38,6 +38,11 @@ func DaemonIsWindowsAtLeastBuild(buildNumber int) func() bool {
}
}
+func SupportCtr() bool {
+ // not support ctr now.
+ return false
+}
+
func DaemonIsLinux() bool {
return testEnv.OSType == "linux"
}
--
2.17.1

View File

@ -0,0 +1,129 @@
From 2a3375c72a5d535864561a0a5fd46dc1fee17013 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Fri, 25 Jan 2019 16:56:08 +0800
Subject: [PATCH 085/111] event: log detailed event with info level
reason: DFX improve event level and record with detailed info.
Change-Id: Ibb5b1058b84de39f9f7058a46a15c2dbd27bc746
Signed-off-by: jingrui <jingrui@huawei.com>
---
.../engine/libcontainerd/client_daemon.go | 51 ++++++++++++++++++-
1 file changed, 49 insertions(+), 2 deletions(-)
diff --git a/components/engine/libcontainerd/client_daemon.go b/components/engine/libcontainerd/client_daemon.go
index cb9cb43a73..491bda281c 100644
--- a/components/engine/libcontainerd/client_daemon.go
+++ b/components/engine/libcontainerd/client_daemon.go
@@ -791,8 +791,6 @@ func (c *client) processEventStream(ctx context.Context, ns string) {
continue
}
- c.logger.WithField("topic", ev.Topic).Debug("event")
-
switch t := v.(type) {
case *apievents.TaskCreate:
et = EventCreate
@@ -801,6 +799,11 @@ func (c *client) processEventStream(ctx context.Context, ns string) {
ProcessID: t.ContainerID,
Pid: t.Pid,
}
+ c.logger.WithFields(logrus.Fields{
+ "topic": ev.Topic,
+ "containerID": t.ContainerID,
+ "Pid": t.Pid,
+ }).Infof("event")
case *apievents.TaskStart:
et = EventStart
ei = EventInfo{
@@ -808,6 +811,11 @@ func (c *client) processEventStream(ctx context.Context, ns string) {
ProcessID: t.ContainerID,
Pid: t.Pid,
}
+ c.logger.WithFields(logrus.Fields{
+ "topic": ev.Topic,
+ "containerID": t.ContainerID,
+ "Pid": t.Pid,
+ }).Infof("event")
case *apievents.TaskExit:
et = EventExit
ei = EventInfo{
@@ -817,6 +825,13 @@ func (c *client) processEventStream(ctx context.Context, ns string) {
ExitCode: t.ExitStatus,
ExitedAt: t.ExitedAt,
}
+ c.logger.WithFields(logrus.Fields{
+ "topic": ev.Topic,
+ "containerID": t.ContainerID,
+ "Pid": t.Pid,
+ "ExitStatus": t.ExitStatus,
+ "ExitedAt": t.ExitedAt,
+ }).Infof("event")
case *apievents.TaskOOM:
et = EventOOM
ei = EventInfo{
@@ -824,12 +839,22 @@ func (c *client) processEventStream(ctx context.Context, ns string) {
OOMKilled: true,
}
oomKilled = true
+ c.logger.WithFields(logrus.Fields{
+ "topic": ev.Topic,
+ "containerID": t.ContainerID,
+ "OOMKilled": true,
+ }).Infof("event")
case *apievents.TaskExecAdded:
et = EventExecAdded
ei = EventInfo{
ContainerID: t.ContainerID,
ProcessID: t.ExecID,
}
+ c.logger.WithFields(logrus.Fields{
+ "topic": ev.Topic,
+ "containerID": t.ContainerID,
+ "execID": t.ExecID,
+ }).Infof("event")
case *apievents.TaskExecStarted:
et = EventExecStarted
ei = EventInfo{
@@ -837,16 +862,38 @@ func (c *client) processEventStream(ctx context.Context, ns string) {
ProcessID: t.ExecID,
Pid: t.Pid,
}
+ c.logger.WithFields(logrus.Fields{
+ "topic": ev.Topic,
+ "containerID": t.ContainerID,
+ "execID": t.ExecID,
+ "Pid": t.Pid,
+ }).Infof("event")
case *apievents.TaskPaused:
et = EventPaused
ei = EventInfo{
ContainerID: t.ContainerID,
}
+ c.logger.WithFields(logrus.Fields{
+ "topic": ev.Topic,
+ "containerID": t.ContainerID,
+ }).Infof("event")
case *apievents.TaskResumed:
et = EventResumed
ei = EventInfo{
ContainerID: t.ContainerID,
}
+ c.logger.WithFields(logrus.Fields{
+ "topic": ev.Topic,
+ "containerID": t.ContainerID,
+ }).Infof("event")
+ case *apievents.TaskDelete:
+ c.logger.WithFields(logrus.Fields{
+ "topic": ev.Topic,
+ "containerID": t.ContainerID,
+ "Pid": t.Pid,
+ "ExitStatus": t.ExitStatus,
+ "ExitedAt": t.ExitedAt,
+ }).Infof("event")
default:
c.logger.WithFields(logrus.Fields{
"topic": ev.Topic,
--
2.17.1

View File

@ -0,0 +1,62 @@
From 99b7f823b7dfe88dc2d4f4073f10cbf3a437bd81 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Fri, 25 Jan 2019 16:59:26 +0800
Subject: [PATCH 086/111] restart: fix daemon restart with
restart=always container
reason: fix daemon gracefully restart while container is start with
restart=always. restart-manager blocked to start container while
restoring, when restoring start container successful, the
restart-manager will start container but error with "id already in use".
related testcase:
TestDaemonRestartKillContainers
TestDockerNetworkHostModeUngracefulDaemonRestart
ref:
- https://github.com/moby/moby/issues/38249
Change-Id: I2545286a8371cb656ec6574d23cd15de4ba60283
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/daemon/daemon_unix.go | 3 +++
components/engine/daemon/start.go | 9 +++++++++
2 files changed, 12 insertions(+)
diff --git a/components/engine/daemon/daemon_unix.go b/components/engine/daemon/daemon_unix.go
index b20c66e27b..9abc9a329a 100644
--- a/components/engine/daemon/daemon_unix.go
+++ b/components/engine/daemon/daemon_unix.go
@@ -1291,6 +1291,9 @@ func setupDaemonRootPropagation(cfg *config.Config) error {
return nil
}
+ if err := os.MkdirAll(filepath.Dir(cleanupFile), 0700); err != nil {
+ return errors.Wrap(err, "error mkdir parent to signal mount cleanup on shutdown")
+ }
if err := ioutil.WriteFile(cleanupFile, nil, 0600); err != nil {
return errors.Wrap(err, "error writing file to signal mount cleanup on shutdown")
}
diff --git a/components/engine/daemon/start.go b/components/engine/daemon/start.go
index c00bd9ceb2..96ae45e11e 100644
--- a/components/engine/daemon/start.go
+++ b/components/engine/daemon/start.go
@@ -108,6 +108,15 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint
return nil
}
+ // fix restartManager restarted the container is already started by restore.
+ if container.Running {
+ _, err := daemon.containerd.Status(context.Background(), container.ID)
+ if err == nil {
+ logrus.Warnf("skip starting the container is exist and running.")
+ return nil
+ }
+ }
+
if container.RemovalInProgress || container.Dead {
return errdefs.Conflict(errors.New("container is marked for removal and cannot be started"))
}
--
2.17.1

View File

@ -0,0 +1,48 @@
From 4f99f2ea6fac5d585cee3b7362b109dcf869beda Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Wed, 30 Jan 2019 13:42:34 +0800
Subject: [PATCH 088/111] attach: add timeout return for getExitStatus
reason:In cli/command/container/attach.go, func getExitStatus() will
return until container turn to unrunning state. When we excute docker
attach and other commands inside container together, for the state of
container will not change, docker attach command is stuck.
Change-Id: Ifda6096643c659341fd6d343eb4a8cbf08e5a71c
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/cli/cli/command/container/attach.go | 4 ++++
5 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/components/cli/cli/command/container/attach.go b/components/cli/cli/command/container/attach.go
index de96a3b7d8..ff1014d70c 100644
--- a/components/cli/cli/command/container/attach.go
+++ b/components/cli/cli/command/container/attach.go
@@ -5,6 +5,7 @@ import (
"fmt"
"io"
"net/http/httputil"
+ "time"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
@@ -150,6 +151,7 @@ func runAttach(dockerCli command.Cli, opts *attachOptions) error {
}
func getExitStatus(errC <-chan error, resultC <-chan container.ContainerWaitOKBody) error {
+ timeout := time.NewTimer(time.Second)
select {
case result := <-resultC:
if result.Error != nil {
@@ -160,6 +162,8 @@ func getExitStatus(errC <-chan error, resultC <-chan container.ContainerWaitOKBo
}
case err := <-errC:
return err
+ case <-timeout.C:
+ return fmt.Errorf("Wait container status timeout.")
}
return nil
--
2.17.1

View File

@ -0,0 +1,31 @@
From 9a48f9b439a03e7fd5eeec4ff2cebac4cddf669f Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 30 Jan 2019 21:28:16 +0800
Subject: [PATCH 089/111] libcontainerd: fix stuck when containerd in
T-state
reason: when containerd is alive but not responding, shall restart
containerd avoid cmd stuck.
Change-Id: Iab220c8988b50b39f4fd84be9454a0b097968751
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/libcontainerd/supervisor/remote_daemon.go | 2 +-
5 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/components/engine/libcontainerd/supervisor/remote_daemon.go b/components/engine/libcontainerd/supervisor/remote_daemon.go
index 095300f753..c5da3a56fe 100644
--- a/components/engine/libcontainerd/supervisor/remote_daemon.go
+++ b/components/engine/libcontainerd/supervisor/remote_daemon.go
@@ -307,7 +307,7 @@ func (r *remote) monitorDaemon(ctx context.Context) {
r.logger.WithError(err).WithField("binary", binaryName).Debug("daemon is not responding")
transientFailureCount++
- if transientFailureCount < maxConnectionRetryCount || system.IsProcessAlive(r.daemonPid) {
+ if transientFailureCount < maxConnectionRetryCount {
delay = time.After(time.Duration(transientFailureCount) * 200 * time.Millisecond)
continue
}
--
2.17.1

View File

@ -0,0 +1,73 @@
From b2750c914429b4f981848d0c829ddfc0c8acc37e Mon Sep 17 00:00:00 2001
From: xiadanni <xiadanni@huawei.com>
Date: Fri, 1 Feb 2019 01:03:12 +0800
Subject: [PATCH 090/111] overlay2: Use index=off if possible
reason: Docker overlay driver can't work with index=on feature of
the Linux kernel "overlay" filesystem. In case the global
default is set to "yes", Docker will fail with EBUSY when
trying to mount.
Cherry-pick from https://github.com/moby/moby/pull/37993/commits/8422d85087bfa770b62ef4e1daaca95ee6783d86
Change-Id: Iad1addaca9983ba35c466951e04c7034b0a18fab
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Signed-off-by: xiadanni <xiadanni@huawei.com>
---
.../daemon/graphdriver/overlay2/overlay.go | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/components/engine/daemon/graphdriver/overlay2/overlay.go b/components/engine/daemon/graphdriver/overlay2/overlay.go
index cf8993e9f3..d87f979673 100644
--- a/components/engine/daemon/graphdriver/overlay2/overlay.go
+++ b/components/engine/daemon/graphdriver/overlay2/overlay.go
@@ -111,6 +111,8 @@ var (
useNaiveDiffLock sync.Once
useNaiveDiffOnly bool
+
+ indexOff string
)
func init() {
@@ -228,7 +230,18 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, fmt.Errorf("Storage Option overlay2.size only supported for backingFS XFS or ext4. Found %v", backingFs)
}
- logger.Debugf("backingFs=%s, projectQuotaSupported=%v", backingFs, projectQuotaSupported)
+ // figure out whether "index=off" option is recognized by the kernel
+ _, err = os.Stat("/sys/module/overlay/parameters/index")
+ switch {
+ case err == nil:
+ indexOff = "index=off,"
+ case os.IsNotExist(err):
+ // old kernel, no index -- do nothing
+ default:
+ logger.Warnf("Unable to detect whether overlay kernel module supports index parameter: %s", err)
+ }
+
+ logger.Debugf("backingFs=%s, projectQuotaSupported=%v, indexOff=%q", backingFs, projectQuotaSupported, indexOff)
return d, nil
}
@@ -632,7 +645,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
for i, s := range splitLowers {
absLowers[i] = path.Join(d.home, s)
}
- opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(absLowers, ":"), path.Join(dir, "diff"), path.Join(dir, "work"))
+ opts := indexOff + "lowerdir=" + strings.Join(absLowers, ":") + ",upperdir=" + path.Join(dir, "diff") + ",workdir=" + path.Join(dir, "work")
mountData := label.FormatMountLabel(opts, mountLabel)
mount := unix.Mount
mountTarget := mergedDir
@@ -661,7 +674,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
// fit within a page and relative links make the mount data much
// smaller at the expense of requiring a fork exec to chroot.
if len(mountData) > pageSize {
- opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", string(lowers), path.Join(id, "diff"), path.Join(id, "work"))
+ opts = indexOff + "lowerdir=" + string(lowers) + ",upperdir=" + path.Join(id, "diff") + ",workdir=" + path.Join(id, "work")
mountData = label.FormatMountLabel(opts, mountLabel)
if len(mountData) > pageSize {
return nil, fmt.Errorf("cannot mount layer, mount label too large %d", len(mountData))
--
2.17.1

View File

@ -0,0 +1,168 @@
From 7bce81e40dbc73b7e778d8676687efc3b04c6d39 Mon Sep 17 00:00:00 2001
From: xiadanni <xiadanni@huawei.com>
Date: Fri, 1 Feb 2019 01:45:57 +0800
Subject: [PATCH 091/111] overlay2: use global logger instance
reason: This simplifies the code a lot.
Cherry-pick from https://github.com/moby/moby/pull/37993/commits/a55d32546a8556f9e6cabbc99836b573b9944f0c
Change-Id: I2c4998d677c8500701e077b2520b96fe49ea4364
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Signed-off-by: xiadanni <xiadanni@huawei.com>
---
.../daemon/graphdriver/overlay2/check.go | 9 ++++-----
.../daemon/graphdriver/overlay2/overlay.go | 20 +++++++++----------
.../daemon/graphdriver/overlay2/randomid.go | 3 +--
3 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/components/engine/daemon/graphdriver/overlay2/check.go b/components/engine/daemon/graphdriver/overlay2/check.go
index d6ee42f47f..1703b7a00c 100644
--- a/components/engine/daemon/graphdriver/overlay2/check.go
+++ b/components/engine/daemon/graphdriver/overlay2/check.go
@@ -12,7 +12,6 @@ import (
"github.com/docker/docker/pkg/system"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -27,7 +26,7 @@ func doesSupportNativeDiff(d string) error {
}
defer func() {
if err := os.RemoveAll(td); err != nil {
- logrus.WithField("storage-driver", "overlay2").Warnf("Failed to remove check directory %v: %v", td, err)
+ logger.Warnf("Failed to remove check directory %v: %v", td, err)
}
}()
@@ -62,7 +61,7 @@ func doesSupportNativeDiff(d string) error {
}
defer func() {
if err := unix.Unmount(filepath.Join(td, "merged"), 0); err != nil {
- logrus.WithField("storage-driver", "overlay2").Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err)
+ logger.Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err)
}
}()
@@ -113,7 +112,7 @@ func supportsMultipleLowerDir(d string) error {
}
defer func() {
if err := os.RemoveAll(td); err != nil {
- logrus.WithField("storage-driver", "overlay2").Warnf("Failed to remove check directory %v: %v", td, err)
+ logger.Warnf("Failed to remove check directory %v: %v", td, err)
}
}()
@@ -128,7 +127,7 @@ func supportsMultipleLowerDir(d string) error {
return errors.Wrap(err, "failed to mount overlay")
}
if err := unix.Unmount(filepath.Join(td, "merged"), 0); err != nil {
- logrus.WithField("storage-driver", "overlay2").Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err)
+ logger.Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err)
}
return nil
}
diff --git a/components/engine/daemon/graphdriver/overlay2/overlay.go b/components/engine/daemon/graphdriver/overlay2/overlay.go
index d87f979673..71474f8f36 100644
--- a/components/engine/daemon/graphdriver/overlay2/overlay.go
+++ b/components/engine/daemon/graphdriver/overlay2/overlay.go
@@ -106,6 +106,7 @@ type Driver struct {
}
var (
+ logger = logrus.WithField("storage-driver", "overlay2")
backingFs = "<unknown>"
projectQuotaSupported = false
@@ -157,8 +158,6 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
backingFs = fsName
}
- logger := logrus.WithField("storage-driver", "overlay2")
-
switch fsMagic {
case graphdriver.FsMagicAufs, graphdriver.FsMagicEcryptfs, graphdriver.FsMagicNfsFs, graphdriver.FsMagicOverlay, graphdriver.FsMagicZfs:
logger.Errorf("'overlay2' is not supported over %s", backingFs)
@@ -306,14 +305,14 @@ func supportsOverlay() error {
return nil
}
}
- logrus.WithField("storage-driver", "overlay2").Error("'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
+ logger.Error("'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
return graphdriver.ErrNotSupported
}
func useNaiveDiff(home string) bool {
useNaiveDiffLock.Do(func() {
if err := doesSupportNativeDiff(home); err != nil {
- logrus.WithField("storage-driver", "overlay2").Warnf("Not using native diff for overlay2, this may cause degraded performance for building images: %v", err)
+ logger.Warnf("Not using native diff for overlay2, this may cause degraded performance for building images: %v", err)
useNaiveDiffOnly = true
}
})
@@ -629,11 +628,11 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
if retErr != nil {
if c := d.ctr.Decrement(mergedDir); c <= 0 {
if mntErr := unix.Unmount(mergedDir, 0); mntErr != nil {
- logrus.WithField("storage-driver", "overlay2").Errorf("error unmounting %v: %v", mergedDir, mntErr)
+ logger.Errorf("error unmounting %v: %v", mergedDir, mntErr)
}
// Cleanup the created merged directory; see the comment in Put's rmdir
if rmErr := unix.Rmdir(mergedDir); rmErr != nil && !os.IsNotExist(rmErr) {
- logrus.WithField("storage-driver", "overlay2").Debugf("Failed to remove %s: %v: %v", id, rmErr, err)
+ logger.Debugf("Failed to remove %s: %v: %v", id, rmErr, err)
}
}
}
@@ -716,7 +715,6 @@ func (d *Driver) Put(id string) error {
}
mountpoint := path.Join(dir, "merged")
- logger := logrus.WithField("storage-driver", "overlay2")
if count := d.ctr.Decrement(mountpoint); count > 0 {
return nil
}
@@ -802,7 +800,7 @@ func (d *Driver) ApplyDiff(id string, parent string, diff io.Reader) (size int64
applyDir := d.getDiffPath(id)
- logrus.WithField("storage-driver", "overlay2").Debugf("Applying tar in %s", applyDir)
+ logger.Debugf("Applying tar in %s", applyDir)
// Overlay doesn't need the parent id to apply the diff
if err := untar(diff, applyDir, &archive.TarOptions{
UIDMaps: d.uidMaps,
@@ -840,7 +838,7 @@ func (d *Driver) Diff(id, parent string) (io.ReadCloser, error) {
}
diffPath := d.getDiffPath(id)
- logrus.WithField("storage-driver", "overlay2").Debugf("Tar with options on %s", diffPath)
+ logger.Debugf("Tar with options on %s", diffPath)
return archive.TarWithOptions(diffPath, &archive.TarOptions{
Compression: archive.Uncompressed,
UIDMaps: d.uidMaps,
diff --git a/components/engine/daemon/graphdriver/overlay2/randomid.go b/components/engine/daemon/graphdriver/overlay2/randomid.go
index 933d9fccb6..6ab50df8e6 100644
--- a/components/engine/daemon/graphdriver/overlay2/randomid.go
+++ b/components/engine/daemon/graphdriver/overlay2/randomid.go
@@ -12,7 +12,6 @@ import (
"syscall"
"time"
- "github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -48,7 +47,7 @@ func generateID(l int) string {
if retryOnError(err) && retries < maxretries {
count += n
retries++
- logrus.Errorf("error generating version 4 uuid, retrying: %v", err)
+ logger.Errorf("error generating version 4 uuid, retrying: %v", err)
continue
}
--
2.17.1

View File

@ -0,0 +1,214 @@
From 5c472ad67723ba45ee92dce62f9f45292213644e Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Fri, 1 Feb 2019 11:02:31 +0800
Subject: [PATCH 092/111] Revert "docker: Lock the RWLayer while
committing/exporting"
reason: This reverts commit a3dbaededfff6d20e16740c47ac69de9a91cccff.
1. rwlayer is already protected by ls.mountL.Lock, no need add lock to
mountedLayer.
2. rwlayer is protected by reference, no need add lock during commit or
export.
known issues:
- commit or export will put reference during hold lock, if put the last
reference, dead lock happens on release layer.
- delete(docker rm) will set container.RWLayer = nil, it's dangrous
after export or commit when calling container.RWLayer.RUnlockRWLayer().
Change-Id: I72cc72a3398133d693cb813fde1964068544ec03
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/daemon/commit.go | 2 --
components/engine/daemon/export.go | 2 --
components/engine/layer/empty.go | 13 +------------
components/engine/layer/layer.go | 7 -------
components/engine/layer/layer_store.go | 4 ----
components/engine/layer/mounted_layer.go | 10 ----------
components/engine/layer/ro_layer.go | 10 ----------
11 files changed, 7 insertions(+), 53 deletions(-)
diff --git a/components/engine/daemon/commit.go b/components/engine/daemon/commit.go
index fc7d2782ef..0f6f440514 100644
--- a/components/engine/daemon/commit.go
+++ b/components/engine/daemon/commit.go
@@ -155,8 +155,6 @@ func (daemon *Daemon) CreateImageFromContainer(name string, c *backend.CreateIma
return "", err
}
- container.RWLayer.RLockRWLayer()
- defer container.RWLayer.RUnlockRWLayer()
id, err := daemon.imageService.CommitImage(backend.CommitConfig{
Author: c.Author,
Comment: c.Comment,
diff --git a/components/engine/daemon/export.go b/components/engine/daemon/export.go
index ebd2d75f40..27bc35967d 100644
--- a/components/engine/daemon/export.go
+++ b/components/engine/daemon/export.go
@@ -34,8 +34,6 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
return errdefs.Conflict(err)
}
- container.RWLayer.RLockRWLayer()
- defer container.RWLayer.RUnlockRWLayer()
data, err := daemon.containerExport(container)
if err != nil {
return fmt.Errorf("Error exporting container %s: %v", name, err)
diff --git a/components/engine/layer/empty.go b/components/engine/layer/empty.go
index 16a49a7abd..c81c702140 100644
--- a/components/engine/layer/empty.go
+++ b/components/engine/layer/empty.go
@@ -6,16 +6,13 @@ import (
"fmt"
"io"
"io/ioutil"
- "sync"
)
// DigestSHA256EmptyTar is the canonical sha256 digest of empty tar file -
// (1024 NULL bytes)
const DigestSHA256EmptyTar = DiffID("sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef")
-type emptyLayer struct {
- sync.RWMutex
-}
+type emptyLayer struct{}
// EmptyLayer is a layer that corresponds to empty tar.
var EmptyLayer = &emptyLayer{}
@@ -58,14 +55,6 @@ func (el *emptyLayer) Metadata() (map[string]string, error) {
return make(map[string]string), nil
}
-func (el *emptyLayer) RLockRWLayer() {
- el.RLock()
-}
-
-func (el *emptyLayer) RUnlockRWLayer() {
- el.RUnlock()
-}
-
// IsEmpty returns true if the layer is an EmptyLayer
func IsEmpty(diffID DiffID) bool {
return diffID == DigestSHA256EmptyTar
diff --git a/components/engine/layer/layer.go b/components/engine/layer/layer.go
index e35a13135b..cb13c98d0b 100644
--- a/components/engine/layer/layer.go
+++ b/components/engine/layer/layer.go
@@ -145,13 +145,6 @@ type RWLayer interface {
// Metadata returns the low level metadata for the mutable layer
Metadata() (map[string]string, error)
-
- // RLockRWLayer locks the RWLayer to block unmounting/removal
- // of that layer
- RLockRWLayer()
-
- // RUnlockRWLayer unlocks the RWLayer
- RUnlockRWLayer()
}
// Metadata holds information about a
diff --git a/components/engine/layer/layer_store.go b/components/engine/layer/layer_store.go
index 553b098dfd..b6fc45e655 100644
--- a/components/engine/layer/layer_store.go
+++ b/components/engine/layer/layer_store.go
@@ -598,7 +598,6 @@ func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWL
// Release parent chain if error
defer func() {
if err != nil {
- m.Lock()
if deferErr := ls.driver.Remove(m.mountID); deferErr != nil {
logrus.Errorf("Error removing mounted layer during create rw layer %s: %s", m.name, deferErr)
}
@@ -610,7 +609,6 @@ func (ls *layerStore) CreateRWLayer(name string, parent ChainID, opts *CreateRWL
if deferErr := ls.store.RemoveMount(m.name); deferErr != nil {
logrus.Errorf("Error removing mount metadata during create rw layer %s: %s", m.name, deferErr)
}
- m.Unlock()
ls.layerL.Lock()
ls.releaseLayer(p)
@@ -688,8 +686,6 @@ func (ls *layerStore) ReleaseRWLayer(l RWLayer) ([]Metadata, error) {
return []Metadata{}, nil
}
- m.Lock()
- defer m.Unlock()
if err := ls.driver.Remove(m.mountID); err != nil {
logrus.Errorf("Error removing mounted layer %s: %s", m.name, err)
m.retakeReference(l)
diff --git a/components/engine/layer/mounted_layer.go b/components/engine/layer/mounted_layer.go
index 66711d6cf7..d6858c662c 100644
--- a/components/engine/layer/mounted_layer.go
+++ b/components/engine/layer/mounted_layer.go
@@ -2,7 +2,6 @@ package layer // import "github.com/docker/docker/layer"
import (
"io"
- "sync"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/containerfs"
@@ -17,7 +16,6 @@ type mountedLayer struct {
layerStore *layerStore
references map[RWLayer]*referencedRWLayer
- sync.RWMutex
}
func (ml *mountedLayer) cacheParent() string {
@@ -60,14 +58,6 @@ func (ml *mountedLayer) Metadata() (map[string]string, error) {
return ml.layerStore.driver.GetMetadata(ml.mountID)
}
-func (ml *mountedLayer) RLockRWLayer() {
- ml.RLock()
-}
-
-func (ml *mountedLayer) RUnlockRWLayer() {
- ml.RUnlock()
-}
-
func (ml *mountedLayer) getReference() RWLayer {
ref := &referencedRWLayer{
mountedLayer: ml,
diff --git a/components/engine/layer/ro_layer.go b/components/engine/layer/ro_layer.go
index 59bcf17d18..3555e8b027 100644
--- a/components/engine/layer/ro_layer.go
+++ b/components/engine/layer/ro_layer.go
@@ -3,7 +3,6 @@ package layer // import "github.com/docker/docker/layer"
import (
"fmt"
"io"
- "sync"
"github.com/docker/distribution"
"github.com/opencontainers/go-digest"
@@ -20,7 +19,6 @@ type roLayer struct {
referenceCount int
references map[Layer]struct{}
- sync.RWMutex
}
// TarStream for roLayer guarantees that the data that is produced is the exact
@@ -94,14 +92,6 @@ func (rl *roLayer) Metadata() (map[string]string, error) {
return rl.layerStore.driver.GetMetadata(rl.cacheID)
}
-func (rl *roLayer) RLockRWLayer() {
- rl.RLock()
-}
-
-func (rl *roLayer) RUnlockRWLayer() {
- rl.RUnlock()
-}
-
type referencedCacheLayer struct {
*roLayer
}
--
2.17.1

View File

@ -0,0 +1,31 @@
From 03024503528f2355a666cb37a6b6bc3902bc977d Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Fri, 1 Feb 2019 17:34:44 +0800
Subject: [PATCH 093/111] docker: do not try to connect containerd if
containerd daemon is down
reason:do not try to connect containerd if containerd daemon is down, reduce
delay time to restart containerd.
Change-Id: I7e6ab9e4c154a82b3b2609440cbfc7d3ea14d28d
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
components/engine/libcontainerd/supervisor/remote_daemon.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/components/engine/libcontainerd/supervisor/remote_daemon.go b/components/engine/libcontainerd/supervisor/remote_daemon.go
index c5da3a56fe..45cc3c3032 100644
--- a/components/engine/libcontainerd/supervisor/remote_daemon.go
+++ b/components/engine/libcontainerd/supervisor/remote_daemon.go
@@ -289,7 +289,7 @@ func (r *remote) monitorDaemon(ctx context.Context) {
}
}
- if client != nil {
+ if client != nil && system.IsProcessAlive(r.daemonPid) {
tctx, cancel := context.WithTimeout(ctx, healthCheckTimeout)
_, err := client.IsServing(tctx)
cancel()
--
2.17.1

View File

@ -0,0 +1,88 @@
From 69edbbf9eca76adf67e2b26ee564b53eaef76aff Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Fri, 1 Feb 2019 19:00:14 +0800
Subject: [PATCH 094/111] docker: change health check minum param to
one second
reason:change health check minum period to one second, include
--health-interval, --health-timeout and --health-start-period.
Change-Id: I1ebab75c23edf4f9006142f92894114c5d447f75
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
components/engine/daemon/container.go | 12 ++++++------
.../engine/integration-cli/docker_api_create_test.go | 7 +++----
2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/components/engine/daemon/container.go b/components/engine/daemon/container.go
index 06a19bb4c8..6d357421f3 100644
--- a/components/engine/daemon/container.go
+++ b/components/engine/daemon/container.go
@@ -421,20 +421,20 @@ func (daemon *Daemon) verifyContainerSettings(platform string, hostConfig *conta
// Validate the healthcheck params of Config
if config.Healthcheck != nil {
- if config.Healthcheck.Interval != 0 && config.Healthcheck.Interval < containertypes.MinimumDuration {
- return nil, errors.Errorf("Interval in Healthcheck cannot be less than %s", containertypes.MinimumDuration)
+ if config.Healthcheck.Interval != 0 && config.Healthcheck.Interval < time.Second {
+ return nil, errors.Errorf("Interval in Healthcheck cannot be less than one second")
}
- if config.Healthcheck.Timeout != 0 && config.Healthcheck.Timeout < containertypes.MinimumDuration {
- return nil, errors.Errorf("Timeout in Healthcheck cannot be less than %s", containertypes.MinimumDuration)
+ if config.Healthcheck.Timeout != 0 && config.Healthcheck.Timeout < time.Second {
+ return nil, errors.Errorf("Timeout in Healthcheck cannot be less than one second")
}
if config.Healthcheck.Retries < 0 {
return nil, errors.Errorf("Retries in Healthcheck cannot be negative")
}
- if config.Healthcheck.StartPeriod != 0 && config.Healthcheck.StartPeriod < containertypes.MinimumDuration {
- return nil, errors.Errorf("StartPeriod in Healthcheck cannot be less than %s", containertypes.MinimumDuration)
+ if config.Healthcheck.StartPeriod != 0 && config.Healthcheck.StartPeriod < time.Second {
+ return nil, errors.Errorf("StartPeriod in Healthcheck cannot be less than one second")
}
}
}
diff --git a/components/engine/integration-cli/docker_api_create_test.go b/components/engine/integration-cli/docker_api_create_test.go
index 8c7fff477e..1bbc7653b3 100644
--- a/components/engine/integration-cli/docker_api_create_test.go
+++ b/components/engine/integration-cli/docker_api_create_test.go
@@ -5,7 +5,6 @@ import (
"net/http"
"time"
- "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/integration-cli/checker"
"github.com/docker/docker/internal/test/request"
@@ -35,7 +34,7 @@ func (s *DockerSuite) TestAPICreateWithInvalidHealthcheckParams(c *check.C) {
buf, err := request.ReadBody(body)
c.Assert(err, checker.IsNil)
- expected := fmt.Sprintf("Interval in Healthcheck cannot be less than %s", container.MinimumDuration)
+ expected := fmt.Sprintf("Interval in Healthcheck cannot be less than one second")
c.Assert(getErrorMessage(c, buf), checker.Contains, expected)
// test invalid Interval in Healthcheck: larger than 0s but less than 1ms
@@ -82,7 +81,7 @@ func (s *DockerSuite) TestAPICreateWithInvalidHealthcheckParams(c *check.C) {
buf, err = request.ReadBody(body)
c.Assert(err, checker.IsNil)
- expected = fmt.Sprintf("Timeout in Healthcheck cannot be less than %s", container.MinimumDuration)
+ expected = fmt.Sprintf("Timeout in Healthcheck cannot be less than one second")
c.Assert(getErrorMessage(c, buf), checker.Contains, expected)
// test invalid Retries in Healthcheck: less than 0
@@ -131,6 +130,6 @@ func (s *DockerSuite) TestAPICreateWithInvalidHealthcheckParams(c *check.C) {
buf, err = request.ReadBody(body)
c.Assert(err, checker.IsNil)
- expected = fmt.Sprintf("StartPeriod in Healthcheck cannot be less than %s", container.MinimumDuration)
+ expected = fmt.Sprintf("StartPeriod in Healthcheck cannot be less than one second")
c.Assert(getErrorMessage(c, buf), checker.Contains, expected)
}
--
2.17.1

View File

@ -0,0 +1,41 @@
From 7f1228356891f66979c7f7e35957ab5392ea8758 Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Fri, 1 Feb 2019 21:18:34 +0800
Subject: [PATCH 095/111] docker: enable container health check after
restart docker
reason:enable container health check after restart docker.
Change-Id: Ic877fdbea8de5b87d2a101c19dbb8a9e8e49c0bb
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
components/engine/daemon/daemon.go | 6 +++++-
5 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/components/engine/daemon/daemon.go b/components/engine/daemon/daemon.go
index b207709f7c..f5d22bb18b 100644
--- a/components/engine/daemon/daemon.go
+++ b/components/engine/daemon/daemon.go
@@ -379,6 +379,10 @@ func (daemon *Daemon) restore() error {
if c.IsRunning() || c.IsPaused() {
c.RestartManager().Cancel() // manually start containers because some need to wait for swarm networking
+ c.Lock()
+ daemon.initHealthMonitor(c)
+ c.Unlock()
+
if c.IsPaused() && alive {
s, err := daemon.containerd.Status(context.Background(), c.ID)
if err != nil {
@@ -930,7 +934,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
for operatingSystem, gd := range d.graphDrivers {
layerStores[operatingSystem], err = layer.NewStoreFromOptions(layer.StoreOptions{
- Root: config.Root,
+ Root: config.Root,
MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
GraphDriver: gd,
GraphDriverOptions: config.GraphOptions,
--
2.17.1

View File

@ -0,0 +1,52 @@
From 086cf3ab125d1c423d07ef877846fd8c1e01f3ac Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Mon, 11 Feb 2019 18:44:50 +0800
Subject: [PATCH 096/111] pause: check tasks before updateCgroups
reason: In the Pause of dockerd, it updateCgroups first, then
check tasks file if any tasks in the cgroups. We should check the
tasks file before updateCgroups
Change-Id: I7f30e314b3db9c50459d995bf071e01a47f359f0
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
components/engine/daemon/freezer/freezer.go | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/components/engine/daemon/freezer/freezer.go b/components/engine/daemon/freezer/freezer.go
index cd8b3513d7..a0ef299852 100644
--- a/components/engine/daemon/freezer/freezer.go
+++ b/components/engine/daemon/freezer/freezer.go
@@ -122,10 +122,6 @@ func (f *freezer) Pause() error {
f.Lock()
defer f.Unlock()
- if err := f.updateCgroup(string(configs.Frozen)); err != nil {
- return err
- }
-
tasks, err := readFile(f.path, "tasks")
if err != nil {
return fmt.Errorf("failed to check container cgroup task status: %v", err)
@@ -134,7 +130,8 @@ func (f *freezer) Pause() error {
if strings.TrimSpace(tasks) == "" {
return fmt.Errorf("error: no tasks running in freeze cgroup")
}
- return nil
+
+ return f.updateCgroup(string(configs.Frozen))
}
// Resume will set the container to running state by writing freeze cgroup.
@@ -186,7 +183,7 @@ func (f *freezer) updateCgroup(state string) error {
}
newState, err := readFile(f.path, "freezer.state")
if err != nil {
- return err
+ return fmt.Errorf("read freezer.state failed after write: %v", err)
}
if strings.TrimSpace(newState) == state {
return nil
--
2.17.1

View File

@ -0,0 +1,45 @@
From 8bd08475a06b5475fc88b207d578a006ad9a45cd Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 13 Feb 2019 00:31:32 +0800
Subject: [PATCH 097/111] restart: fix --restart=unless-stopped not
stop for docker stop
reason: testCE_secure_container_kata_FUN.054.sh
Change-Id: I536bb6cf1fe698da9fe330b110f122d4e8af17d6
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/daemon/monitor.go | 1 +
components/engine/daemon/start.go | 4 +++-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/components/engine/daemon/monitor.go b/components/engine/daemon/monitor.go
index 51159eb76d..7ae85f58a9 100644
--- a/components/engine/daemon/monitor.go
+++ b/components/engine/daemon/monitor.go
@@ -106,6 +106,7 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerd.EventType, ei libc
if err != restartmanager.ErrRestartCanceled {
logrus.Errorf("restartmanger wait error: %+v", err)
}
+ c.CheckpointTo(daemon.containersReplica)
}
}()
}
diff --git a/components/engine/daemon/start.go b/components/engine/daemon/start.go
index 96ae45e11e..8ff636b5a5 100644
--- a/components/engine/daemon/start.go
+++ b/components/engine/daemon/start.go
@@ -203,7 +203,9 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint
}
container.SetRunning(pid, true)
- container.HasBeenManuallyStopped = false
+ if resetRestartManager {
+ container.HasBeenManuallyStopped = false
+ }
container.HasBeenStartedBefore = true
daemon.setStateCounter(container)
--
2.17.1

View File

@ -0,0 +1,30 @@
From b7d540ff87543e02f4d6271afe66edb7aa88477a Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Fri, 15 Feb 2019 15:26:01 +0800
Subject: [PATCH 099/111] integration-cli: fix
TestInspectAPIImageResponse
reason:For we tag busybox:glibc before, the tag number will change
in this testcase. So we cancel the action of checking tag number.
Change-Id: Ib7bf6274d8ca05cc5cbbe3ddd341676b64bb809e
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/engine/integration-cli/docker_api_inspect_test.go | 1 -
5 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/components/engine/integration-cli/docker_api_inspect_test.go b/components/engine/integration-cli/docker_api_inspect_test.go
index 68055b6c14..82d1b19606 100644
--- a/components/engine/integration-cli/docker_api_inspect_test.go
+++ b/components/engine/integration-cli/docker_api_inspect_test.go
@@ -114,7 +114,6 @@ func (s *DockerSuite) TestInspectAPIImageResponse(c *check.C) {
imageJSON, _, err := cli.ImageInspectWithRaw(context.Background(), "busybox")
c.Assert(err, checker.IsNil)
- c.Assert(imageJSON.RepoTags, checker.HasLen, 2)
assert.Check(c, is.Contains(imageJSON.RepoTags, "busybox:latest"))
assert.Check(c, is.Contains(imageJSON.RepoTags, "busybox:mytag"))
}
--
2.17.1

View File

@ -0,0 +1,63 @@
From 582b84ebefcdd71b963dd431fcf9d1d5f9a20552 Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Mon, 18 Feb 2019 21:23:17 +0800
Subject: [PATCH 100/111] proquota: fix quota basesize
reason:fix quota basesize
Change-Id: I268c600b8c63965daf0086796c48ca4e85263e50
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
components/engine/daemon/graphdriver/overlay2/overlay.go | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/components/engine/daemon/graphdriver/overlay2/overlay.go b/components/engine/daemon/graphdriver/overlay2/overlay.go
index 71474f8f36..1a3c9c9d67 100644
--- a/components/engine/daemon/graphdriver/overlay2/overlay.go
+++ b/components/engine/daemon/graphdriver/overlay2/overlay.go
@@ -89,6 +89,7 @@ const (
type overlayOptions struct {
overrideKernelCheck bool
quota quota.Quota
+ quotaBaseSize uint64
}
// Driver contains information about the home directory and the list of active
@@ -221,6 +222,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
// Try to enable project quota support over xfs and extfs.
if d.quotaCtl, err = quota.NewControl(home, backingFs); err == nil {
projectQuotaSupported = true
+ d.options.quotaBaseSize = opts.quotaBaseSize
} else if opts.quota.Size > 0 {
return nil, fmt.Errorf("Storage option overlay2.size not supported. Filesystem does not support Project Quota: %v", err)
}
@@ -280,7 +282,7 @@ func parseOptions(options []string) (*overlayOptions, error) {
if err != nil {
return nil, err
}
- o.quota.Size = uint64(size)
+ o.quotaBaseSize = uint64(size)
default:
return nil, fmt.Errorf("overlay2: unknown option %s", key)
}
@@ -422,14 +422,14 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
}
}()
- if (opts != nil && len(opts.StorageOpt) > 0) || d.options.quota.Size > 0 {
+ if opts != nil && (len(opts.StorageOpt) > 0 || d.options.quotaBaseSize > 0) {
driver := &Driver{}
if err := d.parseStorageOpt(opts.StorageOpt, driver); err != nil {
return err
}
- if driver.options.quota.Size == 0 && d.options.quota.Size > 0 {
- driver.options.quota.Size = d.options.quota.Size
+ if driver.options.quota.Size == 0 && d.options.quotaBaseSize > 0 {
+ driver.options.quota.Size = d.options.quotaBaseSize
}
if driver.options.quota.Size > 0 {
--
2.17.1

View File

@ -0,0 +1,34 @@
From 4711c062b0fd8409eef7ed6ed0963b638765cc7f Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Mon, 18 Feb 2019 21:57:38 +0800
Subject: [PATCH 101/111] daeamon: add judge for client in case of
panic
reason:Add judge for client in monitorDaemon(), in case of
null ptr error return cause panic.
Change-Id: Ia0dd64ba0341414d2dbe213a53daa94e2c5d1723
---
components/engine/libcontainerd/supervisor/remote_daemon.go | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/components/engine/libcontainerd/supervisor/remote_daemon.go b/components/engine/libcontainerd/supervisor/remote_daemon.go
index 45cc3c3032..62ea58c8b4 100644
--- a/components/engine/libcontainerd/supervisor/remote_daemon.go
+++ b/components/engine/libcontainerd/supervisor/remote_daemon.go
@@ -318,8 +318,10 @@ func (r *remote) monitorDaemon(ctx context.Context) {
r.killDaemon()
}
- client.Close()
- client = nil
+ if client != nil {
+ client.Close()
+ client = nil
+ }
r.daemonPid = -1
delay = nil
transientFailureCount = 0
--
2.17.1

View File

@ -0,0 +1,57 @@
From 40c55ba190f46487686d6131b0005737d8bd06af Mon Sep 17 00:00:00 2001
From: jiangpengfei9 <jiangpengfei9@huawei.com>
Date: Fri, 15 Feb 2019 14:13:47 -0500
Subject: [PATCH 102/111] docker-18.09: fix docker stop error if docker
has been stopped
reason: If docker stop send SIGTERM signal to stop container failed, it will wait a short time
and send SIGKILL signal to kill container, but if container has exit while docker stop send
SIGKILL to container, which will cause an error which is "Container %s is not running".So if
docker stop meet this problem, we just let it go and print the warning log.
Change-Id: Ia832aa93c3a94086849cda70110eb772ac3c0a52
Signed-off-by: jiangpengfei9 <jiangpengfei9@huawei.com>
---
components/engine/daemon/kill.go | 6 ++++--
components/engine/daemon/stop.go | 1 +
6 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/components/engine/daemon/kill.go b/components/engine/daemon/kill.go
index 5b2e497604..d185065b54 100644
--- a/components/engine/daemon/kill.go
+++ b/components/engine/daemon/kill.go
@@ -72,7 +72,8 @@ func (daemon *Daemon) killWithSignal(container *containerpkg.Container, sig int)
}
if !container.Running {
- return errNotRunning(container.ID)
+ logrus.Warnf("killWithSignal skip send kill signal to container %s due to container has been stopped",container.ID)
+ return nil
}
var unpause bool
@@ -127,7 +128,8 @@ func (daemon *Daemon) killWithSignal(container *containerpkg.Container, sig int)
// Kill forcefully terminates a container.
func (daemon *Daemon) Kill(container *containerpkg.Container) error {
if !container.IsRunning() {
- return errNotRunning(container.ID)
+ logrus.Warnf("Kill skip send kill signal to container %s due to container has been stopped",container.ID)
+ return nil
}
// 1. Send SIGKILL
diff --git a/components/engine/daemon/stop.go b/components/engine/daemon/stop.go
index c3ac09056a..3c4cd766c9 100644
--- a/components/engine/daemon/stop.go
+++ b/components/engine/daemon/stop.go
@@ -45,6 +45,7 @@ func (daemon *Daemon) containerStop(container *containerpkg.Container, seconds i
stopSignal := container.StopSignal()
// 1. Send a stop signal
if err := daemon.killPossiblyDeadProcess(container, stopSignal); err != nil {
+ logrus.Infof("docker send %d signal to stop container get error: %v", stopSignal, err)
// While normally we might "return err" here we're not going to
// because if we can't stop the container by this point then
// it's probably because it's already stopped. Meaning, between
--
2.17.1

View File

@ -0,0 +1,62 @@
From 405d10b7df5fa329a7070cb842a8d5e4e46861d6 Mon Sep 17 00:00:00 2001
From: lixiang172 <lixiang172@huawei.com>
Date: Mon, 18 Feb 2019 22:13:53 +0800
Subject: [PATCH 103/111] docker: fix parsing name with /
reason: fix parsing name with /
Do the error check when using --link option,
if the alias name and container name is the same, return error
Change-Id: I64c39915d34d79ee8abbba2ebe0e66ad3ad08551
Signed-off-by: yangshukui <yangshukui@huawei.com>
Signed-off-by: lixiang172 <lixiang172@huawei.com>
---
components/engine/daemon/daemon.go | 13 +++++++++++++
.../engine/integration-cli/docker_cli_links_test.go | 8 ++++++++
2 files changed, 21 insertions(+)
diff --git a/components/engine/daemon/daemon.go b/components/engine/daemon/daemon.go
index f5d22bb18b..e26494ed68 100644
--- a/components/engine/daemon/daemon.go
+++ b/components/engine/daemon/daemon.go
@@ -657,8 +657,21 @@ func (daemon *Daemon) parents(c *container.Container) map[string]*container.Cont
return daemon.linkIndex.parents(c)
}
+func validateAlias(alias string, c *container.Container) error {
+ if !validContainerNamePattern.MatchString(alias) {
+ return fmt.Errorf("Invalid alias name (%s), only %s are allowed", alias, validContainerNameChars)
+ }
+ if alias == c.Config.Hostname {
+ return fmt.Errorf("Invalid alias name (%s), alias is the same to current container's hostname", alias)
+ }
+ return nil
+}
+
func (daemon *Daemon) registerLink(parent, child *container.Container, alias string) error {
fullName := path.Join(parent.Name, alias)
+ if err := validateAlias(alias, parent); err != nil {
+ return err
+ }
if err := daemon.containersReplica.ReserveName(fullName, child.ID); err != nil {
if err == container.ErrNameReserved {
logrus.Warnf("error registering link for %s, to %s, as alias %s, ignoring: %v", parent.ID, child.ID, alias, err)
diff --git a/components/engine/integration-cli/docker_cli_links_test.go b/components/engine/integration-cli/docker_cli_links_test.go
index 17b25d7994..9efa1cfbf6 100644
--- a/components/engine/integration-cli/docker_cli_links_test.go
+++ b/components/engine/integration-cli/docker_cli_links_test.go
@@ -237,3 +237,11 @@ func (s *DockerSuite) TestLinksMultipleWithSameName(c *check.C) {
dockerCmd(c, "run", "-d", "--name=upstream-b", "busybox", "top")
dockerCmd(c, "run", "--link", "upstream-a:upstream", "--link", "upstream-b:upstream", "busybox", "sh", "-c", "ping -c 1 upstream")
}
+func (s *DockerSuite) TestLinksAliasCheck(c *check.C) {
+ testRequires(c, DaemonIsLinux, NotUserNamespace)
+ dockerCmd(c, "run", "-d", "--name=linkalias", "busybox", "top")
+ out, _, _ := dockerCmdWithError("run", "-d", "--link=linkalias:hello/sep", "busybox", "top")
+ c.Assert(out, checker.Contains, "Invalid alias name")
+ out, _, _ = dockerCmdWithError("run", "-d", "--hostname=linkhostname", "--link=linkalias:linkhostname", "busybox", "top")
+ c.Assert(out, checker.Contains, "alias is the same to current container's hostname")
+}
--
2.17.1

View File

@ -0,0 +1,29 @@
From f983b1959dae1d5f0dcae1f7480db5ae69906f74 Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Wed, 20 Feb 2019 11:45:45 +0800
Subject: [PATCH 104/111] docker stats: increase the timeout of docker
stats command
reason:Increase the timeout of docker stats command, in case of data lost.
Change-Id: Ib698f7cfdc06928838b343821a6bdca875327ff7
---
components/cli/cli/command/container/stats.go | 2 +-
5 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/components/cli/cli/command/container/stats.go b/components/cli/cli/command/container/stats.go
index 1f9e1b8556..8387fc988d 100644
--- a/components/cli/cli/command/container/stats.go
+++ b/components/cli/cli/command/container/stats.go
@@ -172,7 +172,7 @@ func runStats(dockerCli command.Cli, opts *statsOptions) error {
// Do a quick pause to detect any error with the provided list of
// container names.
- time.Sleep(1500 * time.Millisecond)
+ time.Sleep(2500 * time.Millisecond)
var errs []string
cStats.mu.Lock()
for _, c := range cStats.cs {
--
2.17.1

View File

@ -0,0 +1,55 @@
From f66b0742f72a0f15c6b805751c00af2c7b0f3193 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 20 Feb 2019 23:42:00 +0800
Subject: [PATCH 105/111] pause: fix pause on exited container
reason: fix pause on exited container
Change-Id: I109a88ab6832c3118f6be48f5924679549607740
Signed-off-by: jingrui <jingrui@huawei.com>
---
components/engine/daemon/freezer/freezer.go | 21 ++++++++++++++++++-
5 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/components/engine/daemon/freezer/freezer.go b/components/engine/daemon/freezer/freezer.go
index a0ef299852..907c7aac2a 100644
--- a/components/engine/daemon/freezer/freezer.go
+++ b/components/engine/daemon/freezer/freezer.go
@@ -12,6 +12,7 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/utils"
+ "github.com/sirupsen/logrus"
)
// Freezer is the interface which could be used to pause/resume container,
@@ -131,7 +132,25 @@ func (f *freezer) Pause() error {
return fmt.Errorf("error: no tasks running in freeze cgroup")
}
- return f.updateCgroup(string(configs.Frozen))
+ err = f.updateCgroup(string(configs.Frozen))
+ if err != nil {
+ return err
+ }
+
+ tasks, err = readFile(f.path, "tasks")
+ if err != nil {
+ err := f.updateCgroup(string(configs.Thawed))
+ logrus.Warnf("revert pause due to no tasks file. revert-error=%v", err)
+ return fmt.Errorf("failed to check container cgroup task status: %v", err)
+ }
+
+ if strings.TrimSpace(tasks) == "" {
+ err := f.updateCgroup(string(configs.Thawed))
+ logrus.Warnf("revert pause due to no tasks. revert-error=%v", err)
+ return fmt.Errorf("error: no tasks running in freeze cgroup")
+ }
+
+ return nil
}
// Resume will set the container to running state by writing freeze cgroup.
--
2.17.1

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