1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #26709 from boucher/checkpoint-dir

Allow providing a custom storage directory for docker checkpoints
This commit is contained in:
Michael Crosby 2016-10-28 11:12:44 -07:00 committed by GitHub
commit b57f321a4a
24 changed files with 167 additions and 57 deletions

View file

@ -5,6 +5,6 @@ import "github.com/docker/docker/api/types"
// Backend for Checkpoint // Backend for Checkpoint
type Backend interface { type Backend interface {
CheckpointCreate(container string, config types.CheckpointCreateOptions) error CheckpointCreate(container string, config types.CheckpointCreateOptions) error
CheckpointDelete(container string, checkpointID string) error CheckpointDelete(container string, config types.CheckpointDeleteOptions) error
CheckpointList(container string) ([]types.Checkpoint, error) CheckpointList(container string, config types.CheckpointListOptions) ([]types.Checkpoint, error)
} }

View file

@ -35,7 +35,10 @@ func (s *checkpointRouter) getContainerCheckpoints(ctx context.Context, w http.R
return err return err
} }
checkpoints, err := s.backend.CheckpointList(vars["name"]) checkpoints, err := s.backend.CheckpointList(vars["name"], types.CheckpointListOptions{
CheckpointDir: r.Form.Get("dir"),
})
if err != nil { if err != nil {
return err return err
} }
@ -48,7 +51,11 @@ func (s *checkpointRouter) deleteContainerCheckpoint(ctx context.Context, w http
return err return err
} }
err := s.backend.CheckpointDelete(vars["name"], vars["checkpoint"]) err := s.backend.CheckpointDelete(vars["name"], types.CheckpointDeleteOptions{
CheckpointDir: r.Form.Get("dir"),
CheckpointID: vars["checkpoint"],
})
if err != nil { if err != nil {
return err return err
} }

View file

@ -39,7 +39,7 @@ type stateBackend interface {
ContainerResize(name string, height, width int) error ContainerResize(name string, height, width int) error
ContainerRestart(name string, seconds *int) error ContainerRestart(name string, seconds *int) error
ContainerRm(name string, config *types.ContainerRmConfig) error ContainerRm(name string, config *types.ContainerRmConfig) error
ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string) error ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string, checkpointDir string) error
ContainerStop(name string, seconds *int) error ContainerStop(name string, seconds *int) error
ContainerUnpause(name string) error ContainerUnpause(name string) error
ContainerUpdate(name string, hostConfig *container.HostConfig, validateHostname bool) (types.ContainerUpdateResponse, error) ContainerUpdate(name string, hostConfig *container.HostConfig, validateHostname bool) (types.ContainerUpdateResponse, error)

View file

@ -155,8 +155,9 @@ func (s *containerRouter) postContainersStart(ctx context.Context, w http.Respon
} }
checkpoint := r.Form.Get("checkpoint") checkpoint := r.Form.Get("checkpoint")
checkpointDir := r.Form.Get("checkpoint-dir")
validateHostname := versions.GreaterThanOrEqualTo(version, "1.24") validateHostname := versions.GreaterThanOrEqualTo(version, "1.24")
if err := s.backend.ContainerStart(vars["name"], hostConfig, validateHostname, checkpoint); err != nil { if err := s.backend.ContainerStart(vars["name"], hostConfig, validateHostname, checkpoint, checkpointDir); err != nil {
return err return err
} }

View file

@ -12,8 +12,20 @@ import (
// CheckpointCreateOptions holds parameters to create a checkpoint from a container // CheckpointCreateOptions holds parameters to create a checkpoint from a container
type CheckpointCreateOptions struct { type CheckpointCreateOptions struct {
CheckpointID string CheckpointID string
Exit bool CheckpointDir string
Exit bool
}
// CheckpointListOptions holds parameters to list checkpoints for a container
type CheckpointListOptions struct {
CheckpointDir string
}
// CheckpointDeleteOptions holds parameters to delete a checkpoint from a container
type CheckpointDeleteOptions struct {
CheckpointID string
CheckpointDir string
} }
// ContainerAttachOptions holds parameters to attach to a container. // ContainerAttachOptions holds parameters to attach to a container.
@ -77,7 +89,8 @@ type ContainerRemoveOptions struct {
// ContainerStartOptions holds parameters to start containers. // ContainerStartOptions holds parameters to start containers.
type ContainerStartOptions struct { type ContainerStartOptions struct {
CheckpointID string CheckpointID string
CheckpointDir string
} }
// CopyToContainerOptions holds information // CopyToContainerOptions holds information

View file

@ -124,7 +124,7 @@ type Backend interface {
// ContainerKill stops the container execution abruptly. // ContainerKill stops the container execution abruptly.
ContainerKill(containerID string, sig uint64) error ContainerKill(containerID string, sig uint64) error
// ContainerStart starts a new container // ContainerStart starts a new container
ContainerStart(containerID string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string) error ContainerStart(containerID string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string, checkpointDir string) error
// ContainerWait stops processing until the given container is stopped. // ContainerWait stops processing until the given container is stopped.
ContainerWait(containerID string, timeout time.Duration) (int, error) ContainerWait(containerID string, timeout time.Duration) (int, error)
// ContainerUpdateCmdOnBuild updates container.Path and container.Args // ContainerUpdateCmdOnBuild updates container.Path and container.Args

View file

@ -537,7 +537,7 @@ func (b *Builder) run(cID string) (err error) {
} }
}() }()
if err := b.docker.ContainerStart(cID, nil, true, ""); err != nil { if err := b.docker.ContainerStart(cID, nil, true, "", ""); err != nil {
close(finished) close(finished)
if cancelErr := <-cancelErrCh; cancelErr != nil { if cancelErr := <-cancelErrCh; cancelErr != nil {
logrus.Debugf("Build cancelled (%v) and got an error from ContainerStart: %v", logrus.Debugf("Build cancelled (%v) and got an error from ContainerStart: %v",

View file

@ -10,9 +10,10 @@ import (
) )
type createOptions struct { type createOptions struct {
container string container string
checkpoint string checkpoint string
leaveRunning bool checkpointDir string
leaveRunning bool
} }
func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command { func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
@ -31,6 +32,7 @@ func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
flags := cmd.Flags() flags := cmd.Flags()
flags.BoolVar(&opts.leaveRunning, "leave-running", false, "leave the container running after checkpoint") flags.BoolVar(&opts.leaveRunning, "leave-running", false, "leave the container running after checkpoint")
flags.StringVarP(&opts.checkpointDir, "checkpoint-dir", "", "", "use a custom checkpoint storage directory")
return cmd return cmd
} }
@ -39,8 +41,9 @@ func runCreate(dockerCli *command.DockerCli, opts createOptions) error {
client := dockerCli.Client() client := dockerCli.Client()
checkpointOpts := types.CheckpointCreateOptions{ checkpointOpts := types.CheckpointCreateOptions{
CheckpointID: opts.checkpoint, CheckpointID: opts.checkpoint,
Exit: !opts.leaveRunning, CheckpointDir: opts.checkpointDir,
Exit: !opts.leaveRunning,
} }
err := client.CheckpointCreate(context.Background(), opts.container, checkpointOpts) err := client.CheckpointCreate(context.Background(), opts.container, checkpointOpts)

View file

@ -6,27 +6,44 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/cli" "github.com/docker/docker/cli"
"github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
type listOptions struct {
checkpointDir string
}
func newListCommand(dockerCli *command.DockerCli) *cobra.Command { func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
return &cobra.Command{ var opts listOptions
cmd := &cobra.Command{
Use: "ls CONTAINER", Use: "ls CONTAINER",
Aliases: []string{"list"}, Aliases: []string{"list"},
Short: "List checkpoints for a container", Short: "List checkpoints for a container",
Args: cli.ExactArgs(1), Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runList(dockerCli, args[0]) return runList(dockerCli, args[0], opts)
}, },
} }
flags := cmd.Flags()
flags.StringVarP(&opts.checkpointDir, "checkpoint-dir", "", "", "use a custom checkpoint storage directory")
return cmd
} }
func runList(dockerCli *command.DockerCli, container string) error { func runList(dockerCli *command.DockerCli, container string, opts listOptions) error {
client := dockerCli.Client() client := dockerCli.Client()
checkpoints, err := client.CheckpointList(context.Background(), container) listOpts := types.CheckpointListOptions{
CheckpointDir: opts.checkpointDir,
}
checkpoints, err := client.CheckpointList(context.Background(), container, listOpts)
if err != nil { if err != nil {
return err return err
} }

View file

@ -3,24 +3,42 @@ package checkpoint
import ( import (
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/cli" "github.com/docker/docker/cli"
"github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
type removeOptions struct {
checkpointDir string
}
func newRemoveCommand(dockerCli *command.DockerCli) *cobra.Command { func newRemoveCommand(dockerCli *command.DockerCli) *cobra.Command {
return &cobra.Command{ var opts removeOptions
cmd := &cobra.Command{
Use: "rm CONTAINER CHECKPOINT", Use: "rm CONTAINER CHECKPOINT",
Aliases: []string{"remove"}, Aliases: []string{"remove"},
Short: "Remove a checkpoint", Short: "Remove a checkpoint",
Args: cli.ExactArgs(2), Args: cli.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runRemove(dockerCli, args[0], args[1]) return runRemove(dockerCli, args[0], args[1], opts)
}, },
} }
flags := cmd.Flags()
flags.StringVarP(&opts.checkpointDir, "checkpoint-dir", "", "", "use a custom checkpoint storage directory")
return cmd
} }
func runRemove(dockerCli *command.DockerCli, container string, checkpoint string) error { func runRemove(dockerCli *command.DockerCli, container string, checkpoint string, opts removeOptions) error {
client := dockerCli.Client() client := dockerCli.Client()
return client.CheckpointDelete(context.Background(), container, checkpoint)
removeOpts := types.CheckpointDeleteOptions{
CheckpointID: checkpoint,
CheckpointDir: opts.checkpointDir,
}
return client.CheckpointDelete(context.Background(), container, removeOpts)
} }

View file

@ -17,10 +17,11 @@ import (
) )
type startOptions struct { type startOptions struct {
attach bool attach bool
openStdin bool openStdin bool
detachKeys string detachKeys string
checkpoint string checkpoint string
checkpointDir string
containers []string containers []string
} }
@ -46,6 +47,7 @@ func NewStartCommand(dockerCli *command.DockerCli) *cobra.Command {
if dockerCli.HasExperimental() { if dockerCli.HasExperimental() {
flags.StringVar(&opts.checkpoint, "checkpoint", "", "Restore from this checkpoint") flags.StringVar(&opts.checkpoint, "checkpoint", "", "Restore from this checkpoint")
flags.StringVar(&opts.checkpointDir, "checkpoint-dir", "", "Use a custom checkpoint storage directory")
} }
return cmd return cmd
@ -112,7 +114,8 @@ func runStart(dockerCli *command.DockerCli, opts *startOptions) error {
// no matter it's detached, removed on daemon side(--rm) or exit normally. // no matter it's detached, removed on daemon side(--rm) or exit normally.
statusChan := waitExitOrRemoved(dockerCli, ctx, c.ID, c.HostConfig.AutoRemove) statusChan := waitExitOrRemoved(dockerCli, ctx, c.ID, c.HostConfig.AutoRemove)
startOptions := types.ContainerStartOptions{ startOptions := types.ContainerStartOptions{
CheckpointID: opts.checkpoint, CheckpointID: opts.checkpoint,
CheckpointDir: opts.checkpointDir,
} }
// 4. Start the container. // 4. Start the container.
@ -145,7 +148,8 @@ func runStart(dockerCli *command.DockerCli, opts *startOptions) error {
} }
container := opts.containers[0] container := opts.containers[0]
startOptions := types.ContainerStartOptions{ startOptions := types.ContainerStartOptions{
CheckpointID: opts.checkpoint, CheckpointID: opts.checkpoint,
CheckpointDir: opts.checkpointDir,
} }
return dockerCli.Client().ContainerStart(ctx, container, startOptions) return dockerCli.Client().ContainerStart(ctx, container, startOptions)

View file

@ -1,12 +1,20 @@
package client package client
import ( import (
"net/url"
"github.com/docker/docker/api/types"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
// CheckpointDelete deletes the checkpoint with the given name from the given container // CheckpointDelete deletes the checkpoint with the given name from the given container
func (cli *Client) CheckpointDelete(ctx context.Context, containerID string, checkpointID string) error { func (cli *Client) CheckpointDelete(ctx context.Context, containerID string, options types.CheckpointDeleteOptions) error {
resp, err := cli.delete(ctx, "/containers/"+containerID+"/checkpoints/"+checkpointID, nil, nil) query := url.Values{}
if options.CheckpointDir != "" {
query.Set("dir", options.CheckpointDir)
}
resp, err := cli.delete(ctx, "/containers/"+containerID+"/checkpoints/"+options.CheckpointID, query, nil)
ensureReaderClosed(resp) ensureReaderClosed(resp)
return err return err
} }

View file

@ -8,6 +8,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/docker/docker/api/types"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
@ -16,7 +17,10 @@ func TestCheckpointDeleteError(t *testing.T) {
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
} }
err := client.CheckpointDelete(context.Background(), "container_id", "checkpoint_id") err := client.CheckpointDelete(context.Background(), "container_id", types.CheckpointDeleteOptions{
CheckpointID: "checkpoint_id",
})
if err == nil || err.Error() != "Error response from daemon: Server error" { if err == nil || err.Error() != "Error response from daemon: Server error" {
t.Fatalf("expected a Server Error, got %v", err) t.Fatalf("expected a Server Error, got %v", err)
} }
@ -40,7 +44,10 @@ func TestCheckpointDelete(t *testing.T) {
}), }),
} }
err := client.CheckpointDelete(context.Background(), "container_id", "checkpoint_id") err := client.CheckpointDelete(context.Background(), "container_id", types.CheckpointDeleteOptions{
CheckpointID: "checkpoint_id",
})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -2,16 +2,22 @@ package client
import ( import (
"encoding/json" "encoding/json"
"net/url"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
// CheckpointList returns the volumes configured in the docker host. // CheckpointList returns the volumes configured in the docker host.
func (cli *Client) CheckpointList(ctx context.Context, container string) ([]types.Checkpoint, error) { func (cli *Client) CheckpointList(ctx context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error) {
var checkpoints []types.Checkpoint var checkpoints []types.Checkpoint
resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", nil, nil) query := url.Values{}
if options.CheckpointDir != "" {
query.Set("dir", options.CheckpointDir)
}
resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil)
if err != nil { if err != nil {
return checkpoints, err return checkpoints, err
} }

View file

@ -18,7 +18,7 @@ func TestCheckpointListError(t *testing.T) {
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
} }
_, err := client.CheckpointList(context.Background(), "container_id") _, err := client.CheckpointList(context.Background(), "container_id", types.CheckpointListOptions{})
if err == nil || err.Error() != "Error response from daemon: Server error" { if err == nil || err.Error() != "Error response from daemon: Server error" {
t.Fatalf("expected a Server Error, got %v", err) t.Fatalf("expected a Server Error, got %v", err)
} }
@ -47,7 +47,7 @@ func TestCheckpointList(t *testing.T) {
}), }),
} }
checkpoints, err := client.CheckpointList(context.Background(), "container_id") checkpoints, err := client.CheckpointList(context.Background(), "container_id", types.CheckpointListOptions{})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -14,6 +14,9 @@ func (cli *Client) ContainerStart(ctx context.Context, containerID string, optio
if len(options.CheckpointID) != 0 { if len(options.CheckpointID) != 0 {
query.Set("checkpoint", options.CheckpointID) query.Set("checkpoint", options.CheckpointID)
} }
if len(options.CheckpointDir) != 0 {
query.Set("checkpoint-dir", options.CheckpointDir)
}
resp, err := cli.post(ctx, "/containers/"+containerID+"/start", query, nil, nil) resp, err := cli.post(ctx, "/containers/"+containerID+"/start", query, nil, nil)
ensureReaderClosed(resp) ensureReaderClosed(resp)

View file

@ -13,8 +13,8 @@ type apiClientExperimental interface {
// CheckpointAPIClient defines API client methods for the checkpoints // CheckpointAPIClient defines API client methods for the checkpoints
type CheckpointAPIClient interface { type CheckpointAPIClient interface {
CheckpointCreate(ctx context.Context, container string, options types.CheckpointCreateOptions) error CheckpointCreate(ctx context.Context, container string, options types.CheckpointCreateOptions) error
CheckpointDelete(ctx context.Context, container string, checkpointID string) error CheckpointDelete(ctx context.Context, container string, options types.CheckpointDeleteOptions) error
CheckpointList(ctx context.Context, container string) ([]types.Checkpoint, error) CheckpointList(ctx context.Context, container string, options types.CheckpointListOptions) ([]types.Checkpoint, error)
} }
// PluginAPIClient defines API client methods for the plugins // PluginAPIClient defines API client methods for the plugins

View file

@ -21,7 +21,14 @@ func (daemon *Daemon) CheckpointCreate(name string, config types.CheckpointCreat
return fmt.Errorf("Container %s not running", name) return fmt.Errorf("Container %s not running", name)
} }
err = daemon.containerd.CreateCheckpoint(container.ID, config.CheckpointID, container.CheckpointDir(), config.Exit) var checkpointDir string
if config.CheckpointDir != "" {
checkpointDir = config.CheckpointDir
} else {
checkpointDir = container.CheckpointDir()
}
err = daemon.containerd.CreateCheckpoint(container.ID, config.CheckpointID, checkpointDir, config.Exit)
if err != nil { if err != nil {
return fmt.Errorf("Cannot checkpoint container %s: %s", name, err) return fmt.Errorf("Cannot checkpoint container %s: %s", name, err)
} }
@ -32,18 +39,24 @@ func (daemon *Daemon) CheckpointCreate(name string, config types.CheckpointCreat
} }
// CheckpointDelete deletes the specified checkpoint // CheckpointDelete deletes the specified checkpoint
func (daemon *Daemon) CheckpointDelete(name string, checkpoint string) error { func (daemon *Daemon) CheckpointDelete(name string, config types.CheckpointDeleteOptions) error {
container, err := daemon.GetContainer(name) container, err := daemon.GetContainer(name)
if err != nil { if err != nil {
return err return err
} }
checkpointDir := container.CheckpointDir() var checkpointDir string
return os.RemoveAll(filepath.Join(checkpointDir, checkpoint)) if config.CheckpointDir != "" {
checkpointDir = config.CheckpointDir
} else {
checkpointDir = container.CheckpointDir()
}
return os.RemoveAll(filepath.Join(checkpointDir, config.CheckpointID))
} }
// CheckpointList lists all checkpoints of the specified container // CheckpointList lists all checkpoints of the specified container
func (daemon *Daemon) CheckpointList(name string) ([]types.Checkpoint, error) { func (daemon *Daemon) CheckpointList(name string, config types.CheckpointListOptions) ([]types.Checkpoint, error) {
var out []types.Checkpoint var out []types.Checkpoint
container, err := daemon.GetContainer(name) container, err := daemon.GetContainer(name)
@ -51,7 +64,13 @@ func (daemon *Daemon) CheckpointList(name string) ([]types.Checkpoint, error) {
return nil, err return nil, err
} }
checkpointDir := container.CheckpointDir() var checkpointDir string
if config.CheckpointDir != "" {
checkpointDir = config.CheckpointDir
} else {
checkpointDir = container.CheckpointDir()
}
if err := os.MkdirAll(checkpointDir, 0755); err != nil { if err := os.MkdirAll(checkpointDir, 0755); err != nil {
return nil, err return nil, err
} }

View file

@ -24,7 +24,7 @@ type Backend interface {
SetupIngress(req clustertypes.NetworkCreateRequest, nodeIP string) error SetupIngress(req clustertypes.NetworkCreateRequest, nodeIP string) error
PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
CreateManagedContainer(config types.ContainerCreateConfig, validateHostname bool) (types.ContainerCreateResponse, error) CreateManagedContainer(config types.ContainerCreateConfig, validateHostname bool) (types.ContainerCreateResponse, error)
ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string) error ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string, checkpointDir string) error
ContainerStop(name string, seconds *int) error ContainerStop(name string, seconds *int) error
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error

View file

@ -224,7 +224,7 @@ func (c *containerAdapter) create(ctx context.Context) error {
func (c *containerAdapter) start(ctx context.Context) error { func (c *containerAdapter) start(ctx context.Context) error {
version := httputils.VersionFromContext(ctx) version := httputils.VersionFromContext(ctx)
validateHostname := versions.GreaterThanOrEqualTo(version, "1.24") validateHostname := versions.GreaterThanOrEqualTo(version, "1.24")
return c.backend.ContainerStart(c.container.name(), nil, validateHostname, "") return c.backend.ContainerStart(c.container.name(), nil, validateHostname, "", "")
} }
func (c *containerAdapter) inspect(ctx context.Context) (types.ContainerJSON, error) { func (c *containerAdapter) inspect(ctx context.Context) (types.ContainerJSON, error) {

View file

@ -305,7 +305,7 @@ func (daemon *Daemon) restore() error {
// Make sure networks are available before starting // Make sure networks are available before starting
daemon.waitForNetworks(c) daemon.waitForNetworks(c)
if err := daemon.containerStart(c, "", true); err != nil { if err := daemon.containerStart(c, "", "", true); err != nil {
logrus.Errorf("Failed to start container %s: %s", c.ID, err) logrus.Errorf("Failed to start container %s: %s", c.ID, err)
} }
close(chNotify) close(chNotify)
@ -372,7 +372,7 @@ func (daemon *Daemon) RestartSwarmContainers() {
group.Add(1) group.Add(1)
go func(c *container.Container) { go func(c *container.Container) {
defer group.Done() defer group.Done()
if err := daemon.containerStart(c, "", true); err != nil { if err := daemon.containerStart(c, "", "", true); err != nil {
logrus.Error(err) logrus.Error(err)
} }
}(c) }(c)

View file

@ -62,7 +62,7 @@ func (daemon *Daemon) StateChanged(id string, e libcontainerd.StateInfo) error {
go func() { go func() {
err := <-wait err := <-wait
if err == nil { if err == nil {
if err = daemon.containerStart(c, "", false); err != nil { if err = daemon.containerStart(c, "", "", false); err != nil {
logrus.Debugf("failed to restart contianer: %+v", err) logrus.Debugf("failed to restart contianer: %+v", err)
} }
} }

View file

@ -61,7 +61,7 @@ func (daemon *Daemon) containerRestart(container *container.Container, seconds i
} }
} }
if err := daemon.containerStart(container, "", true); err != nil { if err := daemon.containerStart(container, "", "", true); err != nil {
return err return err
} }

View file

@ -19,7 +19,7 @@ import (
) )
// ContainerStart starts a container. // ContainerStart starts a container.
func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig, validateHostname bool, checkpoint string) error { func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig, validateHostname bool, checkpoint string, checkpointDir string) error {
if checkpoint != "" && !daemon.HasExperimental() { if checkpoint != "" && !daemon.HasExperimental() {
return errors.NewBadRequestError(fmt.Errorf("checkpoint is only supported in experimental mode")) return errors.NewBadRequestError(fmt.Errorf("checkpoint is only supported in experimental mode"))
} }
@ -82,19 +82,19 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos
return err return err
} }
return daemon.containerStart(container, checkpoint, true) return daemon.containerStart(container, checkpoint, checkpointDir, true)
} }
// Start starts a container // Start starts a container
func (daemon *Daemon) Start(container *container.Container) error { func (daemon *Daemon) Start(container *container.Container) error {
return daemon.containerStart(container, "", true) return daemon.containerStart(container, "", "", true)
} }
// containerStart prepares the container to run by setting up everything the // containerStart prepares the container to run by setting up everything the
// container needs, such as storage and networking, as well as links // container needs, such as storage and networking, as well as links
// between containers. The container is left waiting for a signal to // between containers. The container is left waiting for a signal to
// begin running. // begin running.
func (daemon *Daemon) containerStart(container *container.Container, checkpoint string, resetRestartManager bool) (err error) { func (daemon *Daemon) containerStart(container *container.Container, checkpoint string, checkpointDir string, resetRestartManager bool) (err error) {
start := time.Now() start := time.Now()
container.Lock() container.Lock()
defer container.Unlock() defer container.Unlock()
@ -155,7 +155,11 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint
container.ResetRestartManager(true) container.ResetRestartManager(true)
} }
if err := daemon.containerd.Create(container.ID, checkpoint, container.CheckpointDir(), *spec, container.InitializeStdio, createOptions...); err != nil { if checkpointDir == "" {
checkpointDir = container.CheckpointDir()
}
if err := daemon.containerd.Create(container.ID, checkpoint, checkpointDir, *spec, container.InitializeStdio, createOptions...); err != nil {
errDesc := grpc.ErrorDesc(err) errDesc := grpc.ErrorDesc(err)
logrus.Errorf("Create container failed with error: %s", errDesc) logrus.Errorf("Create container failed with error: %s", errDesc)
// if we receive an internal error from the initial start of a container then lets // if we receive an internal error from the initial start of a container then lets