Skip to content

Commit

Permalink
Subscription code updates - GTK GUI
Browse files Browse the repository at this point in the history
Adjust the GTK GUI for the Subscription code changes:
- reflect Satellite being used in the GUI
- better UX when Simple Content Access (SCA) is used
- drop support for displaying attached entitlements
  (support for entitlements has been dropped in RHEL 10 system-wide)

Resolves: RHEL-49661
Related: INSTALLER-3903
Related: INSTALLER-3903
  • Loading branch information
M4rtinK committed Nov 5, 2024
1 parent 4302fca commit 5034c47
Show file tree
Hide file tree
Showing 4 changed files with 498 additions and 395 deletions.
45 changes: 43 additions & 2 deletions pyanaconda/ui/gui/spokes/installation_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
SOURCE_TYPE_CLOSEST_MIRROR, SOURCE_TYPE_CDN, PAYLOAD_STATUS_SETTING_SOURCE, \
PAYLOAD_STATUS_INVALID_SOURCE, PAYLOAD_STATUS_CHECKING_SOFTWARE, SOURCE_TYPE_REPO_PATH, \
DRACUT_REPO_DIR
from pyanaconda.core.i18n import _, CN_
from pyanaconda.core.i18n import _, CN_, C_
from pyanaconda.core.path import join_paths
from pyanaconda.core.payload import parse_nfs_url, create_nfs_url, parse_hdd_url
from pyanaconda.core.regexes import URL_PARSE, HOSTNAME_PATTERN_WITHOUT_ANCHORS
Expand Down Expand Up @@ -122,7 +122,7 @@ def apply(self):
# attached there is no need to refresh the installation source,
# as without the subscription tokens the refresh would fail anyway.
if cdn_source and not self.subscribed:
log.debug("CDN source but no subscribtion attached - skipping payload restart.")
log.debug("CDN source but no subscription attached - skipping payload restart.")
elif source_changed or repo_changed or self._error:
payloadMgr.start(self.payload)
else:
Expand Down Expand Up @@ -311,6 +311,22 @@ def subscribed(self):
subscribed = subscription_proxy.IsSubscriptionAttached
return subscribed

@property
def registered_to_satellite(self):
"""Report if the system is registered to a Satellite instance.
NOTE: This will be always False when the Subscription
module is not available.
:return: True if registered to Satellite, False otherwise
:rtype: bool
"""
registered_to_satellite = False
if is_module_available(SUBSCRIPTION):
subscription_proxy = SUBSCRIPTION.get_proxy()
registered_to_satellite = subscription_proxy.IsRegisteredToSatellite
return registered_to_satellite

@property
def status(self):
# When CDN is selected as installation source and system
Expand All @@ -327,6 +343,11 @@ def status(self):
source_proxy = self.payload.get_source_proxy()
return source_proxy.Description

if cdn_source and self.subscribed and self.registered_to_satellite:
# override the regular CDN source name to make it clear Satellite
# provided repositories are being used
return _("Satellite")

if thread_manager.get(constants.THREAD_CHECK_SOFTWARE):
return _(PAYLOAD_STATUS_CHECKING_SOFTWARE)

Expand Down Expand Up @@ -725,6 +746,26 @@ def refresh(self):
# Update the URL entry validation now that we're done messing with sensitivites
self._update_url_entry_check()

# If subscription module is available we might need to refresh the label
# of the CDN/Satellite radio button, so that it properly describes what is providing
# the repositories available after registration.
#
# For registration to Red Hat hosted infrastructure (also called Hosted Candlepin) the
# global Red Hat CDN efficiently provides quick access to the repositories to customers
# across the world over the public Internet.
#
# If registered to a customer Satellite instance, it is the Satellite instance itself that
# provides the software repositories.
#
# This is an important distinction as Satellite instances are often used in environments
# not connected to the public Internet, so seeing the installation source being provided
# by Red Hat CDN which the machine might not be able to reach could be very confusing.
if is_module_available(SUBSCRIPTION):
if self.registered_to_satellite:
self._cdn_button.set_label(C_("GUI|Software Source", "_Satellite"))
else:
self._cdn_button.set_label(C_("GUI|Software Source", "Red Hat _CDN"))

# Show the info bar with an error message if any.
# This error message has the highest priority.
if self._error:
Expand Down
131 changes: 0 additions & 131 deletions pyanaconda/ui/gui/spokes/lib/subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@
# Red Hat, Inc.
#

import gi
gi.require_version("Gtk", "3.0")
gi.require_version("Pango", "1.0")
from gi.repository import Gtk, Pango

from collections import namedtuple

from pyanaconda.core.i18n import _
Expand Down Expand Up @@ -108,129 +103,3 @@ def fill_combobox(combobox, user_provided_value, valid_values):

# set the active id (what item should be selected in the combobox)
combobox.set_active_id(active_id)


def add_attached_subscription_delegate(listbox, subscription, delegate_index):
"""Add delegate representing an attached subscription to the listbox.
:param listbox: a listbox to add the delegate to
:type listbox: GTK ListBox
:param subscription: a subscription attached to the system
:type: AttachedSubscription instance
:param int delegate_index: index of the delegate in the listbox
"""
log.debug("Subscription GUI: adding subscription to listbox: %s", subscription.name)
# if we are not the first delegate, we should pre-pend a spacer, so that the
# actual delegates are nicely delimited
if delegate_index != 0:
row = Gtk.ListBoxRow()
row.set_name("subscriptions_listbox_row_spacer")
row.set_margin_top(4)
listbox.insert(row, -1)

# construct delegate
row = Gtk.ListBoxRow()
# set a name so that the ListBoxRow instance can be styled via CSS
row.set_name("subscriptions_listbox_row")

main_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
main_vbox.set_margin_top(12)
main_vbox.set_margin_bottom(12)

name_label = Gtk.Label(label='<span size="x-large">{}</span>'.format(subscription.name),
use_markup=True, wrap=True, wrap_mode=Pango.WrapMode.WORD_CHAR,
hexpand=True, xalign=0, yalign=0.5)
name_label.set_margin_start(12)
name_label.set_margin_bottom(12)

# create the first details grid
details_grid_1 = Gtk.Grid()
details_grid_1.set_column_spacing(12)
details_grid_1.set_row_spacing(12)

# first column
service_level_label = Gtk.Label(label="<b>{}</b>".format(_("Service level")),
use_markup=True, xalign=0)
service_level_status_label = Gtk.Label(label=subscription.service_level)
sku_label = Gtk.Label(label="<b>{}</b>".format(_("SKU")),
use_markup=True, xalign=0)
sku_status_label = Gtk.Label(label=subscription.sku, xalign=0)
contract_label = Gtk.Label(label="<b>{}</b>".format(_("Contract")),
use_markup=True, xalign=0)
contract_status_label = Gtk.Label(label=subscription.contract, xalign=0)

# add first column to the grid
details_grid_1.attach(service_level_label, 0, 0, 1, 1)
details_grid_1.attach(service_level_status_label, 1, 0, 1, 1)
details_grid_1.attach(sku_label, 0, 1, 1, 1)
details_grid_1.attach(sku_status_label, 1, 1, 1, 1)
details_grid_1.attach(contract_label, 0, 2, 1, 1)
details_grid_1.attach(contract_status_label, 1, 2, 1, 1)

# second column
start_date_label = Gtk.Label(label="<b>{}</b>".format(_("Start date")),
use_markup=True, xalign=0)
start_date_status_label = Gtk.Label(label=subscription.start_date, xalign=0)
end_date_label = Gtk.Label(label="<b>{}</b>".format(_("End date")),
use_markup=True, xalign=0)
end_date_status_label = Gtk.Label(label=subscription.end_date, xalign=0)
entitlements_label = Gtk.Label(label="<b>{}</b>".format(_("Entitlements")),
use_markup=True, xalign=0)
entitlement_string = _("{} consumed").format(subscription.consumed_entitlement_count)
entitlements_status_label = Gtk.Label(label=entitlement_string, xalign=0)

# create the second details grid
details_grid_2 = Gtk.Grid()
details_grid_2.set_column_spacing(12)
details_grid_2.set_row_spacing(12)

# add second column to the grid
details_grid_2.attach(start_date_label, 0, 0, 1, 1)
details_grid_2.attach(start_date_status_label, 1, 0, 1, 1)
details_grid_2.attach(end_date_label, 0, 1, 1, 1)
details_grid_2.attach(end_date_status_label, 1, 1, 1, 1)
details_grid_2.attach(entitlements_label, 0, 2, 1, 1)
details_grid_2.attach(entitlements_status_label, 1, 2, 1, 1)

details_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=16)
details_hbox.pack_start(details_grid_1, True, True, 12)
details_hbox.pack_start(details_grid_2, True, True, 0)

main_vbox.pack_start(name_label, True, True, 0)
main_vbox.pack_start(details_hbox, True, True, 0)

row.add(main_vbox)

# append delegate to listbox
listbox.insert(row, -1)


def populate_attached_subscriptions_listbox(listbox, attached_subscriptions):
"""Populate the attached subscriptions listbox with delegates.
Unfortunately it does not seem to be possible to create delegate templates
that could be reused for each data item in the listbox via Glade, so
we need to construct them imperatively via Python GTK API.
:param listbox: listbox to populate
:type listbox: GTK ListBox
:param attached_subscriptions: list of AttachedSubscription instances
"""
log.debug("Subscription GUI: populating attached subscriptions listbox")

# start by making sure the listbox is empty
for child in listbox.get_children():
listbox.remove(child)
del(child)

# add one delegate per attached subscription
delegate_index = 0
for subscription in attached_subscriptions:
add_attached_subscription_delegate(listbox, subscription, delegate_index)
delegate_index = delegate_index + 1

# Make sure the delegates are actually visible after the listbox has been cleared.
# Without show_all() nothing would be visible past first clear.
listbox.show_all()

log.debug("Subscription GUI: attached subscriptions listbox has been populated")
Loading

0 comments on commit 5034c47

Please sign in to comment.