Add dry-run option

This will help us validate and debug the prune command.

Change-Id: I54ba30e1963593762e1e1435bc7e67e7eb637d3e
This commit is contained in:
James E. Blair 2024-11-06 14:49:09 -08:00
parent 404b903c77
commit 66bf00a416
2 changed files with 16 additions and 11 deletions

View File

@ -1,5 +1,5 @@
# Copyright 2019 Red Hat, Inc.
# Copyright 2021 Acme Gating, LLC
# Copyright 2021, 2024 Acme Gating, LLC
#
# This module is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -553,8 +553,8 @@ class RegistryServer:
# same host/port settings.
cherrypy.server.httpserver = None
def prune(self):
self.store.prune()
def prune(self, dry_run):
self.store.prune(dry_run)
def main():
@ -566,6 +566,9 @@ def main():
parser.add_argument('-d', dest='debug',
help='Debug log level',
action='store_true')
parser.add_argument('--dry-run', dest='dry_run',
help='Do not actually delete anything when pruning',
action='store_true')
parser.add_argument('command',
nargs='?',
help='Command: serve, prune',
@ -591,7 +594,7 @@ def main():
s.start()
cherrypy.engine.block()
elif args.command == 'prune':
s.prune()
s.prune(args.dry_run)
else:
print("Unknown command: %s", args.command)
sys.exit(1)

View File

@ -258,7 +258,7 @@ class Storage:
path = os.path.join(namespace, 'repos', repo, 'manifests')
return self.backend.list_objects(path)
def prune(self):
def prune(self, dry_run):
"""Prune the registry
Prune all namespaces in the registry according to configured
@ -273,13 +273,14 @@ class Storage:
for namespace in self.backend.list_objects(''):
uploadpath = os.path.join(namespace.path, 'uploads/')
for upload in self.backend.list_objects(uploadpath):
self._prune(upload, upload_target)
self._prune(upload, upload_target, dry_run)
if not manifest_target:
continue
repopath = os.path.join(namespace.path, 'repos/')
kept_manifests = []
for repo in self.backend.list_objects(repopath):
kept_manifests.extend(self._prune(repo, manifest_target))
kept_manifests.extend(
self._prune(repo, manifest_target, dry_run))
# mark/sweep manifest blobs
layers = set()
for manifest in kept_manifests:
@ -290,7 +291,7 @@ class Storage:
blobpath = os.path.join(namespace.path, 'blobs/')
for blob in self.backend.list_objects(blobpath):
if blob.name not in layers:
self._prune(blob, upload_target)
self._prune(blob, upload_target, dry_run)
def _get_layers_from_manifest(self, namespace, path):
self.log.debug('Get layers %s', path)
@ -310,14 +311,15 @@ class Storage:
layers.append(layer['digest'])
return layers
def _prune(self, root_obj, target):
def _prune(self, root_obj, target, dry_run):
kept = []
if root_obj.isdir:
for obj in self.backend.list_objects(root_obj.path):
kept.extend(self._prune(obj, target))
kept.extend(self._prune(obj, target, dry_run))
if not kept and root_obj.ctime < target:
self.log.debug('Prune %s', root_obj.path)
self.backend.delete_object(root_obj.path)
if not dry_run:
self.backend.delete_object(root_obj.path)
else:
self.log.debug('Keep %s', root_obj.path)
kept.append(root_obj)