Browse code

Merge pull request #22049 from boucher/docker-checkpoint-restore

Implement containerd API for checkpoints

Phil Estes authored on 2016/09/10 02:36:55
Showing 51 changed files
... ...
@@ -57,12 +57,17 @@ RUN apt-get update && apt-get install -y \
57 57
 	libapparmor-dev \
58 58
 	libcap-dev \
59 59
 	libltdl-dev \
60
+	libnl-3-dev \
61
+	libprotobuf-c0-dev \
62
+	libprotobuf-dev	\
60 63
 	libsqlite3-dev \
61 64
 	libsystemd-journal-dev \
62 65
 	libtool \
63 66
 	mercurial \
64 67
 	net-tools \
65 68
 	pkg-config \
69
+	protobuf-compiler \
70
+	protobuf-c-compiler \
66 71
 	python-dev \
67 72
 	python-mock \
68 73
 	python-pip \
... ...
@@ -145,6 +150,14 @@ RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint
145 145
 	&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
146 146
 	&& go install -v github.com/golang/lint/golint
147 147
 
148
+# Install CRIU for checkpoint/restore support
149
+ENV CRIU_VERSION 2.2
150
+RUN mkdir -p /usr/src/criu \
151
+	&& curl -sSL https://github.com/xemul/criu/archive/v${CRIU_VERSION}.tar.gz | tar -v -C /usr/src/criu/ -xz --strip-components=1 \
152
+	&& cd /usr/src/criu \
153
+	&& make \
154
+	&& make install-criu
155
+
148 156
 # Install two versions of the registry. The first is an older version that
149 157
 # only supports schema1 manifests. The second is a newer version that supports
150 158
 # both. This allows integration-cli tests to cover push/pull with both schema1
... ...
@@ -230,7 +243,7 @@ RUN set -x \
230 230
 	&& rm -rf "$GOPATH"
231 231
 
232 232
 # Install containerd
233
-ENV CONTAINERD_COMMIT 8508d2bec90b96403143a1104cdcbd56f6aeb361
233
+ENV CONTAINERD_COMMIT 35a736c471ccd3ebfc7b80ceeb0ee303129acd61
234 234
 RUN set -x \
235 235
 	&& export GOPATH="$(mktemp -d)" \
236 236
 	&& git clone https://github.com/docker/containerd.git "$GOPATH/src/github.com/docker/containerd" \
... ...
@@ -186,7 +186,7 @@ RUN set -x \
186 186
 	&& rm -rf "$GOPATH"
187 187
 
188 188
 # Install containerd
189
-ENV CONTAINERD_COMMIT 8508d2bec90b96403143a1104cdcbd56f6aeb361
189
+ENV CONTAINERD_COMMIT 35a736c471ccd3ebfc7b80ceeb0ee303129acd61
190 190
 RUN set -x \
191 191
 	&& export GOPATH="$(mktemp -d)" \
192 192
 	&& git clone https://github.com/docker/containerd.git "$GOPATH/src/github.com/docker/containerd" \
... ...
@@ -184,7 +184,7 @@ RUN set -x \
184 184
 	&& rm -rf "$GOPATH"
185 185
 
186 186
 # Install containerd
187
-ENV CONTAINERD_COMMIT 8508d2bec90b96403143a1104cdcbd56f6aeb361
187
+ENV CONTAINERD_COMMIT 35a736c471ccd3ebfc7b80ceeb0ee303129acd61
188 188
 RUN set -x \
189 189
 	&& export GOPATH="$(mktemp -d)" \
190 190
 	&& git clone https://github.com/docker/containerd.git "$GOPATH/src/github.com/docker/containerd" \
... ...
@@ -104,7 +104,7 @@ RUN set -x \
104 104
 	&& tar -C /usr/local -xzf golang.tar.gz \
105 105
 	&& rm golang.tar.gz \
106 106
 	&& cd go/src && ./make.bash 2>&1 \
107
-	&& rm -rf $TEMPDIR 
107
+	&& rm -rf $TEMPDIR
108 108
 
109 109
 ENV GOROOT_BOOTSTRAP /usr/local/go
110 110
 ENV PATH /usr/local/go/bin/:$PATH
... ...
@@ -204,7 +204,7 @@ RUN set -x \
204 204
 	&& rm -rf "$GOPATH"
205 205
 
206 206
 # Install containerd
207
-ENV CONTAINERD_COMMIT 8508d2bec90b96403143a1104cdcbd56f6aeb361
207
+ENV CONTAINERD_COMMIT 35a736c471ccd3ebfc7b80ceeb0ee303129acd61
208 208
 RUN set -x \
209 209
 	&& export GOPATH="$(mktemp -d)" \
210 210
 	&& git clone https://github.com/docker/containerd.git "$GOPATH/src/github.com/docker/containerd" \
... ...
@@ -196,7 +196,7 @@ RUN set -x \
196 196
 	&& rm -rf "$GOPATH"
197 197
 
198 198
 # Install containerd
199
-ENV CONTAINERD_COMMIT 8508d2bec90b96403143a1104cdcbd56f6aeb361
199
+ENV CONTAINERD_COMMIT 35a736c471ccd3ebfc7b80ceeb0ee303129acd61
200 200
 RUN set -x \
201 201
 	&& export GOPATH="$(mktemp -d)" \
202 202
 	&& git clone https://github.com/docker/containerd.git "$GOPATH/src/github.com/docker/containerd" \
... ...
@@ -68,7 +68,7 @@ RUN set -x \
68 68
 	&& rm -rf "$GOPATH"
69 69
 
70 70
 # Install containerd
71
-ENV CONTAINERD_COMMIT 8508d2bec90b96403143a1104cdcbd56f6aeb361
71
+ENV CONTAINERD_COMMIT 35a736c471ccd3ebfc7b80ceeb0ee303129acd61
72 72
 RUN set -x \
73 73
 	&& export GOPATH="$(mktemp -d)" \
74 74
 	&& git clone https://github.com/docker/containerd.git "$GOPATH/src/github.com/docker/containerd" \
75 75
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+// +build experimental
1
+
2
+package checkpoint
3
+
4
+import "github.com/docker/docker/api/types"
5
+
6
+// Backend for Checkpoint
7
+type Backend interface {
8
+	CheckpointCreate(container string, config types.CheckpointCreateOptions) error
9
+	CheckpointDelete(container string, checkpointID string) error
10
+	CheckpointList(container string) ([]types.Checkpoint, error)
11
+}
0 12
new file mode 100644
... ...
@@ -0,0 +1,28 @@
0
+package checkpoint
1
+
2
+import (
3
+	"github.com/docker/docker/api/server/httputils"
4
+	"github.com/docker/docker/api/server/router"
5
+)
6
+
7
+// checkpointRouter is a router to talk with the checkpoint controller
8
+type checkpointRouter struct {
9
+	backend Backend
10
+	decoder httputils.ContainerDecoder
11
+	routes  []router.Route
12
+}
13
+
14
+// NewRouter initializes a new checkpoint router
15
+func NewRouter(b Backend, decoder httputils.ContainerDecoder) router.Router {
16
+	r := &checkpointRouter{
17
+		backend: b,
18
+		decoder: decoder,
19
+	}
20
+	r.initRoutes()
21
+	return r
22
+}
23
+
24
+// Routes returns the available routers to the checkpoint controller
25
+func (r *checkpointRouter) Routes() []router.Route {
26
+	return r.routes
27
+}
0 28
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+// +build experimental
1
+
2
+package checkpoint
3
+
4
+import (
5
+	"github.com/docker/docker/api/server/router"
6
+)
7
+
8
+func (r *checkpointRouter) initRoutes() {
9
+	r.routes = []router.Route{
10
+		router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints),
11
+		router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint),
12
+		router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint),
13
+	}
14
+}
0 15
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+// +build !experimental
1
+
2
+package checkpoint
3
+
4
+func (r *checkpointRouter) initRoutes() {}
5
+
6
+// Backend is empty so that the package can compile in non-experimental
7
+type Backend interface{}
0 8
new file mode 100644
... ...
@@ -0,0 +1,60 @@
0
+// +build experimental
1
+
2
+package checkpoint
3
+
4
+import (
5
+	"encoding/json"
6
+	"net/http"
7
+
8
+	"github.com/docker/docker/api/server/httputils"
9
+	"github.com/docker/docker/api/types"
10
+	"golang.org/x/net/context"
11
+)
12
+
13
+func (s *checkpointRouter) postContainerCheckpoint(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
14
+	if err := httputils.ParseForm(r); err != nil {
15
+		return err
16
+	}
17
+
18
+	var options types.CheckpointCreateOptions
19
+
20
+	decoder := json.NewDecoder(r.Body)
21
+	if err := decoder.Decode(&options); err != nil {
22
+		return err
23
+	}
24
+
25
+	err := s.backend.CheckpointCreate(vars["name"], options)
26
+	if err != nil {
27
+		return err
28
+	}
29
+
30
+	w.WriteHeader(http.StatusNoContent)
31
+	return nil
32
+}
33
+
34
+func (s *checkpointRouter) getContainerCheckpoints(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
35
+	if err := httputils.ParseForm(r); err != nil {
36
+		return err
37
+	}
38
+
39
+	checkpoints, err := s.backend.CheckpointList(vars["name"])
40
+	if err != nil {
41
+		return err
42
+	}
43
+
44
+	return httputils.WriteJSON(w, http.StatusOK, checkpoints)
45
+}
46
+
47
+func (s *checkpointRouter) deleteContainerCheckpoint(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
48
+	if err := httputils.ParseForm(r); err != nil {
49
+		return err
50
+	}
51
+
52
+	err := s.backend.CheckpointDelete(vars["name"], vars["checkpoint"])
53
+	if err != nil {
54
+		return err
55
+	}
56
+
57
+	w.WriteHeader(http.StatusNoContent)
58
+	return nil
59
+}
... ...
@@ -39,7 +39,7 @@ type stateBackend interface {
39 39
 	ContainerResize(name string, height, width int) error
40 40
 	ContainerRestart(name string, seconds int) error
41 41
 	ContainerRm(name string, config *types.ContainerRmConfig) error
42
-	ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool) error
42
+	ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string) error
43 43
 	ContainerStop(name string, seconds int) error
44 44
 	ContainerUnpause(name string) error
45 45
 	ContainerUpdate(name string, hostConfig *container.HostConfig, validateHostname bool) (types.ContainerUpdateResponse, error)
... ...
@@ -151,10 +151,16 @@ func (s *containerRouter) postContainersStart(ctx context.Context, w http.Respon
151 151
 		hostConfig = c
152 152
 	}
153 153
 
154
+	if err := httputils.ParseForm(r); err != nil {
155
+		return err
156
+	}
157
+
158
+	checkpoint := r.Form.Get("checkpoint")
154 159
 	validateHostname := versions.GreaterThanOrEqualTo(version, "1.24")
155
-	if err := s.backend.ContainerStart(vars["name"], hostConfig, validateHostname); err != nil {
160
+	if err := s.backend.ContainerStart(vars["name"], hostConfig, validateHostname, checkpoint); err != nil {
156 161
 		return err
157 162
 	}
163
+
158 164
 	w.WriteHeader(http.StatusNoContent)
159 165
 	return nil
160 166
 }
... ...
@@ -124,12 +124,19 @@ type Backend interface {
124 124
 	// ContainerKill stops the container execution abruptly.
125 125
 	ContainerKill(containerID string, sig uint64) error
126 126
 	// ContainerStart starts a new container
127
-	ContainerStart(containerID string, hostConfig *container.HostConfig, validateHostname bool) error
127
+	ContainerStart(containerID string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string) error
128 128
 	// ContainerWait stops processing until the given container is stopped.
129 129
 	ContainerWait(containerID string, timeout time.Duration) (int, error)
130 130
 	// ContainerUpdateCmdOnBuild updates container.Path and container.Args
131 131
 	ContainerUpdateCmdOnBuild(containerID string, cmd []string) error
132 132
 
133
+	// CheckpointCreate checkpoints a running container
134
+	CheckpointCreate(container string, config types.CheckpointCreateOptions) error
135
+	// CheckpointDelete deletes a container's checkpoint
136
+	CheckpointDelete(container string, checkpoint string) error
137
+	// CheckpointList lists the available checkpoints for a container
138
+	CheckpointList(container string) ([]types.Checkpoint, error)
139
+
133 140
 	// ContainerCopy copies/extracts a source FileInfo to a destination path inside a container
134 141
 	// specified by a container object.
135 142
 	// TODO: make an Extract method instead of passing `decompress`
... ...
@@ -555,7 +555,7 @@ func (b *Builder) run(cID string) (err error) {
555 555
 		}
556 556
 	}()
557 557
 
558
-	if err := b.docker.ContainerStart(cID, nil, true); err != nil {
558
+	if err := b.docker.ContainerStart(cID, nil, true, ""); err != nil {
559 559
 		return err
560 560
 	}
561 561
 
562 562
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+// +build !experimental
1
+
2
+package checkpoint
3
+
4
+import (
5
+	"github.com/docker/docker/cli/command"
6
+	"github.com/spf13/cobra"
7
+)
8
+
9
+// NewCheckpointCommand appends the `checkpoint` subcommands to rootCmd (only in experimental)
10
+func NewCheckpointCommand(rootCmd *cobra.Command, dockerCli *command.DockerCli) {
11
+}
0 12
new file mode 100644
... ...
@@ -0,0 +1,31 @@
0
+// +build experimental
1
+
2
+package checkpoint
3
+
4
+import (
5
+	"fmt"
6
+
7
+	"github.com/spf13/cobra"
8
+
9
+	"github.com/docker/docker/cli"
10
+	"github.com/docker/docker/cli/command"
11
+)
12
+
13
+// NewCheckpointCommand appends the `checkpoint` subcommands to rootCmd
14
+func NewCheckpointCommand(rootCmd *cobra.Command, dockerCli *command.DockerCli) {
15
+	cmd := &cobra.Command{
16
+		Use:   "checkpoint",
17
+		Short: "Manage Container Checkpoints",
18
+		Args:  cli.NoArgs,
19
+		Run: func(cmd *cobra.Command, args []string) {
20
+			fmt.Fprintf(dockerCli.Err(), "\n"+cmd.UsageString())
21
+		},
22
+	}
23
+	cmd.AddCommand(
24
+		newCreateCommand(dockerCli),
25
+		newListCommand(dockerCli),
26
+		newRemoveCommand(dockerCli),
27
+	)
28
+
29
+	rootCmd.AddCommand(cmd)
30
+}
0 31
new file mode 100644
... ...
@@ -0,0 +1,54 @@
0
+// +build experimental
1
+
2
+package checkpoint
3
+
4
+import (
5
+	"golang.org/x/net/context"
6
+
7
+	"github.com/docker/docker/api/types"
8
+	"github.com/docker/docker/cli"
9
+	"github.com/docker/docker/cli/command"
10
+	"github.com/spf13/cobra"
11
+)
12
+
13
+type createOptions struct {
14
+	container    string
15
+	checkpoint   string
16
+	leaveRunning bool
17
+}
18
+
19
+func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
20
+	var opts createOptions
21
+
22
+	cmd := &cobra.Command{
23
+		Use:   "create CONTAINER CHECKPOINT",
24
+		Short: "Create a checkpoint from a running container",
25
+		Args:  cli.ExactArgs(2),
26
+		RunE: func(cmd *cobra.Command, args []string) error {
27
+			opts.container = args[0]
28
+			opts.checkpoint = args[1]
29
+			return runCreate(dockerCli, opts)
30
+		},
31
+	}
32
+
33
+	flags := cmd.Flags()
34
+	flags.BoolVar(&opts.leaveRunning, "leave-running", false, "leave the container running after checkpoint")
35
+
36
+	return cmd
37
+}
38
+
39
+func runCreate(dockerCli *command.DockerCli, opts createOptions) error {
40
+	client := dockerCli.Client()
41
+
42
+	checkpointOpts := types.CheckpointCreateOptions{
43
+		CheckpointID: opts.checkpoint,
44
+		Exit:         !opts.leaveRunning,
45
+	}
46
+
47
+	err := client.CheckpointCreate(context.Background(), opts.container, checkpointOpts)
48
+	if err != nil {
49
+		return err
50
+	}
51
+
52
+	return nil
53
+}
0 54
new file mode 100644
... ...
@@ -0,0 +1,47 @@
0
+// +build experimental
1
+
2
+package checkpoint
3
+
4
+import (
5
+	"fmt"
6
+	"text/tabwriter"
7
+
8
+	"golang.org/x/net/context"
9
+
10
+	"github.com/docker/docker/cli"
11
+	"github.com/docker/docker/cli/command"
12
+	"github.com/spf13/cobra"
13
+)
14
+
15
+func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
16
+	return &cobra.Command{
17
+		Use:     "ls CONTAINER",
18
+		Aliases: []string{"list"},
19
+		Short:   "List checkpoints for a container",
20
+		Args:    cli.ExactArgs(1),
21
+		RunE: func(cmd *cobra.Command, args []string) error {
22
+			return runList(dockerCli, args[0])
23
+		},
24
+	}
25
+}
26
+
27
+func runList(dockerCli *command.DockerCli, container string) error {
28
+	client := dockerCli.Client()
29
+
30
+	checkpoints, err := client.CheckpointList(context.Background(), container)
31
+	if err != nil {
32
+		return err
33
+	}
34
+
35
+	w := tabwriter.NewWriter(dockerCli.Out(), 20, 1, 3, ' ', 0)
36
+	fmt.Fprintf(w, "CHECKPOINT NAME")
37
+	fmt.Fprintf(w, "\n")
38
+
39
+	for _, checkpoint := range checkpoints {
40
+		fmt.Fprintf(w, "%s\t", checkpoint.Name)
41
+		fmt.Fprint(w, "\n")
42
+	}
43
+
44
+	w.Flush()
45
+	return nil
46
+}
0 47
new file mode 100644
... ...
@@ -0,0 +1,28 @@
0
+// +build experimental
1
+
2
+package checkpoint
3
+
4
+import (
5
+	"golang.org/x/net/context"
6
+
7
+	"github.com/docker/docker/cli"
8
+	"github.com/docker/docker/cli/command"
9
+	"github.com/spf13/cobra"
10
+)
11
+
12
+func newRemoveCommand(dockerCli *command.DockerCli) *cobra.Command {
13
+	return &cobra.Command{
14
+		Use:     "rm CONTAINER CHECKPOINT",
15
+		Aliases: []string{"remove"},
16
+		Short:   "Remove a checkpoint",
17
+		Args:    cli.ExactArgs(2),
18
+		RunE: func(cmd *cobra.Command, args []string) error {
19
+			return runRemove(dockerCli, args[0], args[1])
20
+		},
21
+	}
22
+}
23
+
24
+func runRemove(dockerCli *command.DockerCli, container string, checkpoint string) error {
25
+	client := dockerCli.Client()
26
+	return client.CheckpointDelete(context.Background(), container, checkpoint)
27
+}
... ...
@@ -2,6 +2,7 @@ package commands
2 2
 
3 3
 import (
4 4
 	"github.com/docker/docker/cli/command"
5
+	"github.com/docker/docker/cli/command/checkpoint"
5 6
 	"github.com/docker/docker/cli/command/container"
6 7
 	"github.com/docker/docker/cli/command/image"
7 8
 	"github.com/docker/docker/cli/command/network"
... ...
@@ -67,5 +68,6 @@ func AddCommands(cmd *cobra.Command, dockerCli *command.DockerCli) {
67 67
 		volume.NewVolumeCommand(dockerCli),
68 68
 		system.NewInfoCommand(dockerCli),
69 69
 	)
70
+	checkpoint.NewCheckpointCommand(cmd, dockerCli)
70 71
 	plugin.NewPluginCommand(cmd, dockerCli)
71 72
 }
... ...
@@ -20,6 +20,7 @@ type startOptions struct {
20 20
 	attach     bool
21 21
 	openStdin  bool
22 22
 	detachKeys string
23
+	checkpoint string
23 24
 
24 25
 	containers []string
25 26
 }
... ...
@@ -42,6 +43,9 @@ func NewStartCommand(dockerCli *command.DockerCli) *cobra.Command {
42 42
 	flags.BoolVarP(&opts.attach, "attach", "a", false, "Attach STDOUT/STDERR and forward signals")
43 43
 	flags.BoolVarP(&opts.openStdin, "interactive", "i", false, "Attach container's STDIN")
44 44
 	flags.StringVar(&opts.detachKeys, "detach-keys", "", "Override the key sequence for detaching a container")
45
+
46
+	addExperimentalStartFlags(flags, &opts)
47
+
45 48
 	return cmd
46 49
 }
47 50
 
... ...
@@ -105,9 +109,12 @@ func runStart(dockerCli *command.DockerCli, opts *startOptions) error {
105 105
 		// 3. We should open a channel for receiving status code of the container
106 106
 		// no matter it's detached, removed on daemon side(--rm) or exit normally.
107 107
 		statusChan, statusErr := waitExitOrRemoved(dockerCli, context.Background(), c.ID, c.HostConfig.AutoRemove)
108
+		startOptions := types.ContainerStartOptions{
109
+			CheckpointID: opts.checkpoint,
110
+		}
108 111
 
109 112
 		// 4. Start the container.
110
-		if err := dockerCli.Client().ContainerStart(ctx, c.ID, types.ContainerStartOptions{}); err != nil {
113
+		if err := dockerCli.Client().ContainerStart(ctx, c.ID, startOptions); err != nil {
111 114
 			cancelFun()
112 115
 			<-cErr
113 116
 			if c.HostConfig.AutoRemove && statusErr == nil {
... ...
@@ -134,6 +141,16 @@ func runStart(dockerCli *command.DockerCli, opts *startOptions) error {
134 134
 		if status := <-statusChan; status != 0 {
135 135
 			return cli.StatusError{StatusCode: status}
136 136
 		}
137
+	} else if opts.checkpoint != "" {
138
+		if len(opts.containers) > 1 {
139
+			return fmt.Errorf("You cannot restore multiple containers at once.")
140
+		}
141
+		container := opts.containers[0]
142
+		startOptions := types.ContainerStartOptions{
143
+			CheckpointID: opts.checkpoint,
144
+		}
145
+		return dockerCli.Client().ContainerStart(ctx, container, startOptions)
146
+
137 147
 	} else {
138 148
 		// We're not going to attach to anything.
139 149
 		// Start as many containers as we want.
140 150
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+// +build !experimental
1
+
2
+package container
3
+
4
+import "github.com/spf13/pflag"
5
+
6
+func addExperimentalStartFlags(flags *pflag.FlagSet, opts *startOptions) {
7
+}
0 8
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+// +build experimental
1
+
2
+package container
3
+
4
+import "github.com/spf13/pflag"
5
+
6
+func addExperimentalStartFlags(flags *pflag.FlagSet, opts *startOptions) {
7
+	flags.StringVar(&opts.checkpoint, "checkpoint", "", "Restore from this checkpoint")
8
+}
... ...
@@ -398,18 +398,23 @@ func loadDaemonCliConfig(opts daemonOptions) (*daemon.Config, error) {
398 398
 func initRouter(s *apiserver.Server, d *daemon.Daemon, c *cluster.Cluster) {
399 399
 	decoder := runconfig.ContainerDecoder{}
400 400
 
401
-	routers := []router.Router{
401
+	routers := []router.Router{}
402
+
403
+	// we need to add the checkpoint router before the container router or the DELETE gets masked
404
+	routers = addExperimentalRouters(routers, d, decoder)
405
+
406
+	routers = append(routers, []router.Router{
402 407
 		container.NewRouter(d, decoder),
403 408
 		image.NewRouter(d, decoder),
404 409
 		systemrouter.NewRouter(d, c),
405 410
 		volume.NewRouter(d),
406 411
 		build.NewRouter(dockerfile.NewBuildManager(d)),
407 412
 		swarmrouter.NewRouter(c),
408
-	}
413
+	}...)
414
+
409 415
 	if d.NetworkControllerEnabled() {
410 416
 		routers = append(routers, network.NewRouter(d, c))
411 417
 	}
412
-	routers = addExperimentalRouters(routers)
413 418
 
414 419
 	s.InitRouter(utils.IsDebugEnabled(), routers...)
415 420
 }
... ...
@@ -2,8 +2,12 @@
2 2
 
3 3
 package main
4 4
 
5
-import "github.com/docker/docker/api/server/router"
5
+import (
6
+	"github.com/docker/docker/api/server/httputils"
7
+	"github.com/docker/docker/api/server/router"
8
+	"github.com/docker/docker/daemon"
9
+)
6 10
 
7
-func addExperimentalRouters(routers []router.Router) []router.Router {
11
+func addExperimentalRouters(routers []router.Router, d *daemon.Daemon, decoder httputils.ContainerDecoder) []router.Router {
8 12
 	return routers
9 13
 }
... ...
@@ -3,11 +3,14 @@
3 3
 package main
4 4
 
5 5
 import (
6
+	"github.com/docker/docker/api/server/httputils"
6 7
 	"github.com/docker/docker/api/server/router"
8
+	checkpointrouter "github.com/docker/docker/api/server/router/checkpoint"
7 9
 	pluginrouter "github.com/docker/docker/api/server/router/plugin"
10
+	"github.com/docker/docker/daemon"
8 11
 	"github.com/docker/docker/plugin"
9 12
 )
10 13
 
11
-func addExperimentalRouters(routers []router.Router) []router.Router {
12
-	return append(routers, pluginrouter.NewRouter(plugin.GetManager()))
14
+func addExperimentalRouters(routers []router.Router, d *daemon.Daemon, decoder httputils.ContainerDecoder) []router.Router {
15
+	return append(routers, checkpointrouter.NewRouter(d, decoder), pluginrouter.NewRouter(plugin.GetManager()))
13 16
 }
... ...
@@ -306,6 +306,11 @@ func (container *Container) ConfigPath() (string, error) {
306 306
 	return container.GetRootResourcePath(configFileName)
307 307
 }
308 308
 
309
+// CheckpointDir returns the directory checkpoints are stored in
310
+func (container *Container) CheckpointDir() string {
311
+	return filepath.Join(container.Root, "checkpoints")
312
+}
313
+
309 314
 // StartLogger starts a new logger driver for the container.
310 315
 func (container *Container) StartLogger(cfg containertypes.LogConfig) (logger.Logger, error) {
311 316
 	c, err := logger.GetLogDriver(cfg.Type)
312 317
new file mode 100644
... ...
@@ -0,0 +1,82 @@
0
+package daemon
1
+
2
+import (
3
+	"encoding/json"
4
+	"fmt"
5
+	"io/ioutil"
6
+	"os"
7
+	"path/filepath"
8
+
9
+	"github.com/docker/docker/api/types"
10
+)
11
+
12
+// CheckpointCreate checkpoints the process running in a container with CRIU
13
+func (daemon *Daemon) CheckpointCreate(name string, config types.CheckpointCreateOptions) error {
14
+	container, err := daemon.GetContainer(name)
15
+	if err != nil {
16
+		return err
17
+	}
18
+
19
+	if !container.IsRunning() {
20
+		return fmt.Errorf("Container %s not running", name)
21
+	}
22
+
23
+	err = daemon.containerd.CreateCheckpoint(container.ID, config.CheckpointID, container.CheckpointDir(), config.Exit)
24
+	if err != nil {
25
+		return fmt.Errorf("Cannot checkpoint container %s: %s", name, err)
26
+	}
27
+
28
+	daemon.LogContainerEvent(container, "checkpoint")
29
+
30
+	return nil
31
+}
32
+
33
+// CheckpointDelete deletes the specified checkpoint
34
+func (daemon *Daemon) CheckpointDelete(name string, checkpoint string) error {
35
+	container, err := daemon.GetContainer(name)
36
+	if err != nil {
37
+		return err
38
+	}
39
+
40
+	checkpointDir := container.CheckpointDir()
41
+	return os.RemoveAll(filepath.Join(checkpointDir, checkpoint))
42
+}
43
+
44
+// CheckpointList deletes the specified checkpoint
45
+func (daemon *Daemon) CheckpointList(name string) ([]types.Checkpoint, error) {
46
+	response := []types.Checkpoint{}
47
+
48
+	container, err := daemon.GetContainer(name)
49
+	if err != nil {
50
+		return response, err
51
+	}
52
+
53
+	checkpointDir := container.CheckpointDir()
54
+	if err := os.MkdirAll(checkpointDir, 0755); err != nil {
55
+		return nil, err
56
+	}
57
+
58
+	dirs, err := ioutil.ReadDir(checkpointDir)
59
+	if err != nil {
60
+		return nil, err
61
+	}
62
+
63
+	var out []types.Checkpoint
64
+	for _, d := range dirs {
65
+		if !d.IsDir() {
66
+			continue
67
+		}
68
+		path := filepath.Join(checkpointDir, d.Name(), "config.json")
69
+		data, err := ioutil.ReadFile(path)
70
+		if err != nil {
71
+			return nil, err
72
+		}
73
+		var cpt types.Checkpoint
74
+		if err := json.Unmarshal(data, &cpt); err != nil {
75
+			return nil, err
76
+		}
77
+		out = append(out, cpt)
78
+	}
79
+
80
+	return out, nil
81
+}
... ...
@@ -24,7 +24,7 @@ type Backend interface {
24 24
 	SetupIngress(req clustertypes.NetworkCreateRequest, nodeIP string) error
25 25
 	PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
26 26
 	CreateManagedContainer(config types.ContainerCreateConfig, validateHostname bool) (types.ContainerCreateResponse, error)
27
-	ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool) error
27
+	ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string) error
28 28
 	ContainerStop(name string, seconds int) error
29 29
 	ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
30 30
 	UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error
... ...
@@ -220,7 +220,7 @@ func (c *containerAdapter) create(ctx context.Context) error {
220 220
 func (c *containerAdapter) start(ctx context.Context) error {
221 221
 	version := httputils.VersionFromContext(ctx)
222 222
 	validateHostname := versions.GreaterThanOrEqualTo(version, "1.24")
223
-	return c.backend.ContainerStart(c.container.name(), nil, validateHostname)
223
+	return c.backend.ContainerStart(c.container.name(), nil, validateHostname, "")
224 224
 }
225 225
 
226 226
 func (c *containerAdapter) inspect(ctx context.Context) (types.ContainerJSON, error) {
... ...
@@ -115,6 +115,9 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
115 115
 	if err := idtools.MkdirAs(container.Root, 0700, rootUID, rootGID); err != nil {
116 116
 		return nil, err
117 117
 	}
118
+	if err := idtools.MkdirAs(container.CheckpointDir(), 0700, rootUID, rootGID); err != nil {
119
+		return nil, err
120
+	}
118 121
 
119 122
 	if err := daemon.setHostConfig(container, params.HostConfig); err != nil {
120 123
 		return nil, err
... ...
@@ -287,7 +287,7 @@ func (daemon *Daemon) restore() error {
287 287
 
288 288
 			// Make sure networks are available before starting
289 289
 			daemon.waitForNetworks(c)
290
-			if err := daemon.containerStart(c); err != nil {
290
+			if err := daemon.containerStart(c, ""); err != nil {
291 291
 				logrus.Errorf("Failed to start container %s: %s", c.ID, err)
292 292
 			}
293 293
 			close(chNotify)
... ...
@@ -28,7 +28,7 @@ func (daemon *Daemon) postRunProcessing(container *container.Container, e libcon
28 28
 
29 29
 		// Create a new servicing container, which will start, complete the update, and merge back the
30 30
 		// results if it succeeded, all as part of the below function call.
31
-		if err := daemon.containerd.Create((container.ID + "_servicing"), *spec, servicingOption); err != nil {
31
+		if err := daemon.containerd.Create((container.ID + "_servicing"), "", "", *spec, servicingOption); err != nil {
32 32
 			container.SetExitCode(-1)
33 33
 			return fmt.Errorf("Post-run update servicing failed: %s", err)
34 34
 		}
... ...
@@ -56,7 +56,7 @@ func (daemon *Daemon) containerRestart(container *container.Container, seconds i
56 56
 		}
57 57
 	}
58 58
 
59
-	if err := daemon.containerStart(container); err != nil {
59
+	if err := daemon.containerStart(container, ""); err != nil {
60 60
 		return err
61 61
 	}
62 62
 
... ...
@@ -19,7 +19,7 @@ import (
19 19
 )
20 20
 
21 21
 // ContainerStart starts a container.
22
-func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig, validateHostname bool) error {
22
+func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig, validateHostname bool, checkpoint string) error {
23 23
 	container, err := daemon.GetContainer(name)
24 24
 	if err != nil {
25 25
 		return err
... ...
@@ -78,19 +78,19 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos
78 78
 		return err
79 79
 	}
80 80
 
81
-	return daemon.containerStart(container)
81
+	return daemon.containerStart(container, checkpoint)
82 82
 }
83 83
 
84 84
 // Start starts a container
85 85
 func (daemon *Daemon) Start(container *container.Container) error {
86
-	return daemon.containerStart(container)
86
+	return daemon.containerStart(container, "")
87 87
 }
88 88
 
89 89
 // containerStart prepares the container to run by setting up everything the
90 90
 // container needs, such as storage and networking, as well as links
91 91
 // between containers. The container is left waiting for a signal to
92 92
 // begin running.
93
-func (daemon *Daemon) containerStart(container *container.Container) (err error) {
93
+func (daemon *Daemon) containerStart(container *container.Container, checkpoint string) (err error) {
94 94
 	container.Lock()
95 95
 	defer container.Unlock()
96 96
 
... ...
@@ -150,7 +150,7 @@ func (daemon *Daemon) containerStart(container *container.Container) (err error)
150 150
 		createOptions = append(createOptions, *copts...)
151 151
 	}
152 152
 
153
-	if err := daemon.containerd.Create(container.ID, *spec, createOptions...); err != nil {
153
+	if err := daemon.containerd.Create(container.ID, checkpoint, container.CheckpointDir(), *spec, createOptions...); err != nil {
154 154
 		errDesc := grpc.ErrorDesc(err)
155 155
 		logrus.Errorf("Create container failed with error: %s", errDesc)
156 156
 		// if we receive an internal error from the initial start of a container then lets
... ...
@@ -2,7 +2,7 @@
2 2
 
3 3
 This page contains a list of features in the Docker engine which are
4 4
 experimental. Experimental features are **not** ready for production. They are
5
-provided for test and evaluation in your sandbox environments.  
5
+provided for test and evaluation in your sandbox environments.
6 6
 
7 7
 The information below describes each feature and the GitHub pull requests and
8 8
 issues associated with it. If necessary, links are provided to additional
... ...
@@ -74,9 +74,10 @@ to build a Docker binary with the experimental features enabled:
74 74
  * [External graphdriver plugins](plugins_graphdriver.md)
75 75
  * [Macvlan and Ipvlan Network Drivers](vlan-networks.md)
76 76
  * [Docker Stacks and Distributed Application Bundles](docker-stacks-and-bundles.md)
77
+ * [Checkpoint & Restore](checkpoint-restore.md)
77 78
 
78 79
 ## How to comment on an experimental feature
79 80
 
80
-Each feature's documentation includes a list of proposal pull requests or PRs associated with the feature. If you want to comment on or suggest a change to a feature, please add it to the existing feature PR.  
81
+Each feature's documentation includes a list of proposal pull requests or PRs associated with the feature. If you want to comment on or suggest a change to a feature, please add it to the existing feature PR.
81 82
 
82
-Issues or problems with a feature? Inquire for help on the `#docker` IRC channel or in on the [Docker Google group](https://groups.google.com/forum/#!forum/docker-user).  
83
+Issues or problems with a feature? Inquire for help on the `#docker` IRC channel or in on the [Docker Google group](https://groups.google.com/forum/#!forum/docker-user).
83 84
new file mode 100644
... ...
@@ -0,0 +1,75 @@
0
+# Docker Checkpoint & Restore
1
+
2
+Checkpoint & Restore is a new feature that allows you to freeze a running
3
+container by checkpointing it, which turns its state into a collection of files
4
+on disk. Later, the container can be restored from the point it was frozen.
5
+
6
+This is accomplished using a tool called [CRIU](http://criu.org), which is an
7
+external dependency of this feature. A good overview of the history of
8
+checkpoint and restore in Docker is available in this
9
+[Kubernetes blog post](http://blog.kubernetes.io/2015/07/how-did-quake-demo-from-dockercon-work.html).
10
+
11
+## Installing CRIU
12
+
13
+If you use a Debian system, you can add the CRIU PPA and install with apt-get
14
+[from the criu launchpad](https://launchpad.net/~criu/+archive/ubuntu/ppa).
15
+
16
+Alternatively, you can [build CRIU from source](http://criu.org/Installation).
17
+
18
+You need at least version 2.0 of CRIU to run checkpoint/restore in Docker.
19
+
20
+## Use cases for checkpoint & restore
21
+
22
+This feature is currently focused on single-host use cases for checkpoint and
23
+restore. Here are a few:
24
+
25
+- Restarting the host machine without stopping/starting containers
26
+- Speeding up the start time of slow start applications
27
+- "Rewinding" processes to an earlier point in time
28
+- "Forensic debugging" of running processes
29
+
30
+Another primary use case of checkpoint & restore outside of Docker is the live
31
+migration of a server from one machine to another. This is possible with the
32
+current implementation, but not currently a priority (and so the workflow is
33
+not optimized for the task).
34
+
35
+## Using Checkpoint & Restore
36
+
37
+A new top level commands `docker checkpoint` is introduced, with three subcommands:
38
+- `create` (creates a new checkpoint)
39
+- `ls` (lists existing checkpoints)
40
+- `rm` (deletes an existing checkpoint)
41
+
42
+Additionally, a `--checkpoint` flag is added to the container start command.
43
+
44
+The options for checkpoint create:
45
+
46
+    Usage:  docker checkpoint [OPTIONS] CONTAINER CHECKPOINT_ID
47
+
48
+    Checkpoint the specified container
49
+
50
+      --leave-running=false    leave the container running after checkpoint
51
+
52
+And to restore a container:
53
+
54
+    Usage:  docker start --checkpoint CHECKPOINT_ID [OTHER OPTIONS] CONTAINER
55
+
56
+
57
+A simple example of using checkpoint & restore on a container:
58
+
59
+    $ docker run --security-opt=seccomp:unconfined --name cr -d busybox /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done'
60
+    > abc0123
61
+
62
+    $ docker checkpoint create cr checkpoint1
63
+
64
+    # <later>
65
+    $ docker start --checkpoint checkpoint1 cr
66
+    > abc0123
67
+
68
+This process just logs an incrementing counter to stdout. If you `docker logs`
69
+in between running/checkpoint/restoring you should see that the counter
70
+increases while the process is running, stops while it's checkpointed, and
71
+resumes from the point it left off once you restore.
72
+
73
+Note that seccomp is only supported by CRIU in very up to date kernels.
74
+
... ...
@@ -141,7 +141,7 @@ clone git google.golang.org/cloud dae7e3d993bc3812a2185af60552bb6b847e52a0 https
141 141
 clone git github.com/docker/docker-credential-helpers v0.3.0
142 142
 
143 143
 # containerd
144
-clone git github.com/docker/containerd 8508d2bec90b96403143a1104cdcbd56f6aeb361
144
+clone git github.com/docker/containerd 35a736c471ccd3ebfc7b80ceeb0ee303129acd61
145 145
 
146 146
 # cluster
147 147
 clone git github.com/docker/swarmkit 27fbaef4ceed648bb575969ccc9083a6e104a719
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"github.com/docker/docker/pkg/homedir"
11 11
 	"github.com/docker/docker/pkg/integration/checker"
12 12
 	icmd "github.com/docker/docker/pkg/integration/cmd"
13
+	"github.com/docker/docker/utils"
13 14
 	"github.com/go-check/check"
14 15
 )
15 16
 
... ...
@@ -122,6 +123,12 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
122 122
 		cmdsToTest = append(cmdsToTest, "network ls")
123 123
 		cmdsToTest = append(cmdsToTest, "network rm")
124 124
 
125
+		if utils.ExperimentalBuild() {
126
+			cmdsToTest = append(cmdsToTest, "checkpoint create")
127
+			cmdsToTest = append(cmdsToTest, "checkpoint ls")
128
+			cmdsToTest = append(cmdsToTest, "checkpoint rm")
129
+		}
130
+
125 131
 		// Divide the list of commands into go routines and  run the func testcommand on the commands in parallel
126 132
 		// to save runtime of test
127 133
 
... ...
@@ -133,7 +133,7 @@ func (clnt *client) prepareBundleDir(uid, gid int) (string, error) {
133 133
 	return p, nil
134 134
 }
135 135
 
136
-func (clnt *client) Create(containerID string, spec Spec, options ...CreateOption) (err error) {
136
+func (clnt *client) Create(containerID string, checkpoint string, checkpointDir string, spec Spec, options ...CreateOption) (err error) {
137 137
 	clnt.lock(containerID)
138 138
 	defer clnt.unlock(containerID)
139 139
 
... ...
@@ -180,7 +180,7 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio
180 180
 		return err
181 181
 	}
182 182
 
183
-	return container.start()
183
+	return container.start(checkpoint, checkpointDir)
184 184
 }
185 185
 
186 186
 func (clnt *client) Signal(containerID string, sig int) error {
... ...
@@ -625,3 +625,57 @@ func (en *exitNotifier) close() {
625 625
 func (en *exitNotifier) wait() <-chan struct{} {
626 626
 	return en.c
627 627
 }
628
+
629
+func (clnt *client) CreateCheckpoint(containerID string, checkpointID string, checkpointDir string, exit bool) error {
630
+	clnt.lock(containerID)
631
+	defer clnt.unlock(containerID)
632
+	if _, err := clnt.getContainer(containerID); err != nil {
633
+		return err
634
+	}
635
+
636
+	_, err := clnt.remote.apiClient.CreateCheckpoint(context.Background(), &containerd.CreateCheckpointRequest{
637
+		Id: containerID,
638
+		Checkpoint: &containerd.Checkpoint{
639
+			Name:        checkpointID,
640
+			Exit:        exit,
641
+			Tcp:         true,
642
+			UnixSockets: true,
643
+			Shell:       false,
644
+			EmptyNS:     []string{"network"},
645
+		},
646
+		CheckpointDir: checkpointDir,
647
+	})
648
+	return err
649
+}
650
+
651
+func (clnt *client) DeleteCheckpoint(containerID string, checkpointID string, checkpointDir string) error {
652
+	clnt.lock(containerID)
653
+	defer clnt.unlock(containerID)
654
+	if _, err := clnt.getContainer(containerID); err != nil {
655
+		return err
656
+	}
657
+
658
+	_, err := clnt.remote.apiClient.DeleteCheckpoint(context.Background(), &containerd.DeleteCheckpointRequest{
659
+		Id:            containerID,
660
+		Name:          checkpointID,
661
+		CheckpointDir: checkpointDir,
662
+	})
663
+	return err
664
+}
665
+
666
+func (clnt *client) ListCheckpoints(containerID string, checkpointDir string) (*Checkpoints, error) {
667
+	clnt.lock(containerID)
668
+	defer clnt.unlock(containerID)
669
+	if _, err := clnt.getContainer(containerID); err != nil {
670
+		return nil, err
671
+	}
672
+
673
+	resp, err := clnt.remote.apiClient.ListCheckpoint(context.Background(), &containerd.ListCheckpointRequest{
674
+		Id:            containerID,
675
+		CheckpointDir: checkpointDir,
676
+	})
677
+	if err != nil {
678
+		return nil, err
679
+	}
680
+	return (*Checkpoints)(resp), nil
681
+}
... ...
@@ -12,7 +12,7 @@ func (clnt *client) AddProcess(ctx context.Context, containerID, processFriendly
12 12
 	return nil
13 13
 }
14 14
 
15
-func (clnt *client) Create(containerID string, spec Spec, options ...CreateOption) (err error) {
15
+func (clnt *client) Create(containerID string, checkpoint string, checkpointDir string, spec Spec, options ...CreateOption) (err error) {
16 16
 	return nil
17 17
 }
18 18
 
... ...
@@ -37,7 +37,7 @@ const defaultOwner = "docker"
37 37
 
38 38
 // Create is the entrypoint to create a container from a spec, and if successfully
39 39
 // created, start it too.
40
-func (clnt *client) Create(containerID string, spec Spec, options ...CreateOption) error {
40
+func (clnt *client) Create(containerID string, checkpoint string, checkpointDir string, spec Spec, options ...CreateOption) error {
41 41
 	logrus.Debugln("libcontainerd: client.Create() with spec", spec)
42 42
 
43 43
 	configuration := &hcsshim.ContainerConfig{
... ...
@@ -435,3 +435,15 @@ func (clnt *client) UpdateResources(containerID string, resources Resources) err
435 435
 	// but we should return nil for enabling updating container
436 436
 	return nil
437 437
 }
438
+
439
+func (clnt *client) CreateCheckpoint(containerID string, checkpointID string, checkpointDir string, exit bool) error {
440
+	return errors.New("Windows: Containers do not support checkpoints")
441
+}
442
+
443
+func (clnt *client) DeleteCheckpoint(containerID string, checkpointID string, checkpointDir string) error {
444
+	return errors.New("Windows: Containers do not support checkpoints")
445
+}
446
+
447
+func (clnt *client) ListCheckpoints(containerID string, checkpointDir string) (*Checkpoints, error) {
448
+	return nil, errors.New("Windows: Containers do not support checkpoints")
449
+}
... ...
@@ -86,7 +86,7 @@ func (ctr *container) spec() (*specs.Spec, error) {
86 86
 	return &spec, nil
87 87
 }
88 88
 
89
-func (ctr *container) start() error {
89
+func (ctr *container) start(checkpoint string, checkpointDir string) error {
90 90
 	spec, err := ctr.spec()
91 91
 	if err != nil {
92 92
 		return nil
... ...
@@ -97,11 +97,13 @@ func (ctr *container) start() error {
97 97
 	}
98 98
 
99 99
 	r := &containerd.CreateContainerRequest{
100
-		Id:         ctr.containerID,
101
-		BundlePath: ctr.dir,
102
-		Stdin:      ctr.fifo(syscall.Stdin),
103
-		Stdout:     ctr.fifo(syscall.Stdout),
104
-		Stderr:     ctr.fifo(syscall.Stderr),
100
+		Id:            ctr.containerID,
101
+		BundlePath:    ctr.dir,
102
+		Stdin:         ctr.fifo(syscall.Stdin),
103
+		Stdout:        ctr.fifo(syscall.Stdout),
104
+		Stderr:        ctr.fifo(syscall.Stderr),
105
+		Checkpoint:    checkpoint,
106
+		CheckpointDir: checkpointDir,
105 107
 		// check to see if we are running in ramdisk to disable pivot root
106 108
 		NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "",
107 109
 		Runtime:     ctr.runtime,
... ...
@@ -191,7 +193,7 @@ func (ctr *container) handleEvent(e *containerd.Event) error {
191 191
 					defer ctr.client.unlock(ctr.containerID)
192 192
 					ctr.restarting = false
193 193
 					if err == nil {
194
-						if err = ctr.start(); err != nil {
194
+						if err = ctr.start("", ""); err != nil {
195 195
 							logrus.Errorf("libcontainerd: error restarting %v", err)
196 196
 						}
197 197
 					}
... ...
@@ -261,7 +261,7 @@ func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) err
261 261
 			ctr.restarting = false
262 262
 			ctr.client.deleteContainer(ctr.friendlyName)
263 263
 			if err == nil {
264
-				if err = ctr.client.Create(ctr.containerID, ctr.ociSpec, ctr.options...); err != nil {
264
+				if err = ctr.client.Create(ctr.containerID, "", "", ctr.ociSpec, ctr.options...); err != nil {
265 265
 					logrus.Errorf("libcontainerd: error restarting %v", err)
266 266
 				}
267 267
 			}
... ...
@@ -36,7 +36,7 @@ type Backend interface {
36 36
 
37 37
 // Client provides access to containerd features.
38 38
 type Client interface {
39
-	Create(containerID string, spec Spec, options ...CreateOption) error
39
+	Create(containerID string, checkpoint string, checkpointDir string, spec Spec, options ...CreateOption) error
40 40
 	Signal(containerID string, sig int) error
41 41
 	SignalProcess(containerID string, processFriendlyName string, sig int) error
42 42
 	AddProcess(ctx context.Context, containerID, processFriendlyName string, process Process) error
... ...
@@ -48,6 +48,9 @@ type Client interface {
48 48
 	GetPidsForContainer(containerID string) ([]int, error)
49 49
 	Summary(containerID string) ([]Summary, error)
50 50
 	UpdateResources(containerID string, resources Resources) error
51
+	CreateCheckpoint(containerID string, checkpointID string, checkpointDir string, exit bool) error
52
+	DeleteCheckpoint(containerID string, checkpointID string, checkpointDir string) error
53
+	ListCheckpoints(containerID string, checkpointDir string) (*Checkpoints, error)
51 54
 }
52 55
 
53 56
 // CreateOption allows to configure parameters of container creation.
... ...
@@ -53,3 +53,6 @@ type User specs.User
53 53
 
54 54
 // Resources defines updatable container resource values.
55 55
 type Resources containerd.UpdateResource
56
+
57
+// Checkpoints contains the details of a checkpoint
58
+type Checkpoints containerd.ListCheckpointResponse
... ...
@@ -37,3 +37,13 @@ type Resources struct{}
37 37
 type ServicingOption struct {
38 38
 	IsServicing bool
39 39
 }
40
+
41
+// Checkpoint holds the details of a checkpoint (not supported in windows)
42
+type Checkpoint struct {
43
+	Name string
44
+}
45
+
46
+// Checkpoints contains the details of a checkpoint
47
+type Checkpoints struct {
48
+	Checkpoints []*Checkpoint
49
+}
... ...
@@ -27,7 +27,7 @@ func (pm *Manager) enable(p *v2.Plugin, force bool) error {
27 27
 	}
28 28
 
29 29
 	p.RestartManager = restartmanager.New(container.RestartPolicy{Name: "always"}, 0)
30
-	if err := pm.containerdClient.Create(p.GetID(), libcontainerd.Spec(*spec), libcontainerd.WithRestartManager(p.RestartManager)); err != nil {
30
+	if err := pm.containerdClient.Create(p.GetID(), "", "", libcontainerd.Spec(*spec), libcontainerd.WithRestartManager(p.RestartManager)); err != nil {
31 31
 		if err := p.RestartManager.Cancel(); err != nil {
32 32
 			logrus.Errorf("enable: restartManager.Cancel failed due to %v", err)
33 33
 		}
... ...
@@ -36,6 +36,9 @@ It has these top-level messages:
36 36
 	StateResponse
37 37
 	UpdateContainerRequest
38 38
 	UpdateResource
39
+	BlockIODevice
40
+	WeightDevice
41
+	ThrottleDevice
39 42
 	UpdateContainerResponse
40 43
 	EventsRequest
41 44
 	Event
... ...
@@ -454,17 +457,23 @@ func (m *UpdateContainerRequest) GetResources() *UpdateResource {
454 454
 }
455 455
 
456 456
 type UpdateResource struct {
457
-	BlkioWeight          uint64 `protobuf:"varint,1,opt,name=blkioWeight" json:"blkioWeight,omitempty"`
458
-	CpuShares            uint64 `protobuf:"varint,2,opt,name=cpuShares" json:"cpuShares,omitempty"`
459
-	CpuPeriod            uint64 `protobuf:"varint,3,opt,name=cpuPeriod" json:"cpuPeriod,omitempty"`
460
-	CpuQuota             uint64 `protobuf:"varint,4,opt,name=cpuQuota" json:"cpuQuota,omitempty"`
461
-	CpusetCpus           string `protobuf:"bytes,5,opt,name=cpusetCpus" json:"cpusetCpus,omitempty"`
462
-	CpusetMems           string `protobuf:"bytes,6,opt,name=cpusetMems" json:"cpusetMems,omitempty"`
463
-	MemoryLimit          uint64 `protobuf:"varint,7,opt,name=memoryLimit" json:"memoryLimit,omitempty"`
464
-	MemorySwap           uint64 `protobuf:"varint,8,opt,name=memorySwap" json:"memorySwap,omitempty"`
465
-	MemoryReservation    uint64 `protobuf:"varint,9,opt,name=memoryReservation" json:"memoryReservation,omitempty"`
466
-	KernelMemoryLimit    uint64 `protobuf:"varint,10,opt,name=kernelMemoryLimit" json:"kernelMemoryLimit,omitempty"`
467
-	KernelTCPMemoryLimit uint64 `protobuf:"varint,11,opt,name=kernelTCPMemoryLimit" json:"kernelTCPMemoryLimit,omitempty"`
457
+	BlkioWeight                  uint64            `protobuf:"varint,1,opt,name=blkioWeight" json:"blkioWeight,omitempty"`
458
+	CpuShares                    uint64            `protobuf:"varint,2,opt,name=cpuShares" json:"cpuShares,omitempty"`
459
+	CpuPeriod                    uint64            `protobuf:"varint,3,opt,name=cpuPeriod" json:"cpuPeriod,omitempty"`
460
+	CpuQuota                     uint64            `protobuf:"varint,4,opt,name=cpuQuota" json:"cpuQuota,omitempty"`
461
+	CpusetCpus                   string            `protobuf:"bytes,5,opt,name=cpusetCpus" json:"cpusetCpus,omitempty"`
462
+	CpusetMems                   string            `protobuf:"bytes,6,opt,name=cpusetMems" json:"cpusetMems,omitempty"`
463
+	MemoryLimit                  uint64            `protobuf:"varint,7,opt,name=memoryLimit" json:"memoryLimit,omitempty"`
464
+	MemorySwap                   uint64            `protobuf:"varint,8,opt,name=memorySwap" json:"memorySwap,omitempty"`
465
+	MemoryReservation            uint64            `protobuf:"varint,9,opt,name=memoryReservation" json:"memoryReservation,omitempty"`
466
+	KernelMemoryLimit            uint64            `protobuf:"varint,10,opt,name=kernelMemoryLimit" json:"kernelMemoryLimit,omitempty"`
467
+	KernelTCPMemoryLimit         uint64            `protobuf:"varint,11,opt,name=kernelTCPMemoryLimit" json:"kernelTCPMemoryLimit,omitempty"`
468
+	BlkioLeafWeight              uint64            `protobuf:"varint,12,opt,name=blkioLeafWeight" json:"blkioLeafWeight,omitempty"`
469
+	BlkioWeightDevice            []*WeightDevice   `protobuf:"bytes,13,rep,name=blkioWeightDevice" json:"blkioWeightDevice,omitempty"`
470
+	BlkioThrottleReadBpsDevice   []*ThrottleDevice `protobuf:"bytes,14,rep,name=blkioThrottleReadBpsDevice" json:"blkioThrottleReadBpsDevice,omitempty"`
471
+	BlkioThrottleWriteBpsDevice  []*ThrottleDevice `protobuf:"bytes,15,rep,name=blkioThrottleWriteBpsDevice" json:"blkioThrottleWriteBpsDevice,omitempty"`
472
+	BlkioThrottleReadIopsDevice  []*ThrottleDevice `protobuf:"bytes,16,rep,name=blkioThrottleReadIopsDevice" json:"blkioThrottleReadIopsDevice,omitempty"`
473
+	BlkioThrottleWriteIopsDevice []*ThrottleDevice `protobuf:"bytes,17,rep,name=blkioThrottleWriteIopsDevice" json:"blkioThrottleWriteIopsDevice,omitempty"`
468 474
 }
469 475
 
470 476
 func (m *UpdateResource) Reset()                    { *m = UpdateResource{} }
... ...
@@ -472,13 +481,93 @@ func (m *UpdateResource) String() string            { return proto.CompactTextSt
472 472
 func (*UpdateResource) ProtoMessage()               {}
473 473
 func (*UpdateResource) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{26} }
474 474
 
475
+func (m *UpdateResource) GetBlkioWeightDevice() []*WeightDevice {
476
+	if m != nil {
477
+		return m.BlkioWeightDevice
478
+	}
479
+	return nil
480
+}
481
+
482
+func (m *UpdateResource) GetBlkioThrottleReadBpsDevice() []*ThrottleDevice {
483
+	if m != nil {
484
+		return m.BlkioThrottleReadBpsDevice
485
+	}
486
+	return nil
487
+}
488
+
489
+func (m *UpdateResource) GetBlkioThrottleWriteBpsDevice() []*ThrottleDevice {
490
+	if m != nil {
491
+		return m.BlkioThrottleWriteBpsDevice
492
+	}
493
+	return nil
494
+}
495
+
496
+func (m *UpdateResource) GetBlkioThrottleReadIopsDevice() []*ThrottleDevice {
497
+	if m != nil {
498
+		return m.BlkioThrottleReadIopsDevice
499
+	}
500
+	return nil
501
+}
502
+
503
+func (m *UpdateResource) GetBlkioThrottleWriteIopsDevice() []*ThrottleDevice {
504
+	if m != nil {
505
+		return m.BlkioThrottleWriteIopsDevice
506
+	}
507
+	return nil
508
+}
509
+
510
+type BlockIODevice struct {
511
+	Major int64 `protobuf:"varint,1,opt,name=major" json:"major,omitempty"`
512
+	Minor int64 `protobuf:"varint,2,opt,name=minor" json:"minor,omitempty"`
513
+}
514
+
515
+func (m *BlockIODevice) Reset()                    { *m = BlockIODevice{} }
516
+func (m *BlockIODevice) String() string            { return proto.CompactTextString(m) }
517
+func (*BlockIODevice) ProtoMessage()               {}
518
+func (*BlockIODevice) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{27} }
519
+
520
+type WeightDevice struct {
521
+	BlkIODevice *BlockIODevice `protobuf:"bytes,1,opt,name=blkIODevice" json:"blkIODevice,omitempty"`
522
+	Weight      uint32         `protobuf:"varint,2,opt,name=weight" json:"weight,omitempty"`
523
+	LeafWeight  uint32         `protobuf:"varint,3,opt,name=leafWeight" json:"leafWeight,omitempty"`
524
+}
525
+
526
+func (m *WeightDevice) Reset()                    { *m = WeightDevice{} }
527
+func (m *WeightDevice) String() string            { return proto.CompactTextString(m) }
528
+func (*WeightDevice) ProtoMessage()               {}
529
+func (*WeightDevice) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{28} }
530
+
531
+func (m *WeightDevice) GetBlkIODevice() *BlockIODevice {
532
+	if m != nil {
533
+		return m.BlkIODevice
534
+	}
535
+	return nil
536
+}
537
+
538
+type ThrottleDevice struct {
539
+	BlkIODevice *BlockIODevice `protobuf:"bytes,1,opt,name=blkIODevice" json:"blkIODevice,omitempty"`
540
+	Rate        uint64         `protobuf:"varint,2,opt,name=rate" json:"rate,omitempty"`
541
+}
542
+
543
+func (m *ThrottleDevice) Reset()                    { *m = ThrottleDevice{} }
544
+func (m *ThrottleDevice) String() string            { return proto.CompactTextString(m) }
545
+func (*ThrottleDevice) ProtoMessage()               {}
546
+func (*ThrottleDevice) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29} }
547
+
548
+func (m *ThrottleDevice) GetBlkIODevice() *BlockIODevice {
549
+	if m != nil {
550
+		return m.BlkIODevice
551
+	}
552
+	return nil
553
+}
554
+
475 555
 type UpdateContainerResponse struct {
476 556
 }
477 557
 
478 558
 func (m *UpdateContainerResponse) Reset()                    { *m = UpdateContainerResponse{} }
479 559
 func (m *UpdateContainerResponse) String() string            { return proto.CompactTextString(m) }
480 560
 func (*UpdateContainerResponse) ProtoMessage()               {}
481
-func (*UpdateContainerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{27} }
561
+func (*UpdateContainerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{30} }
482 562
 
483 563
 type EventsRequest struct {
484 564
 	// Tag 1 is deprecated (old uint64 timestamp)
... ...
@@ -490,7 +579,7 @@ type EventsRequest struct {
490 490
 func (m *EventsRequest) Reset()                    { *m = EventsRequest{} }
491 491
 func (m *EventsRequest) String() string            { return proto.CompactTextString(m) }
492 492
 func (*EventsRequest) ProtoMessage()               {}
493
-func (*EventsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{28} }
493
+func (*EventsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{31} }
494 494
 
495 495
 func (m *EventsRequest) GetTimestamp() *google_protobuf.Timestamp {
496 496
 	if m != nil {
... ...
@@ -511,7 +600,7 @@ type Event struct {
511 511
 func (m *Event) Reset()                    { *m = Event{} }
512 512
 func (m *Event) String() string            { return proto.CompactTextString(m) }
513 513
 func (*Event) ProtoMessage()               {}
514
-func (*Event) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29} }
514
+func (*Event) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{32} }
515 515
 
516 516
 func (m *Event) GetTimestamp() *google_protobuf.Timestamp {
517 517
 	if m != nil {
... ...
@@ -535,7 +624,7 @@ type NetworkStats struct {
535 535
 func (m *NetworkStats) Reset()                    { *m = NetworkStats{} }
536 536
 func (m *NetworkStats) String() string            { return proto.CompactTextString(m) }
537 537
 func (*NetworkStats) ProtoMessage()               {}
538
-func (*NetworkStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{30} }
538
+func (*NetworkStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{33} }
539 539
 
540 540
 type CpuUsage struct {
541 541
 	TotalUsage        uint64   `protobuf:"varint,1,opt,name=total_usage,json=totalUsage" json:"total_usage,omitempty"`
... ...
@@ -547,7 +636,7 @@ type CpuUsage struct {
547 547
 func (m *CpuUsage) Reset()                    { *m = CpuUsage{} }
548 548
 func (m *CpuUsage) String() string            { return proto.CompactTextString(m) }
549 549
 func (*CpuUsage) ProtoMessage()               {}
550
-func (*CpuUsage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{31} }
550
+func (*CpuUsage) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{34} }
551 551
 
552 552
 type ThrottlingData struct {
553 553
 	Periods          uint64 `protobuf:"varint,1,opt,name=periods" json:"periods,omitempty"`
... ...
@@ -558,7 +647,7 @@ type ThrottlingData struct {
558 558
 func (m *ThrottlingData) Reset()                    { *m = ThrottlingData{} }
559 559
 func (m *ThrottlingData) String() string            { return proto.CompactTextString(m) }
560 560
 func (*ThrottlingData) ProtoMessage()               {}
561
-func (*ThrottlingData) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{32} }
561
+func (*ThrottlingData) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} }
562 562
 
563 563
 type CpuStats struct {
564 564
 	CpuUsage       *CpuUsage       `protobuf:"bytes,1,opt,name=cpu_usage,json=cpuUsage" json:"cpu_usage,omitempty"`
... ...
@@ -569,7 +658,7 @@ type CpuStats struct {
569 569
 func (m *CpuStats) Reset()                    { *m = CpuStats{} }
570 570
 func (m *CpuStats) String() string            { return proto.CompactTextString(m) }
571 571
 func (*CpuStats) ProtoMessage()               {}
572
-func (*CpuStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{33} }
572
+func (*CpuStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} }
573 573
 
574 574
 func (m *CpuStats) GetCpuUsage() *CpuUsage {
575 575
 	if m != nil {
... ...
@@ -593,7 +682,7 @@ type PidsStats struct {
593 593
 func (m *PidsStats) Reset()                    { *m = PidsStats{} }
594 594
 func (m *PidsStats) String() string            { return proto.CompactTextString(m) }
595 595
 func (*PidsStats) ProtoMessage()               {}
596
-func (*PidsStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{34} }
596
+func (*PidsStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{37} }
597 597
 
598 598
 type MemoryData struct {
599 599
 	Usage    uint64 `protobuf:"varint,1,opt,name=usage" json:"usage,omitempty"`
... ...
@@ -605,7 +694,7 @@ type MemoryData struct {
605 605
 func (m *MemoryData) Reset()                    { *m = MemoryData{} }
606 606
 func (m *MemoryData) String() string            { return proto.CompactTextString(m) }
607 607
 func (*MemoryData) ProtoMessage()               {}
608
-func (*MemoryData) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} }
608
+func (*MemoryData) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{38} }
609 609
 
610 610
 type MemoryStats struct {
611 611
 	Cache       uint64            `protobuf:"varint,1,opt,name=cache" json:"cache,omitempty"`
... ...
@@ -618,7 +707,7 @@ type MemoryStats struct {
618 618
 func (m *MemoryStats) Reset()                    { *m = MemoryStats{} }
619 619
 func (m *MemoryStats) String() string            { return proto.CompactTextString(m) }
620 620
 func (*MemoryStats) ProtoMessage()               {}
621
-func (*MemoryStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} }
621
+func (*MemoryStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{39} }
622 622
 
623 623
 func (m *MemoryStats) GetUsage() *MemoryData {
624 624
 	if m != nil {
... ...
@@ -658,7 +747,7 @@ type BlkioStatsEntry struct {
658 658
 func (m *BlkioStatsEntry) Reset()                    { *m = BlkioStatsEntry{} }
659 659
 func (m *BlkioStatsEntry) String() string            { return proto.CompactTextString(m) }
660 660
 func (*BlkioStatsEntry) ProtoMessage()               {}
661
-func (*BlkioStatsEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{37} }
661
+func (*BlkioStatsEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{40} }
662 662
 
663 663
 type BlkioStats struct {
664 664
 	IoServiceBytesRecursive []*BlkioStatsEntry `protobuf:"bytes,1,rep,name=io_service_bytes_recursive,json=ioServiceBytesRecursive" json:"io_service_bytes_recursive,omitempty"`
... ...
@@ -674,7 +763,7 @@ type BlkioStats struct {
674 674
 func (m *BlkioStats) Reset()                    { *m = BlkioStats{} }
675 675
 func (m *BlkioStats) String() string            { return proto.CompactTextString(m) }
676 676
 func (*BlkioStats) ProtoMessage()               {}
677
-func (*BlkioStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{38} }
677
+func (*BlkioStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} }
678 678
 
679 679
 func (m *BlkioStats) GetIoServiceBytesRecursive() []*BlkioStatsEntry {
680 680
 	if m != nil {
... ...
@@ -742,7 +831,7 @@ type HugetlbStats struct {
742 742
 func (m *HugetlbStats) Reset()                    { *m = HugetlbStats{} }
743 743
 func (m *HugetlbStats) String() string            { return proto.CompactTextString(m) }
744 744
 func (*HugetlbStats) ProtoMessage()               {}
745
-func (*HugetlbStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{39} }
745
+func (*HugetlbStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{42} }
746 746
 
747 747
 type CgroupStats struct {
748 748
 	CpuStats     *CpuStats                `protobuf:"bytes,1,opt,name=cpu_stats,json=cpuStats" json:"cpu_stats,omitempty"`
... ...
@@ -755,7 +844,7 @@ type CgroupStats struct {
755 755
 func (m *CgroupStats) Reset()                    { *m = CgroupStats{} }
756 756
 func (m *CgroupStats) String() string            { return proto.CompactTextString(m) }
757 757
 func (*CgroupStats) ProtoMessage()               {}
758
-func (*CgroupStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{40} }
758
+func (*CgroupStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{43} }
759 759
 
760 760
 func (m *CgroupStats) GetCpuStats() *CpuStats {
761 761
 	if m != nil {
... ...
@@ -802,7 +891,7 @@ type StatsResponse struct {
802 802
 func (m *StatsResponse) Reset()                    { *m = StatsResponse{} }
803 803
 func (m *StatsResponse) String() string            { return proto.CompactTextString(m) }
804 804
 func (*StatsResponse) ProtoMessage()               {}
805
-func (*StatsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} }
805
+func (*StatsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{44} }
806 806
 
807 807
 func (m *StatsResponse) GetNetworkStats() []*NetworkStats {
808 808
 	if m != nil {
... ...
@@ -832,7 +921,7 @@ type StatsRequest struct {
832 832
 func (m *StatsRequest) Reset()                    { *m = StatsRequest{} }
833 833
 func (m *StatsRequest) String() string            { return proto.CompactTextString(m) }
834 834
 func (*StatsRequest) ProtoMessage()               {}
835
-func (*StatsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{42} }
835
+func (*StatsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{45} }
836 836
 
837 837
 func init() {
838 838
 	proto.RegisterType((*GetServerVersionRequest)(nil), "types.GetServerVersionRequest")
... ...
@@ -862,6 +951,9 @@ func init() {
862 862
 	proto.RegisterType((*StateResponse)(nil), "types.StateResponse")
863 863
 	proto.RegisterType((*UpdateContainerRequest)(nil), "types.UpdateContainerRequest")
864 864
 	proto.RegisterType((*UpdateResource)(nil), "types.UpdateResource")
865
+	proto.RegisterType((*BlockIODevice)(nil), "types.BlockIODevice")
866
+	proto.RegisterType((*WeightDevice)(nil), "types.WeightDevice")
867
+	proto.RegisterType((*ThrottleDevice)(nil), "types.ThrottleDevice")
865 868
 	proto.RegisterType((*UpdateContainerResponse)(nil), "types.UpdateContainerResponse")
866 869
 	proto.RegisterType((*EventsRequest)(nil), "types.EventsRequest")
867 870
 	proto.RegisterType((*Event)(nil), "types.Event")
... ...
@@ -1343,156 +1435,168 @@ var _API_serviceDesc = grpc.ServiceDesc{
1343 1343
 }
1344 1344
 
1345 1345
 var fileDescriptor0 = []byte{
1346
-	// 2414 bytes of a gzipped FileDescriptorProto
1347
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xec, 0x59, 0xcd, 0x73, 0x1b, 0x4b,
1348
-	0x11, 0x8f, 0xa4, 0xb5, 0x6c, 0xb5, 0x3e, 0x6c, 0x6f, 0xfc, 0xa1, 0xe8, 0xbd, 0x7c, 0xb0, 0xf5,
1349
-	0x80, 0x00, 0xaf, 0x94, 0xa0, 0xbc, 0x57, 0xa4, 0xa0, 0x8a, 0xaa, 0xc4, 0x0e, 0x8f, 0xf0, 0xe2,
1350
-	0x3c, 0x65, 0x6d, 0xf3, 0x8e, 0xaa, 0xb5, 0x76, 0x22, 0x2d, 0x5e, 0xed, 0x6e, 0x76, 0x47, 0xb6,
1351
-	0x7c, 0xe1, 0xc0, 0x01, 0x6e, 0x70, 0xa5, 0x0a, 0x6e, 0xdc, 0xb8, 0x73, 0x80, 0x7f, 0x80, 0x2a,
1352
-	0xfe, 0x10, 0x6e, 0xdc, 0x39, 0xd2, 0xf3, 0xb9, 0xb3, 0xfa, 0xb0, 0x93, 0x03, 0xc5, 0x85, 0x8b,
1353
-	0x6a, 0xfa, 0x37, 0x3d, 0xdd, 0x3d, 0x3d, 0xdd, 0x3d, 0xbd, 0x23, 0xa8, 0x79, 0x49, 0xd0, 0x4d,
1354
-	0xd2, 0x98, 0xc6, 0xf6, 0x1a, 0xbd, 0x4a, 0x48, 0xd6, 0xb9, 0x3f, 0x8a, 0xe3, 0x51, 0x48, 0x1e,
1355
-	0x71, 0xf0, 0x6c, 0xfa, 0xf6, 0x11, 0x0d, 0x26, 0x24, 0xa3, 0xde, 0x24, 0x11, 0x7c, 0xce, 0x1d,
1356
-	0xd8, 0xff, 0x82, 0xd0, 0x63, 0x92, 0x5e, 0x90, 0xf4, 0xe7, 0x24, 0xcd, 0x82, 0x38, 0x72, 0xc9,
1357
-	0xbb, 0x29, 0xf2, 0x38, 0x33, 0x68, 0x2f, 0x4e, 0x65, 0x49, 0x1c, 0x65, 0xc4, 0xde, 0x81, 0xb5,
1358
-	0x89, 0xf7, 0x8b, 0x38, 0x6d, 0x97, 0x1e, 0x94, 0x1e, 0x36, 0x5d, 0x41, 0x70, 0x34, 0x88, 0x10,
1359
-	0x2d, 0x4b, 0x94, 0x11, 0x0c, 0x4d, 0x3c, 0x3a, 0x1c, 0xb7, 0x2b, 0x02, 0xe5, 0x84, 0xdd, 0x81,
1360
-	0x8d, 0x94, 0x5c, 0x04, 0x4c, 0x6a, 0xdb, 0xc2, 0x89, 0x9a, 0xab, 0x69, 0xe7, 0xd7, 0x25, 0xd8,
1361
-	0x39, 0x4d, 0x7c, 0x8f, 0x92, 0x7e, 0x1a, 0x0f, 0x49, 0x96, 0x49, 0x93, 0xec, 0x16, 0x94, 0x03,
1362
-	0x9f, 0xeb, 0xac, 0xb9, 0x38, 0xb2, 0xb7, 0xa0, 0x92, 0x20, 0x50, 0xe6, 0x00, 0x1b, 0xda, 0xf7,
1363
-	0x00, 0x86, 0x61, 0x9c, 0x91, 0x63, 0xea, 0x07, 0x11, 0xd7, 0xb8, 0xe1, 0x1a, 0x08, 0x33, 0xe6,
1364
-	0x32, 0xf0, 0xe9, 0x98, 0xeb, 0x44, 0x63, 0x38, 0x61, 0xef, 0x41, 0x75, 0x4c, 0x82, 0xd1, 0x98,
1365
-	0xb6, 0xd7, 0x38, 0x2c, 0x29, 0x67, 0x1f, 0x76, 0xe7, 0xec, 0x10, 0xfb, 0x77, 0xfe, 0x51, 0x86,
1366
-	0xbd, 0x83, 0x94, 0xe0, 0xcc, 0x41, 0x1c, 0x51, 0x2f, 0x88, 0x48, 0xba, 0xca, 0x46, 0xb4, 0xe8,
1367
-	0x6c, 0x1a, 0xf9, 0x21, 0xe9, 0x7b, 0xa8, 0x56, 0x98, 0x6a, 0x20, 0xdc, 0xe2, 0x31, 0x19, 0x9e,
1368
-	0x27, 0x71, 0x10, 0x51, 0x6e, 0x31, 0xce, 0xe7, 0x08, 0xb3, 0x38, 0xe3, 0x9b, 0x11, 0x5e, 0x12,
1369
-	0x04, 0xb3, 0x18, 0x07, 0xf1, 0x54, 0x58, 0x5c, 0x73, 0x25, 0x25, 0x71, 0x92, 0xa6, 0xed, 0xaa,
1370
-	0xc6, 0x91, 0x62, 0x78, 0xe8, 0x9d, 0x91, 0x30, 0x6b, 0xaf, 0x3f, 0xa8, 0x30, 0x5c, 0x50, 0xf6,
1371
-	0x03, 0xa8, 0x47, 0x71, 0x3f, 0xb8, 0x88, 0xa9, 0x1b, 0xc7, 0xb4, 0xbd, 0xc1, 0x1d, 0x66, 0x42,
1372
-	0x76, 0x1b, 0xd6, 0xd3, 0x69, 0xc4, 0xe2, 0xa6, 0x5d, 0xe3, 0x22, 0x15, 0xc9, 0xd6, 0xca, 0xe1,
1373
-	0xb3, 0x74, 0x94, 0xb5, 0x81, 0x0b, 0x36, 0x21, 0xfb, 0x13, 0x68, 0xe6, 0x3b, 0x39, 0x0c, 0xd2,
1374
-	0x76, 0x9d, 0x4b, 0x28, 0x82, 0xce, 0x4b, 0xd8, 0x5f, 0xf0, 0xa5, 0x8c, 0xb3, 0x2e, 0xd4, 0x86,
1375
-	0x0a, 0xe4, 0x3e, 0xad, 0xf7, 0xb6, 0xba, 0x3c, 0xb4, 0xbb, 0x39, 0x73, 0xce, 0x82, 0xa2, 0x9a,
1376
-	0xc7, 0xc1, 0x28, 0xf2, 0xc2, 0xf7, 0x8f, 0x18, 0xe6, 0x31, 0xbe, 0x44, 0xc6, 0xa7, 0xa4, 0x9c,
1377
-	0x2d, 0x68, 0x29, 0x51, 0xf2, 0xd0, 0xff, 0x52, 0x81, 0xed, 0x67, 0xbe, 0x7f, 0x43, 0x4c, 0x62,
1378
-	0x60, 0x53, 0x92, 0x62, 0xe8, 0xa3, 0xc4, 0x32, 0x77, 0xa7, 0xa6, 0xed, 0xfb, 0x60, 0x4d, 0x33,
1379
-	0xdc, 0x49, 0x85, 0xef, 0xa4, 0x2e, 0x77, 0x72, 0x8a, 0x90, 0xcb, 0x27, 0x6c, 0x1b, 0x2c, 0x8f,
1380
-	0xf9, 0xd2, 0xe2, 0xbe, 0xe4, 0x63, 0x66, 0x32, 0x89, 0x2e, 0xf0, 0x9c, 0x19, 0xc4, 0x86, 0x0c,
1381
-	0x19, 0x5e, 0xfa, 0xf2, 0x84, 0xd9, 0x50, 0x6d, 0x6b, 0x3d, 0xdf, 0x96, 0x0e, 0x9b, 0x8d, 0xe5,
1382
-	0x61, 0x53, 0x5b, 0x11, 0x36, 0x50, 0x08, 0x1b, 0x07, 0x1a, 0x43, 0x2f, 0xf1, 0xce, 0x82, 0x30,
1383
-	0xa0, 0x01, 0xc9, 0xf0, 0xfc, 0x98, 0x11, 0x05, 0xcc, 0x7e, 0x08, 0x9b, 0x5e, 0x92, 0x78, 0xe9,
1384
-	0x24, 0x4e, 0xd1, 0x35, 0x6f, 0x83, 0x90, 0xb4, 0x1b, 0x5c, 0xc8, 0x3c, 0xcc, 0xa4, 0x65, 0x24,
1385
-	0x0c, 0xa2, 0xe9, 0xec, 0x15, 0x8b, 0xbe, 0x76, 0x93, 0xb3, 0x15, 0x30, 0x26, 0x2d, 0x8a, 0x5f,
1386
-	0x93, 0xcb, 0x7e, 0x1a, 0x5c, 0xe0, 0x9a, 0x11, 0x2a, 0x6d, 0x71, 0x2f, 0xce, 0xc3, 0xf6, 0xb7,
1387
-	0x31, 0x30, 0xc3, 0x60, 0x12, 0xd0, 0xac, 0xbd, 0x89, 0x66, 0xd5, 0x7b, 0x4d, 0xe9, 0x4f, 0x97,
1388
-	0xa3, 0xae, 0x9a, 0x75, 0x0e, 0xa1, 0x2a, 0x20, 0xe6, 0x5e, 0xc6, 0x22, 0x4f, 0x8b, 0x8f, 0x19,
1389
-	0x96, 0xc5, 0x6f, 0x29, 0x3f, 0x2b, 0xcb, 0xe5, 0x63, 0x86, 0x8d, 0xbd, 0xd4, 0xe7, 0xe7, 0x84,
1390
-	0x18, 0x1b, 0x3b, 0x2e, 0x58, 0xec, 0xa0, 0x98, 0xab, 0xa7, 0xf2, 0xc0, 0x9b, 0x2e, 0x1b, 0x32,
1391
-	0x64, 0x24, 0x63, 0x0a, 0x11, 0x1c, 0xda, 0xdf, 0x82, 0x96, 0xe7, 0xfb, 0xe8, 0x9e, 0x18, 0x4f,
1392
-	0xfd, 0x8b, 0xc0, 0xcf, 0x50, 0x52, 0x05, 0x27, 0xe7, 0x50, 0x67, 0x07, 0x6c, 0x33, 0xa0, 0x64,
1393
-	0x9c, 0xfd, 0xaa, 0xa4, 0x13, 0x42, 0xe7, 0xc9, 0xaa, 0x68, 0xfb, 0x7e, 0xa1, 0x7a, 0x94, 0x79,
1394
-	0x5c, 0x6d, 0xab, 0x0c, 0xc9, 0x57, 0x9b, 0x05, 0x65, 0x21, 0x29, 0x2b, 0xcb, 0x92, 0xb2, 0x03,
1395
-	0xed, 0x45, 0x1b, 0xa4, 0x81, 0x43, 0xd8, 0x3f, 0x24, 0x21, 0x79, 0x1f, 0xfb, 0xd0, 0x93, 0x91,
1396
-	0x87, 0xa5, 0x43, 0x24, 0x1c, 0x1f, 0xbf, 0xbf, 0x01, 0x8b, 0x4a, 0xa4, 0x01, 0x47, 0xb0, 0xfb,
1397
-	0x2a, 0xc8, 0xe8, 0xcd, 0xea, 0x17, 0x54, 0x95, 0x97, 0xa9, 0xfa, 0x7d, 0x09, 0x20, 0x97, 0xa5,
1398
-	0x6d, 0x2e, 0x19, 0x36, 0x23, 0x46, 0x66, 0x01, 0x95, 0x19, 0xcd, 0xc7, 0xec, 0xdc, 0xe9, 0x30,
1399
-	0x91, 0x97, 0x0c, 0x1b, 0xb2, 0x8a, 0x38, 0x8d, 0x82, 0xd9, 0x71, 0x3c, 0x3c, 0x27, 0x34, 0xe3,
1400
-	0x15, 0x1b, 0xab, 0xa9, 0x01, 0xf1, 0xb4, 0x1c, 0x93, 0x30, 0xe4, 0x65, 0x7b, 0xc3, 0x15, 0x04,
1401
-	0xab, 0xb1, 0x64, 0x92, 0xd0, 0xab, 0xd7, 0xc7, 0x98, 0xd4, 0x2c, 0xc3, 0x14, 0x89, 0x3b, 0xdd,
1402
-	0x9b, 0xdf, 0xa9, 0x2c, 0x8d, 0x4f, 0xa0, 0x9e, 0xef, 0x22, 0x43, 0x63, 0x2b, 0xcb, 0x8f, 0xde,
1403
-	0xe4, 0x72, 0xee, 0x41, 0xe3, 0x98, 0xe2, 0xa1, 0xae, 0xf0, 0x97, 0xf3, 0x10, 0x5a, 0xba, 0xae,
1404
-	0x72, 0x46, 0x51, 0x19, 0x3c, 0x3a, 0xcd, 0x24, 0x97, 0xa4, 0x9c, 0xbf, 0x56, 0x60, 0x5d, 0x06,
1405
-	0xae, 0xaa, 0x3e, 0xa5, 0xbc, 0xfa, 0xfc, 0x4f, 0x8a, 0xe0, 0xc7, 0x50, 0xcb, 0xae, 0x32, 0x4a,
1406
-	0x26, 0x7d, 0x59, 0x0a, 0x9b, 0x6e, 0x0e, 0xfc, 0xbf, 0x20, 0xe6, 0x05, 0xf1, 0xef, 0x25, 0xa8,
1407
-	0xe9, 0x63, 0xfe, 0xe0, 0x86, 0xe5, 0x53, 0xa8, 0x25, 0xe2, 0xe0, 0x89, 0xa8, 0x6b, 0xf5, 0x5e,
1408
-	0x4b, 0x2a, 0x52, 0x95, 0x2c, 0x67, 0x30, 0xe2, 0xc7, 0x32, 0xe3, 0xc7, 0x68, 0x48, 0xd6, 0x0a,
1409
-	0x0d, 0x09, 0x1e, 0x7e, 0xc2, 0x0a, 0x66, 0x95, 0x17, 0x4c, 0x3e, 0x36, 0x5b, 0x90, 0xf5, 0x42,
1410
-	0x0b, 0xe2, 0x7c, 0x0e, 0xeb, 0x47, 0xde, 0x70, 0x8c, 0xfb, 0x60, 0x0b, 0x87, 0x89, 0x0c, 0x53,
1411
-	0x5c, 0xc8, 0xc6, 0x4c, 0xc9, 0x84, 0xa0, 0xbf, 0xaf, 0x64, 0x75, 0x97, 0x94, 0x73, 0x8e, 0x6d,
1412
-	0x82, 0x48, 0x03, 0x99, 0x4c, 0x8f, 0xb1, 0x8c, 0x2a, 0x87, 0xa8, 0x5c, 0x5a, 0x6c, 0x34, 0x0c,
1413
-	0x1e, 0x3c, 0x96, 0xf5, 0x89, 0xd0, 0x2c, 0xab, 0xae, 0xf2, 0x81, 0xb4, 0xc7, 0x55, 0xd3, 0xce,
1414
-	0x6f, 0x4a, 0xb0, 0x27, 0xba, 0xc8, 0x1b, 0x7b, 0xc5, 0xe5, 0xdd, 0x89, 0x70, 0x5f, 0xa5, 0xe0,
1415
-	0xbe, 0x27, 0x50, 0x4b, 0x49, 0x16, 0x4f, 0x53, 0x74, 0x33, 0xf7, 0x6c, 0xbd, 0xb7, 0xab, 0x32,
1416
-	0x89, 0xeb, 0x72, 0xe5, 0xac, 0x9b, 0xf3, 0x39, 0x7f, 0xac, 0x40, 0xab, 0x38, 0xcb, 0x2a, 0xd6,
1417
-	0x59, 0x78, 0x1e, 0xc4, 0x5f, 0x8b, 0xf6, 0xb7, 0xc4, 0xdd, 0x64, 0x42, 0x2c, 0xab, 0xd0, 0x97,
1418
-	0xc7, 0x78, 0x07, 0xa2, 0x26, 0xe1, 0xc6, 0x1c, 0x90, 0xb3, 0x7d, 0x92, 0x06, 0xb1, 0xba, 0x2e,
1419
-	0x73, 0x80, 0x95, 0x01, 0x24, 0xde, 0x4c, 0x63, 0xea, 0x71, 0x23, 0x2d, 0x57, 0xd3, 0xbc, 0xef,
1420
-	0xc5, 0x33, 0x22, 0xf4, 0x80, 0x9d, 0xda, 0x9a, 0xec, 0x7b, 0x35, 0x92, 0xcf, 0x1f, 0x91, 0x49,
1421
-	0x26, 0xd3, 0xdc, 0x40, 0x98, 0xe5, 0xe2, 0x34, 0x5f, 0xb1, 0xa0, 0xe6, 0x81, 0x81, 0x96, 0x1b,
1422
-	0x10, 0x93, 0x20, 0xc8, 0xe3, 0x4b, 0x2f, 0xe1, 0x69, 0x6f, 0xb9, 0x06, 0x82, 0x81, 0xbc, 0x2d,
1423
-	0x28, 0xf4, 0x06, 0x7e, 0xe5, 0x78, 0xec, 0x62, 0xe6, 0x65, 0xc0, 0x72, 0x17, 0x27, 0x18, 0xf7,
1424
-	0x39, 0x49, 0x23, 0x12, 0x1e, 0x19, 0x5a, 0x41, 0x70, 0x2f, 0x4c, 0xd8, 0x3d, 0xd8, 0x11, 0xe0,
1425
-	0xc9, 0x41, 0xdf, 0x5c, 0x50, 0xe7, 0x0b, 0x96, 0xce, 0xb1, 0x6f, 0xb1, 0x85, 0x38, 0x91, 0x17,
1426
-	0xde, 0x15, 0x34, 0x5f, 0x5c, 0x10, 0xac, 0xe0, 0x2a, 0x72, 0x9e, 0x42, 0x4d, 0x7f, 0xca, 0xc9,
1427
-	0x00, 0xec, 0x74, 0xc5, 0xc7, 0x5e, 0x57, 0x7d, 0xec, 0x75, 0x4f, 0x14, 0x87, 0x9b, 0x33, 0x33,
1428
-	0xaf, 0x64, 0x34, 0x4e, 0x89, 0xff, 0x55, 0x14, 0x5e, 0xa9, 0x2f, 0xa4, 0x1c, 0x91, 0x31, 0x69,
1429
-	0xe9, 0x2b, 0xe1, 0x77, 0x25, 0x58, 0xe3, 0xba, 0x97, 0x76, 0x4f, 0x82, 0xbb, 0xac, 0x23, 0xb8,
1430
-	0x18, 0xaf, 0x4d, 0x1d, 0xaf, 0x32, 0xb2, 0xad, 0x3c, 0xb2, 0x0b, 0x3b, 0xa8, 0x7e, 0xc0, 0x0e,
1431
-	0x9c, 0xdf, 0x96, 0xa1, 0xf1, 0x9a, 0xd0, 0xcb, 0x38, 0x3d, 0x67, 0x59, 0x9c, 0x2d, 0xbd, 0xb0,
1432
-	0xef, 0xe0, 0xf7, 0xe5, 0x6c, 0x70, 0x76, 0x45, 0x75, 0xd4, 0xae, 0xa7, 0xb3, 0xe7, 0x8c, 0xb4,
1433
-	0xef, 0x02, 0xe0, 0x54, 0xdf, 0x13, 0x97, 0xb4, 0x0c, 0xda, 0x74, 0x26, 0x01, 0xfb, 0x23, 0xa8,
1434
-	0xb9, 0xb3, 0x01, 0x16, 0xfb, 0x38, 0xcd, 0x54, 0xd4, 0xa6, 0xb3, 0x17, 0x9c, 0x66, 0x6b, 0x71,
1435
-	0xd2, 0x4f, 0xe3, 0x24, 0x21, 0x3e, 0x8f, 0x5a, 0xbe, 0xf6, 0x50, 0x00, 0x4c, 0xeb, 0x89, 0xd2,
1436
-	0x5a, 0x15, 0x5a, 0x69, 0xae, 0x15, 0xa7, 0x12, 0xa9, 0x55, 0x84, 0x6b, 0x8d, 0x9a, 0x5a, 0x4f,
1437
-	0xb4, 0x56, 0x11, 0xab, 0x1b, 0xd4, 0xd0, 0x7a, 0x92, 0x6b, 0xad, 0xa9, 0xb5, 0x52, 0xab, 0xf3,
1438
-	0xe7, 0x12, 0x6c, 0x60, 0xce, 0x9c, 0x66, 0xde, 0x88, 0xe0, 0xf5, 0x5a, 0xa7, 0x98, 0x5f, 0xe1,
1439
-	0x60, 0xca, 0x48, 0x99, 0xd1, 0xc0, 0x21, 0xc1, 0xf0, 0x0d, 0x68, 0x24, 0x24, 0xc5, 0x4c, 0x92,
1440
-	0x1c, 0x65, 0xac, 0x76, 0x98, 0x39, 0x02, 0x13, 0x2c, 0x5d, 0xb8, 0xcd, 0xe7, 0x06, 0x41, 0x34,
1441
-	0x10, 0xa1, 0x3a, 0x89, 0x7d, 0x22, 0x5d, 0xb5, 0xcd, 0xa7, 0x5e, 0x46, 0x5f, 0xea, 0x09, 0xfb,
1442
-	0xbb, 0xb0, 0xad, 0xf9, 0xd9, 0x15, 0xce, 0xb9, 0x85, 0xeb, 0x36, 0x25, 0xf7, 0xa9, 0x84, 0x9d,
1443
-	0x5f, 0x42, 0xeb, 0x64, 0x8c, 0xe7, 0x4b, 0xf1, 0x8e, 0x1b, 0x1d, 0x7a, 0x58, 0x09, 0xb0, 0xbc,
1444
-	0x27, 0xbc, 0x5e, 0x64, 0xd2, 0x5a, 0x45, 0xda, 0xdf, 0x83, 0x6d, 0x2a, 0x78, 0x89, 0x3f, 0x50,
1445
-	0x3c, 0xe2, 0x34, 0xb7, 0xf4, 0x44, 0x5f, 0x32, 0x7f, 0x13, 0x5a, 0x39, 0x33, 0xbf, 0x2c, 0x84,
1446
-	0xbd, 0x4d, 0x8d, 0xb2, 0x68, 0x72, 0xfe, 0x20, 0x9c, 0x25, 0x22, 0xe7, 0x53, 0x5e, 0xbe, 0x0c,
1447
-	0x57, 0xd5, 0x7b, 0x9b, 0xaa, 0xec, 0x4b, 0x67, 0xf0, 0x92, 0x25, 0xdc, 0xf2, 0x63, 0xd8, 0xa4,
1448
-	0xda, 0xf4, 0x01, 0x66, 0xaa, 0x27, 0x53, 0x4f, 0x95, 0xde, 0xe2, 0xc6, 0xdc, 0x16, 0x2d, 0x6e,
1449
-	0x14, 0x3d, 0x2f, 0xfa, 0x11, 0xa9, 0x50, 0xd8, 0x57, 0x17, 0x18, 0x57, 0xe1, 0xfc, 0x08, 0x6a,
1450
-	0xd8, 0xac, 0x64, 0xc2, 0x3a, 0x74, 0xcc, 0x70, 0x9a, 0xa6, 0x98, 0x7b, 0xca, 0x31, 0x92, 0x64,
1451
-	0xcd, 0x0c, 0xbf, 0xcb, 0xa5, 0x33, 0x04, 0xe1, 0xc4, 0x00, 0xa2, 0x9e, 0x70, 0x6d, 0xc8, 0x63,
1452
-	0x86, 0x80, 0x20, 0x58, 0x9c, 0x4d, 0xbc, 0x99, 0x3e, 0x7a, 0x1e, 0x67, 0x08, 0x88, 0x0d, 0xa2,
1453
-	0xc2, 0xb7, 0x5e, 0x10, 0x0e, 0xe5, 0x43, 0x04, 0x2a, 0x94, 0x64, 0xae, 0xd0, 0x32, 0x15, 0xfe,
1454
-	0xa9, 0x0c, 0x75, 0xa1, 0x51, 0x18, 0x8c, 0x5c, 0x43, 0xbc, 0xf5, 0xb4, 0x4a, 0x4e, 0x60, 0x5f,
1455
-	0xb2, 0x96, 0xab, 0xcb, 0x7b, 0xd4, 0xdc, 0x54, 0x65, 0x1b, 0xde, 0xc2, 0x19, 0x16, 0x66, 0xc3,
1456
-	0x3b, 0x4b, 0xb9, 0x6b, 0x8c, 0x49, 0x18, 0xfc, 0x19, 0x34, 0x44, 0x7c, 0xca, 0x35, 0xd6, 0xaa,
1457
-	0x35, 0x75, 0xc1, 0x26, 0x56, 0x3d, 0x61, 0xad, 0x20, 0xda, 0xcb, 0x5b, 0x8f, 0x7a, 0xef, 0x6e,
1458
-	0x81, 0x9d, 0xef, 0xa4, 0xcb, 0x7f, 0x5f, 0x44, 0x14, 0xef, 0x00, 0xc1, 0xdb, 0x79, 0x0a, 0x90,
1459
-	0x83, 0xac, 0x9e, 0x9d, 0x93, 0x2b, 0xd5, 0xf2, 0xe2, 0x90, 0xed, 0xfd, 0xc2, 0x0b, 0xa7, 0xca,
1460
-	0xa9, 0x82, 0xf8, 0x61, 0xf9, 0x69, 0x09, 0x3f, 0x97, 0x36, 0x9f, 0xb3, 0x0b, 0xd5, 0x58, 0x5e,
1461
-	0x78, 0x3f, 0xb3, 0x96, 0xbe, 0x9f, 0x59, 0xea, 0xfd, 0x0c, 0x4b, 0x6c, 0x9c, 0xc8, 0xeb, 0x1f,
1462
-	0x47, 0xb9, 0x22, 0xcb, 0x50, 0xe4, 0xfc, 0xd3, 0x02, 0xc8, 0xb5, 0xd8, 0xc7, 0xd0, 0x09, 0xe2,
1463
-	0x01, 0xbb, 0xbd, 0x82, 0x21, 0x11, 0x05, 0x69, 0x90, 0x12, 0x0c, 0x9f, 0x2c, 0xb8, 0x20, 0xb2,
1464
-	0xc1, 0xd9, 0x93, 0xfb, 0x9e, 0x33, 0xce, 0xdd, 0x47, 0x4a, 0x2c, 0xe4, 0x95, 0xcb, 0x55, 0xcb,
1465
-	0xec, 0x9f, 0xc1, 0x6e, 0x2e, 0xd4, 0x37, 0xe4, 0x95, 0xaf, 0x95, 0x77, 0x5b, 0xcb, 0xf3, 0x73,
1466
-	0x59, 0x3f, 0x01, 0x84, 0x07, 0x78, 0x99, 0x4d, 0x0b, 0x92, 0x2a, 0xd7, 0x4a, 0xda, 0x0e, 0xe2,
1467
-	0x37, 0x7c, 0x45, 0x2e, 0xe7, 0x0d, 0xdc, 0x31, 0x36, 0xca, 0xd2, 0xde, 0x90, 0x66, 0x5d, 0x2b,
1468
-	0x6d, 0x4f, 0xdb, 0xc5, 0x0a, 0x43, 0x2e, 0xf2, 0x4b, 0xc0, 0x99, 0xc1, 0xa5, 0x17, 0xd0, 0x79,
1469
-	0x79, 0x6b, 0x37, 0xed, 0xf3, 0x6b, 0x5c, 0x54, 0x14, 0x26, 0xf6, 0x39, 0x21, 0xe9, 0xa8, 0xb0,
1470
-	0xcf, 0xea, 0x4d, 0xfb, 0x3c, 0xe2, 0x2b, 0x72, 0x39, 0xcf, 0x01, 0xc1, 0x79, 0x7b, 0xd6, 0xaf,
1471
-	0x95, 0xb2, 0x19, 0xc4, 0x45, 0x5b, 0x0e, 0x60, 0x3b, 0x23, 0x43, 0xbc, 0xea, 0xcd, 0x58, 0xd8,
1472
-	0xb8, 0x56, 0xc6, 0x96, 0x5c, 0xa0, 0x85, 0x38, 0xef, 0xa0, 0xf1, 0xd3, 0xe9, 0x88, 0xd0, 0xf0,
1473
-	0x4c, 0xe7, 0xfc, 0x7f, 0xbb, 0xcc, 0xfc, 0x1b, 0xcb, 0xcc, 0xc1, 0x28, 0x8d, 0xa7, 0x49, 0xa1,
1474
-	0x6a, 0x8b, 0x1c, 0x5e, 0xa8, 0xda, 0x9c, 0x87, 0x57, 0x6d, 0xc1, 0xfd, 0x39, 0x34, 0x44, 0x37,
1475
-	0x27, 0x17, 0x88, 0x2a, 0x64, 0x2f, 0x26, 0xbd, 0xea, 0x1e, 0xc5, 0xb2, 0x9e, 0xec, 0x8c, 0xe5,
1476
-	0xaa, 0x62, 0x35, 0xca, 0xdd, 0x84, 0x9f, 0x46, 0x79, 0xd6, 0xbd, 0x84, 0xe6, 0x58, 0xf8, 0x46,
1477
-	0xae, 0x12, 0x01, 0xf8, 0x89, 0x32, 0x2e, 0xdf, 0x43, 0xd7, 0xf4, 0xa1, 0x70, 0x75, 0x63, 0x6c,
1478
-	0xba, 0xf5, 0x11, 0x00, 0xfb, 0xf6, 0x19, 0xa8, 0x42, 0x65, 0x3e, 0x7d, 0xea, 0x1b, 0x02, 0x3f,
1479
-	0xb4, 0xd4, 0xb0, 0x73, 0x02, 0xdb, 0x0b, 0x32, 0x97, 0x94, 0xa9, 0xef, 0x98, 0x65, 0xaa, 0xde,
1480
-	0xbb, 0x2d, 0x45, 0x9a, 0x4b, 0xcd, 0xda, 0xf5, 0xb7, 0x92, 0xf8, 0x54, 0xd2, 0xaf, 0x53, 0xd8,
1481
-	0xb7, 0x35, 0x23, 0xd1, 0x7c, 0xe9, 0x03, 0xa8, 0x18, 0x82, 0xcc, 0xc6, 0xcc, 0x6d, 0x44, 0x66,
1482
-	0x9b, 0x86, 0x07, 0x31, 0xe4, 0x1e, 0x58, 0x7a, 0x10, 0x86, 0x73, 0xdc, 0xfa, 0xd0, 0x38, 0xed,
1483
-	0x42, 0xa3, 0x68, 0x7d, 0x48, 0xa3, 0x28, 0x5f, 0x3b, 0x56, 0x3d, 0xd5, 0xf6, 0xfe, 0x55, 0x85,
1484
-	0xca, 0xb3, 0xfe, 0x4b, 0xfb, 0x14, 0xb6, 0xe6, 0xff, 0xe9, 0xb0, 0xef, 0x49, 0xb3, 0x56, 0xfc,
1485
-	0x3b, 0xd2, 0xb9, 0xbf, 0x72, 0x5e, 0xb6, 0xec, 0xb7, 0x6c, 0x17, 0x36, 0xe7, 0xde, 0xb5, 0x6d,
1486
-	0x75, 0xd5, 0x2c, 0xff, 0xef, 0xa0, 0x73, 0x6f, 0xd5, 0xb4, 0x29, 0x73, 0xee, 0x1b, 0x41, 0xcb,
1487
-	0x5c, 0xfe, 0x8d, 0xa9, 0x65, 0xae, 0xfa, 0xb4, 0xb8, 0x65, 0xff, 0x00, 0xaa, 0xe2, 0xa5, 0xdb,
1488
-	0xde, 0x91, 0xbc, 0x85, 0x37, 0xf4, 0xce, 0xee, 0x1c, 0xaa, 0x17, 0xbe, 0x82, 0x66, 0xe1, 0xef,
1489
-	0x11, 0xfb, 0xa3, 0x82, 0xae, 0xe2, 0x43, 0x79, 0xe7, 0xe3, 0xe5, 0x93, 0x5a, 0xda, 0x01, 0x40,
1490
-	0xfe, 0x18, 0x6a, 0xb7, 0x25, 0xf7, 0xc2, 0x83, 0x7b, 0xe7, 0xce, 0x92, 0x19, 0x2d, 0x04, 0x8f,
1491
-	0x72, 0xfe, 0xd9, 0xd2, 0x9e, 0xf3, 0xea, 0xfc, 0xa3, 0xa1, 0x3e, 0xca, 0x95, 0xef, 0x9d, 0x5c,
1492
-	0xec, 0xfc, 0x63, 0xa4, 0x16, 0xbb, 0xe2, 0x29, 0x54, 0x8b, 0x5d, 0xf9, 0x8a, 0x79, 0xcb, 0xfe,
1493
-	0x0a, 0x5a, 0xc5, 0xd7, 0x3d, 0x5b, 0x39, 0x69, 0xe9, 0xf3, 0x66, 0xe7, 0xee, 0x8a, 0x59, 0x2d,
1494
-	0xf0, 0x33, 0x58, 0x13, 0xcf, 0x76, 0x2a, 0x1d, 0xcd, 0xd7, 0xbe, 0xce, 0x4e, 0x11, 0xd4, 0xab,
1495
-	0x1e, 0x43, 0x55, 0x7c, 0x5d, 0xea, 0x00, 0x28, 0x7c, 0x6c, 0x76, 0x1a, 0x26, 0xea, 0xdc, 0x7a,
1496
-	0x5c, 0x52, 0x7a, 0xb2, 0x82, 0x9e, 0x6c, 0x99, 0x1e, 0xe3, 0x70, 0xce, 0xaa, 0x3c, 0x5d, 0x9f,
1497
-	0xfc, 0x27, 0x00, 0x00, 0xff, 0xff, 0xc9, 0x06, 0x1e, 0xda, 0xa8, 0x1c, 0x00, 0x00,
1346
+	// 2604 bytes of a gzipped FileDescriptorProto
1347
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xec, 0x59, 0x4b, 0x6f, 0x1c, 0x5b,
1348
+	0xf1, 0xcf, 0x3c, 0x3c, 0xf6, 0xd4, 0x3c, 0xec, 0xe9, 0x38, 0xce, 0x64, 0xf2, 0xfc, 0xb7, 0xee,
1349
+	0x1f, 0x02, 0x5c, 0x39, 0xc1, 0xb9, 0x17, 0x22, 0x90, 0x90, 0x12, 0x3b, 0x5c, 0xcc, 0xcd, 0xc3,
1350
+	0x69, 0x3b, 0x44, 0x48, 0x48, 0xa3, 0xf6, 0xcc, 0xc9, 0x4c, 0xe3, 0x9e, 0xee, 0xbe, 0xdd, 0x67,
1351
+	0xfc, 0xd8, 0xb0, 0x60, 0x01, 0x3b, 0xd8, 0x22, 0xb1, 0x64, 0xc7, 0x9e, 0x05, 0x7c, 0x01, 0x24,
1352
+	0x3e, 0x08, 0x3b, 0xf6, 0x2c, 0xa9, 0x53, 0xe7, 0xd1, 0xa7, 0xe7, 0xe1, 0x24, 0x48, 0x88, 0x0d,
1353
+	0x9b, 0x51, 0x57, 0x9d, 0x3a, 0x55, 0x75, 0xea, 0x54, 0xfd, 0x4e, 0x9d, 0x33, 0x50, 0xf7, 0x93,
1354
+	0x60, 0x3b, 0x49, 0x63, 0x1e, 0x3b, 0x2b, 0xfc, 0x22, 0x61, 0x59, 0xef, 0xee, 0x28, 0x8e, 0x47,
1355
+	0x21, 0x7b, 0x40, 0xcc, 0xe3, 0xe9, 0xbb, 0x07, 0x3c, 0x98, 0xb0, 0x8c, 0xfb, 0x93, 0x44, 0xca,
1356
+	0xb9, 0x37, 0xe0, 0xfa, 0x17, 0x8c, 0x1f, 0xb2, 0xf4, 0x94, 0xa5, 0x3f, 0x61, 0x69, 0x16, 0xc4,
1357
+	0x91, 0xc7, 0xbe, 0x9a, 0xa2, 0x8c, 0x7b, 0x0e, 0xdd, 0xf9, 0xa1, 0x2c, 0x89, 0xa3, 0x8c, 0x39,
1358
+	0x9b, 0xb0, 0x32, 0xf1, 0x7f, 0x1e, 0xa7, 0xdd, 0xd2, 0xbd, 0xd2, 0xfd, 0x96, 0x27, 0x09, 0xe2,
1359
+	0x06, 0x11, 0x72, 0xcb, 0x8a, 0x2b, 0x08, 0xc1, 0x4d, 0x7c, 0x3e, 0x18, 0x77, 0x2b, 0x92, 0x4b,
1360
+	0x84, 0xd3, 0x83, 0xb5, 0x94, 0x9d, 0x06, 0x42, 0x6b, 0xb7, 0x8a, 0x03, 0x75, 0xcf, 0xd0, 0xee,
1361
+	0xaf, 0x4a, 0xb0, 0xf9, 0x26, 0x19, 0xfa, 0x9c, 0x1d, 0xa4, 0xf1, 0x80, 0x65, 0x99, 0x72, 0xc9,
1362
+	0x69, 0x43, 0x39, 0x18, 0x92, 0xcd, 0xba, 0x87, 0x5f, 0xce, 0x06, 0x54, 0x12, 0x64, 0x94, 0x89,
1363
+	0x21, 0x3e, 0x9d, 0x3b, 0x00, 0x83, 0x30, 0xce, 0xd8, 0x21, 0x1f, 0x06, 0x11, 0x59, 0x5c, 0xf3,
1364
+	0x2c, 0x8e, 0x70, 0xe6, 0x2c, 0x18, 0xf2, 0x31, 0xd9, 0x44, 0x67, 0x88, 0x70, 0xb6, 0xa0, 0x36,
1365
+	0x66, 0xc1, 0x68, 0xcc, 0xbb, 0x2b, 0xc4, 0x56, 0x94, 0x7b, 0x1d, 0xae, 0xcd, 0xf8, 0x21, 0xd7,
1366
+	0xef, 0xfe, 0xad, 0x0c, 0x5b, 0xbb, 0x29, 0xc3, 0x91, 0xdd, 0x38, 0xe2, 0x7e, 0x10, 0xb1, 0x74,
1367
+	0x99, 0x8f, 0xe8, 0xd1, 0xf1, 0x34, 0x1a, 0x86, 0xec, 0xc0, 0x47, 0xb3, 0xd2, 0x55, 0x8b, 0x43,
1368
+	0x1e, 0x8f, 0xd9, 0xe0, 0x24, 0x89, 0x83, 0x88, 0x93, 0xc7, 0x38, 0x9e, 0x73, 0x84, 0xc7, 0x19,
1369
+	0x2d, 0x46, 0x46, 0x49, 0x12, 0xc2, 0x63, 0xfc, 0x88, 0xa7, 0xd2, 0xe3, 0xba, 0xa7, 0x28, 0xc5,
1370
+	0x67, 0x69, 0xda, 0xad, 0x19, 0x3e, 0x52, 0x82, 0x1f, 0xfa, 0xc7, 0x2c, 0xcc, 0xba, 0xab, 0xf7,
1371
+	0x2a, 0x82, 0x2f, 0x29, 0xe7, 0x1e, 0x34, 0xa2, 0xf8, 0x20, 0x38, 0x8d, 0xb9, 0x17, 0xc7, 0xbc,
1372
+	0xbb, 0x46, 0x01, 0xb3, 0x59, 0x4e, 0x17, 0x56, 0xd3, 0x69, 0x24, 0xf2, 0xa6, 0x5b, 0x27, 0x95,
1373
+	0x9a, 0x14, 0x73, 0xd5, 0xe7, 0x93, 0x74, 0x94, 0x75, 0x81, 0x14, 0xdb, 0x2c, 0xe7, 0x13, 0x68,
1374
+	0xe5, 0x2b, 0xd9, 0x0b, 0xd2, 0x6e, 0x83, 0x34, 0x14, 0x99, 0xee, 0x3e, 0x5c, 0x9f, 0x8b, 0xa5,
1375
+	0xca, 0xb3, 0x6d, 0xa8, 0x0f, 0x34, 0x93, 0x62, 0xda, 0xd8, 0xd9, 0xd8, 0xa6, 0xd4, 0xde, 0xce,
1376
+	0x85, 0x73, 0x11, 0x54, 0xd5, 0x3a, 0x0c, 0x46, 0x91, 0x1f, 0x7e, 0x78, 0xc6, 0x88, 0x88, 0xd1,
1377
+	0x14, 0x95, 0x9f, 0x8a, 0x72, 0x37, 0xa0, 0xad, 0x55, 0xa9, 0x4d, 0xff, 0x53, 0x05, 0x3a, 0x4f,
1378
+	0x86, 0xc3, 0xf7, 0xe4, 0x24, 0x26, 0x36, 0x67, 0x29, 0xa6, 0x3e, 0x6a, 0x2c, 0x53, 0x38, 0x0d,
1379
+	0xed, 0xdc, 0x85, 0xea, 0x34, 0xc3, 0x95, 0x54, 0x68, 0x25, 0x0d, 0xb5, 0x92, 0x37, 0xc8, 0xf2,
1380
+	0x68, 0xc0, 0x71, 0xa0, 0xea, 0x8b, 0x58, 0x56, 0x29, 0x96, 0xf4, 0x2d, 0x5c, 0x66, 0xd1, 0x29,
1381
+	0xee, 0xb3, 0x60, 0x89, 0x4f, 0xc1, 0x19, 0x9c, 0x0d, 0xd5, 0x0e, 0x8b, 0x4f, 0xbd, 0xac, 0xd5,
1382
+	0x7c, 0x59, 0x26, 0x6d, 0xd6, 0x16, 0xa7, 0x4d, 0x7d, 0x49, 0xda, 0x40, 0x21, 0x6d, 0x5c, 0x68,
1383
+	0x0e, 0xfc, 0xc4, 0x3f, 0x0e, 0xc2, 0x80, 0x07, 0x2c, 0xc3, 0xfd, 0x13, 0x4e, 0x14, 0x78, 0xce,
1384
+	0x7d, 0x58, 0xf7, 0x93, 0xc4, 0x4f, 0x27, 0x71, 0x8a, 0xa1, 0x79, 0x17, 0x84, 0xac, 0xdb, 0x24,
1385
+	0x25, 0xb3, 0x6c, 0xa1, 0x2d, 0x63, 0x61, 0x10, 0x4d, 0xcf, 0x9f, 0x8b, 0xec, 0xeb, 0xb6, 0x48,
1386
+	0xac, 0xc0, 0x13, 0xda, 0xa2, 0xf8, 0x25, 0x3b, 0x3b, 0x48, 0x83, 0x53, 0x9c, 0x33, 0x42, 0xa3,
1387
+	0x6d, 0x8a, 0xe2, 0x2c, 0xdb, 0xf9, 0x3a, 0x26, 0x66, 0x18, 0x4c, 0x02, 0x9e, 0x75, 0xd7, 0xd1,
1388
+	0xad, 0xc6, 0x4e, 0x4b, 0xc5, 0xd3, 0x23, 0xae, 0xa7, 0x47, 0xdd, 0x3d, 0xa8, 0x49, 0x96, 0x08,
1389
+	0xaf, 0x10, 0x51, 0xbb, 0x45, 0xdf, 0x82, 0x97, 0xc5, 0xef, 0x38, 0xed, 0x55, 0xd5, 0xa3, 0x6f,
1390
+	0xc1, 0x1b, 0xfb, 0xe9, 0x90, 0xf6, 0x09, 0x79, 0xe2, 0xdb, 0xf5, 0xa0, 0x2a, 0x36, 0x4a, 0x84,
1391
+	0x7a, 0xaa, 0x36, 0xbc, 0xe5, 0x89, 0x4f, 0xc1, 0x19, 0xa9, 0x9c, 0x42, 0x0e, 0x7e, 0x3a, 0x5f,
1392
+	0x83, 0xb6, 0x3f, 0x1c, 0x62, 0x78, 0x62, 0xdc, 0xf5, 0x2f, 0x82, 0x61, 0x86, 0x9a, 0x2a, 0x38,
1393
+	0x38, 0xc3, 0x75, 0x37, 0xc1, 0xb1, 0x13, 0x4a, 0xe5, 0xd9, 0x2f, 0x4b, 0xa6, 0x20, 0x4c, 0x9d,
1394
+	0x2c, 0xcb, 0xb6, 0x6f, 0x17, 0xd0, 0xa3, 0x4c, 0x79, 0xd5, 0xd1, 0x15, 0x92, 0xcf, 0xb6, 0x01,
1395
+	0x65, 0xae, 0x28, 0x2b, 0x8b, 0x8a, 0xb2, 0x07, 0xdd, 0x79, 0x1f, 0x94, 0x83, 0x03, 0xb8, 0xbe,
1396
+	0xc7, 0x42, 0xf6, 0x21, 0xfe, 0x61, 0x24, 0x23, 0x1f, 0xa1, 0x43, 0x16, 0x1c, 0x7d, 0x7f, 0xb8,
1397
+	0x03, 0xf3, 0x46, 0x94, 0x03, 0x2f, 0xe0, 0xda, 0xf3, 0x20, 0xe3, 0xef, 0x37, 0x3f, 0x67, 0xaa,
1398
+	0xbc, 0xc8, 0xd4, 0xef, 0x4a, 0x00, 0xb9, 0x2e, 0xe3, 0x73, 0xc9, 0xf2, 0x19, 0x79, 0xec, 0x3c,
1399
+	0xe0, 0xaa, 0xa2, 0xe9, 0x5b, 0xec, 0x3b, 0x1f, 0x24, 0xea, 0x90, 0x11, 0x9f, 0x02, 0x11, 0xa7,
1400
+	0x51, 0x70, 0x7e, 0x18, 0x0f, 0x4e, 0x18, 0xcf, 0x08, 0xb1, 0x11, 0x4d, 0x2d, 0x16, 0x95, 0xe5,
1401
+	0x98, 0x85, 0x21, 0xc1, 0xf6, 0x9a, 0x27, 0x09, 0x81, 0xb1, 0x6c, 0x92, 0xf0, 0x8b, 0x97, 0x87,
1402
+	0x58, 0xd4, 0xa2, 0xc2, 0x34, 0x89, 0x2b, 0xdd, 0x9a, 0x5d, 0xa9, 0x82, 0xc6, 0x47, 0xd0, 0xc8,
1403
+	0x57, 0x91, 0xa1, 0xb3, 0x95, 0xc5, 0x5b, 0x6f, 0x4b, 0xb9, 0x77, 0xa0, 0x79, 0xc8, 0x71, 0x53,
1404
+	0x97, 0xc4, 0xcb, 0xbd, 0x0f, 0x6d, 0x83, 0xab, 0x24, 0x28, 0x91, 0xc1, 0xe7, 0xd3, 0x4c, 0x49,
1405
+	0x29, 0xca, 0xfd, 0x73, 0x05, 0x56, 0x55, 0xe2, 0x6a, 0xf4, 0x29, 0xe5, 0xe8, 0xf3, 0x5f, 0x01,
1406
+	0xc1, 0x5b, 0x50, 0xcf, 0x2e, 0x32, 0xce, 0x26, 0x07, 0x0a, 0x0a, 0x5b, 0x5e, 0xce, 0xf8, 0x1f,
1407
+	0x20, 0xe6, 0x80, 0xf8, 0xd7, 0x12, 0xd4, 0xcd, 0x36, 0x7f, 0x74, 0xc3, 0xf2, 0x29, 0xd4, 0x13,
1408
+	0xb9, 0xf1, 0x4c, 0xe2, 0x5a, 0x63, 0xa7, 0xad, 0x0c, 0x69, 0x24, 0xcb, 0x05, 0xac, 0xfc, 0xa9,
1409
+	0xda, 0xf9, 0x63, 0x35, 0x24, 0x2b, 0x85, 0x86, 0x04, 0x37, 0x3f, 0x11, 0x80, 0x59, 0x23, 0xc0,
1410
+	0xa4, 0x6f, 0xbb, 0x05, 0x59, 0x2d, 0xb4, 0x20, 0xee, 0xe7, 0xb0, 0xfa, 0xc2, 0x1f, 0x8c, 0x71,
1411
+	0x1d, 0x62, 0xe2, 0x20, 0x51, 0x69, 0x8a, 0x13, 0xc5, 0xb7, 0x30, 0x32, 0x61, 0x18, 0xef, 0x0b,
1412
+	0x85, 0xee, 0x8a, 0x72, 0x4f, 0xb0, 0x4d, 0x90, 0x65, 0xa0, 0x8a, 0xe9, 0x21, 0xc2, 0xa8, 0x0e,
1413
+	0x88, 0xae, 0xa5, 0xf9, 0x46, 0xc3, 0x92, 0xc1, 0x6d, 0x59, 0x9d, 0x48, 0xcb, 0x0a, 0x75, 0x75,
1414
+	0x0c, 0x94, 0x3f, 0x9e, 0x1e, 0x76, 0x7f, 0x5d, 0x82, 0x2d, 0xd9, 0x45, 0xbe, 0xb7, 0x57, 0x5c,
1415
+	0xdc, 0x9d, 0xc8, 0xf0, 0x55, 0x0a, 0xe1, 0x7b, 0x04, 0xf5, 0x94, 0x65, 0xf1, 0x34, 0xc5, 0x30,
1416
+	0x53, 0x64, 0x1b, 0x3b, 0xd7, 0x74, 0x25, 0x91, 0x2d, 0x4f, 0x8d, 0x7a, 0xb9, 0x9c, 0xfb, 0x8f,
1417
+	0x1a, 0xb4, 0x8b, 0xa3, 0x02, 0xb1, 0x8e, 0xc3, 0x93, 0x20, 0x7e, 0x2b, 0xdb, 0xdf, 0x12, 0x85,
1418
+	0xc9, 0x66, 0x89, 0xaa, 0xc2, 0x58, 0x1e, 0xe2, 0x19, 0x88, 0x96, 0x64, 0x18, 0x73, 0x86, 0x1a,
1419
+	0x3d, 0x60, 0x69, 0x10, 0xeb, 0xe3, 0x32, 0x67, 0x08, 0x18, 0x40, 0xe2, 0xf5, 0x34, 0xe6, 0x3e,
1420
+	0x39, 0x59, 0xf5, 0x0c, 0x4d, 0x7d, 0x2f, 0xee, 0x11, 0xe3, 0xbb, 0x62, 0xd7, 0x56, 0x54, 0xdf,
1421
+	0x6b, 0x38, 0xf9, 0xf8, 0x0b, 0x36, 0xc9, 0x54, 0x99, 0x5b, 0x1c, 0xe1, 0xb9, 0xdc, 0xcd, 0xe7,
1422
+	0x22, 0xa9, 0x29, 0x31, 0xd0, 0x73, 0x8b, 0x25, 0x34, 0x48, 0xf2, 0xf0, 0xcc, 0x4f, 0xa8, 0xec,
1423
+	0xab, 0x9e, 0xc5, 0xc1, 0x44, 0xee, 0x48, 0x0a, 0xa3, 0x81, 0xb7, 0x1c, 0x5f, 0x1c, 0xcc, 0x04,
1424
+	0x03, 0x55, 0x6f, 0x7e, 0x40, 0x48, 0x9f, 0xb0, 0x34, 0x62, 0xe1, 0x0b, 0xcb, 0x2a, 0x48, 0xe9,
1425
+	0xb9, 0x01, 0x67, 0x07, 0x36, 0x25, 0xf3, 0x68, 0xf7, 0xc0, 0x9e, 0xd0, 0xa0, 0x09, 0x0b, 0xc7,
1426
+	0x44, 0xa5, 0x53, 0xe0, 0x9f, 0x33, 0xff, 0x9d, 0xda, 0x8f, 0x26, 0x89, 0xcf, 0xb2, 0x9d, 0x27,
1427
+	0xd0, 0xb1, 0xb6, 0x68, 0x0f, 0xef, 0x4d, 0x03, 0x86, 0xe0, 0x21, 0xb2, 0xf6, 0xaa, 0xca, 0x02,
1428
+	0x7b, 0xc8, 0x9b, 0x97, 0x76, 0xde, 0x40, 0x8f, 0x98, 0x47, 0x63, 0xbc, 0x07, 0xf2, 0x10, 0x33,
1429
+	0xc2, 0x1f, 0x3e, 0x4d, 0x32, 0xa5, 0xab, 0x4d, 0xba, 0x74, 0x46, 0x69, 0x19, 0xa5, 0xed, 0x92,
1430
+	0x89, 0xce, 0x5b, 0xb8, 0x59, 0x18, 0x7d, 0x9b, 0x06, 0x9c, 0xe5, 0x7a, 0xd7, 0x2f, 0xd3, 0x7b,
1431
+	0xd9, 0xcc, 0x39, 0xc5, 0xc2, 0xec, 0x7e, 0x6c, 0x14, 0x6f, 0x7c, 0xb8, 0xe2, 0xe2, 0x4c, 0xe7,
1432
+	0xa7, 0x70, 0x6b, 0xde, 0xae, 0xa5, 0xb9, 0x73, 0x99, 0xe6, 0x4b, 0xa7, 0xba, 0xdf, 0x87, 0xd6,
1433
+	0xd3, 0x10, 0x0f, 0xfe, 0xfd, 0x57, 0xca, 0x56, 0xe1, 0xda, 0x5c, 0x59, 0x78, 0x6d, 0xae, 0xa8,
1434
+	0x6b, 0xb3, 0xfb, 0x0b, 0x68, 0x16, 0x36, 0xec, 0x3b, 0x54, 0xa9, 0x5a, 0x95, 0xba, 0x0c, 0x6d,
1435
+	0x2a, 0xb7, 0x0a, 0x66, 0x3c, 0x5b, 0x50, 0x20, 0xc8, 0x99, 0x4c, 0x26, 0xd9, 0xa0, 0x2a, 0x4a,
1436
+	0x54, 0x47, 0x98, 0x27, 0x9a, 0xbc, 0xfb, 0x58, 0x1c, 0xf7, 0x67, 0xd0, 0x2e, 0x2e, 0xf6, 0xdf,
1437
+	0xf6, 0x00, 0x91, 0x39, 0x45, 0xcc, 0xd1, 0x1d, 0xb6, 0xf8, 0x16, 0xef, 0x0e, 0x73, 0x98, 0xa8,
1438
+	0x9a, 0xbb, 0x0b, 0x68, 0x3d, 0x3b, 0x65, 0xd8, 0xad, 0x68, 0x94, 0x7c, 0x0c, 0x75, 0xf3, 0x6c,
1439
+	0xa1, 0xc0, 0xb6, 0xb7, 0x2d, 0x1f, 0x36, 0xb6, 0xf5, 0xc3, 0xc6, 0xf6, 0x91, 0x96, 0xf0, 0x72,
1440
+	0x61, 0xb1, 0xc6, 0x8c, 0xc7, 0x29, 0x1b, 0xbe, 0x8a, 0xc2, 0x0b, 0xfd, 0x1a, 0x90, 0x73, 0x14,
1441
+	0xfe, 0x56, 0x4d, 0xfb, 0xf3, 0xdb, 0x12, 0xac, 0x90, 0xed, 0x85, 0x37, 0x05, 0x29, 0x5d, 0x36,
1442
+	0x68, 0x5d, 0xc4, 0xe6, 0x96, 0xc1, 0x66, 0x85, 0xe2, 0xd5, 0x1c, 0xc5, 0x0b, 0x2b, 0xa8, 0x7d,
1443
+	0xc4, 0x0a, 0xdc, 0xdf, 0x94, 0xa1, 0xf9, 0x92, 0xf1, 0xb3, 0x38, 0x3d, 0x11, 0x27, 0x56, 0xb6,
1444
+	0xb0, 0x39, 0xbd, 0x01, 0x6b, 0xe9, 0x79, 0xff, 0xf8, 0x82, 0x1b, 0x84, 0x5e, 0x4d, 0xcf, 0x9f,
1445
+	0x0a, 0xd2, 0xb9, 0x0d, 0x80, 0x43, 0x07, 0xbe, 0x6c, 0x48, 0x15, 0x40, 0xa7, 0xe7, 0x8a, 0xe1,
1446
+	0xdc, 0x84, 0xba, 0x77, 0xde, 0xc7, 0xc6, 0x26, 0x4e, 0x33, 0x8d, 0xd0, 0xe9, 0xf9, 0x33, 0xa2,
1447
+	0xc5, 0x5c, 0x1c, 0x1c, 0xa6, 0x71, 0x92, 0xb0, 0x21, 0x21, 0x34, 0xcd, 0xdd, 0x93, 0x0c, 0x61,
1448
+	0xf5, 0x48, 0x5b, 0xad, 0x49, 0xab, 0x3c, 0xb7, 0x8a, 0x43, 0x89, 0xb2, 0x2a, 0xa1, 0xb9, 0xce,
1449
+	0x6d, 0xab, 0x47, 0xc6, 0xaa, 0xc4, 0xe5, 0x35, 0x6e, 0x59, 0x3d, 0xca, 0xad, 0xd6, 0xf5, 0x5c,
1450
+	0x65, 0xd5, 0xfd, 0x63, 0x09, 0xd6, 0xf0, 0x7c, 0x78, 0x93, 0xf9, 0x23, 0x86, 0xad, 0x64, 0x83,
1451
+	0xe3, 0x59, 0x12, 0xf6, 0xa7, 0x82, 0x54, 0xa7, 0x17, 0x10, 0x4b, 0x0a, 0xfc, 0x1f, 0x34, 0x13,
1452
+	0x96, 0xe2, 0xa9, 0xa1, 0x24, 0xca, 0x58, 0xcc, 0x78, 0x4a, 0x48, 0x9e, 0x14, 0xd9, 0x86, 0xab,
1453
+	0x34, 0xd6, 0x0f, 0xa2, 0xbe, 0x84, 0xe5, 0x49, 0x3c, 0x64, 0x2a, 0x54, 0x1d, 0x1a, 0xda, 0x8f,
1454
+	0xbe, 0x34, 0x03, 0xce, 0x37, 0xa1, 0x63, 0xe4, 0x45, 0xbb, 0x4a, 0xd2, 0x32, 0x74, 0xeb, 0x4a,
1455
+	0xfa, 0x8d, 0x62, 0x63, 0x0d, 0xeb, 0x1a, 0x0a, 0xa2, 0xd1, 0x9e, 0x8f, 0xa7, 0x1e, 0xb6, 0x32,
1456
+	0x09, 0x9d, 0x8d, 0x99, 0xf2, 0x56, 0x93, 0xce, 0xb7, 0xa0, 0xc3, 0x55, 0xbd, 0x0d, 0xfb, 0x5a,
1457
+	0x46, 0xee, 0xe6, 0x86, 0x19, 0x38, 0x50, 0xc2, 0xff, 0x0f, 0xed, 0x5c, 0x98, 0x1a, 0x23, 0xe9,
1458
+	0x6f, 0xcb, 0x70, 0x45, 0x36, 0xb9, 0xbf, 0x97, 0xc1, 0x92, 0x99, 0xf3, 0x29, 0x1d, 0xd5, 0x56,
1459
+	0xa8, 0x1a, 0x3b, 0xeb, 0xba, 0xc5, 0x51, 0xc1, 0xa0, 0xe3, 0x59, 0x86, 0xe5, 0x07, 0xb0, 0xce,
1460
+	0x8d, 0xeb, 0x7d, 0xac, 0x54, 0x5f, 0x95, 0xde, 0x0c, 0x12, 0xaa, 0x85, 0x79, 0x6d, 0x5e, 0x5c,
1461
+	0x28, 0x46, 0x5e, 0xf6, 0xde, 0xca, 0xa0, 0xf4, 0xaf, 0x21, 0x79, 0x64, 0x02, 0xe1, 0xb1, 0x8e,
1462
+	0x8d, 0x79, 0x26, 0xbd, 0xc3, 0xc0, 0x0c, 0xa6, 0x69, 0x8a, 0xb5, 0xa7, 0x03, 0xa3, 0x48, 0x01,
1463
+	0x8f, 0xd4, 0xb7, 0xaa, 0x60, 0x48, 0xc2, 0x8d, 0x01, 0xe4, 0xd9, 0x49, 0xd6, 0x50, 0xc6, 0x4e,
1464
+	0x01, 0x49, 0x88, 0x3c, 0x9b, 0xf8, 0xe7, 0x66, 0xeb, 0x29, 0xcf, 0x90, 0x21, 0x17, 0x88, 0x06,
1465
+	0xdf, 0xf9, 0x41, 0x38, 0x50, 0x8f, 0x6e, 0x68, 0x50, 0x91, 0xb9, 0xc1, 0xaa, 0x6d, 0xf0, 0x0f,
1466
+	0x65, 0x68, 0x48, 0x8b, 0xd2, 0x61, 0x94, 0x1a, 0x60, 0x87, 0x67, 0x4c, 0x12, 0x81, 0x3d, 0xf8,
1467
+	0x4a, 0x6e, 0x2e, 0xbf, 0x8f, 0xe5, 0xae, 0x6a, 0xdf, 0xb0, 0xe3, 0xcc, 0xb0, 0x09, 0xb1, 0xa2,
1468
+	0xb3, 0x50, 0xba, 0x2e, 0x84, 0xa4, 0xc3, 0x9f, 0x41, 0x53, 0xe6, 0xa7, 0x9a, 0x53, 0x5d, 0x36,
1469
+	0xa7, 0x21, 0xc5, 0xe4, 0xac, 0x47, 0xe2, 0xda, 0x83, 0xfe, 0x52, 0x9b, 0xdd, 0xd8, 0xb9, 0x5d,
1470
+	0x10, 0xa7, 0x95, 0x6c, 0xd3, 0xef, 0xb3, 0x88, 0x63, 0xbf, 0x23, 0x65, 0x7b, 0x8f, 0x01, 0x72,
1471
+	0xa6, 0xc0, 0xb3, 0x13, 0x76, 0xa1, 0xaf, 0x77, 0xf8, 0x29, 0xd6, 0x7e, 0xea, 0x87, 0x53, 0x1d,
1472
+	0x54, 0x49, 0x7c, 0xaf, 0xfc, 0xb8, 0xe4, 0x0e, 0x60, 0xfd, 0xa9, 0x38, 0x12, 0xad, 0xe9, 0x85,
1473
+	0x43, 0xaf, 0xba, 0xf0, 0xd0, 0xab, 0xea, 0xb7, 0x62, 0x84, 0xd8, 0x38, 0x51, 0xad, 0x2e, 0x7e,
1474
+	0xe5, 0x86, 0xaa, 0x96, 0x21, 0xf7, 0xef, 0x55, 0x80, 0xdc, 0x8a, 0x73, 0x08, 0xbd, 0x20, 0xee,
1475
+	0x8b, 0x4e, 0x0d, 0x4f, 0x1b, 0x09, 0x48, 0xfd, 0x94, 0x61, 0xfa, 0x64, 0xc1, 0x29, 0x53, 0xcd,
1476
+	0xfc, 0x96, 0x39, 0xa6, 0x0a, 0xce, 0x79, 0xd7, 0x91, 0x92, 0x13, 0x09, 0xb9, 0x3c, 0x3d, 0xcd,
1477
+	0xf9, 0x31, 0x5c, 0xcb, 0x95, 0x0e, 0x2d, 0x7d, 0xe5, 0x4b, 0xf5, 0x5d, 0x35, 0xfa, 0x86, 0xb9,
1478
+	0xae, 0x1f, 0x02, 0xb2, 0xfb, 0x78, 0x98, 0x4d, 0x0b, 0x9a, 0x2a, 0x97, 0x6a, 0xea, 0x04, 0xf1,
1479
+	0x6b, 0x9a, 0x91, 0xeb, 0x79, 0x0d, 0x37, 0xac, 0x85, 0x8a, 0xb2, 0xb7, 0xb4, 0x55, 0x2f, 0xd5,
1480
+	0xb6, 0x65, 0xfc, 0x12, 0xc0, 0x90, 0xab, 0xfc, 0x12, 0x70, 0xa4, 0x7f, 0xe6, 0x07, 0x7c, 0x56,
1481
+	0xdf, 0xca, 0xfb, 0xd6, 0xf9, 0x16, 0x27, 0x15, 0x95, 0xc9, 0x75, 0x4e, 0x58, 0x3a, 0x2a, 0xac,
1482
+	0xb3, 0xf6, 0xbe, 0x75, 0xbe, 0xa0, 0x19, 0xb9, 0x9e, 0xa7, 0x80, 0xcc, 0x59, 0x7f, 0x56, 0x2f,
1483
+	0xd5, 0xb2, 0x8e, 0x5d, 0x58, 0xc1, 0x97, 0x5d, 0xe8, 0x64, 0x6c, 0x80, 0x47, 0xbd, 0x9d, 0x0b,
1484
+	0x6b, 0x97, 0xea, 0xd8, 0x50, 0x13, 0x8c, 0x12, 0xf7, 0x2b, 0x68, 0xfe, 0x68, 0x3a, 0x62, 0x3c,
1485
+	0x3c, 0x36, 0x35, 0xff, 0x9f, 0x86, 0x99, 0x7f, 0x22, 0xcc, 0xec, 0x8e, 0xd2, 0x78, 0x9a, 0x14,
1486
+	0x50, 0x5b, 0xd6, 0xf0, 0x1c, 0x6a, 0x93, 0x0c, 0xa1, 0xb6, 0x94, 0xfe, 0x1c, 0x9a, 0xf2, 0xe6,
1487
+	0xa2, 0x26, 0x48, 0x14, 0x72, 0xe6, 0x8b, 0x5e, 0xdf, 0x94, 0xe4, 0xb4, 0x1d, 0x75, 0x0b, 0x54,
1488
+	0xb3, 0x8a, 0x68, 0x94, 0x87, 0xc9, 0x83, 0xe3, 0xbc, 0xea, 0xf6, 0xa1, 0x35, 0x96, 0xb1, 0x51,
1489
+	0xb3, 0x64, 0x02, 0x7e, 0xa2, 0x9d, 0xcb, 0xd7, 0xb0, 0x6d, 0xc7, 0x50, 0x86, 0xba, 0x39, 0xb6,
1490
+	0xc3, 0xfa, 0x00, 0x40, 0xdc, 0xf3, 0xfb, 0x1a, 0xa8, 0xec, 0x67, 0x7e, 0x73, 0x42, 0x78, 0xf5,
1491
+	0x44, 0x7f, 0xf6, 0x8e, 0xa0, 0x33, 0xa7, 0x73, 0x01, 0x4c, 0x7d, 0xc3, 0x86, 0xa9, 0xfc, 0x6a,
1492
+	0x64, 0x4f, 0xb5, 0xb1, 0xeb, 0x2f, 0x25, 0xf9, 0x2c, 0x60, 0x5e, 0x62, 0xb1, 0x6f, 0x6b, 0x45,
1493
+	0xb2, 0xf9, 0x32, 0x1b, 0x60, 0xdf, 0xb1, 0xec, 0xc6, 0xcc, 0x6b, 0x46, 0x76, 0x9b, 0x86, 0x1b,
1494
+	0x31, 0xa0, 0x08, 0x2c, 0xdc, 0x08, 0x2b, 0x38, 0x5e, 0x63, 0x60, 0xed, 0x76, 0xa1, 0x51, 0xac,
1495
+	0x7e, 0x4c, 0xa3, 0xa8, 0x5e, 0xf6, 0x96, 0xfd, 0x2d, 0xb1, 0x83, 0x77, 0xff, 0xca, 0x93, 0x83,
1496
+	0x7d, 0xbc, 0xf7, 0x6d, 0xcc, 0xfe, 0xab, 0xe7, 0xdc, 0x51, 0x6e, 0x2d, 0xf9, 0x27, 0xb0, 0x77,
1497
+	0x77, 0xe9, 0xb8, 0x6a, 0xd9, 0xaf, 0x38, 0x1e, 0xac, 0xcf, 0xfc, 0x87, 0xe3, 0xe8, 0xa3, 0x66,
1498
+	0xf1, 0xff, 0x64, 0xbd, 0x3b, 0xcb, 0x86, 0x6d, 0x9d, 0x33, 0x77, 0x04, 0xa3, 0x73, 0xf1, 0x7b,
1499
+	0x8a, 0xd1, 0xb9, 0xec, 0x6a, 0x71, 0xc5, 0xf9, 0x2e, 0xd4, 0xe4, 0xbf, 0x3a, 0x8e, 0xbe, 0xb8,
1500
+	0x14, 0xfe, 0x2f, 0xea, 0x5d, 0x9b, 0xe1, 0x9a, 0x89, 0xcf, 0xa1, 0x55, 0xf8, 0x2b, 0xd0, 0xb9,
1501
+	0x59, 0xb0, 0x55, 0xfc, 0x53, 0xa8, 0x77, 0x6b, 0xf1, 0xa0, 0xd1, 0xb6, 0x0b, 0x90, 0x3f, 0xfc,
1502
+	0x3b, 0x5d, 0x25, 0x3d, 0xf7, 0xe7, 0x52, 0xef, 0xc6, 0x82, 0x11, 0xa3, 0x04, 0xb7, 0x72, 0xf6,
1503
+	0x89, 0xde, 0x99, 0x89, 0xea, 0xec, 0x03, 0xb9, 0xd9, 0xca, 0xa5, 0x6f, 0xfb, 0xa4, 0x76, 0xf6,
1504
+	0xe1, 0xdd, 0xa8, 0x5d, 0xf2, 0xec, 0x6f, 0xd4, 0x2e, 0x7d, 0xb1, 0xbf, 0xe2, 0xbc, 0x82, 0x76,
1505
+	0xf1, 0x25, 0xdb, 0xd1, 0x41, 0x5a, 0xf8, 0x94, 0xdf, 0xbb, 0xbd, 0x64, 0xd4, 0x28, 0xfc, 0x0c,
1506
+	0x56, 0xe4, 0x13, 0xb5, 0x2e, 0x47, 0xfb, 0x65, 0xbb, 0xb7, 0x59, 0x64, 0x9a, 0x59, 0x0f, 0xa1,
1507
+	0x26, 0x6f, 0x97, 0x26, 0x01, 0x0a, 0x97, 0xcd, 0x5e, 0xd3, 0xe6, 0xba, 0x57, 0x1e, 0x96, 0xb4,
1508
+	0x9d, 0xac, 0x60, 0x27, 0x5b, 0x64, 0xc7, 0xda, 0x9c, 0xe3, 0x1a, 0x95, 0xeb, 0xa3, 0x7f, 0x05,
1509
+	0x00, 0x00, 0xff, 0xff, 0xa7, 0x2d, 0xc6, 0x49, 0x94, 0x1f, 0x00, 0x00,
1498 1510
 }
... ...
@@ -192,7 +192,7 @@ message UpdateContainerRequest {
192 192
 }
193 193
 
194 194
 message UpdateResource {
195
-	uint64 blkioWeight =1;
195
+	uint64 blkioWeight = 1;
196 196
 	uint64 cpuShares = 2;
197 197
 	uint64 cpuPeriod = 3;
198 198
 	uint64 cpuQuota = 4;
... ...
@@ -203,6 +203,28 @@ message UpdateResource {
203 203
 	uint64 memoryReservation = 9;
204 204
 	uint64 kernelMemoryLimit = 10;
205 205
 	uint64 kernelTCPMemoryLimit = 11;
206
+	uint64 blkioLeafWeight = 12;
207
+	repeated WeightDevice blkioWeightDevice = 13;
208
+	repeated ThrottleDevice blkioThrottleReadBpsDevice = 14;
209
+	repeated ThrottleDevice blkioThrottleWriteBpsDevice = 15;
210
+	repeated ThrottleDevice blkioThrottleReadIopsDevice = 16;
211
+	repeated ThrottleDevice blkioThrottleWriteIopsDevice = 17;
212
+}
213
+
214
+message BlockIODevice {
215
+	int64 major = 1;
216
+	int64 minor = 2;
217
+}
218
+
219
+message WeightDevice {
220
+	BlockIODevice blkIODevice = 1;
221
+	uint32 weight = 2;
222
+	uint32 leafWeight = 3;
223
+}
224
+
225
+message ThrottleDevice {
226
+	BlockIODevice blkIODevice = 1;
227
+	uint64 rate = 2;
206 228
 }
207 229
 
208 230
 message UpdateContainerResponse {