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