Skip to content

Commit

Permalink
Subscription code updates - backend
Browse files Browse the repository at this point in the history
This commit contains basically 3 things:
* Satellite support ported for the RHEL 9 branch, adjusted
  for changes done in upstream since RHEL 9 has been branched
* all Satellite support & subscription code fixes from the RHEL 9 branch
* removal of entitlement support as entitlements are no longer supported
  in RHEL 10 & Simple Content Access (SCA) is always used instead

Resolves: RHEL-49661
Related: INSTALLER-3903
Related: INSTALLER-3903
  • Loading branch information
M4rtinK committed Nov 5, 2024
1 parent c3f04c0 commit 22c0b4b
Show file tree
Hide file tree
Showing 11 changed files with 1,010 additions and 572 deletions.
27 changes: 27 additions & 0 deletions pyanaconda/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
InsightsClientMissingError, InsightsConnectError
from pyanaconda.modules.common.errors.payload import SourceSetupError
from pyanaconda.modules.common.errors.storage import UnusableStorageError
from pyanaconda.modules.common.errors.subscription import SatelliteProvisioningError


class ScriptError(Exception):
Expand Down Expand Up @@ -110,6 +111,10 @@ def _get_default_mapping(self):
InsightsClientMissingError.__name__: self._insightsErrorHandler,
InsightsConnectError.__name__: self._insightsErrorHandler,
"KickstartRegistrationError": self._kickstartRegistrationErrorHandler,
"SubscriptionTokenTransferError": self._subscriptionTokenTransferErrorHandler,

# Satellite
SatelliteProvisioningError.__name__: self._target_satellite_provisioning_error_handler,

# General installation errors.
NonCriticalInstallationError.__name__: self._non_critical_error_handler,
Expand Down Expand Up @@ -175,6 +180,13 @@ def _bootloader_error_handler(self, exn):
else:
return ERROR_RAISE

def _target_satellite_provisioning_error_handler(self, exn):
message = _("Failed to provision the target system for Satellite.")
details = str(exn)

self.ui.showDetailedError(message, details)
return ERROR_RAISE

def _non_critical_error_handler(self, exn):
message = _("The following error occurred during the installation:"
"\n\n{details}\n\nWould you like to ignore this and "
Expand Down Expand Up @@ -210,6 +222,21 @@ def _kickstartRegistrationErrorHandler(self, exn):
else:
return ERROR_RAISE

def _subscriptionTokenTransferErrorHandler(self, exn):
message = _("Failed to enable Red Hat subscription on the "
"installed system."
"\n\n"
"Your Red Hat subscription might be invalid "
"(such as due to an expired developer subscription)."
"\n\n"
"Would you like to ignore this and continue with "
"installation?")

if self.ui.showYesNoQuestion(message):
return ERROR_CONTINUE
else:
return ERROR_RAISE

def cb(self, exn):
"""This method is the callback that all error handling should pass
through. The return value is one of the ERROR_* constants defined
Expand Down
10 changes: 0 additions & 10 deletions pyanaconda/modules/common/constants/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,16 +140,6 @@
basename="Unregister"
)

RHSM_ATTACH = DBusObjectIdentifier(
namespace=RHSM_NAMESPACE,
basename="Attach"
)

RHSM_ENTITLEMENT = DBusObjectIdentifier(
namespace=RHSM_NAMESPACE,
basename="Entitlement"
)

RHSM_SYSPURPOSE = DBusObjectIdentifier(
namespace=RHSM_NAMESPACE,
basename="Syspurpose"
Expand Down
6 changes: 6 additions & 0 deletions pyanaconda/modules/common/errors/installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,9 @@ class InsightsConnectError(InstallationError):
class SubscriptionTokenTransferError(InstallationError):
"""Exception for errors during subscription token transfer."""
pass


@dbus_error("TargetSatelliteProvisioningError", namespace=ANACONDA_NAMESPACE)
class TargetSatelliteProvisioningError(InstallationError):
"""Exception for errors when provisioning target system for Satellite."""
pass
12 changes: 9 additions & 3 deletions pyanaconda/modules/common/errors/subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ class UnregistrationError(AnacondaError):
pass


@dbus_error("SubscriptionError", namespace=ANACONDA_NAMESPACE)
class SubscriptionError(AnacondaError):
"""Subscription attempt failed."""
@dbus_error("SatelliteProvisioningError", namespace=ANACONDA_NAMESPACE)
class SatelliteProvisioningError(AnacondaError):
"""Failed to provision the installation environment for Satellite."""
pass


@dbus_error("MultipleOrganizationsError", namespace=ANACONDA_NAMESPACE)
class MultipleOrganizationsError(AnacondaError):
"""Account is member of more than one organization."""
pass
173 changes: 46 additions & 127 deletions pyanaconda/modules/common/structures/subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@

from pyanaconda.modules.common.structures.secret import SecretData, SecretDataList

__all__ = ["SystemPurposeData", "SubscriptionRequest", "AttachedSubscription"]

__all__ = ["SystemPurposeData", "SubscriptionRequest"]

class SystemPurposeData(DBusData):
"""System purpose data."""
Expand Down Expand Up @@ -141,6 +140,7 @@ def __init__(self):
# need to be set
self._organization = ""
self._redhat_account_username = ""
self._redhat_account_organization = ""
# Candlepin instance
self._server_hostname = ""
# CDN base url
Expand Down Expand Up @@ -228,6 +228,27 @@ def account_username(self) -> Str:
def account_username(self, account_username: Str):
self._redhat_account_username = account_username

@property
def account_organization(self) -> Str:
"""Red Hat account organization for subscription purposes.
In case the account for the given username is member
of multiple organizations, organization id needs to
be specified as well or else the registration attempt
will not be successful. This account dependent organization
id is deliberately separate from the org + key org id
to avoid collisions and issues in the GUI when switching
between authentication types.
:return: Red Hat account organization id
:rtype: str
"""
return self._redhat_account_organization

@account_organization.setter
def account_organization(self, account_organization: Str):
self._redhat_account_organization = account_organization

@property
def server_hostname(self) -> Str:
"""Subscription server hostname.
Expand Down Expand Up @@ -392,145 +413,43 @@ def server_proxy_password(self, password: SecretData):
self._server_proxy_password = password


class AttachedSubscription(DBusData):
"""Data for a single attached subscription."""
class OrganizationData(DBusData):
"""Data about a single organization in the Red Hat account system.
A Red Hat account is expected to be member of an organization,
with some accounts being members of more than one organization.
"""

def __init__(self):
self._id = ""
self._name = ""
self._service_level = ""
self._sku = ""
self._contract = ""
self._start_date = ""
self._end_date = ""
# we can expect at least one entitlement
# to be consumed per attached subscription
self._consumed_entitlement_count = 1

@property
def name(self) -> Str:
"""Name of the attached subscription.
Example: "Red Hat Beta Access"
:return: subscription name
:rtype: str
"""
return self._name

@name.setter
def name(self, name: Str):
self._name = name

@property
def service_level(self) -> Str:
"""Service level of the attached subscription.
Example: "Premium"
:return: service level
:rtype: str
"""
return self._service_level

@service_level.setter
def service_level(self, service_level: Str):
self._service_level = service_level

@property
def sku(self) -> Str:
"""SKU id of the attached subscription.
def id(self) -> Str:
"""Id of the organization.
Example: "MBT8547"
Example: "abc123efg456"
:return: SKU id
:rtype: str
"""
return self._sku

@sku.setter
def sku(self, sku: Str):
self._sku = sku

@property
def contract(self) -> Str:
"""Contract identifier.
Example: "32754658"
:return: contract identifier
:rtype: str
"""
return self._contract

@contract.setter
def contract(self, contract: Str):
self._contract = contract

@property
def start_date(self) -> Str:
"""Subscription start date.
We do not guarantee fixed date format,
but we aim for the date to look good
when displayed in a GUI and be human
readable.
For context see the following bug, that
illustrates the issues we are having with
the source date for this property, that
prevent us from providing a consistent
date format:
https://bugzilla.redhat.com/show_bug.cgi?id=1793501
Example: "Nov 04, 2019"
:return: start date of the subscription
:return: organization id
:rtype: str
"""
return self._start_date
return self._id

@start_date.setter
def start_date(self, start_date: Str):
self._start_date = start_date
@id.setter
def id(self, organization_id: Str):
self._id = organization_id

@property
def end_date(self) -> Str:
"""Subscription end date.
We do not guarantee fixed date format,
but we aim for the date to look good
when displayed in a GUI and be human
readable.
For context see the following bug, that
illustrates the issues we are having with
the source date for this property, that
prevent us from providing a consistent
date format:
https://bugzilla.redhat.com/show_bug.cgi?id=1793501
def name(self) -> Str:
"""Name of the organization.
Example: "Nov 04, 2020"
Example: "Foo Organization"
:return: end date of the subscription
:return: organization name
:rtype: str
"""
return self._end_date

@end_date.setter
def end_date(self, end_date: Str):
self._end_date = end_date

@property
def consumed_entitlement_count(self) -> Int:
"""Number of consumed entitlements for this subscription.
Example: "1"
:return: consumed entitlement number
:rtype: int
"""
return self._consumed_entitlement_count
return self._name

@consumed_entitlement_count.setter
def consumed_entitlement_count(self, consumed_entitlement_count: Int):
self._consumed_entitlement_count = consumed_entitlement_count
@name.setter
def name(self, organization_name: Str):
self._name = organization_name
14 changes: 14 additions & 0 deletions pyanaconda/modules/common/task/runnable.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
__all__ = ['Runnable']


from pyanaconda.anaconda_loggers import get_module_logger
log = get_module_logger(__name__)




class Runnable(ABC):
"""Abstract class that allows to run a task."""

Expand Down Expand Up @@ -92,6 +98,8 @@ def start(self):
@async_action_nowait
def _task_started_callback(self):
"""Callback for a started task."""
for i in self._started_signal._methods:
log.debug(i)
self._started_signal.emit()

@abstractmethod
Expand All @@ -102,16 +110,22 @@ def _task_run_callback(self):
@async_action_nowait
def _task_failed_callback(self):
"""Callback for a failed task."""
for i in self._failed_signal._methods:
log.debug(i)
self._failed_signal.emit()

@async_action_nowait
def _task_succeeded_callback(self):
"""Callback for a successful task."""
for i in self._succeeded_signal._methods:
log.debug(i)
self._succeeded_signal.emit()

@async_action_nowait
def _task_stopped_callback(self):
"""Callback for a terminated task."""
for i in self._stopped_signal._methods:
log.debug(i)
self._stopped_signal.emit()

@abstractmethod
Expand Down
Loading

0 comments on commit 22c0b4b

Please sign in to comment.