[libvirt PATCH v4 5/6] ci: util: Add a registry checker for stale images

Erik Skultety posted 6 patches 4 years, 9 months ago
[libvirt PATCH v4 5/6] ci: util: Add a registry checker for stale images
Posted by Erik Skultety 4 years, 9 months ago
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>
---
 ci/helper  | 46 +++++++++++++++++++++++++++++++++++++++++++++-
 ci/util.py | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/ci/helper b/ci/helper
index 31cf72fbdf..0743f95e13 100755
--- 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):
@@ -287,10 +295,46 @@ class Application:
             print("Available cross-compiler container images:\n")
             print(spacing + ("\n" + spacing).join(cross))
 
+    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_refresh(self):
         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)
 
diff --git a/ci/util.py b/ci/util.py
index f9f8320276..90d58454be 100644
--- a/ci/util.py
+++ b/ci/util.py
@@ -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
-- 
2.30.2

Re: [libvirt PATCH v4 5/6] ci: util: Add a registry checker for stale images
Posted by Andrea Bolognani 4 years, 9 months ago
On Thu, 2021-03-18 at 17:11 +0100, Erik Skultety wrote:
> +            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;

There should be one additional leading space here, to align things
better.

Please also move the check_stale_image() function after the
refresh_cirrus() image - basically all action_*() functions should
continue being grouped together.

With those tweaks,

  Reviewed-by: Andrea Bolognani <abologna@redhat.com>

-- 
Andrea Bolognani / Red Hat / Virtualization

Re: [libvirt PATCH v4 5/6] ci: util: Add a registry checker for stale images
Posted by Erik Skultety 4 years, 9 months ago
On Thu, Mar 18, 2021 at 05:32:14PM +0100, Andrea Bolognani wrote:
> On Thu, 2021-03-18 at 17:11 +0100, Erik Skultety wrote:
> > +            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;
> 
> There should be one additional leading space here, to align things
> better.
> 
> Please also move the check_stale_image() function after the
> refresh_cirrus() image - basically all action_*() functions should
> continue being grouped together.
> 
> With those tweaks,
> 
>   Reviewed-by: Andrea Bolognani <abologna@redhat.com>

The series is now merged. Thank you for review. Now, since you're one of the
repo owners in GitLab, would you mind purging the old images? :)

Erik

Re: [libvirt PATCH v4 5/6] ci: util: Add a registry checker for stale images
Posted by Andrea Bolognani 4 years, 9 months ago
On Fri, 2021-03-19 at 11:55 +0100, Erik Skultety wrote:
> The series is now merged. Thank you for review. Now, since you're one of the
> repo owners in GitLab, would you mind purging the old images? :)

Done!

-- 
Andrea Bolognani / Red Hat / Virtualization