From a4e9ee7ebaa55a3ae7360204e418334d42d72d21 Mon Sep 17 00:00:00 2001
From: Jakub Kadlcik <frostyx@email.cz>
Date: Thu, 26 Sep 2024 06:23:06 +0200
Subject: [PATCH] rpmbuild, frontend: activate Red Hat subscription on demand

Fix #2132
---
 .../coprs/views/backend_ns/backend_general.py |  6 ++-
 rpmbuild/copr_rpmbuild/rhsm.py                | 47 +++++++++++++++++++
 rpmbuild/main.py                              |  4 ++
 3 files changed, 56 insertions(+), 1 deletion(-)
 create mode 100644 rpmbuild/copr_rpmbuild/rhsm.py

diff --git a/frontend/coprs_frontend/coprs/views/backend_ns/backend_general.py b/frontend/coprs_frontend/coprs/views/backend_ns/backend_general.py
index 0cd94058a..cf6ad7c52 100755
--- a/frontend/coprs_frontend/coprs/views/backend_ns/backend_general.py
+++ b/frontend/coprs_frontend/coprs/views/backend_ns/backend_general.py
@@ -143,7 +143,11 @@ def get_build_record(task, for_backend=False):
         "sandbox": task.build.sandbox,
         "background": bool(task.build.is_background),
         "chroot": task.mock_chroot.name,
-        "tags": task.mock_chroot.tags + task.tags,
+        "tags": task.mock_chroot.tags + task.tags + (
+            # TODO just for testing purposes, add a boolean
+            # `models.MockChroot.subscription` column to the database?
+            ["subscription"] if task.mock_chroot.name == "rhel-9-x86_64" else []
+        ),
         "allow_user_ssh": bool(task.build.ssh_public_keys),
     }
 
diff --git a/rpmbuild/copr_rpmbuild/rhsm.py b/rpmbuild/copr_rpmbuild/rhsm.py
new file mode 100644
index 000000000..5e757d113
--- /dev/null
+++ b/rpmbuild/copr_rpmbuild/rhsm.py
@@ -0,0 +1,47 @@
+"""
+Red Hat Subscription Management
+
+Activating Red Hat subscription may take a lot of time and historically, the
+subscription service used to be unreliable, so we should wait for the
+subscription only when necessary.
+"""
+
+import time
+import logging
+import subprocess
+
+
+log = logging.getLogger("__main__")
+
+
+def subscription_required(task):
+    """
+    Is subscription required for this task?
+    """
+    return "subscription" in task["tags"]
+
+
+def active_subscription():
+    """
+    Is subscription active on this system?
+    """
+    cmd = ["subscription-manager", "status"]
+    proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    return proc.returncode == 0
+
+
+def wait_for_subscription(timeout=86400):
+    """
+    Wait until this system has an active subscription
+    """
+    start = time.time()
+    attempt = 1
+    while True:
+        log.info("Checking Red Hat subscription (attempt #%s)", attempt)
+        if active_subscription():
+            log.info("Red Hat subscription active")
+            return
+        if time.time() > start + timeout:
+            raise RuntimeError("Waiting for Red Hat subscription timeouted!")
+        time.sleep(30)
+        attempt += 1
diff --git a/rpmbuild/main.py b/rpmbuild/main.py
index ab4edb2d3..c9d744513 100755
--- a/rpmbuild/main.py
+++ b/rpmbuild/main.py
@@ -25,6 +25,7 @@
     locate_srpm,
     package_version,
 )
+from copr_rpmbuild.rhsm import subscription_required, wait_for_subscription
 from six.moves.urllib.parse import urlparse, urljoin, urlencode
 
 log = logging.getLogger(__name__)
@@ -256,6 +257,9 @@ def build_rpm(args, config):
     task = get_task(args, config, build_config_url_path, task_id)
     log_task(task)
 
+    if subscription_required(task):
+        wait_for_subscription()
+
     try:
         source_json = {
             "clone_url": task["git_repo"],