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