forked from sync/gitea-docker-registry-prune
first commit
This commit is contained in:
130
main.go
Normal file
130
main.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/carlmjohnson/requests"
|
||||
)
|
||||
|
||||
func main() {
|
||||
giteaUrl := os.Getenv("GITEA_URL")
|
||||
giteaToken := os.Getenv("GITEA_TOKEN")
|
||||
|
||||
if err := run(giteaUrl, giteaUrl, giteaToken); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("OK")
|
||||
}
|
||||
|
||||
func run(giteaUrl string, registryUrl string, giteaToken string) error {
|
||||
ctx := context.TODO()
|
||||
|
||||
var catalog RegistryCatalog
|
||||
if err := requests.URL(registryUrl).Path("/v2/_catalog").BasicAuth("<token>", giteaToken).ToJSON(&catalog).Fetch(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var images []string
|
||||
var orgs []string
|
||||
for _, repo := range catalog.Repositories {
|
||||
srepo := strings.Split(repo, "/")
|
||||
if len(srepo) == 2 {
|
||||
if !slices.Contains(orgs, srepo[0]) {
|
||||
orgs = append(orgs, srepo[0])
|
||||
}
|
||||
|
||||
var regRepo RegistryRepository
|
||||
if err := requests.URL(registryUrl).Pathf("/v2/%s/tags/list", repo).BasicAuth("<token>", giteaToken).ToJSON(®Repo).Fetch(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, tag := range regRepo.Tags {
|
||||
var regMan RegistryRepositoryManifest
|
||||
if err := requests.URL(registryUrl).Pathf("/v2/%s/manifests/%s", repo, tag).BasicAuth("<token>", giteaToken).ToJSON(®Man).Fetch(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, man := range regMan.Manifests {
|
||||
images = append(images, repo+"/"+man.Digest)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var toPurge, toKeep []string
|
||||
|
||||
client, err := gitea.NewClient(giteaUrl, gitea.SetToken(giteaToken))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, org := range orgs {
|
||||
page := 1
|
||||
pageSize := -1
|
||||
|
||||
for {
|
||||
list, _, err := client.ListPackages(org, gitea.ListPackagesOptions{ListOptions: gitea.ListOptions{Page: page}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pageSize < 0 {
|
||||
pageSize = len(list)
|
||||
}
|
||||
if len(list) < pageSize || len(list) == 0 {
|
||||
break
|
||||
}
|
||||
page++
|
||||
|
||||
for _, pkg := range list {
|
||||
if pkg.Type == "container" && strings.HasPrefix(pkg.Version, "sha") {
|
||||
if slices.Contains(images, org+"/"+pkg.Name+"/"+pkg.Version) {
|
||||
toKeep = append(toKeep, org+"/"+pkg.Name+"/"+pkg.Version)
|
||||
} else {
|
||||
toPurge = append(toPurge, org+"/"+pkg.Name+"/"+pkg.Version)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
slices.Sort(images)
|
||||
slices.Sort(toKeep)
|
||||
|
||||
if !slices.Equal(images, toKeep) {
|
||||
return fmt.Errorf("images from registry don't match with those to keep")
|
||||
}
|
||||
|
||||
for _, p := range toPurge {
|
||||
px := strings.Split(p, "/")
|
||||
if len(px) == 3 {
|
||||
if _, err := client.DeletePackage(px[0], "container", px[1], px[2]); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("removing.. \"%s/%s\" %s\n", px[0], px[1], px[2])
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type RegistryCatalog struct {
|
||||
Repositories []string `json:"repositories"`
|
||||
}
|
||||
|
||||
type RegistryRepository struct {
|
||||
Name string `json:"name"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
type RegistryRepositoryManifest struct {
|
||||
SchemaVersion int `json:"schemaVersion"`
|
||||
MediaType string `json:"mediaType"`
|
||||
Digest string `json:"digest"`
|
||||
Size int `json:"size"`
|
||||
Manifests []RegistryRepositoryManifest `json:"manifests"`
|
||||
}
|
||||
Reference in New Issue
Block a user