github.com/lusis/distribution@v2.0.1+incompatible/registry/storage/purgeuploads.go (about) 1 package storage 2 3 import ( 4 "path" 5 "strings" 6 "time" 7 8 "code.google.com/p/go-uuid/uuid" 9 log "github.com/Sirupsen/logrus" 10 storageDriver "github.com/docker/distribution/registry/storage/driver" 11 ) 12 13 // uploadData stored the location of temporary files created during a layer upload 14 // along with the date the upload was started 15 type uploadData struct { 16 containingDir string 17 startedAt time.Time 18 } 19 20 func newUploadData() uploadData { 21 return uploadData{ 22 containingDir: "", 23 // default to far in future to protect against missing startedat 24 startedAt: time.Now().Add(time.Duration(10000 * time.Hour)), 25 } 26 } 27 28 // PurgeUploads deletes files from the upload directory 29 // created before olderThan. The list of files deleted and errors 30 // encountered are returned 31 func PurgeUploads(driver storageDriver.StorageDriver, olderThan time.Time, actuallyDelete bool) ([]string, []error) { 32 log.Infof("PurgeUploads starting: olderThan=%s, actuallyDelete=%t", olderThan, actuallyDelete) 33 uploadData, errors := getOutstandingUploads(driver) 34 var deleted []string 35 for _, uploadData := range uploadData { 36 if uploadData.startedAt.Before(olderThan) { 37 var err error 38 log.Infof("Upload files in %s have older date (%s) than purge date (%s). Removing upload directory.", 39 uploadData.containingDir, uploadData.startedAt, olderThan) 40 if actuallyDelete { 41 err = driver.Delete(uploadData.containingDir) 42 } 43 if err == nil { 44 deleted = append(deleted, uploadData.containingDir) 45 } else { 46 errors = append(errors, err) 47 } 48 } 49 } 50 51 log.Infof("Purge uploads finished. Num deleted=%d, num errors=%d", len(deleted), len(errors)) 52 return deleted, errors 53 } 54 55 // getOutstandingUploads walks the upload directory, collecting files 56 // which could be eligible for deletion. The only reliable way to 57 // classify the age of a file is with the date stored in the startedAt 58 // file, so gather files by UUID with a date from startedAt. 59 func getOutstandingUploads(driver storageDriver.StorageDriver) (map[string]uploadData, []error) { 60 var errors []error 61 uploads := make(map[string]uploadData, 0) 62 63 inUploadDir := false 64 root, err := defaultPathMapper.path(repositoriesRootPathSpec{}) 65 if err != nil { 66 return uploads, append(errors, err) 67 } 68 err = Walk(driver, root, func(fileInfo storageDriver.FileInfo) error { 69 filePath := fileInfo.Path() 70 _, file := path.Split(filePath) 71 if file[0] == '_' { 72 // Reserved directory 73 inUploadDir = (file == "_uploads") 74 75 if fileInfo.IsDir() && !inUploadDir { 76 return ErrSkipDir 77 } 78 79 } 80 81 uuid, isContainingDir := uUIDFromPath(filePath) 82 if uuid == "" { 83 // Cannot reliably delete 84 return nil 85 } 86 ud, ok := uploads[uuid] 87 if !ok { 88 ud = newUploadData() 89 } 90 if isContainingDir { 91 ud.containingDir = filePath 92 } 93 if file == "startedat" { 94 if t, err := readStartedAtFile(driver, filePath); err == nil { 95 ud.startedAt = t 96 } else { 97 errors = pushError(errors, filePath, err) 98 } 99 100 } 101 102 uploads[uuid] = ud 103 return nil 104 }) 105 106 if err != nil { 107 errors = pushError(errors, root, err) 108 } 109 return uploads, errors 110 } 111 112 // uUIDFromPath extracts the upload UUID from a given path 113 // If the UUID is the last path component, this is the containing 114 // directory for all upload files 115 func uUIDFromPath(path string) (string, bool) { 116 components := strings.Split(path, "/") 117 for i := len(components) - 1; i >= 0; i-- { 118 if uuid := uuid.Parse(components[i]); uuid != nil { 119 return uuid.String(), i == len(components)-1 120 } 121 } 122 return "", false 123 } 124 125 // readStartedAtFile reads the date from an upload's startedAtFile 126 func readStartedAtFile(driver storageDriver.StorageDriver, path string) (time.Time, error) { 127 startedAtBytes, err := driver.GetContent(path) 128 if err != nil { 129 return time.Now(), err 130 } 131 startedAt, err := time.Parse(time.RFC3339, string(startedAtBytes)) 132 if err != nil { 133 return time.Now(), err 134 } 135 return startedAt, nil 136 }