github.com/cvmfs/docker-graphdriver@v0.0.0-20181206110523-155ec6df0521/repository-manager/lib/garbage_collection.go (about)

     1  package lib
     2  
     3  import (
     4  	"encoding/json"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	log "github.com/sirupsen/logrus"
    11  
    12  	da "github.com/cvmfs/docker-graphdriver/repository-manager/docker-api"
    13  )
    14  
    15  func FindImageToGarbageCollect(CVMFSRepo string) ([]da.Manifest, error) {
    16  	removeSchedulePath := RemoveScheduleLocation(CVMFSRepo)
    17  	llog := func(l *log.Entry) *log.Entry {
    18  		return l.WithFields(log.Fields{
    19  			"action": "find image to garbage collect in schedule file",
    20  			"file":   removeSchedulePath})
    21  	}
    22  
    23  	var schedule []da.Manifest
    24  
    25  	_, err := os.Stat(removeSchedulePath)
    26  	if os.IsNotExist(err) {
    27  		return schedule, nil
    28  	}
    29  	if err != nil {
    30  		llog(LogE(err)).Error("Error in stating the schedule file")
    31  		return schedule, err
    32  	}
    33  	scheduleFileRO, err := os.Open(removeSchedulePath)
    34  	if err != nil {
    35  		llog(LogE(err)).Error("Error in opening the schedule file")
    36  		return schedule, err
    37  	}
    38  
    39  	scheduleBytes, err := ioutil.ReadAll(scheduleFileRO)
    40  	if err != nil {
    41  		llog(LogE(err)).Error("Impossible to read the schedule file")
    42  		return schedule, err
    43  	}
    44  
    45  	err = scheduleFileRO.Close()
    46  	if err != nil {
    47  		llog(LogE(err)).Error("Impossible to close the schedule file")
    48  		return schedule, err
    49  	}
    50  
    51  	err = json.Unmarshal(scheduleBytes, &schedule)
    52  	if err != nil {
    53  		llog(LogE(err)).Error("Impossible to unmarshal the schedule file")
    54  		return schedule, err
    55  	}
    56  
    57  	return schedule, nil
    58  }
    59  
    60  // with image and layer we pass the digest of the layer and the digest of the image,
    61  // both without the sha256: prefix
    62  func GarbageCollectSingleLayer(CVMFSRepo, image, layer string) error {
    63  	backlink, err := getBacklinkFromLayer(CVMFSRepo, layer)
    64  	llog := func(l *log.Entry) *log.Entry {
    65  		return l.WithFields(log.Fields{"action": "garbage collect layer",
    66  			"repo":  CVMFSRepo,
    67  			"image": image,
    68  			"layer": layer})
    69  	}
    70  	if err != nil {
    71  		llog(LogE(err)).Error("Impossible to retrieve the backlink information")
    72  		return err
    73  	}
    74  	var newOrigin []string
    75  	for _, origin := range backlink.Origin {
    76  		withoutPrefix := strings.Split(origin, ":")[1]
    77  		if withoutPrefix != image {
    78  			newOrigin = append(newOrigin, origin)
    79  		}
    80  	}
    81  	if len(newOrigin) > 0 {
    82  		backlink.Origin = newOrigin
    83  		backLinkMarshall, err := json.Marshal(backlink)
    84  		if err != nil {
    85  			llog(LogE(err)).Error("Error in marshaling the new backlink")
    86  			return err
    87  		}
    88  
    89  		backlinkPath := getBacklinkPath(CVMFSRepo, layer)
    90  
    91  		err = ExecCommand("cvmfs_server", "transaction", CVMFSRepo).Start()
    92  		if err != nil {
    93  			llog(LogE(err)).Error("Error in opening the transaction")
    94  			return err
    95  		}
    96  
    97  		dir := filepath.Dir(backlinkPath)
    98  		if _, err := os.Stat(dir); os.IsNotExist(err) {
    99  			err = os.MkdirAll(dir, 0666)
   100  			if err != nil {
   101  				llog(LogE(err)).WithFields(log.Fields{"directory": dir}).Error(
   102  					"Error in creating the directory for the backlinks file, skipping...")
   103  				return err
   104  			}
   105  		}
   106  
   107  		err = ioutil.WriteFile(backlinkPath, backLinkMarshall, 0666)
   108  		if err != nil {
   109  			llog(LogE(err)).WithFields(log.Fields{"file": backlinkPath}).Error(
   110  				"Error in writing the backlink file, skipping...")
   111  			return err
   112  		}
   113  
   114  		err = ExecCommand("cvmfs_server", "publish", CVMFSRepo).Start()
   115  		if err != nil {
   116  			llog(LogE(err)).Error("Error in publishing after adding the backlinks")
   117  			return err
   118  		}
   119  		// write it to file
   120  		return nil
   121  	} else {
   122  		err = RemoveLayer(CVMFSRepo, layer)
   123  		if err != nil {
   124  			llog(LogE(err)).Error("Error in deleting the layer")
   125  		}
   126  		return err
   127  	}
   128  }