Accepting request 480841 from Virtualization:containers

1

OBS-URL: https://build.opensuse.org/request/show/480841
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/docker?expand=0&rev=52
This commit is contained in:
Dominique Leuenberger 2017-03-22 22:18:14 +00:00 committed by Git OBS Bridge
commit b61db04550
12 changed files with 539 additions and 459 deletions

View File

@ -3,8 +3,8 @@
<param name="url">https://github.com/docker/docker.git</param>
<param name="scm">git</param>
<param name="exclude">.git</param>
<param name="versionformat">1.12.6</param>
<param name="revision">v1.12.6</param>
<param name="versionformat">1.13.0</param>
<param name="revision">v1.13.0</param>
</service>
<service name="recompress" mode="disabled">
<param name="file">docker-*.tar</param>

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ade8df08afa29834e772ae9061975801ff35bd2b4c7979df4ff4df8f22ffce8c
size 11190120

3
docker-1.13.0.tar.xz Normal file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1da90f2f637d55c7bef034761f0781a7cc4facdefc50b9d77f0c6a78185efe0a
size 5130016

View File

@ -1,413 +0,0 @@
From 17cd15ba4160f0e0830453529b9b01edc308d847 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
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 <asarai@suse.de>
---
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
+}

View File

@ -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

View File

@ -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.

View File

@ -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
@ -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<version>
# 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 <<EOF
export AUTO_GOPATH=1
export DOCKER_BUILDTAGS="exclude_graphdriver_aufs apparmor selinux"
export DOCKER_BUILDTAGS="$BUILDTAGS"
export DOCKER_GITCOMMIT=%{git_version}
EOF
) > 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

View File

@ -1,18 +1,8 @@
From 0f0c0fcb5b956782385e25c7c6c625e6c79ac78f Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thipp@suse.de>
Date: Wed, 7 Sep 2016 10:54:09 +0200
Subject: [PATCH] integration-cli: fix TestInfoEnsureSucceeds
Signed-off-by: Thomas Hipp <thipp@suse.de>
---
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 {

View File

@ -0,0 +1,49 @@
From dd7159060f60ea04007c069df189a29fda2c655f Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
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 <asarai@suse.de>
---
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

View File

@ -0,0 +1,59 @@
From 790a81ea9acce318d0e037771c253951b874140b Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
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 <asarai@suse.de>
---
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

View File

@ -0,0 +1,39 @@
From 0c4cf4fac76f2a5272a808665985a2e0df6af0db Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
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 <asarai@suse.de>
---
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

View File

@ -0,0 +1,290 @@
From a3106907d4786ed7d624201debdd43dc41fb4b97 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
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 <asarai@suse.de>
---
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