github.com/skanehira/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 }