mirror of
https://github.com/Quiq/docker-registry-ui.git
synced 2025-09-05 07:00:55 +00:00
Initial commit.
This commit is contained in:
132
registry/tasks.go
Normal file
132
registry/tasks.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/hhkbp2/go-logging"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type tagData struct {
|
||||
name string
|
||||
created time.Time
|
||||
}
|
||||
|
||||
func (t tagData) String() string {
|
||||
return fmt.Sprintf(`"%s <%s>"`, t.name, t.created.Format("2006-01-02 15:04:05"))
|
||||
}
|
||||
|
||||
type timeSlice []tagData
|
||||
|
||||
func (p timeSlice) Len() int {
|
||||
return len(p)
|
||||
}
|
||||
|
||||
func (p timeSlice) Less(i, j int) bool {
|
||||
return p[i].created.After(p[j].created)
|
||||
}
|
||||
|
||||
func (p timeSlice) Swap(i, j int) {
|
||||
p[i], p[j] = p[j], p[i]
|
||||
}
|
||||
|
||||
// PurgeOldTags purge old tags.
|
||||
func PurgeOldTags(client *Client, purgeDryRun bool, purgeTagsKeepDays, purgeTagsKeepCount int) {
|
||||
logger := setupLogging("registry.tasks.PurgeOldTags")
|
||||
// Reduce client logging.
|
||||
client.logger.SetLevel(logging.LevelError)
|
||||
|
||||
dryRunText := ""
|
||||
if purgeDryRun {
|
||||
logger.Warn("Dry-run mode enabled.")
|
||||
dryRunText = "skipped"
|
||||
}
|
||||
logger.Info("Scanning registry for repositories, tags and their creation dates...")
|
||||
catalog := client.Repositories(true)
|
||||
// catalog := map[string][]string{"library": []string{""}}
|
||||
now := time.Now().UTC()
|
||||
repos := map[string]timeSlice{}
|
||||
count := 0
|
||||
for namespace := range catalog {
|
||||
count = count + len(catalog[namespace])
|
||||
for _, repo := range catalog[namespace] {
|
||||
if namespace != "library" {
|
||||
repo = fmt.Sprintf("%s/%s", namespace, repo)
|
||||
}
|
||||
|
||||
tags := client.Tags(repo)
|
||||
logger.Infof("[%s] scanning %d tags...", repo, len(tags))
|
||||
if len(tags) == 0 {
|
||||
continue
|
||||
}
|
||||
for _, tag := range tags {
|
||||
_, infoV1, _ := client.TagInfo(repo, tag, true)
|
||||
if infoV1 == "" {
|
||||
logger.Errorf("[%s] manifest missed for tag %s", repo, tag)
|
||||
continue
|
||||
}
|
||||
created := gjson.Get(gjson.Get(infoV1, "history.0.v1Compatibility").String(), "created").Time()
|
||||
repos[repo] = append(repos[repo], tagData{name: tag, created: created})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.Infof("Scanned %d repositories.", count)
|
||||
logger.Info("Filtering out tags for purging...")
|
||||
purgeTags := map[string][]string{}
|
||||
keepTags := map[string][]string{}
|
||||
count = 0
|
||||
for _, repo := range SortedMapKeys(repos) {
|
||||
// Sort tags by "created" from newest to oldest.
|
||||
sortedTags := make(timeSlice, 0, len(repos[repo]))
|
||||
for _, d := range repos[repo] {
|
||||
sortedTags = append(sortedTags, d)
|
||||
}
|
||||
sort.Sort(sortedTags)
|
||||
repos[repo] = sortedTags
|
||||
|
||||
// Filter out tags by retention days.
|
||||
for _, tag := range repos[repo] {
|
||||
delta := int(now.Sub(tag.created).Hours() / 24)
|
||||
if delta > purgeTagsKeepDays {
|
||||
purgeTags[repo] = append(purgeTags[repo], tag.name)
|
||||
} else {
|
||||
keepTags[repo] = append(keepTags[repo], tag.name)
|
||||
}
|
||||
}
|
||||
|
||||
// Keep minimal count of tags no matter how old they are.
|
||||
if len(repos[repo])-len(purgeTags[repo]) < purgeTagsKeepCount {
|
||||
if len(purgeTags[repo]) > purgeTagsKeepCount {
|
||||
keepTags[repo] = append(keepTags[repo], purgeTags[repo][:purgeTagsKeepCount]...)
|
||||
purgeTags[repo] = purgeTags[repo][purgeTagsKeepCount:]
|
||||
} else {
|
||||
keepTags[repo] = append(keepTags[repo], purgeTags[repo]...)
|
||||
delete(purgeTags, repo)
|
||||
}
|
||||
}
|
||||
|
||||
count = count + len(purgeTags[repo])
|
||||
logger.Infof("[%s] All %d: %v", repo, len(repos[repo]), repos[repo])
|
||||
logger.Infof("[%s] Keep %d: %v", repo, len(keepTags[repo]), keepTags[repo])
|
||||
logger.Infof("[%s] Purge %d: %v", repo, len(purgeTags[repo]), purgeTags[repo])
|
||||
}
|
||||
|
||||
logger.Infof("There are %d tags to purge.", count)
|
||||
if count > 0 {
|
||||
logger.Info("Purging old tags...")
|
||||
}
|
||||
|
||||
for _, repo := range SortedMapKeys(purgeTags) {
|
||||
logger.Infof("[%s] Purging %d tags... %s", repo, len(purgeTags[repo]), dryRunText)
|
||||
if purgeDryRun {
|
||||
continue
|
||||
}
|
||||
for _, tag := range purgeTags[repo] {
|
||||
client.DeleteTag(repo, tag)
|
||||
}
|
||||
}
|
||||
logger.Info("Done.")
|
||||
}
|
Reference in New Issue
Block a user