zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/pkg/retention/rules.go (about) 1 package retention 2 3 import ( 4 "fmt" 5 "sort" 6 "time" 7 8 "zotregistry.io/zot/pkg/retention/types" 9 ) 10 11 const ( 12 // rules name. 13 daysPullName = "pulledWithin" 14 daysPushName = "pushedWithin" 15 latestPullName = "mostRecentlyPulledCount" 16 latestPushName = "mostRecentlyPushedCount" 17 ) 18 19 // rules implementatio 20 21 type DaysPull struct { 22 duration time.Duration 23 } 24 25 func NewDaysPull(duration time.Duration) DaysPull { 26 return DaysPull{duration: duration} 27 } 28 29 func (dp DaysPull) Name() string { 30 return fmt.Sprintf("%s:%d", daysPullName, dp.duration) 31 } 32 33 func (dp DaysPull) Perform(candidates []*types.Candidate) []*types.Candidate { 34 filtered := make([]*types.Candidate, 0) 35 36 timestamp := time.Now().Add(-dp.duration) 37 38 for _, candidate := range candidates { 39 // we check pushtimestamp because we don't want to delete tags pushed after timestamp 40 // ie: if the tag doesn't meet PulledWithin: "3days" and the image is 1day old then do not remove! 41 if candidate.PullTimestamp.After(timestamp) || candidate.PushTimestamp.After(timestamp) { 42 candidate.RetainedBy = dp.Name() 43 filtered = append(filtered, candidate) 44 } 45 } 46 47 return filtered 48 } 49 50 type DaysPush struct { 51 duration time.Duration 52 } 53 54 func NewDaysPush(duration time.Duration) DaysPush { 55 return DaysPush{duration: duration} 56 } 57 58 func (dp DaysPush) Name() string { 59 return fmt.Sprintf("%s:%d", daysPushName, dp.duration) 60 } 61 62 func (dp DaysPush) Perform(candidates []*types.Candidate) []*types.Candidate { 63 filtered := make([]*types.Candidate, 0) 64 65 timestamp := time.Now().Add(-dp.duration) 66 67 for _, candidate := range candidates { 68 if candidate.PushTimestamp.After(timestamp) { 69 candidate.RetainedBy = dp.Name() 70 71 filtered = append(filtered, candidate) 72 } 73 } 74 75 return filtered 76 } 77 78 type latestPull struct { 79 count int 80 } 81 82 func NewLatestPull(count int) latestPull { 83 return latestPull{count: count} 84 } 85 86 func (lp latestPull) Name() string { 87 return fmt.Sprintf("%s:%d", latestPullName, lp.count) 88 } 89 90 func (lp latestPull) Perform(candidates []*types.Candidate) []*types.Candidate { 91 sort.Slice(candidates, func(i, j int) bool { 92 return candidates[i].PullTimestamp.After(candidates[j].PullTimestamp) 93 }) 94 95 // take top count candidates 96 upper := lp.count 97 if lp.count > len(candidates) { 98 upper = len(candidates) 99 } 100 101 candidates = candidates[:upper] 102 103 for _, candidate := range candidates { 104 candidate.RetainedBy = lp.Name() 105 } 106 107 return candidates 108 } 109 110 type latestPush struct { 111 count int 112 } 113 114 func NewLatestPush(count int) latestPush { 115 return latestPush{count: count} 116 } 117 118 func (lp latestPush) Name() string { 119 return fmt.Sprintf("%s:%d", latestPushName, lp.count) 120 } 121 122 func (lp latestPush) Perform(candidates []*types.Candidate) []*types.Candidate { 123 sort.Slice(candidates, func(i, j int) bool { 124 return candidates[i].PushTimestamp.After(candidates[j].PushTimestamp) 125 }) 126 127 // take top count candidates 128 upper := lp.count 129 if lp.count > len(candidates) { 130 upper = len(candidates) 131 } 132 133 candidates = candidates[:upper] 134 135 for _, candidate := range candidates { 136 candidate.RetainedBy = lp.Name() 137 } 138 139 return candidates 140 }