From 6006ec64083d1f1d190ef340c78b8c5481c45c70 Mon Sep 17 00:00:00 2001 From: Jiri Hnidek Date: Mon, 9 Sep 2024 17:31:38 +0200 Subject: [PATCH] feat: dnf plugin - outsource uploading of profile to rhsmcertd. * Card ID: CCT-505, RHEL-35656 * When rhsmcertd is running, then uploading of profile is outsourced to rhsmcertd process simply by sending SIGUSR1 signal and dnf is not blocked by this activity * When it is not possible to send SIGUSR1 signal, then try to send DNF profile in blocking mode * This should also fix issue described in RHEL-35656 --- src/plugins/dnf/subscription_manager.py | 52 +++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/plugins/dnf/subscription_manager.py b/src/plugins/dnf/subscription_manager.py index dffd76cca6..d8883e172c 100644 --- a/src/plugins/dnf/subscription_manager.py +++ b/src/plugins/dnf/subscription_manager.py @@ -15,17 +15,19 @@ import os import logging import shutil +import signal from subscription_manager import injection as inj -from subscription_manager.action_client import ProfileActionClient from subscription_manager.repolib import RepoActionInvoker from subscription_manager.entcertlib import EntCertActionInvoker from rhsmlib.facts.hwprobe import ClassicCheck -from subscription_manager.utils import chroot, is_simple_content_access +from subscription_manager.utils import chroot, is_simple_content_access, is_process_running from subscription_manager.injectioninit import init_dep_injection from subscription_manager.i18n import ungettext, ugettext as _ from rhsm import logutil from rhsm import config +from rhsm.utils import LiveStatusMessage +from rhsm.connection import RemoteServerException from dnfpluginscore import logger import dnf @@ -152,6 +154,7 @@ def _update(cache_only): Update entitlement certificates and redhat.repo :param cache_only: is True, when rhsm.full_refresh_on_yum is set to 0 in rhsm.conf """ + logger.info(_("Updating Subscription Management repositories.")) identity: Identity = inj.require(inj.IDENTITY) ent_dir: EntitlementDirectory = inj.require(inj.ENT_DIR) @@ -241,7 +244,48 @@ def transaction(self): cfg = config.get_config_parser() if "1" == cfg.get("rhsm", "package_profile_on_trans"): log.debug("Uploading package profile") - package_profile_client = ProfileActionClient() - package_profile_client.update() + self._upload_profile() else: log.debug("Uploading package profile disabled in configuration file") + + def _upload_profile_blocking(self) -> None: + """ + Try to upload DNF profile to server + """ + log.debug("Uploading DNF profile in blocking mode") + with LiveStatusMessage("Uploading DNF profile"): + try: + profile_mgr = inj.require(inj.PROFILE_MANAGER) + identity = inj.require(inj.IDENTITY) + profile_mgr.update_check(self.cp, identity.uuid) + except RemoteServerException as err: + # When it is not possible to upload profile ATM, then print only error about this + # to rhsm.log. The rhsmcertd will try to upload it next time. + log.error("Unable to upload profile: {err}".format(err=str(err))) + + def _upload_profile(self) -> None: + """ + Try to upload DNF profile to server, when it is supported by server. This method + tries to "outsource" this activity to rhsmcertd first. When it is not possible due to + various reasons, then we try to do it ourselves in blocking way. + """ + # First try to get PID of rhsmcertd from lock file + try: + with open("/var/lock/subsys/rhsmcertd", "r") as lock_file: + rhsmcertd_pid = int(lock_file.readline()) + except (IOError, ValueError) as err: + log.info(f"Unable to read rhsmcertd lock file: {err}") + else: + if is_process_running("rhsmcertd", rhsmcertd_pid) is True: + # This will only send SIGUSR1 signal, which triggers gathering and uploading + # of DNF profile by rhsmcertd. We try to "outsource" this activity to rhsmcertd + # server to not block registration process + log.debug(f"Sending SIGUSR1 signal to rhsmcertd process ({rhsmcertd_pid})") + try: + os.kill(rhsmcertd_pid, signal.SIGUSR1) + except OSError as err: + log.debug(f"Unable to send SIGUSR1 signal to rhsmcertd process: {err}") + self._upload_profile_blocking() + else: + log.info(f"rhsmcertd process with given PID: {rhsmcertd_pid} is not running") + self._upload_profile_blocking()