github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/daemon/checkpoint.go (about)

     1  package daemon
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	"github.com/docker/docker/api/types"
    12  	"github.com/docker/docker/daemon/names"
    13  )
    14  
    15  var (
    16  	validCheckpointNameChars   = names.RestrictedNameChars
    17  	validCheckpointNamePattern = names.RestrictedNamePattern
    18  )
    19  
    20  // getCheckpointDir verifies checkpoint directory for create,remove, list options and checks if checkpoint already exists
    21  func getCheckpointDir(checkDir, checkpointID, ctrName, ctrID, ctrCheckpointDir string, create bool) (string, error) {
    22  	var checkpointDir string
    23  	var err2 error
    24  	if checkDir != "" {
    25  		checkpointDir = filepath.Join(checkDir, ctrID, "checkpoints")
    26  	} else {
    27  		checkpointDir = ctrCheckpointDir
    28  	}
    29  	checkpointAbsDir := filepath.Join(checkpointDir, checkpointID)
    30  	stat, err := os.Stat(checkpointAbsDir)
    31  	if create {
    32  		switch {
    33  		case err == nil && stat.IsDir():
    34  			err2 = fmt.Errorf("checkpoint with name %s already exists for container %s", checkpointID, ctrName)
    35  		case err != nil && os.IsNotExist(err):
    36  			err2 = os.MkdirAll(checkpointAbsDir, 0700)
    37  		case err != nil:
    38  			err2 = err
    39  		case err == nil:
    40  			err2 = fmt.Errorf("%s exists and is not a directory", checkpointAbsDir)
    41  		}
    42  	} else {
    43  		switch {
    44  		case err != nil:
    45  			err2 = fmt.Errorf("checkpoint %s does not exists for container %s", checkpointID, ctrName)
    46  		case err == nil && stat.IsDir():
    47  			err2 = nil
    48  		case err == nil:
    49  			err2 = fmt.Errorf("%s exists and is not a directory", checkpointAbsDir)
    50  		}
    51  	}
    52  	return checkpointAbsDir, err2
    53  }
    54  
    55  // CheckpointCreate checkpoints the process running in a container with CRIU
    56  func (daemon *Daemon) CheckpointCreate(name string, config types.CheckpointCreateOptions) error {
    57  	container, err := daemon.GetContainer(name)
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	if !container.IsRunning() {
    63  		return fmt.Errorf("Container %s not running", name)
    64  	}
    65  
    66  	if container.Config.Tty {
    67  		return fmt.Errorf("checkpoint not support on containers with tty")
    68  	}
    69  
    70  	if !validCheckpointNamePattern.MatchString(config.CheckpointID) {
    71  		return fmt.Errorf("Invalid checkpoint ID (%s), only %s are allowed", config.CheckpointID, validCheckpointNameChars)
    72  	}
    73  
    74  	checkpointDir, err := getCheckpointDir(config.CheckpointDir, config.CheckpointID, name, container.ID, container.CheckpointDir(), true)
    75  	if err != nil {
    76  		return fmt.Errorf("cannot checkpoint container %s: %s", name, err)
    77  	}
    78  
    79  	err = daemon.containerd.CreateCheckpoint(context.Background(), container.ID, checkpointDir, config.Exit)
    80  	if err != nil {
    81  		os.RemoveAll(checkpointDir)
    82  		return fmt.Errorf("Cannot checkpoint container %s: %s", name, err)
    83  	}
    84  
    85  	daemon.LogContainerEvent(container, "checkpoint")
    86  
    87  	return nil
    88  }
    89  
    90  // CheckpointDelete deletes the specified checkpoint
    91  func (daemon *Daemon) CheckpointDelete(name string, config types.CheckpointDeleteOptions) error {
    92  	container, err := daemon.GetContainer(name)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	checkpointDir, err := getCheckpointDir(config.CheckpointDir, config.CheckpointID, name, container.ID, container.CheckpointDir(), false)
    97  	if err == nil {
    98  		return os.RemoveAll(filepath.Join(checkpointDir, config.CheckpointID))
    99  	}
   100  	return err
   101  }
   102  
   103  // CheckpointList lists all checkpoints of the specified container
   104  func (daemon *Daemon) CheckpointList(name string, config types.CheckpointListOptions) ([]types.Checkpoint, error) {
   105  	var out []types.Checkpoint
   106  
   107  	container, err := daemon.GetContainer(name)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  
   112  	checkpointDir, err := getCheckpointDir(config.CheckpointDir, "", name, container.ID, container.CheckpointDir(), false)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  
   117  	if err := os.MkdirAll(checkpointDir, 0755); err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	dirs, err := ioutil.ReadDir(checkpointDir)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	for _, d := range dirs {
   127  		if !d.IsDir() {
   128  			continue
   129  		}
   130  		path := filepath.Join(checkpointDir, d.Name(), "config.json")
   131  		data, err := ioutil.ReadFile(path)
   132  		if err != nil {
   133  			return nil, err
   134  		}
   135  		var cpt types.Checkpoint
   136  		if err := json.Unmarshal(data, &cpt); err != nil {
   137  			return nil, err
   138  		}
   139  		out = append(out, cpt)
   140  	}
   141  
   142  	return out, nil
   143  }