This function checks whether there are any stale Docker images in the
registry that can be purged. Since we're pulling available container
images from our GitLab registry with the 'list-images' action, it
could happen that we'd list old (already unsupported) images and make
them available for the user to consume and run a build in them.
Naturally, the build will most likely fail leaving the user confused.

Signed-off-by: Erik Skultety <eskul...@redhat.com>
---
 ci/helper  | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 ci/util.py | 13 +++++++++++++
 2 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/ci/helper b/ci/helper
index 1b7675c58a..dbe3f80555 100755
--- a/ci/helper
+++ b/ci/helper
@@ -136,9 +136,16 @@ class Parser:
         refreshparser = subparsers.add_parser(
             "refresh",
             help="refresh data generated with lcitool",
-            parents=[lcitoolparser],
+            parents=[lcitoolparser, gitlabparser],
             formatter_class=argparse.ArgumentDefaultsHelpFormatter,
         )
+        refreshparser.add_argument(
+            "--check-stale",
+            action="store",
+            choices=["yes", "no"],
+            default="yes",
+            help="check for existence of stale images on the GitLab instance"
+        )
         refreshparser.set_defaults(func=Application.action_refresh)
 
     def parse(self):
@@ -286,10 +293,55 @@ class Application:
             print("Available cross-compiler container images:\n")
             print("\t" + "\n\t".join(cross))
 
+    def _list_stale_images(self):
+        # get list of hosts supported by lcitool
+        lcitool_hosts = self.lcitool_get_hosts()
+
+        # get images from gitlab registry
+        registry_uri = util.get_registry_uri(self.args.namespace,
+                                             self.args.gitlab_uri)
+        images = util.get_registry_images(registry_uri)
+
+        # extract distro names from the list of registry images
+        registry_distros = [util.get_image_distro(i["name"]) for i in images]
+
+        # check for stale images in GitLab registry
+        stale = set(registry_distros) - set(lcitool_hosts)
+        if stale:
+            stale_images = {}
+            for item in stale:
+                for img in images:
+                    if item in img["name"]:
+                        stale_images[img["name"]] = img["id"]
+
+        return stale_images
+
     def action_refresh(self):
+        # refresh Dockerfiles and vars files
         self.refresh_containers()
         self.refresh_cirrus()
 
+        # check for stale images
+        if self.args.check_stale == "yes" and not self.args.quiet:
+            namespace = self.args.namespace
+            gitlab_uri = self.args.gitlab_uri
+
+            stale_images = self._list_stale_images()
+            if stale_images:
+                spacing = "\n" + 4 * " "
+                stale_fmt = [f"{k}: {v}" for k, v in stale_images.items()]
+
+                print(f"""
+The following images are stale and can be purged from the registry:
+{spacing + spacing.join(stale_fmt)}
+
+You can remove the above images over the API with the following code snippet:
+
+    $ for image_id in {' '.join([str(id) for id in stale_images.values()])}; do
+          curl --request DELETE --header "PRIVATE-TOKEN: <access_token>" \\
+          {util.get_registry_uri(namespace, gitlab_uri)}/$image_id
+      done""")
+
     def run(self):
         self.args.func(self)
 
diff --git a/ci/util.py b/ci/util.py
index 8a2d6d8f47..f50c0e6100 100644
--- a/ci/util.py
+++ b/ci/util.py
@@ -37,3 +37,16 @@ def get_registry_images(uri: str) -> Dict[str, str]:
 
     # read the HTTP response and load the JSON part of it
     return json.loads(r.read().decode())
+
+
+def get_image_distro(image_name: str):
+    name_prefix = "ci-"
+    name_suffix = "-cross-"
+
+    distro = image_name[len(name_prefix):]
+
+    index = distro.find(name_suffix)
+    if index > 0:
+        distro = distro[:index]
+
+    return distro
-- 
2.29.2

Reply via email to