Signed-off-by: boucher <rboucher@gmail.com>
| ... | ... |
@@ -5,6 +5,6 @@ import "github.com/docker/docker/api/types" |
| 5 | 5 |
// Backend for Checkpoint |
| 6 | 6 |
type Backend interface {
|
| 7 | 7 |
CheckpointCreate(container string, config types.CheckpointCreateOptions) error |
| 8 |
- CheckpointDelete(container string, checkpointID string) error |
|
| 9 |
- CheckpointList(container string) ([]types.Checkpoint, error) |
|
| 8 |
+ CheckpointDelete(container string, config types.CheckpointDeleteOptions) error |
|
| 9 |
+ CheckpointList(container string, config types.CheckpointListOptions) ([]types.Checkpoint, error) |
|
| 10 | 10 |
} |
| ... | ... |
@@ -35,7 +35,10 @@ func (s *checkpointRouter) getContainerCheckpoints(ctx context.Context, w http.R |
| 35 | 35 |
return err |
| 36 | 36 |
} |
| 37 | 37 |
|
| 38 |
- checkpoints, err := s.backend.CheckpointList(vars["name"]) |
|
| 38 |
+ checkpoints, err := s.backend.CheckpointList(vars["name"], types.CheckpointListOptions{
|
|
| 39 |
+ CheckpointDir: r.Form.Get("dir"),
|
|
| 40 |
+ }) |
|
| 41 |
+ |
|
| 39 | 42 |
if err != nil {
|
| 40 | 43 |
return err |
| 41 | 44 |
} |
| ... | ... |
@@ -48,7 +51,11 @@ func (s *checkpointRouter) deleteContainerCheckpoint(ctx context.Context, w http |
| 48 | 48 |
return err |
| 49 | 49 |
} |
| 50 | 50 |
|
| 51 |
- err := s.backend.CheckpointDelete(vars["name"], vars["checkpoint"]) |
|
| 51 |
+ err := s.backend.CheckpointDelete(vars["name"], types.CheckpointDeleteOptions{
|
|
| 52 |
+ CheckpointDir: r.Form.Get("dir"),
|
|
| 53 |
+ CheckpointID: vars["checkpoint"], |
|
| 54 |
+ }) |
|
| 55 |
+ |
|
| 52 | 56 |
if err != nil {
|
| 53 | 57 |
return err |
| 54 | 58 |
} |
| ... | ... |
@@ -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, checkpoint string) error |
|
| 42 |
+ ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string, checkpointDir 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) |
| ... | ... |
@@ -155,8 +155,9 @@ func (s *containerRouter) postContainersStart(ctx context.Context, w http.Respon |
| 155 | 155 |
} |
| 156 | 156 |
|
| 157 | 157 |
checkpoint := r.Form.Get("checkpoint")
|
| 158 |
+ checkpointDir := r.Form.Get("checkpoint-dir")
|
|
| 158 | 159 |
validateHostname := versions.GreaterThanOrEqualTo(version, "1.24") |
| 159 |
- if err := s.backend.ContainerStart(vars["name"], hostConfig, validateHostname, checkpoint); err != nil {
|
|
| 160 |
+ if err := s.backend.ContainerStart(vars["name"], hostConfig, validateHostname, checkpoint, checkpointDir); err != nil {
|
|
| 160 | 161 |
return err |
| 161 | 162 |
} |
| 162 | 163 |
|
| ... | ... |
@@ -12,8 +12,20 @@ import ( |
| 12 | 12 |
|
| 13 | 13 |
// CheckpointCreateOptions holds parameters to create a checkpoint from a container |
| 14 | 14 |
type CheckpointCreateOptions struct {
|
| 15 |
- CheckpointID string |
|
| 16 |
- Exit bool |
|
| 15 |
+ CheckpointID string |
|
| 16 |
+ CheckpointDir string |
|
| 17 |
+ Exit bool |
|
| 18 |
+} |
|
| 19 |
+ |
|
| 20 |
+// CheckpointListOptions holds parameters to list checkpoints for a container |
|
| 21 |
+type CheckpointListOptions struct {
|
|
| 22 |
+ CheckpointDir string |
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+// CheckpointDeleteOptions holds parameters to delete a checkpoint from a container |
|
| 26 |
+type CheckpointDeleteOptions struct {
|
|
| 27 |
+ CheckpointID string |
|
| 28 |
+ CheckpointDir string |
|
| 17 | 29 |
} |
| 18 | 30 |
|
| 19 | 31 |
// ContainerAttachOptions holds parameters to attach to a container. |
| ... | ... |
@@ -77,7 +89,8 @@ type ContainerRemoveOptions struct {
|
| 77 | 77 |
|
| 78 | 78 |
// ContainerStartOptions holds parameters to start containers. |
| 79 | 79 |
type ContainerStartOptions struct {
|
| 80 |
- CheckpointID string |
|
| 80 |
+ CheckpointID string |
|
| 81 |
+ CheckpointDir string |
|
| 81 | 82 |
} |
| 82 | 83 |
|
| 83 | 84 |
// CopyToContainerOptions holds information |
| ... | ... |
@@ -124,7 +124,7 @@ 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, checkpoint string) error |
|
| 127 |
+ ContainerStart(containerID string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string, checkpointDir 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 |
| ... | ... |
@@ -537,7 +537,7 @@ func (b *Builder) run(cID string) (err error) {
|
| 537 | 537 |
} |
| 538 | 538 |
}() |
| 539 | 539 |
|
| 540 |
- if err := b.docker.ContainerStart(cID, nil, true, ""); err != nil {
|
|
| 540 |
+ if err := b.docker.ContainerStart(cID, nil, true, "", ""); err != nil {
|
|
| 541 | 541 |
close(finished) |
| 542 | 542 |
if cancelErr := <-cancelErrCh; cancelErr != nil {
|
| 543 | 543 |
logrus.Debugf("Build cancelled (%v) and got an error from ContainerStart: %v",
|
| ... | ... |
@@ -10,9 +10,10 @@ import ( |
| 10 | 10 |
) |
| 11 | 11 |
|
| 12 | 12 |
type createOptions struct {
|
| 13 |
- container string |
|
| 14 |
- checkpoint string |
|
| 15 |
- leaveRunning bool |
|
| 13 |
+ container string |
|
| 14 |
+ checkpoint string |
|
| 15 |
+ checkpointDir string |
|
| 16 |
+ leaveRunning bool |
|
| 16 | 17 |
} |
| 17 | 18 |
|
| 18 | 19 |
func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| ... | ... |
@@ -31,6 +32,7 @@ func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 31 | 31 |
|
| 32 | 32 |
flags := cmd.Flags() |
| 33 | 33 |
flags.BoolVar(&opts.leaveRunning, "leave-running", false, "leave the container running after checkpoint") |
| 34 |
+ flags.StringVarP(&opts.checkpointDir, "checkpoint-dir", "", "", "use a custom checkpoint storage directory") |
|
| 34 | 35 |
|
| 35 | 36 |
return cmd |
| 36 | 37 |
} |
| ... | ... |
@@ -39,8 +41,9 @@ func runCreate(dockerCli *command.DockerCli, opts createOptions) error {
|
| 39 | 39 |
client := dockerCli.Client() |
| 40 | 40 |
|
| 41 | 41 |
checkpointOpts := types.CheckpointCreateOptions{
|
| 42 |
- CheckpointID: opts.checkpoint, |
|
| 43 |
- Exit: !opts.leaveRunning, |
|
| 42 |
+ CheckpointID: opts.checkpoint, |
|
| 43 |
+ CheckpointDir: opts.checkpointDir, |
|
| 44 |
+ Exit: !opts.leaveRunning, |
|
| 44 | 45 |
} |
| 45 | 46 |
|
| 46 | 47 |
err := client.CheckpointCreate(context.Background(), opts.container, checkpointOpts) |
| ... | ... |
@@ -6,27 +6,44 @@ import ( |
| 6 | 6 |
|
| 7 | 7 |
"golang.org/x/net/context" |
| 8 | 8 |
|
| 9 |
+ "github.com/docker/docker/api/types" |
|
| 9 | 10 |
"github.com/docker/docker/cli" |
| 10 | 11 |
"github.com/docker/docker/cli/command" |
| 11 | 12 |
"github.com/spf13/cobra" |
| 12 | 13 |
) |
| 13 | 14 |
|
| 15 |
+type listOptions struct {
|
|
| 16 |
+ checkpointDir string |
|
| 17 |
+} |
|
| 18 |
+ |
|
| 14 | 19 |
func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 15 |
- return &cobra.Command{
|
|
| 20 |
+ var opts listOptions |
|
| 21 |
+ |
|
| 22 |
+ cmd := &cobra.Command{
|
|
| 16 | 23 |
Use: "ls CONTAINER", |
| 17 | 24 |
Aliases: []string{"list"},
|
| 18 | 25 |
Short: "List checkpoints for a container", |
| 19 | 26 |
Args: cli.ExactArgs(1), |
| 20 | 27 |
RunE: func(cmd *cobra.Command, args []string) error {
|
| 21 |
- return runList(dockerCli, args[0]) |
|
| 28 |
+ return runList(dockerCli, args[0], opts) |
|
| 22 | 29 |
}, |
| 23 | 30 |
} |
| 31 |
+ |
|
| 32 |
+ flags := cmd.Flags() |
|
| 33 |
+ flags.StringVarP(&opts.checkpointDir, "checkpoint-dir", "", "", "use a custom checkpoint storage directory") |
|
| 34 |
+ |
|
| 35 |
+ return cmd |
|
| 36 |
+ |
|
| 24 | 37 |
} |
| 25 | 38 |
|
| 26 |
-func runList(dockerCli *command.DockerCli, container string) error {
|
|
| 39 |
+func runList(dockerCli *command.DockerCli, container string, opts listOptions) error {
|
|
| 27 | 40 |
client := dockerCli.Client() |
| 28 | 41 |
|
| 29 |
- checkpoints, err := client.CheckpointList(context.Background(), container) |
|
| 42 |
+ listOpts := types.CheckpointListOptions{
|
|
| 43 |
+ CheckpointDir: opts.checkpointDir, |
|
| 44 |
+ } |
|
| 45 |
+ |
|
| 46 |
+ checkpoints, err := client.CheckpointList(context.Background(), container, listOpts) |
|
| 30 | 47 |
if err != nil {
|
| 31 | 48 |
return err |
| 32 | 49 |
} |
| ... | ... |
@@ -3,24 +3,42 @@ package checkpoint |
| 3 | 3 |
import ( |
| 4 | 4 |
"golang.org/x/net/context" |
| 5 | 5 |
|
| 6 |
+ "github.com/docker/docker/api/types" |
|
| 6 | 7 |
"github.com/docker/docker/cli" |
| 7 | 8 |
"github.com/docker/docker/cli/command" |
| 8 | 9 |
"github.com/spf13/cobra" |
| 9 | 10 |
) |
| 10 | 11 |
|
| 12 |
+type removeOptions struct {
|
|
| 13 |
+ checkpointDir string |
|
| 14 |
+} |
|
| 15 |
+ |
|
| 11 | 16 |
func newRemoveCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 12 |
- return &cobra.Command{
|
|
| 17 |
+ var opts removeOptions |
|
| 18 |
+ |
|
| 19 |
+ cmd := &cobra.Command{
|
|
| 13 | 20 |
Use: "rm CONTAINER CHECKPOINT", |
| 14 | 21 |
Aliases: []string{"remove"},
|
| 15 | 22 |
Short: "Remove a checkpoint", |
| 16 | 23 |
Args: cli.ExactArgs(2), |
| 17 | 24 |
RunE: func(cmd *cobra.Command, args []string) error {
|
| 18 |
- return runRemove(dockerCli, args[0], args[1]) |
|
| 25 |
+ return runRemove(dockerCli, args[0], args[1], opts) |
|
| 19 | 26 |
}, |
| 20 | 27 |
} |
| 28 |
+ |
|
| 29 |
+ flags := cmd.Flags() |
|
| 30 |
+ flags.StringVarP(&opts.checkpointDir, "checkpoint-dir", "", "", "use a custom checkpoint storage directory") |
|
| 31 |
+ |
|
| 32 |
+ return cmd |
|
| 21 | 33 |
} |
| 22 | 34 |
|
| 23 |
-func runRemove(dockerCli *command.DockerCli, container string, checkpoint string) error {
|
|
| 35 |
+func runRemove(dockerCli *command.DockerCli, container string, checkpoint string, opts removeOptions) error {
|
|
| 24 | 36 |
client := dockerCli.Client() |
| 25 |
- return client.CheckpointDelete(context.Background(), container, checkpoint) |
|
| 37 |
+ |
|
| 38 |
+ removeOpts := types.CheckpointDeleteOptions{
|
|
| 39 |
+ CheckpointID: checkpoint, |
|
| 40 |
+ CheckpointDir: opts.checkpointDir, |
|
| 41 |
+ } |
|
| 42 |
+ |
|
| 43 |
+ return client.CheckpointDelete(context.Background(), container, removeOpts) |
|
| 26 | 44 |
} |
| ... | ... |
@@ -17,10 +17,11 @@ import ( |
| 17 | 17 |
) |
| 18 | 18 |
|
| 19 | 19 |
type startOptions struct {
|
| 20 |
- attach bool |
|
| 21 |
- openStdin bool |
|
| 22 |
- detachKeys string |
|
| 23 |
- checkpoint string |
|
| 20 |
+ attach bool |
|
| 21 |
+ openStdin bool |
|
| 22 |
+ detachKeys string |
|
| 23 |
+ checkpoint string |
|
| 24 |
+ checkpointDir string |
|
| 24 | 25 |
|
| 25 | 26 |
containers []string |
| 26 | 27 |
} |
| ... | ... |
@@ -46,6 +47,7 @@ func NewStartCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 46 | 46 |
|
| 47 | 47 |
if dockerCli.HasExperimental() {
|
| 48 | 48 |
flags.StringVar(&opts.checkpoint, "checkpoint", "", "Restore from this checkpoint") |
| 49 |
+ flags.StringVar(&opts.checkpointDir, "checkpoint-dir", "", "Use a custom checkpoint storage directory") |
|
| 49 | 50 |
} |
| 50 | 51 |
|
| 51 | 52 |
return cmd |
| ... | ... |
@@ -112,7 +114,8 @@ func runStart(dockerCli *command.DockerCli, opts *startOptions) error {
|
| 112 | 112 |
// no matter it's detached, removed on daemon side(--rm) or exit normally. |
| 113 | 113 |
statusChan := waitExitOrRemoved(dockerCli, ctx, c.ID, c.HostConfig.AutoRemove) |
| 114 | 114 |
startOptions := types.ContainerStartOptions{
|
| 115 |
- CheckpointID: opts.checkpoint, |
|
| 115 |
+ CheckpointID: opts.checkpoint, |
|
| 116 |
+ CheckpointDir: opts.checkpointDir, |
|
| 116 | 117 |
} |
| 117 | 118 |
|
| 118 | 119 |
// 4. Start the container. |
| ... | ... |
@@ -145,7 +148,8 @@ func runStart(dockerCli *command.DockerCli, opts *startOptions) error {
|
| 145 | 145 |
} |
| 146 | 146 |
container := opts.containers[0] |
| 147 | 147 |
startOptions := types.ContainerStartOptions{
|
| 148 |
- CheckpointID: opts.checkpoint, |
|
| 148 |
+ CheckpointID: opts.checkpoint, |
|
| 149 |
+ CheckpointDir: opts.checkpointDir, |
|
| 149 | 150 |
} |
| 150 | 151 |
return dockerCli.Client().ContainerStart(ctx, container, startOptions) |
| 151 | 152 |
|
| ... | ... |
@@ -1,12 +1,20 @@ |
| 1 | 1 |
package client |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "net/url" |
|
| 5 |
+ |
|
| 6 |
+ "github.com/docker/docker/api/types" |
|
| 4 | 7 |
"golang.org/x/net/context" |
| 5 | 8 |
) |
| 6 | 9 |
|
| 7 | 10 |
// CheckpointDelete deletes the checkpoint with the given name from the given container |
| 8 |
-func (cli *Client) CheckpointDelete(ctx context.Context, containerID string, checkpointID string) error {
|
|
| 9 |
- resp, err := cli.delete(ctx, "/containers/"+containerID+"/checkpoints/"+checkpointID, nil, nil) |
|
| 11 |
+func (cli *Client) CheckpointDelete(ctx context.Context, containerID string, options types.CheckpointDeleteOptions) error {
|
|
| 12 |
+ query := url.Values{}
|
|
| 13 |
+ if options.CheckpointDir != "" {
|
|
| 14 |
+ query.Set("dir", options.CheckpointDir)
|
|
| 15 |
+ } |
|
| 16 |
+ |
|
| 17 |
+ resp, err := cli.delete(ctx, "/containers/"+containerID+"/checkpoints/"+options.CheckpointID, query, nil) |
|
| 10 | 18 |
ensureReaderClosed(resp) |
| 11 | 19 |
return err |
| 12 | 20 |
} |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"strings" |
| 9 | 9 |
"testing" |
| 10 | 10 |
|
| 11 |
+ "github.com/docker/docker/api/types" |
|
| 11 | 12 |
"golang.org/x/net/context" |
| 12 | 13 |
) |
| 13 | 14 |
|
| ... | ... |
@@ -16,7 +17,10 @@ func TestCheckpointDeleteError(t *testing.T) {
|
| 16 | 16 |
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), |
| 17 | 17 |
} |
| 18 | 18 |
|
| 19 |
- err := client.CheckpointDelete(context.Background(), "container_id", "checkpoint_id") |
|
| 19 |
+ err := client.CheckpointDelete(context.Background(), "container_id", types.CheckpointDeleteOptions{
|
|
| 20 |
+ CheckpointID: "checkpoint_id", |
|
| 21 |
+ }) |
|
| 22 |
+ |
|
| 20 | 23 |
if err == nil || err.Error() != "Error response from daemon: Server error" {
|
| 21 | 24 |
t.Fatalf("expected a Server Error, got %v", err)
|
| 22 | 25 |
} |
| ... | ... |
@@ -40,7 +44,10 @@ func TestCheckpointDelete(t *testing.T) {
|
| 40 | 40 |
}), |
| 41 | 41 |
} |
| 42 | 42 |
|
| 43 |
- err := client.CheckpointDelete(context.Background(), "container_id", "checkpoint_id") |
|
| 43 |
+ err := client.CheckpointDelete(context.Background(), "container_id", types.CheckpointDeleteOptions{
|
|
| 44 |
+ CheckpointID: "checkpoint_id", |
|
| 45 |
+ }) |
|
| 46 |
+ |
|
| 44 | 47 |
if err != nil {
|
| 45 | 48 |
t.Fatal(err) |
| 46 | 49 |
} |
| ... | ... |
@@ -2,16 +2,22 @@ package client |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 |
+ "net/url" |
|
| 5 | 6 |
|
| 6 | 7 |
"github.com/docker/docker/api/types" |
| 7 | 8 |
"golang.org/x/net/context" |
| 8 | 9 |
) |
| 9 | 10 |
|
| 10 | 11 |
// CheckpointList returns the volumes configured in the docker host. |
| 11 |
-func (cli *Client) CheckpointList(ctx context.Context, container string) ([]types.Checkpoint, error) {
|
|
| 12 |
+func (cli *Client) CheckpointList(ctx context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) {
|
|
| 12 | 13 |
var checkpoints []types.Checkpoint |
| 13 | 14 |
|
| 14 |
- resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", nil, nil) |
|
| 15 |
+ query := url.Values{}
|
|
| 16 |
+ if options.CheckpointDir != "" {
|
|
| 17 |
+ query.Set("dir", options.CheckpointDir)
|
|
| 18 |
+ } |
|
| 19 |
+ |
|
| 20 |
+ resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil) |
|
| 15 | 21 |
if err != nil {
|
| 16 | 22 |
return checkpoints, err |
| 17 | 23 |
} |
| ... | ... |
@@ -18,7 +18,7 @@ func TestCheckpointListError(t *testing.T) {
|
| 18 | 18 |
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), |
| 19 | 19 |
} |
| 20 | 20 |
|
| 21 |
- _, err := client.CheckpointList(context.Background(), "container_id") |
|
| 21 |
+ _, err := client.CheckpointList(context.Background(), "container_id", types.CheckpointListOptions{})
|
|
| 22 | 22 |
if err == nil || err.Error() != "Error response from daemon: Server error" {
|
| 23 | 23 |
t.Fatalf("expected a Server Error, got %v", err)
|
| 24 | 24 |
} |
| ... | ... |
@@ -47,7 +47,7 @@ func TestCheckpointList(t *testing.T) {
|
| 47 | 47 |
}), |
| 48 | 48 |
} |
| 49 | 49 |
|
| 50 |
- checkpoints, err := client.CheckpointList(context.Background(), "container_id") |
|
| 50 |
+ checkpoints, err := client.CheckpointList(context.Background(), "container_id", types.CheckpointListOptions{})
|
|
| 51 | 51 |
if err != nil {
|
| 52 | 52 |
t.Fatal(err) |
| 53 | 53 |
} |
| ... | ... |
@@ -14,6 +14,9 @@ func (cli *Client) ContainerStart(ctx context.Context, containerID string, optio |
| 14 | 14 |
if len(options.CheckpointID) != 0 {
|
| 15 | 15 |
query.Set("checkpoint", options.CheckpointID)
|
| 16 | 16 |
} |
| 17 |
+ if len(options.CheckpointDir) != 0 {
|
|
| 18 |
+ query.Set("checkpoint-dir", options.CheckpointDir)
|
|
| 19 |
+ } |
|
| 17 | 20 |
|
| 18 | 21 |
resp, err := cli.post(ctx, "/containers/"+containerID+"/start", query, nil, nil) |
| 19 | 22 |
ensureReaderClosed(resp) |
| ... | ... |
@@ -13,8 +13,8 @@ type apiClientExperimental interface {
|
| 13 | 13 |
// CheckpointAPIClient defines API client methods for the checkpoints |
| 14 | 14 |
type CheckpointAPIClient interface {
|
| 15 | 15 |
CheckpointCreate(ctx context.Context, container string, options types.CheckpointCreateOptions) error |
| 16 |
- CheckpointDelete(ctx context.Context, container string, checkpointID string) error |
|
| 17 |
- CheckpointList(ctx context.Context, container string) ([]types.Checkpoint, error) |
|
| 16 |
+ CheckpointDelete(ctx context.Context, container string, options types.CheckpointDeleteOptions) error |
|
| 17 |
+ CheckpointList(ctx context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) |
|
| 18 | 18 |
} |
| 19 | 19 |
|
| 20 | 20 |
// PluginAPIClient defines API client methods for the plugins |
| ... | ... |
@@ -21,7 +21,14 @@ func (daemon *Daemon) CheckpointCreate(name string, config types.CheckpointCreat |
| 21 | 21 |
return fmt.Errorf("Container %s not running", name)
|
| 22 | 22 |
} |
| 23 | 23 |
|
| 24 |
- err = daemon.containerd.CreateCheckpoint(container.ID, config.CheckpointID, container.CheckpointDir(), config.Exit) |
|
| 24 |
+ var checkpointDir string |
|
| 25 |
+ if config.CheckpointDir != "" {
|
|
| 26 |
+ checkpointDir = config.CheckpointDir |
|
| 27 |
+ } else {
|
|
| 28 |
+ checkpointDir = container.CheckpointDir() |
|
| 29 |
+ } |
|
| 30 |
+ |
|
| 31 |
+ err = daemon.containerd.CreateCheckpoint(container.ID, config.CheckpointID, checkpointDir, config.Exit) |
|
| 25 | 32 |
if err != nil {
|
| 26 | 33 |
return fmt.Errorf("Cannot checkpoint container %s: %s", name, err)
|
| 27 | 34 |
} |
| ... | ... |
@@ -32,18 +39,24 @@ func (daemon *Daemon) CheckpointCreate(name string, config types.CheckpointCreat |
| 32 | 32 |
} |
| 33 | 33 |
|
| 34 | 34 |
// CheckpointDelete deletes the specified checkpoint |
| 35 |
-func (daemon *Daemon) CheckpointDelete(name string, checkpoint string) error {
|
|
| 35 |
+func (daemon *Daemon) CheckpointDelete(name string, config types.CheckpointDeleteOptions) error {
|
|
| 36 | 36 |
container, err := daemon.GetContainer(name) |
| 37 | 37 |
if err != nil {
|
| 38 | 38 |
return err |
| 39 | 39 |
} |
| 40 | 40 |
|
| 41 |
- checkpointDir := container.CheckpointDir() |
|
| 42 |
- return os.RemoveAll(filepath.Join(checkpointDir, checkpoint)) |
|
| 41 |
+ var checkpointDir string |
|
| 42 |
+ if config.CheckpointDir != "" {
|
|
| 43 |
+ checkpointDir = config.CheckpointDir |
|
| 44 |
+ } else {
|
|
| 45 |
+ checkpointDir = container.CheckpointDir() |
|
| 46 |
+ } |
|
| 47 |
+ |
|
| 48 |
+ return os.RemoveAll(filepath.Join(checkpointDir, config.CheckpointID)) |
|
| 43 | 49 |
} |
| 44 | 50 |
|
| 45 | 51 |
// CheckpointList lists all checkpoints of the specified container |
| 46 |
-func (daemon *Daemon) CheckpointList(name string) ([]types.Checkpoint, error) {
|
|
| 52 |
+func (daemon *Daemon) CheckpointList(name string, config types.CheckpointListOptions) ([]types.Checkpoint, error) {
|
|
| 47 | 53 |
var out []types.Checkpoint |
| 48 | 54 |
|
| 49 | 55 |
container, err := daemon.GetContainer(name) |
| ... | ... |
@@ -51,7 +64,13 @@ func (daemon *Daemon) CheckpointList(name string) ([]types.Checkpoint, error) {
|
| 51 | 51 |
return nil, err |
| 52 | 52 |
} |
| 53 | 53 |
|
| 54 |
- checkpointDir := container.CheckpointDir() |
|
| 54 |
+ var checkpointDir string |
|
| 55 |
+ if config.CheckpointDir != "" {
|
|
| 56 |
+ checkpointDir = config.CheckpointDir |
|
| 57 |
+ } else {
|
|
| 58 |
+ checkpointDir = container.CheckpointDir() |
|
| 59 |
+ } |
|
| 60 |
+ |
|
| 55 | 61 |
if err := os.MkdirAll(checkpointDir, 0755); err != nil {
|
| 56 | 62 |
return nil, err |
| 57 | 63 |
} |
| ... | ... |
@@ -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, checkpoint string) error |
|
| 27 |
+ ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string, checkpointDir 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 |
| ... | ... |
@@ -224,7 +224,7 @@ func (c *containerAdapter) create(ctx context.Context) error {
|
| 224 | 224 |
func (c *containerAdapter) start(ctx context.Context) error {
|
| 225 | 225 |
version := httputils.VersionFromContext(ctx) |
| 226 | 226 |
validateHostname := versions.GreaterThanOrEqualTo(version, "1.24") |
| 227 |
- return c.backend.ContainerStart(c.container.name(), nil, validateHostname, "") |
|
| 227 |
+ return c.backend.ContainerStart(c.container.name(), nil, validateHostname, "", "") |
|
| 228 | 228 |
} |
| 229 | 229 |
|
| 230 | 230 |
func (c *containerAdapter) inspect(ctx context.Context) (types.ContainerJSON, error) {
|
| ... | ... |
@@ -305,7 +305,7 @@ func (daemon *Daemon) restore() error {
|
| 305 | 305 |
|
| 306 | 306 |
// Make sure networks are available before starting |
| 307 | 307 |
daemon.waitForNetworks(c) |
| 308 |
- if err := daemon.containerStart(c, "", true); err != nil {
|
|
| 308 |
+ if err := daemon.containerStart(c, "", "", true); err != nil {
|
|
| 309 | 309 |
logrus.Errorf("Failed to start container %s: %s", c.ID, err)
|
| 310 | 310 |
} |
| 311 | 311 |
close(chNotify) |
| ... | ... |
@@ -372,7 +372,7 @@ func (daemon *Daemon) RestartSwarmContainers() {
|
| 372 | 372 |
group.Add(1) |
| 373 | 373 |
go func(c *container.Container) {
|
| 374 | 374 |
defer group.Done() |
| 375 |
- if err := daemon.containerStart(c, "", true); err != nil {
|
|
| 375 |
+ if err := daemon.containerStart(c, "", "", true); err != nil {
|
|
| 376 | 376 |
logrus.Error(err) |
| 377 | 377 |
} |
| 378 | 378 |
}(c) |
| ... | ... |
@@ -62,7 +62,7 @@ func (daemon *Daemon) StateChanged(id string, e libcontainerd.StateInfo) error {
|
| 62 | 62 |
go func() {
|
| 63 | 63 |
err := <-wait |
| 64 | 64 |
if err == nil {
|
| 65 |
- if err = daemon.containerStart(c, "", false); err != nil {
|
|
| 65 |
+ if err = daemon.containerStart(c, "", "", false); err != nil {
|
|
| 66 | 66 |
logrus.Debugf("failed to restart contianer: %+v", err)
|
| 67 | 67 |
} |
| 68 | 68 |
} |
| ... | ... |
@@ -61,7 +61,7 @@ func (daemon *Daemon) containerRestart(container *container.Container, seconds i |
| 61 | 61 |
} |
| 62 | 62 |
} |
| 63 | 63 |
|
| 64 |
- if err := daemon.containerStart(container, "", true); err != nil {
|
|
| 64 |
+ if err := daemon.containerStart(container, "", "", true); err != nil {
|
|
| 65 | 65 |
return err |
| 66 | 66 |
} |
| 67 | 67 |
|
| ... | ... |
@@ -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, checkpoint string) error {
|
|
| 22 |
+func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig, validateHostname bool, checkpoint string, checkpointDir string) error {
|
|
| 23 | 23 |
if checkpoint != "" && !daemon.HasExperimental() {
|
| 24 | 24 |
return errors.NewBadRequestError(fmt.Errorf("checkpoint is only supported in experimental mode"))
|
| 25 | 25 |
} |
| ... | ... |
@@ -82,19 +82,19 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos |
| 82 | 82 |
return err |
| 83 | 83 |
} |
| 84 | 84 |
|
| 85 |
- return daemon.containerStart(container, checkpoint, true) |
|
| 85 |
+ return daemon.containerStart(container, checkpoint, checkpointDir, true) |
|
| 86 | 86 |
} |
| 87 | 87 |
|
| 88 | 88 |
// Start starts a container |
| 89 | 89 |
func (daemon *Daemon) Start(container *container.Container) error {
|
| 90 |
- return daemon.containerStart(container, "", true) |
|
| 90 |
+ return daemon.containerStart(container, "", "", true) |
|
| 91 | 91 |
} |
| 92 | 92 |
|
| 93 | 93 |
// containerStart prepares the container to run by setting up everything the |
| 94 | 94 |
// container needs, such as storage and networking, as well as links |
| 95 | 95 |
// between containers. The container is left waiting for a signal to |
| 96 | 96 |
// begin running. |
| 97 |
-func (daemon *Daemon) containerStart(container *container.Container, checkpoint string, resetRestartManager bool) (err error) {
|
|
| 97 |
+func (daemon *Daemon) containerStart(container *container.Container, checkpoint string, checkpointDir string, resetRestartManager bool) (err error) {
|
|
| 98 | 98 |
start := time.Now() |
| 99 | 99 |
container.Lock() |
| 100 | 100 |
defer container.Unlock() |
| ... | ... |
@@ -155,7 +155,11 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint |
| 155 | 155 |
container.ResetRestartManager(true) |
| 156 | 156 |
} |
| 157 | 157 |
|
| 158 |
- if err := daemon.containerd.Create(container.ID, checkpoint, container.CheckpointDir(), *spec, container.InitializeStdio, createOptions...); err != nil {
|
|
| 158 |
+ if checkpointDir == "" {
|
|
| 159 |
+ checkpointDir = container.CheckpointDir() |
|
| 160 |
+ } |
|
| 161 |
+ |
|
| 162 |
+ if err := daemon.containerd.Create(container.ID, checkpoint, checkpointDir, *spec, container.InitializeStdio, createOptions...); err != nil {
|
|
| 159 | 163 |
errDesc := grpc.ErrorDesc(err) |
| 160 | 164 |
logrus.Errorf("Create container failed with error: %s", errDesc)
|
| 161 | 165 |
// if we receive an internal error from the initial start of a container then lets |