From 66bf00a4164d8de792db55e8c47a135f0dfaf07f Mon Sep 17 00:00:00 2001 From: "James E. Blair" Date: Wed, 6 Nov 2024 14:49:09 -0800 Subject: [PATCH] Add dry-run option This will help us validate and debug the prune command. Change-Id: I54ba30e1963593762e1e1435bc7e67e7eb637d3e --- zuul_registry/main.py | 11 +++++++---- zuul_registry/storage.py | 16 +++++++++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/zuul_registry/main.py b/zuul_registry/main.py index 50d91dd..5f2dff7 100644 --- a/zuul_registry/main.py +++ b/zuul_registry/main.py @@ -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) diff --git a/zuul_registry/storage.py b/zuul_registry/storage.py index 2563701..fde2bdf 100644 --- a/zuul_registry/storage.py +++ b/zuul_registry/storage.py @@ -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)