docker/patch/0011-hookspec-Allow-adding-custom-hooks.patch
2019-09-30 10:37:25 -04:00

289 lines
12 KiB
Diff

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