]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
ci: util: Add a registry checker for stale images
authorErik Skultety <eskultet@redhat.com>
Mon, 15 Mar 2021 14:42:13 +0000 (15:42 +0100)
committerErik Skultety <eskultet@redhat.com>
Fri, 19 Mar 2021 10:50:07 +0000 (11:50 +0100)
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 <eskultet@redhat.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
ci/helper
ci/util.py

index 31cf72fbdf4dc7f47f7c473488157586cd05e0e6..65abd68e3c09c99d2a4370d53fe2eba5cafc9430 100755 (executable)
--- a/ci/helper
+++ b/ci/helper
@@ -10,6 +10,7 @@ import pty
 import shutil
 import subprocess
 import sys
+import textwrap
 
 import util
 
@@ -130,7 +131,7 @@ 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(
@@ -139,6 +140,13 @@ class Parser:
             default=False,
             help="refresh data silently"
         )
+        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):
@@ -256,6 +264,39 @@ class Application:
 
             self.generate_vars(host)
 
+    def check_stale_images(self):
+        namespace = self.args.namespace
+        gitlab_uri = self.args.gitlab_uri
+        registry_uri = util.get_registry_uri(namespace, gitlab_uri)
+        lcitool_hosts = self.lcitool_get_hosts()
+
+        stale_images = util.get_registry_stale_images(registry_uri,
+                                                      lcitool_hosts)
+        if stale_images:
+            spacing = "\n" + 4 * " "
+            stale_fmt = [f"{k} (ID: {v})" for k, v in stale_images.items()]
+            stale_details = spacing.join(stale_fmt)
+            stale_ids = ' '.join([str(id) for id in stale_images.values()])
+            registry_uri = util.get_registry_uri(namespace, gitlab_uri)
+
+            msg = textwrap.dedent(f"""
+                The following images are stale and can be purged from the registry:
+
+                    STALE_DETAILS
+
+                You can delete the images listed above using this shell snippet:
+
+                    $ for image_id in {stale_ids}; do
+                          curl --request DELETE --header "PRIVATE-TOKEN: <access_token>" \\
+                               {registry_uri}/$image_id;
+                      done
+
+                You can generate a personal access token here:
+
+                    {gitlab_uri}/-/profile/personal_access_tokens
+            """)
+            print(msg.replace("STALE_DETAILS", stale_details))
+
     def action_build(self):
         self.make_run(f"ci-build@{self.args.target}")
 
@@ -291,6 +332,9 @@ class Application:
         self.refresh_containers()
         self.refresh_cirrus()
 
+        if self.args.check_stale == "yes" and not self.args.quiet:
+            self.check_stale_images()
+
     def run(self):
         self.args.func(self)
 
index f9f8320276d788bf11c6c4b2a083b2e11dc382eb..90d58454bee1f6eb4a80f6fa5d457e401728331e 100644 (file)
@@ -38,3 +38,44 @@ def get_registry_images(uri: str) -> List[Dict]:
 
     # read the HTTP response and load the JSON part of it
     return json.loads(r.read().decode())
+
+
+def get_image_distro(image_name: str) -> str:
+    """
+    Extract the name of the distro in the GitLab image registry name, e.g.
+        ci-debian-9-cross-mipsel --> debian-9
+
+    :param image_name: name of the GitLab registry image
+    :return: distro name as a string
+    """
+    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
+
+
+def get_registry_stale_images(registry_uri: str,
+                              supported_distros: List[str]) -> Dict[str, int]:
+    """
+    Check the GitLab image registry for images that we no longer support and
+    which should be deleted.
+
+    :param uri: URI pointing to a GitLab instance's image registry
+    :param supported_distros: list of hosts supported by lcitool
+    :return: dictionary formatted as: {<gitlab_image_name>: <gitlab_image_id>}
+    """
+
+    images = get_registry_images(registry_uri)
+
+    stale_images = {}
+    for img in images:
+        if get_image_distro(img["name"]) not in supported_distros:
+            stale_images[img["name"]] = img["id"]
+
+    return stale_images