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 }