diff --git a/_service b/_service index 6520ecd..e2962f5 100644 --- a/_service +++ b/_service @@ -3,8 +3,8 @@ https://github.com/docker/docker.git git .git - 1.12.6 - v1.12.6 + 1.13.0 + v1.13.0 docker-*.tar diff --git a/docker-1.12.6.tar.xz b/docker-1.12.6.tar.xz deleted file mode 100644 index 250ec17..0000000 --- a/docker-1.12.6.tar.xz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ade8df08afa29834e772ae9061975801ff35bd2b4c7979df4ff4df8f22ffce8c -size 11190120 diff --git a/docker-1.13.0.tar.xz b/docker-1.13.0.tar.xz new file mode 100644 index 0000000..8e5b482 --- /dev/null +++ b/docker-1.13.0.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1da90f2f637d55c7bef034761f0781a7cc4facdefc50b9d77f0c6a78185efe0a +size 5130016 diff --git a/docker-mount-secrets.patch b/docker-mount-secrets.patch deleted file mode 100644 index b6e8963..0000000 --- a/docker-mount-secrets.patch +++ /dev/null @@ -1,413 +0,0 @@ -From 17cd15ba4160f0e0830453529b9b01edc308d847 Mon Sep 17 00:00:00 2001 -From: Aleksa Sarai -Date: Mon, 11 Apr 2016 22:54:35 +1000 -Subject: [PATCH] SUSE: implement SUSE container secrets - -This allows for us to pass in host credentials to a container, allowing -for SUSEConnect to work with containers. - -THIS PATCH IS NOT TO BE UPSTREAMED, DUE TO THE FACT THAT IT IS -SUSE-SPECIFIC, AND UPSTREAM DOES NOT APPROVE OF THIS CONCEPT BECAUSE IT -MAKES BUILDS NOT ENTIRELY REPRODUCIBLE. - -Signed-off-by: Aleksa Sarai ---- - container/container_unix.go | 63 ++++++++++++ - daemon/container_operations_unix.go | 50 ++++++++++ - daemon/daemon_unix.go | 6 +- - daemon/oci_linux.go | 6 ++ - daemon/start.go | 6 ++ - daemon/suse_secrets.go | 184 ++++++++++++++++++++++++++++++++++++ - 6 files changed, 313 insertions(+), 2 deletions(-) - create mode 100644 daemon/suse_secrets.go - -diff --git a/container/container_unix.go b/container/container_unix.go -index 2727b81..07a0710 100644 ---- a/container/container_unix.go -+++ b/container/container_unix.go -@@ -35,6 +35,8 @@ type Container struct { - HostsPath string - ShmPath string - ResolvConfPath string -+ // SUSE:secrets :: We need to add the container-specific secrets path here. -+ SuseSecretsPath string - SeccompProfile string - NoNewPrivileges bool - } -@@ -256,6 +258,67 @@ func (container *Container) IpcMounts() []Mount { - return mounts - } - -+// SUSE:secrets :: SuseSecretsResourcePath returns the path to the container's -+// personal /run/secrets tmpfs. -+func (container *Container) SuseSecretsResourcePath() (string, error) { -+ return container.GetRootResourcePath("suse.secrets") -+} -+ -+// SUSE:secrets :: SuseSecretMounts returns the list of mounts required for the -+// SUSE-specific /run/secrets patch. The container's personal /run/secrets tmpfs -+// has already been set up at this point. -+func (container *Container) SuseSecretMounts() []Mount { -+ var mounts []Mount -+ -+ logrus.WithFields(logrus.Fields{ -+ "container": container.ID, -+ "path": container.SuseSecretsPath, -+ "hasmount": container.HasMountFor("/run/secrets"), -+ }).Debug("SUSE:secrets :: adding container secrets to mountpoint") -+ -+ // TODO(SUSE): How do we register for HasMountFor(). -+ if !container.HasMountFor("/run/secrets") { -+ label.SetFileLabel(container.SuseSecretsPath, container.MountLabel) -+ mounts = append(mounts, Mount{ -+ Source: container.SuseSecretsPath, -+ Destination: "/run/secrets", -+ Writable: true, -+ Propagation: volume.DefaultPropagationMode, -+ }) -+ } -+ -+ return mounts -+} -+ -+// SUSE:secrets :: Unmounts the container's personal /run/secrets tmpfs using the -+// provided function. This is done to clean up the mountpoints properly. -+func (container *Container) UnmountSuseSecretMounts(unmount func(string) error) { -+ logrus.WithFields(logrus.Fields{ -+ "container": container.ID, -+ "hasmount": container.HasMountFor("/run/secrets"), -+ }).Debug("SUSE:secrets :: requested to clean up container secrets") -+ -+ if !container.HasMountFor("/run/secrets") { -+ logrus.Debugf("SUSE:secrets :: cleaning up secrets mount for container") -+ -+ suseSecretsPath, err := container.SuseSecretsResourcePath() -+ if err != nil { -+ logrus.Error("SUSE:secrets :: failed to clean up secrets mounts: no secrets resource path found for container %v: %v", container.ID, err) -+ } -+ -+ if suseSecretsPath != "" { -+ logrus.WithFields(logrus.Fields{ -+ "path": suseSecretsPath, -+ }).Debugf("SUSE:secrets :: actually unmounting conatiner secrets") -+ -+ if err := unmount(suseSecretsPath); err != nil && !os.IsNotExist(err) { -+ // We can't error out here. -+ logrus.Warnf("SUSE:secrets :: failed to clean up secrets mounts: failed to umount %s: %v", suseSecretsPath, err) -+ } -+ } -+ } -+} -+ - // UpdateContainer updates configuration of a container. - func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfig) error { - container.Lock() -diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_unix.go -index 55bd3fc..a3ab7fb 100644 ---- a/daemon/container_operations_unix.go -+++ b/daemon/container_operations_unix.go -@@ -184,6 +184,56 @@ func (daemon *Daemon) getPidContainer(container *container.Container) (*containe - return c, nil - } - -+// SUSE:secrets :: Create a container's personal /run/secrets tmpfs and fill it -+// with the host's credentials. -+func (daemon *Daemon) setupSuseSecrets(c *container.Container) (err error) { -+ c.SuseSecretsPath, err = c.SuseSecretsResourcePath() -+ if err != nil { -+ return err -+ } -+ -+ if !c.HasMountFor("/run/secrets") { -+ rootUID, rootGID := daemon.GetRemappedUIDGID() -+ if err = idtools.MkdirAllAs(c.SuseSecretsPath, 0700, rootUID, rootGID); err != nil { -+ return fmt.Errorf("SUSE:secrets :: failed to create container secret: %v", err) -+ } -+ if err = syscall.Mount("tmpfs", c.SuseSecretsPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel("", c.GetMountLabel())); err != nil { -+ return fmt.Errorf("SUSE:secrets :: mounting secrets tmpfs: %v", err) -+ } -+ // We need to defer a cleanup, to make sure errors that occur before the container -+ // starts don't cause wasted memory due to tmpfs-es that aren't being used. -+ defer func() { -+ if err != nil { -+ logrus.Infof("SUSE::secrets :: cleaning up secrets mount due to failed setup") -+ c.UnmountSuseSecretMounts(detachMounted) -+ } -+ }() -+ if err = os.Chown(c.SuseSecretsPath, rootUID, rootGID); err != nil { -+ return fmt.Errorf("SUSE:secrets :: failed to chown container secret to (uid=%d,gid=%d): %v", rootUID, rootGID, err) -+ } -+ -+ // Now we need to inject the credentials. But in order to play properly with -+ // user namespaces, they must be owned by rootUID:rootGID. -+ -+ data, err := getHostSuseSecretData() -+ if err != nil { -+ return fmt.Errorf("SUSE:secrets :: failed to get host secret data: %v", err) -+ } -+ -+ uidMap, gidMap := daemon.GetUIDGIDMaps() -+ for _, s := range data { -+ if err := s.SaveTo(c.SuseSecretsPath, uidMap, gidMap); err != nil { -+ logrus.WithFields(logrus.Fields{ -+ "s.path": s.Path, -+ "path": c.SuseSecretsPath, -+ }).Errorf("SUSE:secrets :: failed to save secret data: %v", err) -+ } -+ } -+ } -+ -+ return -+} -+ - func (daemon *Daemon) setupIpcDirs(c *container.Container) error { - var err error - -diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go -index f266912..2ced1b8 100644 ---- a/daemon/daemon_unix.go -+++ b/daemon/daemon_unix.go -@@ -809,8 +809,10 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e - // the container from unwanted side-effects on the rw layer. - func setupInitLayer(initLayer string, rootUID, rootGID int) error { - for pth, typ := range map[string]string{ -- "/dev/pts": "dir", -- "/dev/shm": "dir", -+ "/dev/pts": "dir", -+ "/dev/shm": "dir", -+ // SUSE:secrets :: We need to add the mountpoint in the init layer. -+ "/run/secrets": "dir", - "/proc": "dir", - "/sys": "dir", - "/.dockerenv": "file", -diff --git a/daemon/oci_linux.go b/daemon/oci_linux.go -index 4459d02..6af7d35 100644 ---- a/daemon/oci_linux.go -+++ b/daemon/oci_linux.go -@@ -656,6 +656,10 @@ func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, e - if err := daemon.setupIpcDirs(c); err != nil { - return nil, err - } -+ // SUSE:secrets :: We need to set up the container-specific secrets tmpfs here. -+ if err := daemon.setupSuseSecrets(c); err != nil { -+ return nil, err -+ } - - ms, err := daemon.setupMounts(c) - if err != nil { -@@ -663,6 +667,8 @@ func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, e - } - ms = append(ms, c.IpcMounts()...) - ms = append(ms, c.TmpfsMounts()...) -+ // SUSE:secrets :: We add the mounts to the OCI config which containerd then uses. -+ ms = append(ms, c.SuseSecretMounts()...) - sort.Sort(mounts(ms)) - if err := setMounts(daemon, &s, c, ms); err != nil { - return nil, fmt.Errorf("linux mounts: %v", err) -diff --git a/daemon/start.go b/daemon/start.go -index fcf24c5..57a8c33 100644 ---- a/daemon/start.go -+++ b/daemon/start.go -@@ -173,6 +173,12 @@ func (daemon *Daemon) Cleanup(container *container.Container) { - - container.UnmountIpcMounts(detachMounted) - -+ // TODO(SUSE): Make sure this gets called by containerCleanup. Do we need to -+ // port this part of the patch there as well? -+ -+ // SUSE:secrets :: We need to unmount stuff here so that we clean up properly. -+ container.UnmountSuseSecretMounts(detachMounted) -+ - if err := daemon.conditionalUnmountOnCleanup(container); err != nil { - // FIXME: remove once reference counting for graphdrivers has been refactored - // Ensure that all the mounts are gone -diff --git a/daemon/suse_secrets.go b/daemon/suse_secrets.go -new file mode 100644 -index 0000000..417a1a9 ---- /dev/null -+++ b/daemon/suse_secrets.go -@@ -0,0 +1,184 @@ -+package daemon -+ -+// SUSE:secrets :: This is a set of functions to copy host credentials into a -+// container's /run/secrets. -+ -+import ( -+ "io/ioutil" -+ "os" -+ "path/filepath" -+ "syscall" -+ -+ "github.com/Sirupsen/logrus" -+ "github.com/docker/docker/pkg/idtools" -+) -+ -+// TODO(SUSE): We need to reimplement this to use tar. Immediately. -+ -+// Creating a fake file. -+type SuseFakeFile struct { -+ Path string -+ Uid int -+ Gid int -+ Mode os.FileMode -+ Data []byte -+} -+ -+func (s *SuseFakeFile) SaveTo(dir string, uidMap, gidMap []idtools.IDMap) error { -+ // Create non-existant path components with an owner of root (other FakeFiles -+ // will clean this up if the owner is critical). -+ rootUid, rootGid, err := idtools.GetRootUIDGID(uidMap, gidMap) -+ -+ path := filepath.Join(dir, s.Path) -+ if err := idtools.MkdirAllNewAs(filepath.Dir(path), 0755, rootUid, rootGid); err != nil && !os.IsExist(err) { -+ return err -+ } -+ -+ uid, err := idtools.ToHost(s.Uid, uidMap) -+ if err != nil { -+ return err -+ } -+ -+ gid, err := idtools.ToHost(s.Gid, gidMap) -+ if err != nil { -+ return err -+ } -+ -+ if s.Mode.IsDir() { -+ if err := idtools.MkdirAs(path, s.Mode, uid, gid); err != nil { -+ return err -+ } -+ } else { -+ if err := ioutil.WriteFile(path, s.Data, s.Mode); err != nil { -+ return err -+ } -+ } -+ -+ return os.Chown(path, uid, gid) -+} -+ -+// readDir will recurse into a directory prefix/dir, and return the set of secrets -+// in that directory. The Path attribute of each has the prefix stripped. Symlinks -+// are evaluated. -+func readDir(prefix, dir string) ([]*SuseFakeFile, error) { -+ var suseFiles []*SuseFakeFile -+ -+ path := filepath.Join(prefix, dir) -+ -+ fi, err := os.Stat(path) -+ if err != nil { -+ // Ignore dangling symlinks. -+ if os.IsNotExist(err) { -+ logrus.Warnf("SUSE:secrets :: dangling symlink: %s", path) -+ return suseFiles, nil -+ } -+ return nil, err -+ } -+ -+ stat, ok := fi.Sys().(*syscall.Stat_t) -+ if !ok { -+ logrus.Warnf("SUSE:secrets :: failed to cast directory stat_t: defaulting to owned by root:root: %s", path) -+ } -+ -+ suseFiles = append(suseFiles, &SuseFakeFile{ -+ Path: dir, -+ Uid: int(stat.Uid), -+ Gid: int(stat.Gid), -+ Mode: fi.Mode(), -+ }) -+ -+ files, err := ioutil.ReadDir(path) -+ if err != nil { -+ return nil, err -+ } -+ -+ for _, f := range files { -+ subpath := filepath.Join(dir, f.Name()) -+ -+ if f.IsDir() { -+ secrets, err := readDir(prefix, subpath) -+ if err != nil { -+ return nil, err -+ } -+ suseFiles = append(suseFiles, secrets...) -+ } else { -+ secrets, err := readFile(prefix, subpath) -+ if err != nil { -+ return nil, err -+ } -+ suseFiles = append(suseFiles, secrets...) -+ } -+ } -+ -+ return suseFiles, nil -+} -+ -+func readFile(prefix, file string) ([]*SuseFakeFile, error) { -+ var suseFiles []*SuseFakeFile -+ -+ path := filepath.Join(prefix, file) -+ fi, err := os.Stat(path) -+ if err != nil { -+ // Ignore dangling symlinks. -+ if os.IsNotExist(err) { -+ logrus.Warnf("SUSE:secrets :: dangling symlink: %s", path) -+ return suseFiles, nil -+ } -+ return nil, err -+ } -+ -+ stat, ok := fi.Sys().(*syscall.Stat_t) -+ if !ok { -+ logrus.Warnf("SUSE:secrets :: failed to cast file stat_t: defaulting to owned by root:root: %s", path) -+ } -+ -+ if fi.IsDir() { -+ secrets, err := readDir(prefix, file) -+ if err != nil { -+ return nil, err -+ } -+ suseFiles = append(suseFiles, secrets...) -+ } else { -+ bytes, err := ioutil.ReadFile(path) -+ if err != nil { -+ return nil, err -+ } -+ suseFiles = append(suseFiles, &SuseFakeFile{ -+ Path: file, -+ Uid: int(stat.Uid), -+ Gid: int(stat.Gid), -+ Mode: fi.Mode(), -+ Data: bytes, -+ }) -+ } -+ -+ return suseFiles, nil -+} -+ -+func getHostSuseSecretData() ([]*SuseFakeFile, error) { -+ secrets := []*SuseFakeFile{} -+ -+ credentials, err := readDir("/etc/zypp", "credentials.d") -+ if err != nil { -+ if os.IsNotExist(err) { -+ credentials = []*SuseFakeFile{} -+ } else { -+ logrus.Errorf("SUSE:secrets :: error while reading zypp credentials: %s", err) -+ return nil, err -+ } -+ } -+ secrets = append(secrets, credentials...) -+ -+ suseConnect, err := readFile("/etc", "SUSEConnect") -+ if err != nil { -+ if os.IsNotExist(err) { -+ suseConnect = []*SuseFakeFile{} -+ } else { -+ logrus.Errorf("SUSE:secrets :: error while reading /etc/SUSEConnect: %s", err) -+ return nil, err -+ } -+ } -+ secrets = append(secrets, suseConnect...) -+ -+ return secrets, nil -+} diff --git a/docker.changes b/docker.changes index 779dc97..1e620f2 100644 --- a/docker.changes +++ b/docker.changes @@ -1,3 +1,56 @@ +------------------------------------------------------------------- +Fri Mar 17 11:08:03 UTC 2017 - asarai@suse.com + +- Add a backport of fix to AppArmor lazy loading docker-exec case. + https://github.com/docker/docker/pull/31773 + + pr31773-daemon-also-ensureDefaultApparmorProfile-in-exec-pat.patch + +------------------------------------------------------------------- +Wed Mar 8 00:48:46 UTC 2017 - asarai@suse.com + +- Clean up docker-mount-secrets.patch to use the new swarm secrets internals of + Docker 1.13.0, which removes the need to implement any secret handling + ourselves. This resulted in a split up of the patch. + - docker-mount-secrets.patch + + secrets-0001-daemon-allow-directory-creation-in-run-secrets.patch + + secrets-0002-SUSE-implement-SUSE-container-secrets.patch + +------------------------------------------------------------------- +Mon Mar 6 15:31:02 UTC 2017 - jmassaguerpla@suse.com + +- Remove old plugins.json to prevent docker-1.13 to fail to start + +------------------------------------------------------------------- +Mon Mar 6 12:52:14 UTC 2017 - jmassaguerpla@suse.com + +- Fix bsc#1026827: systemd TasksMax default throttles docker + +------------------------------------------------------------------- +Mon Mar 6 10:09:14 UTC 2017 - jmassaguerpla@suse.com + +- Fix post section by adding shadow as a package requirement + Otherwise the groupadd instruction fails + +------------------------------------------------------------------- +Sun Mar 5 04:54:52 UTC 2017 - asarai@suse.com + +- Add patch to fix TestDaemonCommand failure in %check. This is an upstream + bug, and has an upstream PR to fix it https://github.com/docker/docker/pull/31549. + + pr31549-cmd-docker-fix-TestDaemonCommand.patch + +------------------------------------------------------------------- +Wed Feb 1 15:59:40 UTC 2017 - jmassaguerpla@suse.com + +- update docker to 1.13.0 + + see details in https://github.com/docker/docker/releases/tag/v1.13.0 + +- use the same buildflags for building docker and for building the + tests. + +- enable pkcs11: + https://github.com/docker/docker/commit/37fa75b3447007bb8ea311f02610bb383b0db77f + ------------------------------------------------------------------- Fri Jan 27 12:30:18 UTC 2017 - bg@suse.com @@ -8,20 +61,20 @@ Thu Jan 26 15:43:38 UTC 2017 - jmassaguerpla@suse.com - provide the oci runtime so that containers which were using an old runtime option, when started on the new docker version, the runtime - is changed to the new one. fix bsc#1020806 bsc#1016992 + is changed to the new one. fix bsc#1020806 bsc#1016992 ------------------------------------------------------------------- Fri Jan 13 13:56:15 UTC 2017 - jmassaguerpla@suse.com - fix CVE-2016-9962 bsc#1012568 . Fix it by updating to 1.12.6 plus an extra commit to fix liverestore: - https://github.com/docker/docker/commit/97cd32a6a9076306baa637a29bba84c3f1f3d218 + https://github.com/docker/docker/commit/97cd32a6a9076306baa637a29bba84c3f1f3d218 ------------------------------------------------------------------- Wed Jan 11 12:47:16 UTC 2017 - jmassaguerpla@suse.com - add "a wait" when starting docker service to fix - bsc#1019251 + bsc#1019251 ------------------------------------------------------------------- Tue Dec 20 12:41:33 UTC 2016 - normand@linux.vnet.ibm.com diff --git a/docker.service b/docker.service index e654024..4b5b5d4 100644 --- a/docker.service +++ b/docker.service @@ -23,7 +23,7 @@ LimitCORE=infinity # Uncomment TasksMax if your systemd version supports it. # Only systemd 226 and above support this property. -#TasksMax=infinity +TasksMax=infinity # Set delegate yes so that systemd does not reset the cgroups of docker containers # Only systemd 218 and above support this property. diff --git a/docker.spec b/docker.spec index 553f681..9705ee9 100644 --- a/docker.spec +++ b/docker.spec @@ -36,7 +36,7 @@ %global docker_migration_warnfile %{docker_store}/docker-update-message.txt %define docker_graph %{docker_store}/graph %define git_version 78d1802 -%define version_unconverted 1.12.6 +%define version_unconverted 1.13.0 %define __arch_install_post export NO_BRP_STRIP_DEBUG=true # When upgrading to a new version requires the service not to be restarted # Due to a long migration process update last_migration_version to the new version @@ -44,7 +44,7 @@ # 1.10.1 %global last_migration_version 1.10.1 Name: docker -Version: 1.12.6 +Version: 1.13.0 Release: 0 Summary: The Linux container runtime License: Apache-2.0 @@ -59,7 +59,7 @@ Source7: README_SUSE.md Source8: docker-audit.rules Source9: docker-update-message.txt Source10: tests.sh -Source11: docker_service_helper.sh +Source11: docker_service_helper.sh # Fixes for architecture-specific issues (gcc-go). Patch100: gcc-go-patches.patch Patch102: netlink_netns_powerpc.patch @@ -68,14 +68,21 @@ Patch103: boltdb_bolt_add_brokenUnaligned.patch # which is not snapshotted when images are committed. Note that if you modify # this patch, please also modify the patch in the suse-secrets-v # branch in http://github.com/suse/docker.mirror. -Patch200: docker-mount-secrets.patch +Patch200: secrets-0001-daemon-allow-directory-creation-in-run-secrets.patch +Patch201: secrets-0002-SUSE-implement-SUSE-container-secrets.patch +# PATCH-FIX-UPSTREAM: Backports. Patch300: integration-cli-fix-TestInfoEnsureSucceeds.patch +Patch301: pr31549-cmd-docker-fix-TestDaemonCommand.patch +Patch302: pr31773-daemon-also-ensureDefaultApparmorProfile-in-exec-pat.patch BuildRequires: audit BuildRequires: bash-completion +BuildRequires: ca-certificates BuildRequires: device-mapper-devel >= 1.2.68 BuildRequires: glibc-devel-static BuildRequires: libapparmor-devel BuildRequires: libbtrfs-devel >= 3.8 +BuildRequires: libseccomp-devel +BuildRequires: libtool BuildRequires: procps BuildRequires: sqlite3-devel BuildRequires: systemd-devel @@ -83,12 +90,13 @@ BuildRequires: zsh Requires: apparmor-parser Requires: bridge-utils Requires: ca-certificates-mozilla +Requires: docker-libnetwork = 0.0.0+git20161019.0f53435 # Containerd and runC are required as they are the only currently supported # execdrivers of Docker. NOTE: The version pinning here matches upstream's # Dockerfile to ensure that we don't use a slightly incompatible version of # runC or containerd (which would be bad). -Requires: containerd = 0.2.5+gitr569_2a5e70c -Requires: runc = 0.1.1+gitr2819_50a19c6 +Requires: containerd = 0.2.5+gitr608_03e5862 +Requires: runc = 0.1.1+gitr2942_2f7393a # Provides mkfs.ext4 - used by Docker when devicemapper storage driver is used Requires: e2fsprogs Requires: git-core >= 1.7 @@ -100,6 +108,7 @@ Requires: tar >= 1.26 Requires: xz >= 4.9 Requires(post): %fillup_prereq Requires(post): udev +Requires(post): shadow # Not necessary, but must be installed to have a smooth upgrade. Recommends: docker-image-migrator Conflicts: lxc < 1.0 @@ -169,6 +178,7 @@ Test package for docker. It contains the source code and the tests. # nothing %else %patch200 -p1 +%patch201 -p1 %endif %ifnarch %{go_arches} %patch100 -p1 @@ -176,6 +186,8 @@ Test package for docker. It contains the source code and the tests. %patch103 -p1 %endif %patch300 -p1 +%patch301 -p1 +%patch302 -p1 cp %{SOURCE7} . cp %{SOURCE10} . @@ -188,9 +200,18 @@ ln -s %{_bindir}/go-6 $tmphack/go export PATH=$tmphack:$PATH %endif +# Note that these commands do not allow %%elseif. +# For versions equal to or below SLE12 && openSUSE_13.2 libdevmapper.h is not +# recent enough to define dm_task_deferred_remove(). (This is not true of +# SLE12_SP1 but we cannot distinguish it with this macro.) +BUILDTAGS="exclude_graphdriver_aufs apparmor seccomp selinux pkcs11" +%if 0%{?suse_version} <= 1320 + BUILDTAGS="libdm_no_deferred_remove $BUILDTAGS" +%endif + (cat < docker_build_env @@ -233,22 +254,13 @@ cp -avr %{buildroot}/usr/src/%{name} $HOME/go/src/github.com/docker/docker cd $HOME/go/src/github.com/docker/docker -# Note that these commands do not allow %%elseif. -# For versions equal to or below SLE12 && openSUSE_13.2 libdevmapper.h is not -# recent enough to define dm_task_deferred_remove(). (This is not true of -# SLE12_SP1 but we cannot distinguish it with this macro.) -EXCLUDE_TAGS= -%if 0%{?suse_version} <= 1320 - EXCLUDE_TAGS="libdm_no_deferred_remove $EXCLUDE_TAGS" -%endif - # The command is taken from hack/make/test-unit and various test runs. # Everything that follows github.com/docker/pkg/integration-cli are packages # containing tests that cannot run in an obs build context. PKG_LIST=$(go list -e \ -f '{{if ne .Name "github.com/docker/docker"}} {{.ImportPath}} {{end}}' \ - -tags $EXCLUDE_TAGS \ + -tags "$DOCKER_BUILDTAGS" \ -a "${BUILDFLAGS[@]}" ... \ | grep 'github.com/docker/docker' \ | grep -v 'github.com/docker/docker/vendor' \ @@ -273,7 +285,7 @@ PKG_LIST=$(go list -e \ | grep -v 'github.com/docker/docker/man$' \ | grep -v 'github.com/docker/docker/pkg/integration$') -go test -cover -ldflags -w -tags $EXCLUDE_TAGS -a -test.timeout=10m $PKG_LIST +go test -cover -ldflags -w -tags "$DOCKER_BUILDTAGS" -a -test.timeout=10m $PKG_LIST %endif %install @@ -282,11 +294,9 @@ install -d %{buildroot}%{_bindir} %ifarch %{go_arches} install -D -m755 bundles/latest/dynbinary-client/%{name} %{buildroot}/%{_bindir}/%{name} install -D -m755 bundles/latest/dynbinary-daemon/%{name}d %{buildroot}/%{_bindir}/%{name}d -install -D -m755 bundles/latest/dynbinary-daemon/%{name}-proxy %{buildroot}/%{_bindir}/%{name}-proxy %else install -D -m755 bundles/latest/dyngccgo/%{name} %{buildroot}/%{_bindir}/%{name} install -D -m755 bundles/latest/dyngccgo/%{name}d %{buildroot}/%{_bindir}/%{name}d -install -D -m755 bundles/latest/dyngccgo/%{name}-proxy %{buildroot}/%{_bindir}/%{name}-proxy %endif install -d %{buildroot}/%{_prefix}/lib/docker install -Dd -m 0755 \ @@ -374,6 +384,13 @@ else rm %{docker_migration_warnfile} fi fi +# If plugins.json is present, docker will fail to start +# https://github.com/docker/docker/releases/1.13.0 +if [ -e /var/lib/docker/plugins/plugins.json ];then + echo "Warning: Disabling previous installed plugins" + echo "Otherwise docker will fail to boot" + mv /var/lib/docker/plugins/plugins.json /var/lib/docker/plugins/_plugins.json.old +fi %service_add_post %{name}.service %{fillup_only -n docker} @@ -392,7 +409,6 @@ fi %doc README.md LICENSE README_SUSE.md %{_bindir}/docker %{_bindir}/dockerd -%{_bindir}/docker-proxy %{_sbindir}/rcdocker %{_libexecdir}/docker/ %{_unitdir}/%{name}.service diff --git a/integration-cli-fix-TestInfoEnsureSucceeds.patch b/integration-cli-fix-TestInfoEnsureSucceeds.patch index e7c1dc0..fd4d91b 100644 --- a/integration-cli-fix-TestInfoEnsureSucceeds.patch +++ b/integration-cli-fix-TestInfoEnsureSucceeds.patch @@ -1,18 +1,8 @@ -From 0f0c0fcb5b956782385e25c7c6c625e6c79ac78f Mon Sep 17 00:00:00 2001 -From: Thomas Hipp -Date: Wed, 7 Sep 2016 10:54:09 +0200 -Subject: [PATCH] integration-cli: fix TestInfoEnsureSucceeds - -Signed-off-by: Thomas Hipp ---- - integration-cli/docker_cli_info_test.go | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - diff --git a/integration-cli/docker_cli_info_test.go b/integration-cli/docker_cli_info_test.go -index a48e69a..c265a36 100644 +index 62ce7e2..46516f9 100644 --- a/integration-cli/docker_cli_info_test.go +++ b/integration-cli/docker_cli_info_test.go -@@ -36,7 +36,7 @@ func (s *DockerSuite) TestInfoEnsureSucceeds(c *check.C) { +@@ -40,7 +40,7 @@ func (s *DockerSuite) TestInfoEnsureSucceeds(c *check.C) { } if DaemonIsLinux.Condition() { @@ -20,7 +10,4 @@ index a48e69a..c265a36 100644 + stringsToCheck = append(stringsToCheck, "Runtimes:", "Default Runtime: oci") } - if utils.ExperimentalBuild() { --- -2.9.3 - + if experimentalDaemon { diff --git a/pr31549-cmd-docker-fix-TestDaemonCommand.patch b/pr31549-cmd-docker-fix-TestDaemonCommand.patch new file mode 100644 index 0000000..3cad3ae --- /dev/null +++ b/pr31549-cmd-docker-fix-TestDaemonCommand.patch @@ -0,0 +1,49 @@ +From dd7159060f60ea04007c069df189a29fda2c655f Mon Sep 17 00:00:00 2001 +From: Aleksa Sarai +Date: Sun, 5 Mar 2017 15:25:11 +1100 +Subject: [PATCH] cmd: docker: fix TestDaemonCommand + +In more recent versions of Cobra, `--help` parsing is done before +anything else resulting in TestDaemonCommand not actually passing. I'm +actually unsure if this test ever passed since it appears that !daemon +is not being run as part of the test suite. + +Signed-off-by: Aleksa Sarai +--- + cmd/docker/daemon_none.go | 6 ++++-- + cmd/docker/daemon_none_test.go | 2 +- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/cmd/docker/daemon_none.go b/cmd/docker/daemon_none.go +index 65f9f37be22f..6fbd00012526 100644 +--- a/cmd/docker/daemon_none.go ++++ b/cmd/docker/daemon_none.go +@@ -12,8 +12,10 @@ import ( + + func newDaemonCommand() *cobra.Command { + return &cobra.Command{ +- Use: "daemon", +- Hidden: true, ++ Use: "daemon", ++ Hidden: true, ++ Args: cobra.ArbitraryArgs, ++ DisableFlagParsing: true, + RunE: func(cmd *cobra.Command, args []string) error { + return runDaemon() + }, +diff --git a/cmd/docker/daemon_none_test.go b/cmd/docker/daemon_none_test.go +index 32032fe1b344..bd42add98696 100644 +--- a/cmd/docker/daemon_none_test.go ++++ b/cmd/docker/daemon_none_test.go +@@ -10,7 +10,7 @@ import ( + + func TestDaemonCommand(t *testing.T) { + cmd := newDaemonCommand() +- cmd.SetArgs([]string{"--help"}) ++ cmd.SetArgs([]string{"--version"}) + err := cmd.Execute() + + assert.Error(t, err, "Please run `dockerd`") +-- +2.12.0 + diff --git a/pr31773-daemon-also-ensureDefaultApparmorProfile-in-exec-pat.patch b/pr31773-daemon-also-ensureDefaultApparmorProfile-in-exec-pat.patch new file mode 100644 index 0000000..0e853d5 --- /dev/null +++ b/pr31773-daemon-also-ensureDefaultApparmorProfile-in-exec-pat.patch @@ -0,0 +1,59 @@ +From 790a81ea9acce318d0e037771c253951b874140b Mon Sep 17 00:00:00 2001 +From: Aleksa Sarai +Date: Mon, 13 Mar 2017 14:57:35 +1100 +Subject: [PATCH] daemon: also ensureDefaultApparmorProfile in exec path + +When 567ef8e7858c ("daemon: switch to 'ensure' workflow for AppArmor +profiles") was merged, it didn't correctly handle the exec path if +AppArmor profiles were deleted. Fix this by duplicating the +ensureDefaultApparmorProfile code in the exec code. + +Fixes: 567ef8e7858c ("daemon: switch to 'ensure' workflow for AppArmor profiles") +Signed-off-by: Aleksa Sarai +--- + daemon/exec_linux.go | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/daemon/exec_linux.go b/daemon/exec_linux.go +index 5aeedc347027..bb11c11e447c 100644 +--- a/daemon/exec_linux.go ++++ b/daemon/exec_linux.go +@@ -5,6 +5,7 @@ import ( + "github.com/docker/docker/daemon/caps" + "github.com/docker/docker/daemon/exec" + "github.com/docker/docker/libcontainerd" ++ "github.com/opencontainers/runc/libcontainer/apparmor" + "github.com/opencontainers/runtime-spec/specs-go" + ) + +@@ -23,5 +24,27 @@ func execSetPlatformOpt(c *container.Container, ec *exec.Config, p *libcontainer + if ec.Privileged { + p.Capabilities = caps.GetAllCapabilities() + } ++ if apparmor.IsEnabled() { ++ var appArmorProfile string ++ if c.AppArmorProfile != "" { ++ appArmorProfile = c.AppArmorProfile ++ } else if c.HostConfig.Privileged { ++ appArmorProfile = "unconfined" ++ } else { ++ appArmorProfile = "docker-default" ++ } ++ ++ if appArmorProfile == "docker-default" { ++ // Unattended upgrades and other fun services can unload AppArmor ++ // profiles inadvertently. Since we cannot store our profile in ++ // /etc/apparmor.d, nor can we practically add other ways of ++ // telling the system to keep our profile loaded, in order to make ++ // sure that we keep the default profile enabled we dynamically ++ // reload it if necessary. ++ if err := ensureDefaultAppArmorProfile(); err != nil { ++ return err ++ } ++ } ++ } + return nil + } +-- +2.12.0 + diff --git a/secrets-0001-daemon-allow-directory-creation-in-run-secrets.patch b/secrets-0001-daemon-allow-directory-creation-in-run-secrets.patch new file mode 100644 index 0000000..c1665a2 --- /dev/null +++ b/secrets-0001-daemon-allow-directory-creation-in-run-secrets.patch @@ -0,0 +1,39 @@ +From 0c4cf4fac76f2a5272a808665985a2e0df6af0db Mon Sep 17 00:00:00 2001 +From: Aleksa Sarai +Date: Wed, 8 Mar 2017 12:41:54 +1100 +Subject: [PATCH 1/2] daemon: allow directory creation in /run/secrets + +Since FileMode can have the directory bit set, allow a SecretStore +implementation to return secrets that are actually directories. This is +useful for creating directories and subdirectories of secrets. + +Backport: https://github.com/docker/docker/pull/31632 +Signed-off-by: Aleksa Sarai +--- + daemon/container_operations_unix.go | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_unix.go +index 2296045765d4..8527a7907373 100644 +--- a/daemon/container_operations_unix.go ++++ b/daemon/container_operations_unix.go +@@ -195,8 +195,14 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) { + if secret == nil { + return fmt.Errorf("unable to get secret from secret store") + } +- if err := ioutil.WriteFile(fPath, secret.Spec.Data, s.File.Mode); err != nil { +- return errors.Wrap(err, "error injecting secret") ++ if s.File.Mode.IsDir() { ++ if err := os.Mkdir(fPath, s.File.Mode); err != nil { ++ return errors.Wrap(err, "error injecting secret dir") ++ } ++ } else { ++ if err := ioutil.WriteFile(fPath, secret.Spec.Data, s.File.Mode); err != nil { ++ return errors.Wrap(err, "error injecting secret") ++ } + } + + uid, err := strconv.Atoi(s.File.UID) +-- +2.12.0 + diff --git a/secrets-0002-SUSE-implement-SUSE-container-secrets.patch b/secrets-0002-SUSE-implement-SUSE-container-secrets.patch new file mode 100644 index 0000000..a785381 --- /dev/null +++ b/secrets-0002-SUSE-implement-SUSE-container-secrets.patch @@ -0,0 +1,290 @@ +From a3106907d4786ed7d624201debdd43dc41fb4b97 Mon Sep 17 00:00:00 2001 +From: Aleksa Sarai +Date: Wed, 8 Mar 2017 11:43:29 +1100 +Subject: [PATCH 2/2] SUSE: implement SUSE container secrets + +This allows for us to pass in host credentials to a container, allowing +for SUSEConnect to work with containers. + +THIS PATCH IS NOT TO BE UPSTREAMED, DUE TO THE FACT THAT IT IS +SUSE-SPECIFIC, AND UPSTREAM DOES NOT APPROVE OF THIS CONCEPT BECAUSE IT +MAKES BUILDS NOT ENTIRELY REPRODUCIBLE. + +Signed-off-by: Aleksa Sarai +--- + daemon/start.go | 5 + + daemon/suse_secrets.go | 246 +++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 251 insertions(+) + create mode 100644 daemon/suse_secrets.go + +diff --git a/daemon/start.go b/daemon/start.go +index 6c94fd5482d0..3c06eed778d7 100644 +--- a/daemon/start.go ++++ b/daemon/start.go +@@ -146,6 +146,11 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint + return err + } + ++ // SUSE:secrets -- inject the SUSE secret store ++ if err := daemon.injectSuseSecretStore(container); err != nil { ++ return err ++ } ++ + spec, err := daemon.createSpec(container) + if err != nil { + return err +diff --git a/daemon/suse_secrets.go b/daemon/suse_secrets.go +new file mode 100644 +index 000000000000..591abc998e67 +--- /dev/null ++++ b/daemon/suse_secrets.go +@@ -0,0 +1,246 @@ ++/* ++ * suse-secrets: patch for Docker to implement SUSE secrets ++ * Copyright (C) 2017 SUSE LLC. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package daemon ++ ++import ( ++ "fmt" ++ "io/ioutil" ++ "os" ++ "path/filepath" ++ "syscall" ++ ++ "github.com/Sirupsen/logrus" ++ "github.com/docker/distribution/digest" ++ "github.com/docker/docker/container" ++ ++ swarmtypes "github.com/docker/docker/api/types/swarm" ++ swarmexec "github.com/docker/swarmkit/agent/exec" ++ swarmapi "github.com/docker/swarmkit/api" ++) ++ ++func init() { ++ // Output to tell us in logs that SUSE:secrets is enabled. ++ logrus.Infof("SUSE:secrets :: enabled") ++} ++ ++// Creating a fake file. ++type SuseFakeFile struct { ++ Path string ++ Uid int ++ Gid int ++ Mode os.FileMode ++ Data []byte ++} ++ ++func (s SuseFakeFile) id() string { ++ return fmt.Sprintf("suse::%s:%s", digest.FromBytes(s.Data), s.Path) ++} ++ ++func (s SuseFakeFile) toSecret() *swarmapi.Secret { ++ return &swarmapi.Secret{ ++ ID: s.id(), ++ Internal: true, ++ Spec: swarmapi.SecretSpec{ ++ Data: s.Data, ++ }, ++ } ++} ++ ++func (s SuseFakeFile) toSecretReference() *swarmtypes.SecretReference { ++ return &swarmtypes.SecretReference{ ++ SecretID: s.id(), ++ SecretName: s.id(), ++ File: &swarmtypes.SecretReferenceFileTarget{ ++ Name: s.Path, ++ UID: fmt.Sprintf("%d", s.Uid), ++ GID: fmt.Sprintf("%d", s.Gid), ++ Mode: s.Mode, ++ }, ++ } ++} ++ ++// readDir will recurse into a directory prefix/dir, and return the set of secrets ++// in that directory. The Path attribute of each has the prefix stripped. Symlinks ++// are evaluated. ++func readDir(prefix, dir string) ([]*SuseFakeFile, error) { ++ var suseFiles []*SuseFakeFile ++ ++ path := filepath.Join(prefix, dir) ++ ++ fi, err := os.Stat(path) ++ if err != nil { ++ // Ignore dangling symlinks. ++ if os.IsNotExist(err) { ++ logrus.Warnf("SUSE:secrets :: dangling symlink: %s", path) ++ return suseFiles, nil ++ } ++ return nil, err ++ } ++ ++ stat, ok := fi.Sys().(*syscall.Stat_t) ++ if !ok { ++ logrus.Warnf("SUSE:secrets :: failed to cast directory stat_t: defaulting to owned by root:root: %s", path) ++ } ++ ++ suseFiles = append(suseFiles, &SuseFakeFile{ ++ Path: dir, ++ Uid: int(stat.Uid), ++ Gid: int(stat.Gid), ++ Mode: fi.Mode(), ++ }) ++ ++ files, err := ioutil.ReadDir(path) ++ if err != nil { ++ return nil, err ++ } ++ ++ for _, f := range files { ++ subpath := filepath.Join(dir, f.Name()) ++ ++ if f.IsDir() { ++ secrets, err := readDir(prefix, subpath) ++ if err != nil { ++ return nil, err ++ } ++ suseFiles = append(suseFiles, secrets...) ++ } else { ++ secrets, err := readFile(prefix, subpath) ++ if err != nil { ++ return nil, err ++ } ++ suseFiles = append(suseFiles, secrets...) ++ } ++ } ++ ++ return suseFiles, nil ++} ++ ++// readFile returns a secret given a file under a given prefix. ++func readFile(prefix, file string) ([]*SuseFakeFile, error) { ++ var suseFiles []*SuseFakeFile ++ ++ path := filepath.Join(prefix, file) ++ fi, err := os.Stat(path) ++ if err != nil { ++ // Ignore dangling symlinks. ++ if os.IsNotExist(err) { ++ logrus.Warnf("SUSE:secrets :: dangling symlink: %s", path) ++ return suseFiles, nil ++ } ++ return nil, err ++ } ++ ++ stat, ok := fi.Sys().(*syscall.Stat_t) ++ if !ok { ++ logrus.Warnf("SUSE:secrets :: failed to cast file stat_t: defaulting to owned by root:root: %s", path) ++ } ++ ++ if fi.IsDir() { ++ secrets, err := readDir(prefix, file) ++ if err != nil { ++ return nil, err ++ } ++ suseFiles = append(suseFiles, secrets...) ++ } else { ++ bytes, err := ioutil.ReadFile(path) ++ if err != nil { ++ return nil, err ++ } ++ suseFiles = append(suseFiles, &SuseFakeFile{ ++ Path: file, ++ Uid: int(stat.Uid), ++ Gid: int(stat.Gid), ++ Mode: fi.Mode(), ++ Data: bytes, ++ }) ++ } ++ ++ return suseFiles, nil ++} ++ ++// getHostSuseSecretData returns the list of SuseFakeFiles the need to be added ++// as SUSE secrets. ++func getHostSuseSecretData() ([]*SuseFakeFile, error) { ++ secrets := []*SuseFakeFile{} ++ ++ credentials, err := readDir("/etc/zypp", "credentials.d") ++ if err != nil { ++ if os.IsNotExist(err) { ++ credentials = []*SuseFakeFile{} ++ } else { ++ logrus.Errorf("SUSE:secrets :: error while reading zypp credentials: %s", err) ++ return nil, err ++ } ++ } ++ secrets = append(secrets, credentials...) ++ ++ suseConnect, err := readFile("/etc", "SUSEConnect") ++ if err != nil { ++ if os.IsNotExist(err) { ++ suseConnect = []*SuseFakeFile{} ++ } else { ++ logrus.Errorf("SUSE:secrets :: error while reading /etc/SUSEConnect: %s", err) ++ return nil, err ++ } ++ } ++ secrets = append(secrets, suseConnect...) ++ ++ return secrets, nil ++} ++ ++// In order to reduce the amount of code touched outside of this file, we ++// implement the swarm API for SecretGetter. This asserts that this requirement ++// will always be matched. ++var _ swarmexec.SecretGetter = &suseSecretGetter{} ++ ++type suseSecretGetter struct { ++ dfl swarmexec.SecretGetter ++ secrets map[string]*swarmapi.Secret ++} ++ ++func (s *suseSecretGetter) Get(id string) *swarmapi.Secret { ++ logrus.Debugf("SUSE:secrets :: id=%s requested from suseSecretGetter", id) ++ ++ secret, ok := s.secrets[id] ++ if !ok { ++ // fallthrough ++ return s.dfl.Get(id) ++ } ++ ++ return secret ++} ++ ++func (daemon *Daemon) injectSuseSecretStore(c *container.Container) error { ++ newSecretStore := &suseSecretGetter{ ++ dfl: c.SecretStore, ++ secrets: make(map[string]*swarmapi.Secret), ++ } ++ ++ secrets, err := getHostSuseSecretData() ++ if err != nil { ++ return err ++ } ++ ++ for _, secret := range secrets { ++ newSecretStore.secrets[secret.id()] = secret.toSecret() ++ c.SecretReferences = append(c.SecretReferences, secret.toSecretReference()) ++ } ++ ++ c.SecretStore = newSecretStore ++ return nil ++} +-- +2.12.0 +