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  }