zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/pkg/retention/rules.go (about)

     1  package retention
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"time"
     7  
     8  	"zotregistry.dev/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  }