Skip to content

Commit

Permalink
Merge pull request #5982 from M4rtinK/rhel-10-sync_subscription_code_…
Browse files Browse the repository at this point in the history
…from_rhel_9

Sync subscription code from rhel 9
  • Loading branch information
M4rtinK authored Nov 11, 2024
2 parents 63a3b36 + 7a151a5 commit 8bb5ddd
Show file tree
Hide file tree
Showing 20 changed files with 3,086 additions and 1,634 deletions.
2 changes: 1 addition & 1 deletion anaconda.spec.in
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Source0: https://github.com/rhinstaller/%{name}/releases/download/%{name}-%{vers
%define pythonblivetver 1:3.9.0-1
%define rpmver 4.15.0
%define simplelinever 1.9.0-1
%define subscriptionmanagerver 1.26
%define subscriptionmanagerver 1.29.31
%define utillinuxver 2.15.1
%define rpmostreever 2023.2
%define s390utilscorever 2.31.0
Expand Down
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
57 changes: 57 additions & 0 deletions pyanaconda/modules/subscription/installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
from pyanaconda.modules.common.task import Task
from pyanaconda.modules.common.errors.installation import InsightsConnectError, \
InsightsClientMissingError, SubscriptionTokenTransferError
from pyanaconda.modules.common.errors.subscription import SatelliteProvisioningError
from pyanaconda.modules.subscription import satellite

from pyanaconda.anaconda_loggers import get_module_logger
log = get_module_logger(__name__)
Expand Down Expand Up @@ -245,3 +247,58 @@ def run(self):

# transfer the RHSM config file
self._transfer_file(self.RHSM_CONFIG_FILE_PATH, "RHSM config file")


class ProvisionTargetSystemForSatelliteTask(Task):
"""Provision target system for communication with Satellite.
If the System gets registered to Satellite at installation time,
the provisioning is applied only to the installation environment.
This task makes sure it is applied also on the target system.
Run the appropriate Satellite provisioning script on the target system.
This should assure the target system has all the needed certificates
installed and rhsm.conf tweaks applied.
"""

def __init__(self, provisioning_script):
"""Create a new task.
:param str provisioning_script: Satellite provisioning script in string form
"""
super().__init__()
self._provisioning_script = provisioning_script

@property
def name(self):
return "Provisioning target system for Satellite"

def run(self):
"""Provision target system for Satellite.
First check if we are actually registered to a Satellite instance
by checking if we got a provisioning script.
If not, do nothing.
If we are registered to a Satellite instance, run the Satellite
provisioning script that has been downloaded from the instance previously.
"""
if self._provisioning_script:
log.debug("subscription: provisioning target system for Satellite")
provisioning_success = satellite.run_satellite_provisioning_script(
provisioning_script=self._provisioning_script,
run_on_target_system=True

)
if provisioning_success:
log.debug("subscription: target system successfully provisioned for Satellite")
else:
raise SatelliteProvisioningError("Satellite provisioning script failed.")
else:
# lets assume here that no provisioning script == not registered to Satellite
log.debug(
"subscription: not registered to Satellite, skipping Satellite provisioning."
)
Loading

0 comments on commit 8bb5ddd

Please sign in to comment.