2023-11-01 18:16:18 +02:00
package retention
import (
"fmt"
"sort"
"time"
2024-02-01 06:34:07 +02:00
"zotregistry.dev/zot/pkg/retention/types"
2023-11-01 18:16:18 +02:00
)
const (
// rules name.
daysPullName = "pulledWithin"
daysPushName = "pushedWithin"
latestPullName = "mostRecentlyPulledCount"
latestPushName = "mostRecentlyPushedCount"
)
// rules implementatio
type DaysPull struct {
duration time . Duration
}
func NewDaysPull ( duration time . Duration ) DaysPull {
return DaysPull { duration : duration }
}
func ( dp DaysPull ) Name ( ) string {
return fmt . Sprintf ( "%s:%d" , daysPullName , dp . duration )
}
func ( dp DaysPull ) Perform ( candidates [ ] * types . Candidate ) [ ] * types . Candidate {
filtered := make ( [ ] * types . Candidate , 0 )
timestamp := time . Now ( ) . Add ( - dp . duration )
for _ , candidate := range candidates {
// we check pushtimestamp because we don't want to delete tags pushed after timestamp
// ie: if the tag doesn't meet PulledWithin: "3days" and the image is 1day old then do not remove!
if candidate . PullTimestamp . After ( timestamp ) || candidate . PushTimestamp . After ( timestamp ) {
candidate . RetainedBy = dp . Name ( )
filtered = append ( filtered , candidate )
}
}
return filtered
}
type DaysPush struct {
duration time . Duration
}
func NewDaysPush ( duration time . Duration ) DaysPush {
return DaysPush { duration : duration }
}
func ( dp DaysPush ) Name ( ) string {
return fmt . Sprintf ( "%s:%d" , daysPushName , dp . duration )
}
func ( dp DaysPush ) Perform ( candidates [ ] * types . Candidate ) [ ] * types . Candidate {
filtered := make ( [ ] * types . Candidate , 0 )
timestamp := time . Now ( ) . Add ( - dp . duration )
for _ , candidate := range candidates {
if candidate . PushTimestamp . After ( timestamp ) {
candidate . RetainedBy = dp . Name ( )
filtered = append ( filtered , candidate )
}
}
return filtered
}
type latestPull struct {
count int
}
func NewLatestPull ( count int ) latestPull {
return latestPull { count : count }
}
func ( lp latestPull ) Name ( ) string {
return fmt . Sprintf ( "%s:%d" , latestPullName , lp . count )
}
func ( lp latestPull ) Perform ( candidates [ ] * types . Candidate ) [ ] * types . Candidate {
sort . Slice ( candidates , func ( i , j int ) bool {
return candidates [ i ] . PullTimestamp . After ( candidates [ j ] . PullTimestamp )
} )
// take top count candidates
upper := lp . count
if lp . count > len ( candidates ) {
upper = len ( candidates )
}
candidates = candidates [ : upper ]
for _ , candidate := range candidates {
candidate . RetainedBy = lp . Name ( )
}
return candidates
}
type latestPush struct {
count int
}
func NewLatestPush ( count int ) latestPush {
return latestPush { count : count }
}
func ( lp latestPush ) Name ( ) string {
return fmt . Sprintf ( "%s:%d" , latestPushName , lp . count )
}
func ( lp latestPush ) Perform ( candidates [ ] * types . Candidate ) [ ] * types . Candidate {
sort . Slice ( candidates , func ( i , j int ) bool {
return candidates [ i ] . PushTimestamp . After ( candidates [ j ] . PushTimestamp )
} )
// take top count candidates
upper := lp . count
if lp . count > len ( candidates ) {
upper = len ( candidates )
}
candidates = candidates [ : upper ]
for _ , candidate := range candidates {
candidate . RetainedBy = lp . Name ( )
}
return candidates
}