代码拉取完成,页面将自动刷新
同步操作将从 src-anolis-os/anaconda 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
From 3bf64459635f20bdb221ae11616b07f0fd009d3a Mon Sep 17 00:00:00 2001
From: Liwei Ge <geliwei@openanolis.org>
Date: Fri, 13 May 2022 15:21:39 +0800
Subject: [PATCH 3/7] install: remove system purpose components
---
configure | 5 +-
configure.ac | 1 -
...project.Anaconda.Modules.Subscription.conf | 14 -
...ject.Anaconda.Modules.Subscription.service | 4 -
pyanaconda/core/constants.py | 32 -
pyanaconda/core/kickstart/commands.py | 1 -
pyanaconda/core/subscription.py | 40 -
pyanaconda/installation.py | 14 +-
pyanaconda/modules/Makefile.am | 2 +-
pyanaconda/modules/Makefile.in | 2 +-
.../modules/common/constants/namespaces.py | 6 -
.../modules/common/constants/objects.py | 40 +-
.../modules/common/constants/services.py | 7 +-
.../modules/common/errors/installation.py | 5 -
.../modules/common/errors/subscription.py | 39 -
.../modules/common/structures/subscription.py | 537 --------
pyanaconda/modules/subscription/Makefile.am | 21 -
pyanaconda/modules/subscription/Makefile.in | 567 --------
pyanaconda/modules/subscription/__main__.py | 25 -
.../modules/subscription/installation.py | 248 ----
pyanaconda/modules/subscription/kickstart.py | 28 -
.../modules/subscription/subscription.py | 789 -----------
.../subscription/subscription_interface.py | 211 ---
.../modules/subscription/system_purpose.py | 227 ----
pyanaconda/payload/dnf/payload.py | 38 +-
.../ui/gui/spokes/installation_source.glade | 21 +-
.../ui/gui/spokes/installation_source.py | 35 +-
pyanaconda/ui/gui/spokes/lib/subscription.py | 236 ----
.../ui/gui/spokes/software_selection.py | 10 -
pyanaconda/ui/gui/spokes/subscription.glade | 992 --------------
pyanaconda/ui/gui/spokes/subscription.py | 1154 -----------------
pyanaconda/ui/lib/subscription.py | 406 ------
32 files changed, 16 insertions(+), 5741 deletions(-)
delete mode 100644 data/dbus/org.fedoraproject.Anaconda.Modules.Subscription.conf
delete mode 100644 data/dbus/org.fedoraproject.Anaconda.Modules.Subscription.service
delete mode 100644 pyanaconda/core/subscription.py
delete mode 100644 pyanaconda/modules/common/errors/subscription.py
delete mode 100644 pyanaconda/modules/common/structures/subscription.py
delete mode 100644 pyanaconda/modules/subscription/Makefile.am
delete mode 100644 pyanaconda/modules/subscription/Makefile.in
delete mode 100644 pyanaconda/modules/subscription/__main__.py
delete mode 100644 pyanaconda/modules/subscription/installation.py
delete mode 100644 pyanaconda/modules/subscription/kickstart.py
delete mode 100644 pyanaconda/modules/subscription/subscription.py
delete mode 100644 pyanaconda/modules/subscription/subscription_interface.py
delete mode 100644 pyanaconda/modules/subscription/system_purpose.py
delete mode 100644 pyanaconda/ui/gui/spokes/lib/subscription.py
delete mode 100644 pyanaconda/ui/gui/spokes/subscription.glade
delete mode 100644 pyanaconda/ui/gui/spokes/subscription.py
delete mode 100644 pyanaconda/ui/lib/subscription.py
diff --git a/configure b/configure
index 7a7fbed..e97c1d7 100755
--- a/configure
+++ b/configure
@@ -14574,9 +14574,7 @@ s_arch="`echo $build_cpu | sed -e s/i.86/i386/ -e s/powerpc.*/ppc/`"
subdirs="$subdirs widgets"
-
-
-ac_config_files="$ac_config_files Makefile anaconda.spec data/Makefile data/command-stubs/Makefile docs/Makefile dracut/Makefile data/conf.d/Makefile data/product.d/Makefile data/liveinst/Makefile data/liveinst/console.apps/Makefile data/liveinst/gnome/Makefile data/liveinst/pam.d/Makefile data/systemd/Makefile data/dbus/Makefile data/window-manager/Makefile data/window-manager/config/Makefile po/Makefile scripts/Makefile pyanaconda/Makefile pyanaconda/version.py pyanaconda/core/Makefile pyanaconda/core/kickstart/Makefile pyanaconda/core/configuration/Makefile pyanaconda/core/startup/Makefile pyanaconda/isys/Makefile pyanaconda/payload/Makefile pyanaconda/payload/dnf/Makefile pyanaconda/payload/live/Makefile pyanaconda/payload/source/Makefile pyanaconda/ui/Makefile pyanaconda/ui/categories/Makefile pyanaconda/ui/lib/Makefile pyanaconda/ui/gui/hubs/Makefile pyanaconda/ui/gui/spokes/Makefile pyanaconda/ui/gui/spokes/advstorage/Makefile pyanaconda/ui/gui/spokes/lib/Makefile pyanaconda/ui/gui/Makefile pyanaconda/ui/tui/hubs/Makefile pyanaconda/ui/tui/spokes/Makefile pyanaconda/ui/tui/Makefile pyanaconda/modules/Makefile pyanaconda/modules/common/Makefile pyanaconda/modules/common/base/Makefile pyanaconda/modules/common/task/Makefile pyanaconda/modules/common/errors/Makefile pyanaconda/modules/common/constants/Makefile pyanaconda/modules/common/structures/Makefile pyanaconda/modules/boss/Makefile pyanaconda/modules/boss/install_manager/Makefile pyanaconda/modules/boss/kickstart_manager/Makefile pyanaconda/modules/boss/module_manager/Makefile pyanaconda/modules/security/Makefile pyanaconda/modules/timezone/Makefile pyanaconda/modules/network/Makefile pyanaconda/modules/network/firewall/Makefile pyanaconda/modules/localization/Makefile pyanaconda/modules/users/Makefile pyanaconda/modules/payloads/Makefile pyanaconda/modules/payloads/packages/Makefile pyanaconda/modules/payloads/payload/Makefile pyanaconda/modules/payloads/payload/dnf/Makefile pyanaconda/modules/payloads/payload/live_os/Makefile pyanaconda/modules/payloads/payload/live_image/Makefile pyanaconda/modules/payloads/base/Makefile pyanaconda/modules/payloads/source/Makefile pyanaconda/modules/payloads/source/cdn/Makefile pyanaconda/modules/payloads/source/cdrom/Makefile pyanaconda/modules/payloads/source/closest_mirror/Makefile pyanaconda/modules/payloads/source/harddrive/Makefile pyanaconda/modules/payloads/source/hmc/Makefile pyanaconda/modules/payloads/source/live_os/Makefile pyanaconda/modules/payloads/source/nfs/Makefile pyanaconda/modules/payloads/source/repo_files/Makefile pyanaconda/modules/payloads/source/url/Makefile pyanaconda/modules/storage/Makefile pyanaconda/modules/storage/bootloader/Makefile pyanaconda/modules/storage/checker/Makefile pyanaconda/modules/storage/dasd/Makefile pyanaconda/modules/storage/devicetree/Makefile pyanaconda/modules/storage/disk_initialization/Makefile pyanaconda/modules/storage/disk_selection/Makefile pyanaconda/modules/storage/fcoe/Makefile pyanaconda/modules/storage/iscsi/Makefile pyanaconda/modules/storage/nvdimm/Makefile pyanaconda/modules/storage/partitioning/Makefile pyanaconda/modules/storage/partitioning/automatic/Makefile pyanaconda/modules/storage/partitioning/blivet/Makefile pyanaconda/modules/storage/partitioning/custom/Makefile pyanaconda/modules/storage/partitioning/interactive/Makefile pyanaconda/modules/storage/partitioning/manual/Makefile pyanaconda/modules/storage/snapshot/Makefile pyanaconda/modules/storage/zfcp/Makefile pyanaconda/modules/services/Makefile pyanaconda/modules/subscription/Makefile data/post-scripts/Makefile data/pixmaps/Makefile tests/Makefile utils/Makefile utils/dd/Makefile"
+ac_config_files="$ac_config_files Makefile anaconda.spec data/Makefile data/command-stubs/Makefile docs/Makefile dracut/Makefile data/conf.d/Makefile data/product.d/Makefile data/liveinst/Makefile data/liveinst/console.apps/Makefile data/liveinst/gnome/Makefile data/liveinst/pam.d/Makefile data/systemd/Makefile data/dbus/Makefile data/window-manager/Makefile data/window-manager/config/Makefile po/Makefile scripts/Makefile pyanaconda/Makefile pyanaconda/version.py pyanaconda/core/Makefile pyanaconda/core/kickstart/Makefile pyanaconda/core/configuration/Makefile pyanaconda/core/startup/Makefile pyanaconda/isys/Makefile pyanaconda/payload/Makefile pyanaconda/payload/dnf/Makefile pyanaconda/payload/live/Makefile pyanaconda/payload/source/Makefile pyanaconda/ui/Makefile pyanaconda/ui/categories/Makefile pyanaconda/ui/lib/Makefile pyanaconda/ui/gui/hubs/Makefile pyanaconda/ui/gui/spokes/Makefile pyanaconda/ui/gui/spokes/advstorage/Makefile pyanaconda/ui/gui/spokes/lib/Makefile pyanaconda/ui/gui/Makefile pyanaconda/ui/tui/hubs/Makefile pyanaconda/ui/tui/spokes/Makefile pyanaconda/ui/tui/Makefile pyanaconda/modules/Makefile pyanaconda/modules/common/Makefile pyanaconda/modules/common/base/Makefile pyanaconda/modules/common/task/Makefile pyanaconda/modules/common/errors/Makefile pyanaconda/modules/common/constants/Makefile pyanaconda/modules/common/structures/Makefile pyanaconda/modules/boss/Makefile pyanaconda/modules/boss/install_manager/Makefile pyanaconda/modules/boss/kickstart_manager/Makefile pyanaconda/modules/boss/module_manager/Makefile pyanaconda/modules/security/Makefile pyanaconda/modules/timezone/Makefile pyanaconda/modules/network/Makefile pyanaconda/modules/network/firewall/Makefile pyanaconda/modules/localization/Makefile pyanaconda/modules/users/Makefile pyanaconda/modules/payloads/Makefile pyanaconda/modules/payloads/packages/Makefile pyanaconda/modules/payloads/payload/Makefile pyanaconda/modules/payloads/payload/dnf/Makefile pyanaconda/modules/payloads/payload/live_os/Makefile pyanaconda/modules/payloads/payload/live_image/Makefile pyanaconda/modules/payloads/base/Makefile pyanaconda/modules/payloads/source/Makefile pyanaconda/modules/payloads/source/cdn/Makefile pyanaconda/modules/payloads/source/cdrom/Makefile pyanaconda/modules/payloads/source/closest_mirror/Makefile pyanaconda/modules/payloads/source/harddrive/Makefile pyanaconda/modules/payloads/source/hmc/Makefile pyanaconda/modules/payloads/source/live_os/Makefile pyanaconda/modules/payloads/source/nfs/Makefile pyanaconda/modules/payloads/source/repo_files/Makefile pyanaconda/modules/payloads/source/url/Makefile pyanaconda/modules/storage/Makefile pyanaconda/modules/storage/bootloader/Makefile pyanaconda/modules/storage/checker/Makefile pyanaconda/modules/storage/dasd/Makefile pyanaconda/modules/storage/devicetree/Makefile pyanaconda/modules/storage/disk_initialization/Makefile pyanaconda/modules/storage/disk_selection/Makefile pyanaconda/modules/storage/fcoe/Makefile pyanaconda/modules/storage/iscsi/Makefile pyanaconda/modules/storage/nvdimm/Makefile pyanaconda/modules/storage/partitioning/Makefile pyanaconda/modules/storage/partitioning/automatic/Makefile pyanaconda/modules/storage/partitioning/blivet/Makefile pyanaconda/modules/storage/partitioning/custom/Makefile pyanaconda/modules/storage/partitioning/interactive/Makefile pyanaconda/modules/storage/partitioning/manual/Makefile pyanaconda/modules/storage/snapshot/Makefile pyanaconda/modules/storage/zfcp/Makefile pyanaconda/modules/services/Makefile data/post-scripts/Makefile data/pixmaps/Makefile tests/Makefile utils/Makefile utils/dd/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -15686,7 +15684,6 @@ do
"pyanaconda/modules/storage/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES pyanaconda/modules/storage/snapshot/Makefile" ;;
"pyanaconda/modules/storage/zfcp/Makefile") CONFIG_FILES="$CONFIG_FILES pyanaconda/modules/storage/zfcp/Makefile" ;;
"pyanaconda/modules/services/Makefile") CONFIG_FILES="$CONFIG_FILES pyanaconda/modules/services/Makefile" ;;
- "pyanaconda/modules/subscription/Makefile") CONFIG_FILES="$CONFIG_FILES pyanaconda/modules/subscription/Makefile" ;;
"data/post-scripts/Makefile") CONFIG_FILES="$CONFIG_FILES data/post-scripts/Makefile" ;;
"data/pixmaps/Makefile") CONFIG_FILES="$CONFIG_FILES data/pixmaps/Makefile" ;;
"tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;;
diff --git a/configure.ac b/configure.ac
index 74f6d1d..2101b7d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -206,7 +206,6 @@ AC_CONFIG_FILES([Makefile
pyanaconda/modules/storage/snapshot/Makefile
pyanaconda/modules/storage/zfcp/Makefile
pyanaconda/modules/services/Makefile
- pyanaconda/modules/subscription/Makefile
data/post-scripts/Makefile
data/pixmaps/Makefile
tests/Makefile
diff --git a/data/dbus/org.fedoraproject.Anaconda.Modules.Subscription.conf b/data/dbus/org.fedoraproject.Anaconda.Modules.Subscription.conf
deleted file mode 100644
index 52df985..0000000
--- a/data/dbus/org.fedoraproject.Anaconda.Modules.Subscription.conf
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE busconfig PUBLIC
- "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
- <policy user="root">
- <allow own="org.fedoraproject.Anaconda.Modules.Subscription"/>
- <allow send_destination="org.fedoraproject.Anaconda.Modules.Subscription"/>
- </policy>
- <policy context="default">
- <deny own="org.fedoraproject.Anaconda.Modules.Subscription"/>
- <allow send_destination="org.fedoraproject.Anaconda.Modules.Subscription"/>
- </policy>
-</busconfig>
-
diff --git a/data/dbus/org.fedoraproject.Anaconda.Modules.Subscription.service b/data/dbus/org.fedoraproject.Anaconda.Modules.Subscription.service
deleted file mode 100644
index 0df2f81..0000000
--- a/data/dbus/org.fedoraproject.Anaconda.Modules.Subscription.service
+++ /dev/null
@@ -1,4 +0,0 @@
-[D-BUS Service]
-Name=org.fedoraproject.Anaconda.Modules.Subscription
-Exec=/usr/libexec/anaconda/start-module pyanaconda.modules.subscription
-User=root
diff --git a/pyanaconda/core/constants.py b/pyanaconda/core/constants.py
index 25267f8..b4a9c4d 100644
--- a/pyanaconda/core/constants.py
+++ b/pyanaconda/core/constants.py
@@ -129,8 +129,6 @@ THREAD_KEYBOARD_INIT = "AnaKeyboardThread"
THREAD_ADD_LAYOUTS_INIT = "AnaAddLayoutsInitThread"
THREAD_NTP_SERVER_CHECK = "AnaNTPserver"
THREAD_DBUS_TASK = "AnaTaskThread"
-THREAD_SUBSCRIPTION = "AnaSubscriptionThread"
-THREAD_SUBSCRIPTION_SPOKE_INIT = "AnaSubscriptionSpokeInitThread"
# Geolocation constants
@@ -442,17 +440,6 @@ SOURCE_REPO_FILE_TYPES = (
SOURCE_TYPE_CDN,
)
-# Payload sources overriden by the CDN
-
-# This set lists sources the Red Hat CDN should automatically
-# override if the system gets registered during installation.
-# At the moment there is just the CDROM source, as almost
-# always the CDN content will be much more up to date and
-# more secure than the local content on the DVD image.
-SOURCE_TYPES_OVERRIDEN_BY_CDN = (
- SOURCE_TYPE_CDROM
-)
-
# Payload URL source types.
URL_TYPE_BASEURL = "BASEURL"
URL_TYPE_MIRRORLIST = "MIRRORLIST"
@@ -461,25 +448,6 @@ URL_TYPE_METALINK = "METALINK"
# Default values of DNF repository configuration
DNF_DEFAULT_REPO_COST = 1000
-# Subscription request types
-#
-# Subscription request can currently be one of two types:
-# - using username and password for authentication
-# - using organization id and one or more authentication keys
-# for authentication
-SUBSCRIPTION_REQUEST_TYPE_USERNAME_PASSWORD = "username_password"
-SUBSCRIPTION_REQUEST_TYPE_ORG_KEY = "org_activation_key"
-
-SUBSCRIPTION_REQUEST_VALID_TYPES = {
- SUBSCRIPTION_REQUEST_TYPE_USERNAME_PASSWORD,
- SUBSCRIPTION_REQUEST_TYPE_ORG_KEY,
-}
-
-# Default authentication for subscription requests is
-# username password - this is basically to avoid the invalid
-# case of request not having a type set.
-DEFAULT_SUBSCRIPTION_REQUEST_TYPE = SUBSCRIPTION_REQUEST_TYPE_USERNAME_PASSWORD
-
# How long to wait for the RHSM service to become available after it is started.
# - in seconds
# - based on the default 90 second systemd service activation timeout
diff --git a/pyanaconda/core/kickstart/commands.py b/pyanaconda/core/kickstart/commands.py
index c5e1b29..e48ecee 100644
--- a/pyanaconda/core/kickstart/commands.py
+++ b/pyanaconda/core/kickstart/commands.py
@@ -67,7 +67,6 @@ from pykickstart.commands.reboot import F23_Reboot as Reboot
from pykickstart.commands.repo import RHEL8_Repo as Repo
from pykickstart.commands.reqpart import F23_ReqPart as ReqPart
from pykickstart.commands.rescue import F10_Rescue as Rescue
-from pykickstart.commands.rhsm import RHEL8_RHSM as RHSM
from pykickstart.commands.rootpw import F18_RootPw as RootPw
from pykickstart.commands.selinux import FC3_SELinux as SELinux
from pykickstart.commands.services import FC6_Services as Services
diff --git a/pyanaconda/core/subscription.py b/pyanaconda/core/subscription.py
deleted file mode 100644
index 03e8c1a..0000000
--- a/pyanaconda/core/subscription.py
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# Subscription related helper functions.
-#
-# Copyright (C) 2020 Red Hat, Inc. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-import os
-
-from pyanaconda.core import util
-from pyanaconda.core.constants import RHSM_SYSPURPOSE_FILE_PATH
-
-
-def check_system_purpose_set(sysroot="/"):
- """Check if System Purpose has been set for the system.
-
- By manipulating the sysroot parameter it is possible to
- check is System Purpose has been set for both the installation
- environment and the target system.
-
- For installation environment use "/", for the target system
- path to the installation root.
-
- :param str sysroot: system root where to check
- :return: True if System Purpose has been set, False otherwise
- """
- syspurpose_path = util.join_paths(sysroot, RHSM_SYSPURPOSE_FILE_PATH)
- return os.path.exists(syspurpose_path)
diff --git a/pyanaconda/installation.py b/pyanaconda/installation.py
index 6981562..6505838 100644
--- a/pyanaconda/installation.py
+++ b/pyanaconda/installation.py
@@ -22,7 +22,7 @@ from pyanaconda.core.constants import PAYLOAD_LIVE_TYPES
from pyanaconda.core.kernel import kernel_arguments
from pyanaconda.modules.common.constants.objects import BOOTLOADER, SNAPSHOT, FIREWALL
from pyanaconda.modules.common.constants.services import STORAGE, USERS, SERVICES, NETWORK, SECURITY, \
- LOCALIZATION, TIMEZONE, BOSS, SUBSCRIPTION
+ LOCALIZATION, TIMEZONE, BOSS
from pyanaconda.modules.common.structures.requirement import Requirement
from pyanaconda.modules.common.task import sync_run_task
from pyanaconda.modules.common.util import is_module_available
@@ -80,16 +80,6 @@ def _prepare_configuration(payload, ksdata):
configuration_queue.queue_started.connect(lambda x: progress_message(x.status_message))
configuration_queue.task_completed.connect(lambda x: progress_step(x.name))
- # add installation tasks for the Subscription DBus module
- if is_module_available(SUBSCRIPTION):
- # we only run the tasks if the Subscription module is available
- subscription_config = TaskQueue("Subscription configuration",
- N_("Configuring Red Hat subscription"))
- subscription_proxy = SUBSCRIPTION.get_proxy()
- subscription_dbus_tasks = subscription_proxy.InstallWithTasks()
- subscription_config.append_dbus_tasks(SUBSCRIPTION, subscription_dbus_tasks)
- configuration_queue.append(subscription_config)
-
# schedule the execute methods of ksdata that require an installed system to be present
os_config = TaskQueue("Installed system configuration", N_("Configuring installed system"))
@@ -316,7 +306,7 @@ def _prepare_installation(payload, ksdata):
# add package requirements from modules
# - iterate over all modules we know have valid package requirements
# - add any requirements found to the payload requirement tracking
- modules_with_package_requirements = [SECURITY, NETWORK, TIMEZONE, STORAGE, SUBSCRIPTION]
+ modules_with_package_requirements = [SECURITY, NETWORK, TIMEZONE, STORAGE]
for module in modules_with_package_requirements:
# Skip unavailable modules.
if not is_module_available(module):
diff --git a/pyanaconda/modules/Makefile.am b/pyanaconda/modules/Makefile.am
index 903cf32..7bd86b5 100644
--- a/pyanaconda/modules/Makefile.am
+++ b/pyanaconda/modules/Makefile.am
@@ -15,7 +15,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-SUBDIRS = common boss timezone network localization security users payloads storage services subscription
+SUBDIRS = common boss timezone network localization security users payloads storage services
pkgpyexecdir = $(pyexecdir)/py$(PACKAGE_NAME)
modulesdir = $(pkgpyexecdir)/modules
diff --git a/pyanaconda/modules/Makefile.in b/pyanaconda/modules/Makefile.in
index 8402ce3..97ebc74 100644
--- a/pyanaconda/modules/Makefile.in
+++ b/pyanaconda/modules/Makefile.in
@@ -372,7 +372,7 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-SUBDIRS = common boss timezone network localization security users payloads storage services subscription
+SUBDIRS = common boss timezone network localization security users payloads storage services
modulesdir = $(pkgpyexecdir)/modules
modules_PYTHON = $(srcdir)/*.py
MAINTAINERCLEANFILES = Makefile.in
diff --git a/pyanaconda/modules/common/constants/namespaces.py b/pyanaconda/modules/common/constants/namespaces.py
index 9f66178..1556296 100644
--- a/pyanaconda/modules/common/constants/namespaces.py
+++ b/pyanaconda/modules/common/constants/namespaces.py
@@ -101,12 +101,6 @@ SOURCE_NAMESPACE = (
"Source"
)
-# System service namespaces
-
-RHSM_NAMESPACE = (
- "com", "redhat", "RHSM1"
-)
-
NETWORK_MANAGER_NAMESPACE = (
"org", "freedesktop", "NetworkManager"
)
diff --git a/pyanaconda/modules/common/constants/objects.py b/pyanaconda/modules/common/constants/objects.py
index ea2fdc7..ec653fa 100644
--- a/pyanaconda/modules/common/constants/objects.py
+++ b/pyanaconda/modules/common/constants/objects.py
@@ -19,7 +19,7 @@
from dasbus.identifier import DBusObjectIdentifier
from pyanaconda.modules.common.constants.namespaces import STORAGE_NAMESPACE, NETWORK_NAMESPACE, \
PARTITIONING_NAMESPACE, DEVICE_TREE_NAMESPACE, \
- PAYLOADS_NAMESPACE, RHSM_NAMESPACE
+ PAYLOADS_NAMESPACE
# Storage objects.
@@ -116,41 +116,3 @@ PAYLOAD_PACKAGES = DBusObjectIdentifier(
basename="Packages"
)
-# System services
-
-# Subscription objects.
-
-RHSM_CONFIG = DBusObjectIdentifier(
- namespace=RHSM_NAMESPACE,
- basename="Config"
-)
-
-RHSM_REGISTER_SERVER = DBusObjectIdentifier(
- namespace=RHSM_NAMESPACE,
- basename="RegisterServer"
-)
-
-RHSM_REGISTER = DBusObjectIdentifier(
- namespace=RHSM_NAMESPACE,
- basename="Register"
-)
-
-RHSM_UNREGISTER = DBusObjectIdentifier(
- namespace=RHSM_NAMESPACE,
- 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"
-)
diff --git a/pyanaconda/modules/common/constants/services.py b/pyanaconda/modules/common/constants/services.py
index 95eaa1d..6febe5f 100644
--- a/pyanaconda/modules/common/constants/services.py
+++ b/pyanaconda/modules/common/constants/services.py
@@ -20,8 +20,7 @@ from pyanaconda.core.dbus import SystemBus, DBus
from dasbus.identifier import DBusServiceIdentifier
from pyanaconda.modules.common.constants.namespaces import BOSS_NAMESPACE, TIMEZONE_NAMESPACE, \
NETWORK_NAMESPACE, LOCALIZATION_NAMESPACE, SECURITY_NAMESPACE, USERS_NAMESPACE, \
- PAYLOADS_NAMESPACE, STORAGE_NAMESPACE, SERVICES_NAMESPACE, SUBSCRIPTION_NAMESPACE, \
- RHSM_NAMESPACE, NETWORK_MANAGER_NAMESPACE
+ PAYLOADS_NAMESPACE, STORAGE_NAMESPACE, SERVICES_NAMESPACE, NETWORK_MANAGER_NAMESPACE
# Anaconda services.
@@ -93,10 +92,6 @@ LOCALED = DBusServiceIdentifier(
message_bus=SystemBus
)
-RHSM = DBusServiceIdentifier(
- namespace=RHSM_NAMESPACE,
- message_bus=SystemBus
-)
NETWORK_MANAGER = DBusServiceIdentifier(
namespace=NETWORK_MANAGER_NAMESPACE,
diff --git a/pyanaconda/modules/common/errors/installation.py b/pyanaconda/modules/common/errors/installation.py
index 07da2f7..6f3200b 100644
--- a/pyanaconda/modules/common/errors/installation.py
+++ b/pyanaconda/modules/common/errors/installation.py
@@ -86,8 +86,3 @@ class InsightsConnectError(InstallationError):
"""Exception for error when connecting to Red Hat Insights."""
pass
-
-@dbus_error("SubscriptionTokenTransferError", namespace=ANACONDA_NAMESPACE)
-class SubscriptionTokenTransferError(InstallationError):
- """Exception for errors during subscription token transfer."""
- pass
diff --git a/pyanaconda/modules/common/errors/subscription.py b/pyanaconda/modules/common/errors/subscription.py
deleted file mode 100644
index a1f9cce..0000000
--- a/pyanaconda/modules/common/errors/subscription.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# DBus errors related to subscription handling
-#
-# Copyright (C) 2020 Red Hat, Inc. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-from pyanaconda.core.dbus import dbus_error
-from pyanaconda.modules.common.constants.namespaces import ANACONDA_NAMESPACE
-from pyanaconda.modules.common.errors.general import AnacondaError
-
-
-@dbus_error("RegistrationError", namespace=ANACONDA_NAMESPACE)
-class RegistrationError(AnacondaError):
- """Registration attempt failed."""
- pass
-
-
-@dbus_error("UnregistrationError", namespace=ANACONDA_NAMESPACE)
-class UnregistrationError(AnacondaError):
- """Unregistration attempt failed."""
- pass
-
-
-@dbus_error("SubscriptionError", namespace=ANACONDA_NAMESPACE)
-class SubscriptionError(AnacondaError):
- """Subscription attempt failed."""
- pass
diff --git a/pyanaconda/modules/common/structures/subscription.py b/pyanaconda/modules/common/structures/subscription.py
deleted file mode 100644
index 004d349..0000000
--- a/pyanaconda/modules/common/structures/subscription.py
+++ /dev/null
@@ -1,537 +0,0 @@
-#
-# DBus structures for subscription related data.
-#
-# Copyright (C) 2020 Red Hat, Inc. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-from dasbus.structure import DBusData
-from dasbus.typing import * # pylint: disable=wildcard-import
-
-from pyanaconda.core.constants import DEFAULT_SUBSCRIPTION_REQUEST_TYPE
-
-from pyanaconda.modules.common.structures.secret import SecretData, SecretDataList
-
-__all__ = ["SystemPurposeData", "SubscriptionRequest"]
-
-class SystemPurposeData(DBusData):
- """System purpose data."""
-
- def __init__(self):
- self._role = ""
- self._sla = ""
- self._usage = ""
- self._addons = []
-
- @property
- def role(self) -> Str:
- """Return the System Purpose role (if any).
-
- :return: system purpose role
- """
- return self._role
-
- @role.setter
- def role(self, role: Str):
- self._role = role
-
- @property
- def sla(self) -> Str:
- """Return the System Purpose SLA (if any).
-
- :return: system purpose SLA
- """
- return self._sla
-
- @sla.setter
- def sla(self, sla: Str):
- self._sla = sla
-
- @property
- def usage(self) -> Str:
- """Return the System Purpose usage (if any).
-
- :return: system purpose usage
- """
- return self._usage
-
- @usage.setter
- def usage(self, usage: Str):
- self._usage = usage
-
- @property
- def addons(self) -> List[Str]:
- """Return list of additional layered products or features (if any).
-
- :return: system purpose addons
- """
- return self._addons
-
- @addons.setter
- def addons(self, addons: List[Str]):
- self._addons = addons
-
- def check_data_available(self):
- """A helper function used to determining if some system purpose data is available.
-
- Otherwise we would have to query all the fields each time we want to check if we
- have any system purpose data available.
-
- :return: is any system purpose data is available
- :rtype: bool
- """
- return any((self.role, self.sla, self.usage, self.addons))
-
- def __eq__(self, other_instance):
- """Used to determining if other SystemPurposeData instance has the same data.
-
- Otherwise we would have to compare all the fields each time we want to check if the
- two SystemPurposeData instances have the same data.
-
- :param other_instance: another SystemPurposeData to compare with this one
- :type other_instance: SystemPurposeData instance
- :return: True if the other structure has the same system purpose data as this one,
- False otherwise
- :rtype: bool
- """
- # if the other instance is not instance of SubscriptionRequest,
- # then it is always considered to be different
- if not isinstance(other_instance, SystemPurposeData):
- return False
- # addon ordering is not important
- if set(self.addons) != set(other_instance.addons):
- return False
- elif(self.role != other_instance.role):
- return False
- elif(self.sla != other_instance.sla):
- return False
- elif(self.usage != other_instance.usage):
- return False
- else:
- return True
-
-
-class SubscriptionRequest(DBusData):
- """Data for a subscription request.
-
- NOTE: Names of some of the fields are based on
- how the given keys are called in rhsm.conf.
- """
-
- def __init__(self):
- # subscription request type
- # (based on authentication method used)
- self._type = DEFAULT_SUBSCRIPTION_REQUEST_TYPE
- # user identification
- # - in case an account is member
- # of multiple organizations, both
- # organization and account username
- # need to be set
- self._organization = ""
- self._redhat_account_username = ""
- # Candlepin instance
- self._server_hostname = ""
- # CDN base url
- self._rhsm_baseurl = ""
- # RHSM HTTP proxy
- self._server_proxy_hostname = ""
- self._server_proxy_port = -1
- self._server_proxy_user = ""
- # private data
- # - we are using SecretData & SecretDataList
- # nested DBus structures to protect this
- # sensitive data
- # - this way they can be set-only & easily
- # removed from SubscriptionRequest on
- # output from the Subscription module
- # - they also support a robust way of clearing
- # previously set sensitive data if required
- self._redhat_account_password = SecretData()
- self._activation_keys = SecretDataList()
- self._server_proxy_password = SecretData()
-
- @property
- def type(self) -> Str:
- """Subscription request type.
-
- Subscription request type is based on the authentication method used.
-
- At the moment the following two are supported:
- - username + password
- - organization id + one or more activation keys
-
- By default username + password is used.
-
- Valid values are:
- "username_password"
- "org_activation_key"
-
- :return: subscription request type
- :rtype: str
- """
- return self._type
-
- @type.setter
- def type(self, request_type: Str):
- self._type = request_type
-
- @property
- def organization(self) -> Str:
- """Organization id for subscription purposes.
-
- In most cases one of the following will be used:
- - org id + one or more activation keys
- - username + password
-
- There is also a less often expected use case,
- which applies if the same user account exists
- in multiple organizations on the same Candlepin
- instance. In such a case both username and
- organization id needs to be set.
-
- :return: organization id
- :rtype: str
- """
- return self._organization
-
- @organization.setter
- def organization(self, organization: Str):
- self._organization = organization
-
- @property
- def account_username(self) -> Str:
- """Red Hat account username 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.
-
- :return: Red Hat account username
- :rtype: str
- """
- return self._redhat_account_username
-
- @account_username.setter
- def account_username(self, account_username: Str):
- self._redhat_account_username = account_username
-
- @property
- def server_hostname(self) -> Str:
- """Subscription server hostname.
-
- This is basically a URL pointing to a Candlepin
- instance to be used. It could be the one handling
- general subscriptions hosted by Red Hat or one
- embedded in a Satellite deployment.
-
- If no custom server hostname is set, the default
- value used by subscription manager will be used,
- which is usually the URL pointing to the general
- purpose Red Hat hosted Candlepin instance.
-
- :return: Candlepin instance URL
- :rtype: str
- """
- return self._server_hostname
-
- @server_hostname.setter
- def server_hostname(self, server_hostname: Str):
- self._server_hostname = server_hostname
-
- @property
- def rhsm_baseurl(self) -> Str:
- """CDN repository base URL.
-
- Sets the base URL for the RHSM generated
- repo file.
-
- Setting this to a non default value only
- makes sense if registering against Satellite
- (as you would want to use the repos hosted
- on the given Satellite instance) or possibly
- during testing.
-
- If no custom rhsm baseurl is set, the default
- value used by subscription managed will be used,
- which is generally baseurl for the Red Hat CDN.
-
- :return: RHSM base url
- :rtype: str
- """
- return self._rhsm_baseurl
-
- @rhsm_baseurl.setter
- def rhsm_baseurl(self, rhsm_baseurl: Str):
- self._rhsm_baseurl = rhsm_baseurl
-
- @property
- def server_proxy_hostname(self) -> Str:
- """RHSM HTTP proxy - hostname.
-
- This is the hostname of the RHSM HTTP
- proxy, which will be used for subscription
- purposes only, eq. this will not configure
- a system wide HTTP proxy.
-
- :return: RHSM HTTP proxy hostname
- :rtype: str
- """
- return self._server_proxy_hostname
-
- @server_proxy_hostname.setter
- def server_proxy_hostname(self, hostname: Str):
- self._server_proxy_hostname = hostname
-
- @property
- def server_proxy_port(self) -> Int:
- """RHSM HTTP proxy - port number.
-
- -1 means port has not been set.
-
- :returns: RHSM HTTP proxy port number
- :rtype: int
- """
- return self._server_proxy_port
-
- @server_proxy_port.setter
- def server_proxy_port(self, port_number: Int):
- self._server_proxy_port = port_number
-
- @property
- def server_proxy_user(self) -> Str:
- """RHSM HTTP proxy - access username.
-
- :return: RHSM HTTP proxy access username
- :rtype: str
- """
- return self._server_proxy_user
-
- @server_proxy_user.setter
- def server_proxy_user(self, username: Str):
- self._server_proxy_user = username
-
- # private data
- # - generally sensitive data such as passwords
- # or activation keys
- # - these values should be "write only",
- # meaning data goes to the Subscription
- # module but can't be read out later one
- # via the public API
- # - only the Subscription module should have
- # have access to these data internally &
- # use them appropriately (eq. register
- # the system, authenticate to HTTP proxy, etc.)
- # - it should be also possible to explicitly
- # clear a previously set secret
- # - to protect these values we are using
- # SecretData & SecretDataList, see their
- # implementation for more information
-
- @property
- def account_password(self) -> SecretData:
- """Red Hat account password.
-
- NOTE: This property is stored in SecretData
- nested DBus structure to protect its contents.
-
- :return: Red hat account password stored in a SecretData instance
- :rtype: SecretData instance
- """
- return self._redhat_account_password
-
- @account_password.setter
- def account_password(self, password: SecretData):
- if password:
- self.account_password_set = True
- self._redhat_account_password = password
-
- @property
- def activation_keys(self) -> SecretDataList:
- """List of activation keys.
-
- For a successful activation key based registration
- at least one activation key needs to be set.
-
- NOTE: This property is stored in SecretDataList
- nested DBus structure to protect its contents.
-
- :return: list of activation keys stored in SecretDataList instance
- :rtype: SecretDataList instance
- """
- return self._activation_keys
-
- @activation_keys.setter
- def activation_keys(self, activation_keys: SecretDataList):
- self._activation_keys = activation_keys
-
- @property
- def server_proxy_password(self) -> SecretData:
- """RHSM HTTP proxy - access password.
-
- NOTE: This property is stored in SecretData
- nested DBus structure to protect its contents.
-
- :return: RHSM HTTP proxy password stored in SecretData instance
- :rtype: SecretData instance
- """
- return self._server_proxy_password
-
- @server_proxy_password.setter
- def server_proxy_password(self, password: SecretData):
- self._server_proxy_password = password
-
-
-class AttachedSubscription(DBusData):
- """Data for a single attached subscription."""
-
- def __init__(self):
- 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.
-
- Example: "MBT8547"
-
- :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
- :rtype: str
- """
- return self._start_date
-
- @start_date.setter
- def start_date(self, start_date: Str):
- self._start_date = start_date
-
- @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
-
- Example: "Nov 04, 2020"
-
- :return: end date of the subscription
- :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
-
- @consumed_entitlement_count.setter
- def consumed_entitlement_count(self, consumed_entitlement_count: Int):
- self._consumed_entitlement_count = consumed_entitlement_count
diff --git a/pyanaconda/modules/subscription/Makefile.am b/pyanaconda/modules/subscription/Makefile.am
deleted file mode 100644
index bd9d154..0000000
--- a/pyanaconda/modules/subscription/Makefile.am
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Copyright (C) 2020 Red Hat, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-pkgpyexecdir = $(pyexecdir)/py$(PACKAGE_NAME)
-subscriptiondir = $(pkgpyexecdir)/modules/subscription
-subscription_PYTHON = $(srcdir)/*.py
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/pyanaconda/modules/subscription/Makefile.in b/pyanaconda/modules/subscription/Makefile.in
deleted file mode 100644
index 2bf4319..0000000
--- a/pyanaconda/modules/subscription/Makefile.in
+++ /dev/null
@@ -1,567 +0,0 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-#
-# Copyright (C) 2020 Red Hat, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
-am__make_running_with_option = \
- case $${target_option-} in \
- ?) ;; \
- *) echo "am__make_running_with_option: internal error: invalid" \
- "target option '$${target_option-}' specified" >&2; \
- exit 1;; \
- esac; \
- has_opt=no; \
- sane_makeflags=$$MAKEFLAGS; \
- if $(am__is_gnu_make); then \
- sane_makeflags=$$MFLAGS; \
- else \
- case $$MAKEFLAGS in \
- *\\[\ \ ]*) \
- bs=\\; \
- sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
- | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
- esac; \
- fi; \
- skip_next=no; \
- strip_trailopt () \
- { \
- flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
- }; \
- for flg in $$sane_makeflags; do \
- test $$skip_next = yes && { skip_next=no; continue; }; \
- case $$flg in \
- *=*|--*) continue;; \
- -*I) strip_trailopt 'I'; skip_next=yes;; \
- -*I?*) strip_trailopt 'I';; \
- -*O) strip_trailopt 'O'; skip_next=yes;; \
- -*O?*) strip_trailopt 'O';; \
- -*l) strip_trailopt 'l'; skip_next=yes;; \
- -*l?*) strip_trailopt 'l';; \
- -[dEDm]) skip_next=yes;; \
- -[JT]) skip_next=yes;; \
- esac; \
- case $$flg in \
- *$$target_option*) has_opt=yes; break;; \
- esac; \
- done; \
- test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-subdir = pyanaconda/modules/subscription
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
- $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
- $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
- $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
- $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(subscription_PYTHON) \
- $(am__DIST_COMMON)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo " GEN " $@;
-am__v_GEN_1 =
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 =
-SOURCES =
-DIST_SOURCES =
-am__can_run_installinfo = \
- case $$AM_UPDATE_INFO_DIR in \
- n|no|NO) false;; \
- *) (install-info --version) >/dev/null 2>&1;; \
- esac
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
- $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
- *) f=$$p;; \
- esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
- srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
- for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
- for p in $$list; do echo "$$p $$p"; done | \
- sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
- $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
- if (++n[$$2] == $(am__install_max)) \
- { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
- END { for (dir in files) print dir, files[dir] }'
-am__base_list = \
- sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
- sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__uninstall_files_from_dir = { \
- test -z "$$files" \
- || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
- || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
- $(am__cd) "$$dir" && rm -f $$files; }; \
- }
-am__py_compile = PYTHON=$(PYTHON) $(SHELL) $(py_compile)
-am__installdirs = "$(DESTDIR)$(subscriptiondir)"
-am__pep3147_tweak = \
- sed -e 's|\.py$$||' -e 's|[^/]*$$|__pycache__/&.*.py|'
-py_compile = $(top_srcdir)/py-compile
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/py-compile
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-ACLOCAL = @ACLOCAL@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-ANACONDA_RELEASE = @ANACONDA_RELEASE@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-GREP = @GREP@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBARCHIVE_CFLAGS = @LIBARCHIVE_CFLAGS@
-LIBARCHIVE_LIBS = @LIBARCHIVE_LIBS@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-MSGCAT = @MSGCAT@
-MSGFMT = @MSGFMT@
-MSGMERGE = @MSGMERGE@
-NM = @NM@
-NMEDIT = @NMEDIT@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_RELEASE = @PACKAGE_RELEASE@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-PKG_CONFIG = @PKG_CONFIG@
-PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
-PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
-PYTHON = @PYTHON@
-PYTHON3_CFLAGS = @PYTHON3_CFLAGS@
-PYTHON3_LIBS = @PYTHON3_LIBS@
-PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
-PYTHON_PLATFORM = @PYTHON_PLATFORM@
-PYTHON_PREFIX = @PYTHON_PREFIX@
-PYTHON_VERSION = @PYTHON_VERSION@
-RANLIB = @RANLIB@
-RPM_CFLAGS = @RPM_CFLAGS@
-RPM_LIBS = @RPM_LIBS@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-STRIP = @STRIP@
-VERSION = @VERSION@
-XGETTEXT = @XGETTEXT@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-pkgpyexecdir = $(pyexecdir)/py$(PACKAGE_NAME)
-pkgpythondir = @pkgpythondir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-pyexecdir = @pyexecdir@
-pythondir = @pythondir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-subdirs = @subdirs@
-sysconfdir = @sysconfdir@
-target_alias = @target_alias@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-subscriptiondir = $(pkgpyexecdir)/modules/subscription
-subscription_PYTHON = $(srcdir)/*.py
-MAINTAINERCLEANFILES = Makefile.in
-all: all-am
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
- @for dep in $?; do \
- case '$(am__configure_deps)' in \
- *$$dep*) \
- ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
- && { if test -f $@; then exit 0; else break; fi; }; \
- exit 1;; \
- esac; \
- done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign pyanaconda/modules/subscription/Makefile'; \
- $(am__cd) $(top_srcdir) && \
- $(AUTOMAKE) --foreign pyanaconda/modules/subscription/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
- @case '$?' in \
- *config.status*) \
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
- *) \
- echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
- cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
- esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: $(am__configure_deps)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): $(am__aclocal_m4_deps)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-mostlyclean-libtool:
- -rm -f *.lo
-
-clean-libtool:
- -rm -rf .libs _libs
-install-subscriptionPYTHON: $(subscription_PYTHON)
- @$(NORMAL_INSTALL)
- @list='$(subscription_PYTHON)'; dlist=; list2=; test -n "$(subscriptiondir)" || list=; \
- if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(subscriptiondir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(subscriptiondir)" || exit 1; \
- fi; \
- for p in $$list; do \
- if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \
- if test -f $$b$$p; then \
- $(am__strip_dir) \
- dlist="$$dlist $$f"; \
- list2="$$list2 $$b$$p"; \
- else :; fi; \
- done; \
- for file in $$list2; do echo $$file; done | $(am__base_list) | \
- while read files; do \
- echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(subscriptiondir)'"; \
- $(INSTALL_DATA) $$files "$(DESTDIR)$(subscriptiondir)" || exit $$?; \
- done || exit $$?; \
- if test -n "$$dlist"; then \
- $(am__py_compile) --destdir "$(DESTDIR)" \
- --basedir "$(subscriptiondir)" $$dlist; \
- else :; fi
-
-uninstall-subscriptionPYTHON:
- @$(NORMAL_UNINSTALL)
- @list='$(subscription_PYTHON)'; test -n "$(subscriptiondir)" || list=; \
- py_files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- test -n "$$py_files" || exit 0; \
- dir='$(DESTDIR)$(subscriptiondir)'; \
- pyc_files=`echo "$$py_files" | sed 's|$$|c|'`; \
- pyo_files=`echo "$$py_files" | sed 's|$$|o|'`; \
- py_files_pep3147=`echo "$$py_files" | $(am__pep3147_tweak)`; \
- echo "$$py_files_pep3147";\
- pyc_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|c|'`; \
- pyo_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|o|'`; \
- st=0; \
- for files in \
- "$$py_files" \
- "$$pyc_files" \
- "$$pyo_files" \
- "$$pyc_files_pep3147" \
- "$$pyo_files_pep3147" \
- ; do \
- $(am__uninstall_files_from_dir) || st=$$?; \
- done; \
- exit $$st
-tags TAGS:
-
-ctags CTAGS:
-
-cscope cscopelist:
-
-
-distdir: $(BUILT_SOURCES)
- $(MAKE) $(AM_MAKEFLAGS) distdir-am
-
-distdir-am: $(DISTFILES)
- @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
- topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
- list='$(DISTFILES)'; \
- dist_files=`for file in $$list; do echo $$file; done | \
- sed -e "s|^$$srcdirstrip/||;t" \
- -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
- case $$dist_files in \
- */*) $(MKDIR_P) `echo "$$dist_files" | \
- sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
- sort -u` ;; \
- esac; \
- for file in $$dist_files; do \
- if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
- if test -d $$d/$$file; then \
- dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
- if test -d "$(distdir)/$$file"; then \
- find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
- fi; \
- if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
- cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
- find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
- fi; \
- cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
- else \
- test -f "$(distdir)/$$file" \
- || cp -p $$d/$$file "$(distdir)/$$file" \
- || exit 1; \
- fi; \
- done
-check-am: all-am
-check: check-am
-all-am: Makefile
-installdirs:
- for dir in "$(DESTDIR)$(subscriptiondir)"; do \
- test -z "$$dir" || $(MKDIR_P) "$$dir"; \
- done
-install: install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
-
-install-am: all-am
- @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-am
-install-strip:
- if test -z '$(STRIP)'; then \
- $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
- install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
- install; \
- else \
- $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
- install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
- "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
- fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
- -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
- -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
- @echo "This command is intended for maintainers to use"
- @echo "it deletes files that may require special tools to rebuild."
- -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
-clean: clean-am
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-am
- -rm -f Makefile
-distclean-am: clean-am distclean-generic
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-html-am:
-
-info: info-am
-
-info-am:
-
-install-data-am: install-subscriptionPYTHON
-
-install-dvi: install-dvi-am
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-am
-
-install-html-am:
-
-install-info: install-info-am
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-am
-
-install-pdf-am:
-
-install-ps: install-ps-am
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
- -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-am
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-am
-
-pdf-am:
-
-ps: ps-am
-
-ps-am:
-
-uninstall-am: uninstall-subscriptionPYTHON
-
-.MAKE: install-am install-strip
-
-.PHONY: all all-am check check-am clean clean-generic clean-libtool \
- cscopelist-am ctags-am distclean distclean-generic \
- distclean-libtool distdir dvi dvi-am html html-am info info-am \
- install install-am install-data install-data-am install-dvi \
- install-dvi-am install-exec install-exec-am install-html \
- install-html-am install-info install-info-am install-man \
- install-pdf install-pdf-am install-ps install-ps-am \
- install-strip install-subscriptionPYTHON installcheck \
- installcheck-am installdirs maintainer-clean \
- maintainer-clean-generic mostlyclean mostlyclean-generic \
- mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
- uninstall-am uninstall-subscriptionPYTHON
-
-.PRECIOUS: Makefile
-
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/pyanaconda/modules/subscription/__main__.py b/pyanaconda/modules/subscription/__main__.py
deleted file mode 100644
index e0f3dfa..0000000
--- a/pyanaconda/modules/subscription/__main__.py
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# Subscription DBus service launcher.
-#
-# Copyright (C) 2020 Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details. You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-from pyanaconda.modules.common import init
-init()
-
-from pyanaconda.modules.subscription.subscription import SubscriptionService
-service = SubscriptionService()
-service.run()
diff --git a/pyanaconda/modules/subscription/installation.py b/pyanaconda/modules/subscription/installation.py
deleted file mode 100644
index 1e86949..0000000
--- a/pyanaconda/modules/subscription/installation.py
+++ /dev/null
@@ -1,248 +0,0 @@
-#
-# Copyright (C) 2020 Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details. You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-import os
-import glob
-import shutil
-
-from dasbus.typing import get_variant, Str
-
-from pyanaconda.core import util
-from pyanaconda.core.constants import RHSM_SYSPURPOSE_FILE_PATH
-from pyanaconda.core.subscription import check_system_purpose_set
-
-from pyanaconda.modules.common.task import Task
-from pyanaconda.modules.common.errors.installation import InsightsConnectError, \
- InsightsClientMissingError, SubscriptionTokenTransferError
-
-from pyanaconda.anaconda_loggers import get_module_logger
-log = get_module_logger(__name__)
-
-
-class ConnectToInsightsTask(Task):
- """Connect the target system to Red Hat Insights."""
-
- INSIGHTS_TOOL_PATH = "/usr/bin/insights-client"
-
- def __init__(self, sysroot, subscription_attached, connect_to_insights):
- """Create a new task.
-
- :param str sysroot: target system root path
- :param bool subscription_attached: if True then the system has been subscribed,
- False otherwise
- :param bool connect_to_insights: if True then connect the system to Insights,
- if False do nothing
- """
- super().__init__()
- self._sysroot = sysroot
- self._subscription_attached = subscription_attached
- self._connect_to_insights = connect_to_insights
-
- @property
- def name(self):
- return "Connect the target system to Red Hat Insights"
-
- def run(self):
- """Connect the target system to Red Hat Insights."""
- # check if we should connect to Red Hat Insights
- if not self._connect_to_insights:
- log.debug("insights-connect-task: Insights not requested, skipping")
- return
- elif not self._subscription_attached:
- log.debug("insights-connect-task: "
- "Insights requested but target system is not subscribed, skipping")
- return
-
- insights_path = util.join_paths(self._sysroot, self.INSIGHTS_TOOL_PATH)
- # check the insights client utility is available
- if not os.path.isfile(insights_path):
- raise InsightsClientMissingError(
- "The insight-client tool ({}) is not available.".format(self.INSIGHTS_TOOL_PATH)
- )
-
- # tell the insights client to connect to insights
- log.debug("insights-connect-task: connecting to insights")
- rc = util.execWithRedirect(self.INSIGHTS_TOOL_PATH, ["--register"], root=self._sysroot)
- if rc:
- raise InsightsConnectError("Failed to connect to Red Hat Insights.")
-
-
-class RestoreRHSMDefaultsTask(Task):
- """Restore RHSM defaults we changed for install time purposes.
-
- At the moment this means setting the RHSM log level back to INFO
- from DEBUG and making sure SSL certificate validation is enabled
- (as we might turn it off for the installation run if requested by
- the user).
- """
-
- def __init__(self, rhsm_config_proxy):
- """Create a new task.
- :param rhsm_config_proxy: DBus proxy for the RHSM Config object
- """
- super().__init__()
- self._rhsm_config_proxy = rhsm_config_proxy
-
- @property
- def name(self):
- return "Restoring subscription manager defaults"
-
- def run(self):
- """Restore RHSM defaults we changed.
-
- We previously set the RHSM log level to DEBUG, which is also
- reflected in rhsm.conf. This would mean RHSM would continue to
- log in debug mode also on the system once rhsm.conf has been
- copied over to the target system.
-
- The same thing needs to be done for the server.insecure key
- that we migh set to "1" previously on user request.
-
- So set the log level back to INFO before we copy the config file
- and make sure server.insecure is equal to "0".
- """
- log.debug("subscription: setting RHSM log level back to INFO")
- log.debug("subscription: making sure RHSM SSL certificate validation is enabled")
- config_dict = {
- "logging.default_log_level": get_variant(Str, "INFO"),
- "server.insecure": get_variant(Str, "0")
- }
-
- # set all the values at once atomically
- self._rhsm_config_proxy.SetAll(config_dict, "")
-
-
-class TransferSubscriptionTokensTask(Task):
- """Transfer subscription tokens to the target system."""
-
- RHSM_REPO_FILE_PATH = "/etc/yum.repos.d/redhat.repo"
- RHSM_CONFIG_FILE_PATH = "/etc/rhsm/rhsm.conf"
- RHSM_ENTITLEMENT_KEYS_PATH = "/etc/pki/entitlement"
- RHSM_CONSUMER_KEY_PATH = "/etc/pki/consumer/key.pem"
- RHSM_CONSUMER_CERT_PATH = "/etc/pki/consumer/cert.pem"
-
- TARGET_REPO_FOLDER_PATH = "/etc/yum.repos.d"
-
- def __init__(self, sysroot, transfer_subscription_tokens):
- """Create a new task.
-
- :param str sysroot: target system root path
- :param bool transfer_subscription_tokens: if True attempt to transfer subscription
- tokens to target system (we always transfer
- system purpose data unconditionally)
- """
- super().__init__()
- self._sysroot = sysroot
- self._transfer_subscription_tokens = transfer_subscription_tokens
-
- @property
- def name(self):
- return "Transfer subscription tokens to target system"
-
- def _copy_pem_files(self, input_folder, output_folder, not_empty=True):
- """Copy all pem files from input_folder to output_folder.
-
- Files with the pem extension are generally encryption keys and certificates.
- If output_folder does not exist, it & any parts of its path will
- be created.
-
- :param str input_folder: input folder for the pem files
- :param str output_folder: output folder where to copy the pem files
- :return: False if the input directory does not exists or is empty,
- True after all pem files have be successfully copied
- :rtype: bool
- """
- # check the input folder exists
- if not os.path.isdir(input_folder):
- return False
- # optionally check the input folder is not empty
- if not_empty and not os.listdir(input_folder):
- return False
- # make sure the output folder exist
- util.mkdirChain(output_folder)
- # transfer all the pem files in the input folder
- for pem_file_path in glob.glob(os.path.join(input_folder, "*.pem")):
- shutil.copy(pem_file_path, output_folder)
- # if we got this far the pem copy operation was a success
- return True
-
- def _copy_file(self, file_path, target_file_path):
- if not os.path.isfile(file_path):
- return False
- # make sure the output folder exists
- util.mkdirChain(os.path.dirname(target_file_path))
- shutil.copy(file_path, target_file_path)
- return True
-
- def _transfer_file(self, target_path, target_name):
- """Transfer a file with nice logs and raise an exception if it does not exist."""
- log.debug("subscription: transferring %s", target_name)
- target_repo_file_path = util.join_paths(self._sysroot, target_path)
- if not self._copy_file(target_path, target_repo_file_path):
- msg = "{} ({}) is missing".format(target_name, self.RHSM_REPO_FILE_PATH)
- raise SubscriptionTokenTransferError(msg)
-
- def _transfer_system_purpose(self):
- """Transfer the system purpose file if present.
-
- A couple notes:
- - this might be needed even if the system has not been subscribed
- during the installation and is therefore always attempted
- - this means the syspurpose tool has been called in the installation
- environment & we need to transfer the results to the target system
- """
- if check_system_purpose_set(sysroot="/"):
- log.debug("subscription: transferring syspurpose file")
- target_syspurpose_file_path = self._sysroot + RHSM_SYSPURPOSE_FILE_PATH
- self._copy_file(RHSM_SYSPURPOSE_FILE_PATH, target_syspurpose_file_path)
-
- def _transfer_entitlement_keys(self):
- """Transfer the entitlement keys."""
- log.debug("subscription: transferring entitlement keys")
- target_entitlement_keys_path = self._sysroot + self.RHSM_ENTITLEMENT_KEYS_PATH
- if not self._copy_pem_files(self.RHSM_ENTITLEMENT_KEYS_PATH, target_entitlement_keys_path):
- msg = "RHSM entitlement keys (from {}) are missing.".format(
- self.RHSM_ENTITLEMENT_KEYS_PATH)
- raise SubscriptionTokenTransferError(msg)
-
- def run(self):
- """Transfer the subscription tokens to the target system.
-
- Otherwise the target system would have to be registered and subscribed again
- due to missing subscription tokens.
- """
- self._transfer_system_purpose()
-
- # the other subscription tokens are only relevant if the system has been subscribed
- if not self._transfer_subscription_tokens:
- log.debug("subscription: transfer of subscription tokens not requested")
- return
-
- # transfer entitlement keys
- self._transfer_entitlement_keys()
-
- # transfer the consumer key
- self._transfer_file(self.RHSM_CONSUMER_KEY_PATH, "RHSM consumer key")
-
- # transfer the consumer cert
- self._transfer_file(self.RHSM_CONSUMER_CERT_PATH, "RHSM consumer cert")
-
- # transfer the redhat.repo file
- self._transfer_file(self.RHSM_REPO_FILE_PATH, "RHSM repo file")
-
- # transfer the RHSM config file
- self._transfer_file(self.RHSM_CONFIG_FILE_PATH, "RHSM config file")
diff --git a/pyanaconda/modules/subscription/kickstart.py b/pyanaconda/modules/subscription/kickstart.py
deleted file mode 100644
index 509961f..0000000
--- a/pyanaconda/modules/subscription/kickstart.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Kickstart handler for the subscription module.
-#
-# Copyright (C) 2020 Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details. You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-from pyanaconda.core.kickstart import KickstartSpecification, commands as COMMANDS
-
-
-class SubscriptionKickstartSpecification(KickstartSpecification):
-
- commands = {
- "syspurpose": COMMANDS.Syspurpose,
- "rhsm": COMMANDS.RHSM
- }
diff --git a/pyanaconda/modules/subscription/subscription.py b/pyanaconda/modules/subscription/subscription.py
deleted file mode 100644
index d71e108..0000000
--- a/pyanaconda/modules/subscription/subscription.py
+++ /dev/null
@@ -1,789 +0,0 @@
-#
-# Kickstart module for subscription handling.
-#
-# Copyright (C) 2020 Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details. You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-import copy
-import warnings
-
-from dasbus.typing import get_native
-
-from pyanaconda.core.payload import ProxyString, ProxyStringError
-from pyanaconda.core.signal import Signal
-from pyanaconda.core.constants import SECRET_TYPE_HIDDEN, SUBSCRIPTION_REQUEST_TYPE_ORG_KEY, \
- SUBSCRIPTION_REQUEST_VALID_TYPES
-from pyanaconda.core.configuration.anaconda import conf
-
-from pyanaconda.modules.common.errors.general import InvalidValueError
-from pyanaconda.modules.common.base import KickstartService
-from pyanaconda.modules.common.structures.subscription import SystemPurposeData, \
- SubscriptionRequest
-from pyanaconda.modules.common.structures.secret import get_public_copy
-from pyanaconda.core.dbus import DBus
-
-from pyanaconda.modules.common.constants.services import SUBSCRIPTION
-from pyanaconda.modules.common.constants.objects import RHSM_CONFIG, RHSM_REGISTER_SERVER, \
- RHSM_UNREGISTER, RHSM_ATTACH, RHSM_ENTITLEMENT, RHSM_SYSPURPOSE
-from pyanaconda.modules.common.containers import TaskContainer
-from pyanaconda.modules.common.structures.requirement import Requirement
-
-from pyanaconda.modules.subscription import system_purpose
-from pyanaconda.modules.subscription.kickstart import SubscriptionKickstartSpecification
-from pyanaconda.modules.subscription.subscription_interface import SubscriptionInterface
-from pyanaconda.modules.subscription.installation import ConnectToInsightsTask, \
- RestoreRHSMDefaultsTask, TransferSubscriptionTokensTask
-from pyanaconda.modules.subscription.initialization import StartRHSMTask
-from pyanaconda.modules.subscription.runtime import SetRHSMConfigurationTask, \
- RegisterWithUsernamePasswordTask, RegisterWithOrganizationKeyTask, \
- UnregisterTask, AttachSubscriptionTask, SystemPurposeConfigurationTask, \
- ParseAttachedSubscriptionsTask
-from pyanaconda.modules.subscription.rhsm_observer import RHSMObserver
-from pyanaconda.modules.subscription.utils import detect_sca_from_registration_data
-
-
-from pykickstart.errors import KickstartParseWarning
-
-from pyanaconda.anaconda_loggers import get_module_logger
-log = get_module_logger(__name__)
-
-
-class SubscriptionService(KickstartService):
- """The Subscription service."""
-
- def __init__(self):
- super().__init__()
-
- # system purpose
-
- self._valid_roles = []
- self._valid_slas = []
- self._valid_usage_types = []
-
- self._system_purpose_data = SystemPurposeData()
- self.system_purpose_data_changed = Signal()
-
- self._load_valid_system_purpose_values()
-
- # subscription request
-
- self._subscription_request = SubscriptionRequest()
- self.subscription_request_changed = Signal()
-
- # attached subscriptions
- self._attached_subscriptions = []
- self.attached_subscriptions_changed = Signal()
-
- # Insights
-
- # What are the defaults for Red Hat Insights ?
- # - during a kickstart installation, the user
- # needs to opt-in by using the rhsm command
- # with the --connect-to-insights option
- # - during a GUI interactive installation the
- # "connect to Insights" checkbox is checked by default,
- # making Insights opt-out
- # - in both cases the system also needs to be subscribed,
- # or else the system can't be connected to Insights
- self._connect_to_insights = False
- self.connect_to_insights_changed = Signal()
-
- # registration status
- self.registered_changed = Signal()
- self._registered = False
-
- # simple content access
- self.simple_content_access_enabled_changed = Signal()
- self._sca_enabled = False
-
- # subscription status
- self.subscription_attached_changed = Signal()
- self._subscription_attached = False
-
- # RHSM service startup and access
- self._rhsm_startup_task = StartRHSMTask(verify_ssl=conf.payload.verify_ssl)
- self._rhsm_observer = RHSMObserver(self._rhsm_startup_task.is_service_available)
-
- # RHSM config default values cache
- self._rhsm_config_defaults = None
-
- def publish(self):
- """Publish the module."""
- TaskContainer.set_namespace(SUBSCRIPTION.namespace)
- DBus.publish_object(SUBSCRIPTION.object_path, SubscriptionInterface(self))
- DBus.register_service(SUBSCRIPTION.service_name)
-
- def run(self):
- """Initiate RHSM service startup before starting the main loop.
-
- This way RHSM service can startup in parallel without blocking
- startup of the Subscription module.
- """
- self._rhsm_startup_task.start()
- super().run()
-
- @property
- def kickstart_specification(self):
- """Return the kickstart specification."""
- return SubscriptionKickstartSpecification
-
- def process_kickstart(self, data):
- """Process the kickstart data."""
- log.debug("Processing kickstart data...")
-
- # system purpose
- #
- # Try if any of the values in kickstart match a valid field.
- # If it does, write the valid field value instead of the value from kickstart.
- #
- # This way a value in kickstart that has a different case and/or trailing white space
- # can still be used to preselect a value in a UI instead of being marked as a custom
- # user specified value.
- system_purpose_data = SystemPurposeData()
-
- system_purpose_data.role = system_purpose.process_field(
- data.syspurpose.role,
- self.valid_roles,
- "role"
- )
-
- system_purpose_data.sla = system_purpose.process_field(
- data.syspurpose.sla,
- self.valid_slas,
- "sla"
- )
-
- system_purpose_data.usage = system_purpose.process_field(
- data.syspurpose.usage,
- self.valid_usage_types,
- "usage"
- )
-
- if data.syspurpose.addons:
- # As we do not have a list of valid addons available, we just use what was provided
- # by the user in kickstart verbatim.
- system_purpose_data.addons = data.syspurpose.addons
-
- self.set_system_purpose_data(system_purpose_data)
-
- # apply system purpose data, if any, so that it is all in place when we start
- # talking to the RHSM service
- if self.system_purpose_data.check_data_available():
- self._apply_syspurpose()
-
- # subscription request
-
- subscription_request = SubscriptionRequest()
-
- # credentials
- if data.rhsm.organization:
- subscription_request.organization = data.rhsm.organization
- if data.rhsm.activation_keys:
- subscription_request.activation_keys.set_secret(data.rhsm.activation_keys)
-
- # if org id and at least one activation key is set, switch authentication
- # type to ORG & KEY
- if data.rhsm.organization and data.rhsm.activation_keys:
- subscription_request.type = SUBSCRIPTION_REQUEST_TYPE_ORG_KEY
-
- # custom URLs
- if data.rhsm.server_hostname:
- subscription_request.server_hostname = data.rhsm.server_hostname
- if data.rhsm.rhsm_baseurl:
- subscription_request.rhsm_baseurl = data.rhsm.rhsm_baseurl
-
- # HTTP proxy
- if data.rhsm.proxy:
- # first try to parse the proxy string from kickstart
- try:
- proxy = ProxyString(data.rhsm.proxy)
- if proxy.host:
- # ensure port is an integer and set to -1 if unknown
- port = int(proxy.port) if proxy.port else -1
-
- subscription_request.server_proxy_hostname = proxy.host
- subscription_request.server_proxy_port = port
-
- # ensure no username translates to the expected ""
- # instead of the None returned by the ProxyString class
- subscription_request.server_proxy_user = proxy.username or ""
- subscription_request.server_proxy_password.set_secret(proxy.password)
- except ProxyStringError as e:
- # should not be fatal, but definitely logged as error
- message = "Failed to parse proxy for the rhsm command: {}".format(str(e))
- warnings.warn(message, KickstartParseWarning)
-
- # set the resulting subscription request
- self.set_subscription_request(subscription_request)
-
- # insights
- self.set_connect_to_insights(bool(data.rhsm.connect_to_insights))
-
- def setup_kickstart(self, data):
- """Return the kickstart string.
-
- NOTE: We are not writing out the rhsm command as the input can contain
- sensitive data (activation keys, proxy passwords) that we would have
- to omit from the output kickstart. This in turn would make the rhsm
- command incomplete & would turn the output kickstart invalid as a result.
- For this reason we skip the rhsm command completely in the output
- kickstart.
- """
-
- # system purpose
- data.syspurpose.role = self.system_purpose_data.role
- data.syspurpose.sla = self.system_purpose_data.sla
- data.syspurpose.usage = self.system_purpose_data.usage
- data.syspurpose.addons = self.system_purpose_data.addons
-
- # system purpose configuration
-
- def _load_valid_system_purpose_values(self):
- """Load lists of valid roles, SLAs and usage types.
-
- About role/sla/validity:
- - an older installation image might have older list of valid fields,
- missing fields that have become valid after the image has been released
- - fields that have been valid in the past might be dropped in the future
- - there is no list of valid addons
-
- Due to this we need to take into account that the listing might not always be
- comprehensive and that we need to allow what might on a first glance look like
- invalid values to be written to the target system.
- """
- roles, slas, usage_types = system_purpose.get_valid_fields()
- self._valid_roles = roles
- self._valid_slas = slas
- self._valid_usage_types = usage_types
-
- @property
- def valid_roles(self):
- """Return a list of valid roles.
-
- :return: list of valid roles
- :rtype: list of strings
- """
- return self._valid_roles
-
- @property
- def valid_slas(self):
- """Return a list of valid SLAs.
-
- :return: list of valid SLAs
- :rtype: list of strings
- """
- return self._valid_slas
-
- @property
- def valid_usage_types(self):
- """Return a list of valid usage types.
-
- :return: list of valid usage types
- :rtype: list of strings
- """
- return self._valid_usage_types
-
- @property
- def system_purpose_data(self):
- """System purpose data.
-
- A DBus structure holding information about system purpose,
- such as role, sla, usage and addons.
-
- :return: system purpose DBus structure
- :rtype: DBusData instance
- """
- return self._system_purpose_data
-
- def set_system_purpose_data(self, system_purpose_data):
- """Set system purpose data.
-
- Set the complete DBus structure containing system purpose data.
-
- :param system_purpose_data: system purpose data structure to be set
- :type system_purpose_data: DBus structure
- """
- self._system_purpose_data = system_purpose_data
- self.system_purpose_data_changed.emit()
- log.debug("System purpose data set to %s.", system_purpose_data)
-
- def _apply_syspurpose(self):
- """Apply system purpose information to the installation environment."""
- log.debug("subscription: Applying system purpose data")
- task = SystemPurposeConfigurationTask(system_purpose_data=self.system_purpose_data)
- task.run()
-
- def set_system_purpose_with_task(self):
- """Set system purpose for the installed system with an installation task.
- :return: a DBus path of an installation task
- """
- task = SystemPurposeConfigurationTask(system_purpose_data=self.system_purpose_data)
- return task
-
- # subscription request
-
- def _validate_subscription_request_type(self, request_type):
- """Check that subscription request is of known type."""
- if request_type not in SUBSCRIPTION_REQUEST_VALID_TYPES:
- raise InvalidValueError(
- "Invalid subscription request type set '{}'".format(request_type)
- )
-
- @property
- def subscription_request(self):
- """Subscription request.
-
- A DBus structure holding data to be used to subscribe the system.
-
- :return: subscription request DBus structure
- :rtype: DBusData instance
- """
- # Return a deep copy of the subscription request that
- # has also been cleared of private data.
- # Thankfully the secret Dbus structures modules
- # has the get_public_copy() method that does just
- # that. It creates a deep copy & clears
- # all SecretData and SecretDataList instances.
- return get_public_copy(self._subscription_request)
-
- def set_subscription_request(self, subscription_request):
- """Set a subscription request.
-
- Set the complete DBus structure containing subscription
- request data.
-
- :param subscription_request: subscription request structure to be set
- :type subscription_request: DBus structure
- """
- self._replace_current_subscription_request(subscription_request)
- self.subscription_request_changed.emit()
- log.debug("A subscription request set: %s", str(self._subscription_request))
-
- @property
- def attached_subscriptions(self):
- """A list of attached subscriptions.
-
- The list holds DBus structures with each structure holding information about
- one attached subscription. A system that has been successfully registered and
- subscribed usually has one or more subscriptions attached.
-
- :return: list of DBus structures, one per attached subscription
- :rtype: list of AttachedSubscription instances
- """
- return self._attached_subscriptions
-
- def set_attached_subscriptions(self, attached_subscriptions):
- """Set the list of attached subscriptions.
-
- :param attached_subscriptions: list of attached subscriptions to be set
- :type attached_subscriptions: list of AttachedSubscription instances
- """
- self._attached_subscriptions = attached_subscriptions
- self.attached_subscriptions_changed.emit()
- # as there is no public setter in the DBus API, we need to emit
- # the properties changed signal here manually
- self.module_properties_changed.emit()
- log.debug("Attached subscriptions set: %s", str(self._attached_subscriptions))
-
- def _replace_current_subscription_request(self, new_request):
- """Replace current subscription request without loosing sensitive data.
-
- We need to do this to prevent blank SecretData & SecretDataList instances
- from wiping out previously set secret data. The instances will be blank
- every time a SubscriptionRequest that went through get_public_copy() comes
- back with the secret data fields unchanged.
-
- So what we do is depends on type of the incoming secret data:
-
- - SECRET_TYPE_NONE - use structure from new request unchanged,
- clearing previously set data (if any)
- - SECRET_TYPE_HIDDEN - secret data has been set previously and
- cleared when SubscriptionRequest was sent out;
- put secret data from current request to the
- new one to prevent it from being lost
- (this will also switch the secret data
- instance to SECRET_TYPE_TEXT so that
- the Subscription module can read it
- internally)
- - SECRET_TYPE_TEXT - this is new secret entry, we can keep it as is
- """
- current_request = self._subscription_request
-
- # Red Hat account password
- if new_request.account_password.type == SECRET_TYPE_HIDDEN:
- new_request.account_password = copy.deepcopy(
- current_request.account_password)
-
- # activation keys used together with an organization id
- if new_request.activation_keys.type == SECRET_TYPE_HIDDEN:
- new_request.activation_keys = copy.deepcopy(
- current_request.activation_keys)
-
- # RHSM HTTP proxy password
- if new_request.server_proxy_password.type == SECRET_TYPE_HIDDEN:
- new_request.server_proxy_password = copy.deepcopy(
- current_request.server_proxy_password)
-
- # replace current request
- self._subscription_request = new_request
-
- @property
- def connect_to_insights(self):
- """Indicates if the target system should be connected to Red Hat Insights.
-
- :return: True to connect, False not to connect the target system to Insights
- :rtype: bool
- """
- return self._connect_to_insights
-
- def set_connect_to_insights(self, connect):
- """Set if the target system should be connected to Red Hat Insights.
-
- :param bool connect: set to True to connect, set to False not to connect
- """
- self._connect_to_insights = connect
- self.connect_to_insights_changed.emit()
- log.debug("Connect target system to Insights set to: %s", self._connect_to_insights)
-
- # registration status
-
- @property
- def registered(self):
- """Return True if the system has been registered.
-
- NOTE: Together with the subscription_attached property
- the registered property can be used to detect that
- the system is registered but has not subscription
- attached. This is generally a sign something went
- wrong, usually when trying to attach subscription.
-
- :return: True if the system has been registered, False otherwise
- :rtype: bool
- """
- return self._registered
-
- def set_registered(self, system_registered):
- """Set if the system is registered.
-
- :param bool system_registered: True if system has been registered, False otherwise
- """
- self._registered = system_registered
- self.registered_changed.emit()
- # as there is no public setter in the DBus API, we need to emit
- # the properties changed signal here manually
- self.module_properties_changed.emit()
- log.debug("System registered set to: %s", system_registered)
-
- # simple content access status
- @property
- def simple_content_access_enabled(self):
- """Return True if the system has been registered with SCA enabled.
-
- :return: True if the system has been registered in SCA mode, False otherwise
- :rtype: bool
- """
- return self._sca_enabled
-
- def set_simple_content_access_enabled(self, sca_enabled):
- """Set if Simple Content Access is enabled.
-
- :param bool sca_enabled: True if SCA is enabled, False otherwise
- """
- self._sca_enabled = sca_enabled
- self.simple_content_access_enabled_changed.emit()
- # as there is no public setter in the DBus API, we need to emit
- # the properties changed signal here manually
- self.module_properties_changed.emit()
- log.debug("Simple Content Access enabled set to: %s", sca_enabled)
-
- # subscription status
-
- @property
- def subscription_attached(self):
- """Return True if a subscription has been attached to the system.
-
- :return: True if a subscription has been attached to the system, False otherwise
- :rtype: bool
- """
- return self._subscription_attached
-
- def set_subscription_attached(self, system_subscription_attached):
- """Set a subscription has been attached to the system.
-
- :param bool system_registered: True if subscription has been attached, False otherwise
- """
- self._subscription_attached = system_subscription_attached
- self.subscription_attached_changed.emit()
- # as there is no public setter in the DBus API, we need to emit
- # the properties changed signal here manually
- self.module_properties_changed.emit()
- log.debug("Subscription attached set to: %s", system_subscription_attached)
-
- # tasks
-
- def install_with_tasks(self):
- """Return the installation tasks of this module.
-
- Order of execution is important:
- - before transferring subscription tokens we need to restore
- the INFO log level in rhsm.conf or else target system will
- end up with RHSM logging in DEBUG mode
- - transfer subscription tokens
- - connect to insights, this can run only once subscription
- tokens are in place on the target system or else it would
- fail as Insights client needs the subscription tokens to
- authenticate to the Red Hat Insights online service
-
- :returns: list of installation tasks
- """
- return [
- RestoreRHSMDefaultsTask(
- rhsm_config_proxy=self.rhsm_observer.get_proxy(RHSM_CONFIG)
- ),
- TransferSubscriptionTokensTask(
- sysroot=conf.target.system_root,
- transfer_subscription_tokens=self.subscription_attached
- ),
- ConnectToInsightsTask(
- sysroot=conf.target.system_root,
- subscription_attached=self.subscription_attached,
- connect_to_insights=self.connect_to_insights
- )
- ]
-
- # RHSM DBus API access
-
- @property
- def rhsm_observer(self):
- """Provide access to the RHSM DBus service observer.
-
- This observer handles various peculiarities of the
- RHSM DBus API startup and should be used as the
- only access point to the RHSM Dbus API.
-
- If you need to RHSM DBus API object, just call the
- get_proxy() method of the observer with object
- identifier.
-
- :return: RHSM DBus API observer
- :rtype: RHSMObserver instance
- """
- return self._rhsm_observer
-
- def _flatten_rhsm_nested_dict(self, nested_dict):
- """Convert the GetAll() returned nested dict into a flat one.
-
- RHSM returns a nested dict with categories on top
- and category keys & values inside. This is not convenient
- for setting keys based on original values, so
- let's normalize the dict to the flat key based
- structure similar to what's used by SetAll().
-
- :param dict nested_dict: the nested dict returned by GetAll()
- :return: flat key/value dictionary, similar to format used by SetAll()
- :rtype: dict
- """
- flat_dict = {}
- for category_key, category_dict in nested_dict.items():
- for key, value in category_dict.items():
- flat_key = "{}.{}".format(category_key, key)
- flat_dict[flat_key] = value
- return flat_dict
-
- def get_rhsm_config_defaults(self):
- """Return RHSM config default values.
-
- We need to have these available in case the user decides
- to return to default values from a custom value at
- runtime.
-
- This method is lazy evaluated, the first call it fetches
- the full config dict from RHSM and subsequent calls are
- then served from cache.
-
- Due to this it is important not to set RHSM configuration
- values before first calling this method to populate the cache
- or else the method might return non-default (Anaconda overwritten)
- data.
-
- NOTE: While RHSM GetAll() DBus call returns a nested dictionary,
- we turn it into a flat key/value dict, in the same format SetAll()
- uses.
-
- :return : dictionary of default RHSM configuration values
- :rtype: dict
- """
- if self._rhsm_config_defaults is None:
- # config defaults cache not yet populated, do it now
- proxy = self.rhsm_observer.get_proxy(RHSM_CONFIG)
- # turn the variant into a dict with get_native()
- nested_dict = get_native(proxy.GetAll(""))
- # flatten the nested dict
- flat_dict = self._flatten_rhsm_nested_dict(nested_dict)
- self._rhsm_config_defaults = flat_dict
- return self._rhsm_config_defaults
-
- def set_rhsm_config_with_task(self):
- """Set RHSM config values based on current subscription request.
-
- :return: a DBus path of an installation task
- """
- # NOTE: we access self._subscription_request directly
- # to avoid the sensitive data clearing happening
- # in the subscription_request property getter
- rhsm_config_proxy = self.rhsm_observer.get_proxy(RHSM_CONFIG)
- task = SetRHSMConfigurationTask(rhsm_config_proxy=rhsm_config_proxy,
- rhsm_config_defaults=self.get_rhsm_config_defaults(),
- subscription_request=self._subscription_request)
- return task
-
- def register_username_password_with_task(self):
- """Register with username and password based on current subscription request.
-
- :return: a DBus path of an installation task
- """
- # NOTE: we access self._subscription_request directly
- # to avoid the sensitive data clearing happening
- # in the subscription_request property getter
- username = self._subscription_request.account_username
- password = self._subscription_request.account_password.value
- register_server_proxy = self.rhsm_observer.get_proxy(RHSM_REGISTER_SERVER)
- task = RegisterWithUsernamePasswordTask(rhsm_register_server_proxy=register_server_proxy,
- username=username,
- password=password)
- # if the task succeeds, it means the system has been registered
- task.succeeded_signal.connect(
- lambda: self.set_registered(True))
- # set SCA state based on data returned by the registration task
- task.succeeded_signal.connect(
- lambda: self.set_simple_content_access_enabled(
- detect_sca_from_registration_data(task.get_result())
- )
- )
-
- return task
-
- def register_organization_key_with_task(self):
- """Register with organization and activation key(s) based on current subscription request.
-
- :return: a DBus path of an installation task
- """
- # NOTE: we access self._subscription_request directly
- # to avoid the sensitive data clearing happening
- # in the subscription_request property getter
- organization = self._subscription_request.organization
- activation_keys = self._subscription_request.activation_keys.value
- register_server_proxy = self.rhsm_observer.get_proxy(RHSM_REGISTER_SERVER)
- task = RegisterWithOrganizationKeyTask(rhsm_register_server_proxy=register_server_proxy,
- organization=organization,
- activation_keys=activation_keys)
- # if the task succeeds, it means the system has been registered
- task.succeeded_signal.connect(
- lambda: self.set_registered(True))
- # set SCA state based on data returned by the registration task
- task.succeeded_signal.connect(
- lambda: self.set_simple_content_access_enabled(
- detect_sca_from_registration_data(task.get_result())
- )
- )
- return task
-
- def unregister_with_task(self):
- """Unregister the system.
-
- :return: a DBus path of an installation task
- """
- rhsm_unregister_proxy = self.rhsm_observer.get_proxy(RHSM_UNREGISTER)
- task = UnregisterTask(rhsm_unregister_proxy=rhsm_unregister_proxy)
- # we will no longer be registered and subscribed if the task is successful,
- # so set the corresponding properties appropriately
- task.succeeded_signal.connect(
- lambda: self.set_registered(False))
- task.succeeded_signal.connect(
- lambda: self.set_subscription_attached(False))
- # and clear attached subscriptions
- task.succeeded_signal.connect(
- lambda: self.set_attached_subscriptions([]))
- # also when we are no longer registered then we are are
- # thus no longer in Simple Content Access mode
- task.succeeded_signal.connect(
- lambda: self.set_simple_content_access_enabled(False))
- return task
-
- def attach_subscription_with_task(self):
- """Attach a subscription.
-
- This should only be run on a system that has been successfully registered.
- Attached subscription depends on system type, system purpose data
- and entitlements available for the account that has been used for registration.
-
- :return: a DBus path of an installation task
- """
- sla = self.system_purpose_data.sla
- rhsm_attach_proxy = self.rhsm_observer.get_proxy(RHSM_ATTACH)
- task = AttachSubscriptionTask(rhsm_attach_proxy=rhsm_attach_proxy,
- sla=sla)
- # if the task succeeds, it means a subscription has been attached
- task.succeeded_signal.connect(
- lambda: self.set_subscription_attached(True))
- return task
-
- def _set_system_subscription_data(self, system_subscription_data):
- """A helper method invoked in ParseAttachedSubscritionsTask completed signal.
-
- :param system_subscription_data: a named tuple holding attached subscriptions
- and final system purpose data
- """
- self.set_attached_subscriptions(system_subscription_data.attached_subscriptions)
- self.set_system_purpose_data(system_subscription_data.system_purpose_data)
-
- def parse_attached_subscriptions_with_task(self):
- """Parse attached subscriptions with task.
-
- Parse data about attached subscriptions and final system purpose data.
- This data is available as JSON strings via the RHSM DBus API.
-
- :return: a DBus path of an installation task
- """
- rhsm_entitlement_proxy = self.rhsm_observer.get_proxy(RHSM_ENTITLEMENT)
- rhsm_syspurpose_proxy = self.rhsm_observer.get_proxy(RHSM_SYSPURPOSE)
- task = ParseAttachedSubscriptionsTask(rhsm_entitlement_proxy=rhsm_entitlement_proxy,
- rhsm_syspurpose_proxy=rhsm_syspurpose_proxy)
- # if the task succeeds, set attached subscriptions and system purpose data
- task.succeeded_signal.connect(
- lambda: self._set_system_subscription_data(task.get_result())
- )
- return task
-
- def collect_requirements(self):
- """Return installation requirements for this module.
-
- :return: a list of requirements
- """
- requirements = []
- # check if we need the insights-client package, which is needed to connect the
- # target system to Red Hat Insights
- if self.subscription_attached and self.connect_to_insights:
- # establishing a connection to Red Hat Insights has been requested
- # and we need the insights-client package to be present in the
- # target system chroot for that
- requirements.append(
- Requirement.for_package(
- "insights-client",
- reason="Needed to connect the target system to Red Hat Insights."
- )
- )
- return requirements
diff --git a/pyanaconda/modules/subscription/subscription_interface.py b/pyanaconda/modules/subscription/subscription_interface.py
deleted file mode 100644
index 8bbf38b..0000000
--- a/pyanaconda/modules/subscription/subscription_interface.py
+++ /dev/null
@@ -1,211 +0,0 @@
-#
-# DBus interface for the subscription module.
-#
-# Copyright (C) 2020 Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details. You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-from pyanaconda.modules.common.constants.services import SUBSCRIPTION
-from pyanaconda.modules.common.base import KickstartModuleInterface
-from pyanaconda.modules.common.structures.subscription import SystemPurposeData, \
- SubscriptionRequest, AttachedSubscription
-from pyanaconda.modules.common.containers import TaskContainer
-from dasbus.server.interface import dbus_interface
-from dasbus.server.property import emits_properties_changed
-from dasbus.typing import * # pylint: disable=wildcard-import
-
-
-@dbus_interface(SUBSCRIPTION.interface_name)
-class SubscriptionInterface(KickstartModuleInterface):
- """DBus interface for the Subscription service."""
-
- def connect_signals(self):
- super().connect_signals()
- self.watch_property("SystemPurposeData",
- self.implementation.system_purpose_data_changed)
- self.watch_property("SubscriptionRequest",
- self.implementation.subscription_request_changed)
- self.watch_property("AttachedSubscriptions",
- self.implementation.attached_subscriptions_changed)
- self.watch_property("InsightsEnabled",
- self.implementation.connect_to_insights_changed)
- self.watch_property("IsRegistered",
- self.implementation.registered_changed)
- self.watch_property("IsSimpleContentAccessEnabled",
- self.implementation.simple_content_access_enabled_changed)
- self.watch_property("IsSubscriptionAttached",
- self.implementation.subscription_attached_changed)
-
- def GetValidRoles(self) -> List[Str]:
- """Return all valid system purpose roles.
-
- These are OS release specific, but could look like this:
-
- "Red Hat Enterprise Linux Server"
- "Red Hat Enterprise Linux Workstation"
- "Red Hat Enterprise Linux Compute Node"
- """
- return self.implementation.valid_roles
-
- def GetValidSLAs(self) -> List[Str]:
- """Return all valid system purpose SLAs.
-
- These are OS release specific, but could look like this:
-
- "Premium"
- "Standard"
- "Self-Support"
- """
- return self.implementation.valid_slas
-
- def GetValidUsageTypes(self) -> List[Str]:
- """List all valid system purpose usage types.
-
- These are OS release specific, but could look like this:
-
- "Production",
- "Development/Test",
- "Disaster Recovery"
- """
- return self.implementation.valid_usage_types
-
- @property
- def SystemPurposeData(self) -> Structure:
- """Return DBus structure holding current system purpose data."""
- return SystemPurposeData.to_structure(self.implementation.system_purpose_data)
-
- @emits_properties_changed
- def SetSystemPurposeData(self, system_purpose_data: Structure):
- """Set a new DBus structure holding system purpose data.
-
- :param system_purpose_data: DBus structure corresponding to SystemPurposeData
- """
- converted_data = SystemPurposeData.from_structure(system_purpose_data)
- self.implementation.set_system_purpose_data(converted_data)
-
- def SetSystemPurposeWithTask(self) -> ObjPath:
- """Set system purpose for the installed system with an installation task.
-
- :return: a DBus path of an installation task
- """
- return TaskContainer.to_object_path(
- self.implementation.set_system_purpose_with_task()
- )
-
- @property
- def SubscriptionRequest(self) -> Structure:
- """Return DBus structure holding current subscription request.
-
- Subscription request holds data necessary for a successful subscription attempt.
- """
- return SubscriptionRequest.to_structure(self.implementation.subscription_request)
-
- @emits_properties_changed
- def SetSubscriptionRequest(self, subscription_request: Structure):
- """Set a new DBus structure holding subscription request data.
-
- :param subscription_request: DBus structure corresponding to SubscriptionRequest
- """
- converted_data = SubscriptionRequest.from_structure(subscription_request)
- self.implementation.set_subscription_request(converted_data)
-
- @property
- def AttachedSubscriptions(self) -> List[Structure]:
- """Return a list of DBus structures holding data about attached subscriptions."""
- return AttachedSubscription.to_structure_list(
- self.implementation.attached_subscriptions
- )
-
- @property
- def InsightsEnabled(self) -> Int:
- """Connect the target system to Red Hat Insights."""
- return self.implementation.connect_to_insights
-
- @emits_properties_changed
- def SetInsightsEnabled(self, connect_to_insights: Bool):
- """Set if the target system should be connected to Red Hat Insights.
-
- :param bool connect_to_insights: True to connect, False not to connect
- """
- self.implementation.set_connect_to_insights(connect_to_insights)
-
- @property
- def IsRegistered(self) -> Bool:
- """Report if the system is registered."""
- return self.implementation.registered
-
- @property
- def IsSimpleContentAccessEnabled(self) -> Bool:
- """Report if Simple Content Access is enabled."""
- return self.implementation.simple_content_access_enabled
-
- @property
- def IsSubscriptionAttached(self) -> Bool:
- """Report if an entitlement has been successfully attached."""
- return self.implementation.subscription_attached
-
- def SetRHSMConfigWithTask(self) -> ObjPath:
- """Set RHSM configuration with a runtime DBus task.
-
- :return: a DBus path of an installation task
- """
- return TaskContainer.to_object_path(
- self.implementation.set_rhsm_config_with_task()
- )
-
- def RegisterUsernamePasswordWithTask(self) -> ObjPath:
- """Register with username & password using a runtime DBus task.
-
- :return: a DBus path of an installation task
- """
- return TaskContainer.to_object_path(
- self.implementation.register_username_password_with_task()
- )
-
- def RegisterOrganizationKeyWithTask(self) -> ObjPath:
- """Register with organization & keys(s) using a runtime DBus task.
-
- :return: a DBus path of an installation task
- """
- return TaskContainer.to_object_path(
- self.implementation.register_organization_key_with_task()
- )
-
- def UnregisterWithTask(self) -> ObjPath:
- """Unregister using a runtime DBus task.
-
- :return: a DBus path of an installation task
- """
- return TaskContainer.to_object_path(
- self.implementation.unregister_with_task()
- )
-
- def AttachSubscriptionWithTask(self) -> ObjPath:
- """Attach subscription using a runtime DBus task.
-
- :return: a DBus path of an installation task
- """
- return TaskContainer.to_object_path(
- self.implementation.attach_subscription_with_task()
- )
-
- def ParseAttachedSubscriptionsWithTask(self) -> ObjPath:
- """Parse attached subscriptions using a runtime DBus task.
-
- :return: a DBus path of an installation task
- """
- return TaskContainer.to_object_path(
- self.implementation.parse_attached_subscriptions_with_task()
- )
diff --git a/pyanaconda/modules/subscription/system_purpose.py b/pyanaconda/modules/subscription/system_purpose.py
deleted file mode 100644
index 189719f..0000000
--- a/pyanaconda/modules/subscription/system_purpose.py
+++ /dev/null
@@ -1,227 +0,0 @@
-#
-# System purpose library.
-#
-# Copyright (C) 2020 Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details. You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-
-import os
-import json
-
-from pyanaconda.core import util
-from pyanaconda.core.constants import RHSM_SYSPURPOSE_FILE_PATH
-from pyanaconda.core.subscription import check_system_purpose_set
-
-from pyanaconda.anaconda_loggers import get_module_logger
-log = get_module_logger(__name__)
-
-VALID_FIELDS_FILE_PATH = "/etc/rhsm/syspurpose/valid_fields.json"
-SYSPURPOSE_UTILITY_PATH = "/usr/sbin/syspurpose"
-
-def get_valid_fields(valid_fields_file_path=VALID_FIELDS_FILE_PATH):
- """Get valid role, sla and usage fields for system purpose use.
-
- If no valid fields are provided, the fields file is not found or can not be
- parsed then all three lists will be empty.
-
- :param str valid_fields_file_path: path to a JSON file holding the valid field listings
-
- :return: role, sla and usage type lists
- :rtype: [roles], [slas], [usages]
- """
- valid_roles = []
- valid_slas = []
- valid_usage_types = []
- if os.path.exists(valid_fields_file_path):
- try:
- with open(valid_fields_file_path, "rt") as f:
- valid_fields_json = json.load(f)
- valid_roles = valid_fields_json.get("role", [])
- valid_slas = valid_fields_json.get("service_level_agreement", [])
- valid_usage_types = valid_fields_json.get("usage", [])
- except (IOError, json.JSONDecodeError):
- log.exception("parsing of syspurpose valid fields file at %s failed",
- valid_fields_file_path)
- else:
- log.warning("system purpose valid fields file not found at %s", valid_fields_file_path)
- return valid_roles, valid_slas, valid_usage_types
-
-
-def _normalize_field(raw_field):
- """Normalize a field for matching.
-
- Fields specified in free form by users can have different case or trailing white space,
- while still technically being a match on a valid field.
-
- So convert the field to lower case and strip any trailing white space and return the result.
-
- :param str raw_field: raw not normalized field
- :return: normalized field suitable for matching
- :rtype: str
- """
- return raw_field.strip().lower()
-
-
-def _match_field(raw_field, valid_fields):
- """Try to match the field on an item in a list of fields.
-
- If a match is found return the first matching item from the list.
- If no match is found, return None.
-
- :param raw_field str: field to match
- :param list valid_fields: list of valid fields to match against
- :return: a matching valid field or None if no match is found
- :rtype: str or None
- """
- matching_valid_field = None
- normalized_field = _normalize_field(raw_field)
-
- for valid_field in valid_fields:
- if normalized_field == _normalize_field(valid_field):
- # looks like the fields match, no need to search any further
- matching_valid_field = valid_field
- break
-
- return matching_valid_field
-
-
-def process_field(syspurpose_value, valid_values, value_name):
- """Process a single system purpose value provided by the user.
-
- At the moment this value generally comes from kickstart
- as we don't support free form system purpose value entry in the UI.
-
- We try to match the user provided value to value in a lit of well
- known valid values, so that it can be displayed correct in the UI.
-
- If the user for example uses "production" for usage, we will match
- it to Production and then display that in the UI.
-
- If the value does not match any known one, we will just return
- it & display it in its current form.
-
- :param str syspurpose_value: system purpose value to be processed
- :param valid_values: list of well known valid values for the given
- type of system purpose value
- :type valid_values: list of str
- :param str value_name: name of the system purpose value to be used
- in log messages
-
- :return: matched well known or original value if no match was found
- :rtype: str
- """
- if syspurpose_value:
- value_match = _match_field(syspurpose_value, valid_values)
- else:
- value_match = None
-
- if value_match:
- log.info("%s system purpose value %s from kickstart matched to known valid field %s",
- value_name,
- syspurpose_value,
- value_match)
- return value_match
- elif syspurpose_value:
- log.info("using custom %s system purpose value from kickstart: %s",
- value_name,
- syspurpose_value)
- return syspurpose_value
- else:
- return ""
-
-
-def _call_syspurpose_tool(sysroot, args):
- """Helper function for invoking the syspurpose tool with error checking.
-
- :param str sysroot: system root path
- :param args: list of arguments for syspurpose
- :type args: list of str
- :return: syspurpose tool return code (non zero means failure)
- """
- rc = util.execWithRedirect("syspurpose", args, root=sysroot)
- if rc:
- log.error("subscription: syspurpose invocation failed for args %s with rc %s", args, rc)
- return rc
-
-
-def give_the_system_purpose(sysroot, role, sla, usage, addons):
- """Set system purpose for the installed system by calling the syspurpose tool.
-
- The tool is called in the specified system root, so this method should only
- be called once the given system root contains the syspurpose utility.
-
- :param str sysroot: system root path
- :param role: role of the system
- :type role: str or None
- :param sla: Service Level Agreement for the system
- :type sla: str or None
- :param usage: intended usage of the system
- :type usage: str or None
- :param list addons: any additional layered products or features
- """
- # first check if system purpose data has already been set
- if check_system_purpose_set(sysroot):
- # Remove existing system purpose data.
- #
- # This is important, as otherwise it would be both not possible to
- # clear existing system purpose data if say a user sets all values
- # to "not specified" in the GUI after setting them to some values
- # previously. Also due to syspurpose setting one value at a time
- # one could end up with unwanted hybrid configuration combining
- # new and old date, if not all fields are set in the most recent
- # invocation.
- log.debug("subscription: clearing old system purpose data")
- syspurpose_path = util.join_paths(sysroot, RHSM_SYSPURPOSE_FILE_PATH)
- os.remove(syspurpose_path)
-
- if role or sla or usage or addons:
- # using join_paths() as both paths are absolute
- syspurpose_sysroot_path = util.join_paths(sysroot, SYSPURPOSE_UTILITY_PATH)
- if os.path.exists(syspurpose_sysroot_path):
- # The syspurpose utility can only set one value at a time,
- # so we might need to call it multiple times to set all the
- # requested values.
- #
- # Also as the values can contain white space we need to make sure the
- # values passed to arguments are all properly quoted.
- if role:
- args = ["set-role", role]
- if _call_syspurpose_tool(sysroot, args):
- return False
- if sla:
- args = ["set-sla", sla]
-
- if _call_syspurpose_tool(sysroot, args):
- return False
- if usage:
- args = ["set-usage", usage]
- if _call_syspurpose_tool(sysroot, args):
- return False
- if addons:
- args = ["add", "addons"]
- for addon in addons:
- args.append(addon)
- if _call_syspurpose_tool(sysroot, args):
- return False
- log.debug("subscription: system purpose has been set")
- return True
- else:
- log.error("subscription: the syspurpose tool is missing, cannot set system purpose")
- return False
- else:
- log.warning("subscription: not calling syspurpose as no fields have been provided")
- # doing nothing is still not a failure
- return True
diff --git a/pyanaconda/payload/dnf/payload.py b/pyanaconda/payload/dnf/payload.py
index a17d48b..3b9a806 100644
--- a/pyanaconda/payload/dnf/payload.py
+++ b/pyanaconda/payload/dnf/payload.py
@@ -64,7 +64,7 @@ from pyanaconda.core.util import decode_bytes, join_paths
from pyanaconda.flags import flags
from pyanaconda.kickstart import RepoData
from pyanaconda.modules.common.constants.objects import DEVICE_TREE
-from pyanaconda.modules.common.constants.services import LOCALIZATION, STORAGE, SUBSCRIPTION
+from pyanaconda.modules.common.constants.services import LOCALIZATION, STORAGE
from pyanaconda.modules.payloads.source.utils import has_network_protocol
from pyanaconda.modules.common.errors.installation import SecurityInstallationError
from pyanaconda.modules.common.errors.storage import DeviceSetupError, MountFilesystemError
@@ -828,24 +828,9 @@ class DNFPayload(Payload):
# is any locking needed here?
repo_names = [constants.BASE_REPO_NAME] + constants.DEFAULT_REPOS
with self._repos_lock:
- if self.source_type == SOURCE_TYPE_CDN:
- if is_module_available(SUBSCRIPTION):
- subscription_proxy = SUBSCRIPTION.get_proxy()
- if subscription_proxy.IsSubscriptionAttached:
- # If CDN is used as the installation source and we have
- # a subscription attached then any of the enabled repos
- # should be fine as the base repo.
- # If CDN is used but subscription has not been attached
- # there will be no redhat.repo file to parse and we
- # don't need to do anything.
- for repo in self._base.repos.iter_enabled():
- return repo.id
- else:
- log.error("CDN install source set but Subscription module is not available")
- else:
- for repo in self._base.repos.iter_enabled():
- if repo.id in repo_names:
- return repo.id
+ for repo in self._base.repos.iter_enabled():
+ if repo.id in repo_names:
+ return repo.id
return None
@@ -1642,20 +1627,7 @@ class DNFPayload(Payload):
# We need to check this again separately in case REPO_FILES were set above.
if source_type in SOURCE_REPO_FILE_TYPES:
- # If this is a kickstart install, just return now as we normally do not
- # want to read the on media repo files in such a case. On the other hand,
- # the local repo files are a valid use case if the system is subscribed
- # and the CDN is selected as the installation source.
- if self.source_type == SOURCE_TYPE_CDN and is_module_available(SUBSCRIPTION):
- # only check if the Subscription module is available & CDN is the
- # installation source
- subscription_proxy = SUBSCRIPTION.get_proxy()
- load_cdn_repos = subscription_proxy.IsSubscriptionAttached
- else:
- # if the Subscription module is not available, we simply can't use
- # the CDN repos, making our decision here simple
- load_cdn_repos = False
- if flags.automatedInstall and not load_cdn_repos:
+ if flags.automatedInstall:
return
# Otherwise, fall back to the default repos that we disabled above
diff --git a/pyanaconda/ui/gui/spokes/installation_source.glade b/pyanaconda/ui/gui/spokes/installation_source.glade
index e53fa23..cd97865 100644
--- a/pyanaconda/ui/gui/spokes/installation_source.glade
+++ b/pyanaconda/ui/gui/spokes/installation_source.glade
@@ -630,25 +630,6 @@
<property name="position">3</property>
</packing>
</child>
- <child>
- <object class="GtkRadioButton" id="cdnRadioButton">
- <property name="label" translatable="yes" context="GUI|Software Source">Red Hat _CDN</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="no_show_all">True</property>
- <property name="margin_left">12</property>
- <property name="use_underline">True</property>
- <property name="xalign">0</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">isoRadioButton</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">4</property>
- </packing>
- </child>
<child>
<object class="GtkRadioButton" id="isoRadioButton">
<property name="label" translatable="yes" context="GUI|Software Source">_ISO file:</property>
@@ -664,7 +645,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">5</property>
+ <property name="position">4</property>
</packing>
</child>
<child>
diff --git a/pyanaconda/ui/gui/spokes/installation_source.py b/pyanaconda/ui/gui/spokes/installation_source.py
index d0d4da7..e64bb63 100644
--- a/pyanaconda/ui/gui/spokes/installation_source.py
+++ b/pyanaconda/ui/gui/spokes/installation_source.py
@@ -34,14 +34,13 @@ from pyanaconda.core.process_watchers import PidWatcher
from pyanaconda.flags import flags
from pyanaconda.core.i18n import _, N_, CN_
from pyanaconda.modules.common.structures.payload import RepoConfigurationData
-from pyanaconda.modules.common.constants.services import SUBSCRIPTION
+from pyanaconda.modules.common.constants.services import LOCALIZATION
from pyanaconda.payload.image import find_optical_install_media, find_potential_hdiso_sources, \
get_hdiso_source_info, get_hdiso_source_description
from pyanaconda.core.payload import ProxyString, ProxyStringError, parse_nfs_url, create_nfs_url
from pyanaconda.core.util import cmp_obj_attrs, id_generator
from pyanaconda.ui.communication import hubQ
from pyanaconda.ui.helpers import InputCheck, InputCheckHandler, SourceSwitchHandler
-from pyanaconda.ui.lib.subscription import switch_source
from pyanaconda.ui.gui import GUIObject
from pyanaconda.ui.gui.helpers import GUIDialogInputCheckHandler, GUISpokeInputCheckHandler
from pyanaconda.ui.gui.spokes import NormalSpoke
@@ -437,12 +436,7 @@ class SourceSpoke(NormalSpoke, GUISpokeInputCheckHandler, SourceSwitchHandler):
repo_changed = self._update_payload_repos()
source_proxy = self.payload.get_source_proxy()
cdn_source = source_proxy.Type == SOURCE_TYPE_CDN
- # If CDN is the current installation source but no subscription is
- # 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.")
- elif source_changed or repo_changed or self._error:
+ if source_changed or repo_changed or self._error:
payloadMgr.restart_thread(self.payload, checkmount=False)
else:
log.debug("Nothing has changed - skipping payload restart.")
@@ -637,34 +631,11 @@ class SourceSpoke(NormalSpoke, GUISpokeInputCheckHandler, SourceSwitchHandler):
not threadMgr.get(constants.THREAD_SOFTWARE_WATCHER) and
not threadMgr.get(constants.THREAD_CHECK_SOFTWARE))
- @property
- def subscribed(self):
- """Report if the system is currently subscribed.
-
- NOTE: This will be always False when the Subscription
- module is no available.
-
- :return: True if subscribed, False otherwise
- :rtype: bool
- """
- subscribed = False
- if is_module_available(SUBSCRIPTION):
- subscription_proxy = SUBSCRIPTION.get_proxy()
- subscribed = subscription_proxy.IsSubscriptionAttached
- return subscribed
-
@property
def status(self):
- # When CDN is selected as installation source and system
- # is not yet subscribed, the automatic repo refresh will
- # fail. This is expected as CDN can't be used until the
- # system has been registered. So prevent the error
- # message and show CDN is used instead. If CDN still
- # fails after registration, the regular error message
- # will be displayed.
source_proxy = self.payload.get_source_proxy()
cdn_source = source_proxy.Type == SOURCE_TYPE_CDN
- if cdn_source and not self.subscribed:
+ if cdn_source:
source_proxy = self.payload.get_source_proxy()
return source_proxy.Description
elif threadMgr.get(constants.THREAD_CHECK_SOFTWARE):
diff --git a/pyanaconda/ui/gui/spokes/lib/subscription.py b/pyanaconda/ui/gui/spokes/lib/subscription.py
deleted file mode 100644
index 47b96b5..0000000
--- a/pyanaconda/ui/gui/spokes/lib/subscription.py
+++ /dev/null
@@ -1,236 +0,0 @@
-# Helper methods for the Subscription spoke.
-#
-# Copyright (C) 2020 Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details. You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# 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 _
-
-from pyanaconda.anaconda_loggers import get_module_logger
-log = get_module_logger(__name__)
-
-
-TextComboBoxItem = namedtuple("TextComboBoxItem", ["value", "display_string", "is_preselected"])
-
-def handle_user_provided_value(user_provided_value, valid_values):
- """Handle user provided value (if any) based on list of valid values.
-
- There are three possible outcomes:
- - the value matches one of the valid values, so we preselect the valid value
- - the value does not match a valid value, so we append a custom value
- to the list and preselect it
- - the user provided value is not available (empty string), no matching will be done
- and no value will be preselected
-
- :param str user_provided_value: a value provided by user
- :param list valid_values: a list of valid values
- :returns: list of values with one value preselected
- :rtype: list of TextComboBoxItem tuples
- """
- preselected_value_list = []
- value_matched = False
- for valid_value in valid_values:
- preselect = False
- if user_provided_value and not value_matched:
- if user_provided_value == valid_value:
- preselect = True
- value_matched = True
- item = TextComboBoxItem(value=valid_value,
- display_string=valid_value,
- is_preselected=preselect)
- preselected_value_list.append(item)
- # check if the user provided value matched a valid value
- if user_provided_value and not value_matched:
- # user provided value did not match any valid value,
- # add it as a custom value to the list and preselect it
- other_value_string = _("Other ({})").format(user_provided_value)
- item = TextComboBoxItem(value=user_provided_value,
- display_string=other_value_string,
- is_preselected=True)
- preselected_value_list.append(item)
- return preselected_value_list
-
-
-def fill_combobox(combobox, user_provided_value, valid_values):
- """Fill the given ComboBoxText instance with data based on current value & valid values.
-
- Please note that it is possible that the list box will be empty if no
- list of valid values are available and the user has not supplied any value
- via kickstart or the DBUS API.
-
- NOTE: Removes any existing values from the GTK ComboBoxText instance before
- filling it.
-
- :param combobox: the combobox to fill
- :param user_provided_value: the value provided by the user (if any)
- :type user_provided_value: str or None
- :param list valid_values: list of known valid values
- """
- preselected_value_list = handle_user_provided_value(user_provided_value,
- valid_values)
- # make sure the combo box is empty
- combobox.remove_all()
-
- # add the "Not Specified" option as the first item
- # - otherwise the user would not be able to unselect option clicked previously
- # or selected via kickstart
- # - set the active id to this value by default
-
- active_id = ""
- combobox.append("", _("Not Specified"))
-
- if preselected_value_list:
- for value, display_string, preselected in preselected_value_list:
- combobox.append(value, display_string)
- # the value has been preselected, set the active id accordingly
- if preselected:
- active_id = value
-
- # 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")
diff --git a/pyanaconda/ui/gui/spokes/software_selection.py b/pyanaconda/ui/gui/spokes/software_selection.py
index 1044d9b..6f40535 100644
--- a/pyanaconda/ui/gui/spokes/software_selection.py
+++ b/pyanaconda/ui/gui/spokes/software_selection.py
@@ -35,9 +35,7 @@ from pyanaconda.ui.gui.spokes.lib.detailederror import DetailedErrorDialog
from pyanaconda.ui.gui.utils import blockedHandler, escape_markup
from pyanaconda.core.async_utils import async_action_wait
from pyanaconda.ui.categories.software import SoftwareCategory
-from pyanaconda.ui.lib.subscription import check_cdn_is_installation_source
-from pyanaconda.modules.common.constants.services import SUBSCRIPTION
from pyanaconda.modules.common.util import is_module_available
from pyanaconda.anaconda_loggers import get_module_logger
@@ -302,14 +300,6 @@ class SoftwareSelectionSpoke(NormalSpoke):
cdn_source = check_cdn_is_installation_source(self.payload)
- subscribed = False
- if is_module_available(SUBSCRIPTION):
- subscription_proxy = SUBSCRIPTION.get_proxy()
- subscribed = subscription_proxy.IsSubscriptionAttached
-
- if cdn_source and not subscribed:
- return _("Red Hat CDN requires registration.")
-
if not self.ready:
return _("Installation source not set up")
diff --git a/pyanaconda/ui/gui/spokes/subscription.glade b/pyanaconda/ui/gui/spokes/subscription.glade
deleted file mode 100644
index 2b1b0dd..0000000
--- a/pyanaconda/ui/gui/spokes/subscription.glade
+++ /dev/null
@@ -1,993 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.1 -->
-<interface>
- <requires lib="gtk+" version="3.20"/>
- <requires lib="AnacondaWidgets" version="1.0"/>
- <object class="AnacondaSpokeWindow" id="subscription_window">
- <property name="can_focus">False</property>
- <property name="window_name" translatable="yes">CONNECT TO RED HAT</property>
- <signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
- <child internal-child="main_box">
- <object class="GtkBox" id="AnacondaSpokeWindow-main_box1">
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child internal-child="nav_box">
- <object class="GtkEventBox" id="AnacondaSpokeWindow-nav_box1">
- <property name="can_focus">False</property>
- <child internal-child="nav_area">
- <object class="GtkGrid" id="AnacondaSpokeWindow-nav_area1">
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child internal-child="alignment">
- <object class="GtkAlignment" id="AnacondaSpokeWindow-alignment1">
- <property name="can_focus">False</property>
- <property name="yalign">0</property>
- <property name="top_padding">12</property>
- <property name="bottom_padding">48</property>
- <property name="left_padding">48</property>
- <property name="right_padding">48</property>
- <child internal-child="action_area">
- <object class="GtkBox" id="AnacondaSpokeWindow-action_area1">
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">8</property>
- <child>
- <object class="GtkNotebook" id="main_notebook">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="vexpand">True</property>
- <property name="show_tabs">False</property>
- <property name="show_border">False</property>
- <child>
- <object class="GtkScrolledWindow" id="registration_scrolled_window">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkViewport" id="registration_viewport">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="shadow_type">none</property>
- <child>
- <object class="GtkBox" id="registration_box">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="orientation">vertical</property>
- <property name="spacing">4</property>
- <child>
- <object class="GtkGrid" id="registration_grid">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="row_spacing">4</property>
- <property name="column_spacing">4</property>
- <child>
- <object class="GtkLabel" id="authentication_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">end</property>
- <property name="label" translatable="yes">Authentication</property>
- <property name="justify">right</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="authetication_method_hbox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkRadioButton" id="account_radio_button">
- <property name="label" translatable="yes" context="GUI|Subscription|Authentication|Account">_Account</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_account_radio_button_toggled" swapped="no"/>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="activation_key_radio_button">
- <property name="label" translatable="yes" context="GUI|Subscription|Authetication|Activation Key">Activation _Key</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">account_radio_button</property>
- <signal name="toggled" handler="on_activation_key_radio_button_toggled" swapped="no"/>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkRevealer" id="account_revealer">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="transition_type">none</property>
- <property name="reveal_child">True</property>
- <child>
- <object class="GtkGrid" id="account_grid">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="hexpand">True</property>
- <property name="row_spacing">4</property>
- <property name="column_spacing">4</property>
- <child>
- <object class="GtkLabel" id="username_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">User name</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="username_entry">
- <property name="width_request">250</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hexpand">True</property>
- <signal name="changed" handler="on_username_entry_changed" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="password_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">Password</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="password_entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hexpand">True</property>
- <property name="visibility">False</property>
- <property name="invisible_char">●</property>
- <signal name="changed" handler="on_password_entry_changed" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkRevealer" id="activation_key_revealer">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="transition_type">none</property>
- <child>
- <object class="GtkGrid" id="activation_key_grid">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="hexpand">True</property>
- <property name="row_spacing">4</property>
- <property name="column_spacing">4</property>
- <child>
- <object class="GtkLabel" id="organization_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">Organization</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="activation_key_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">Activation Key</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="organization_entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hexpand">True</property>
- <signal name="changed" handler="on_organization_entry_changed" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="activation_key_entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hexpand">True</property>
- <property name="placeholder_text" translatable="yes">key1,key2,...</property>
- <signal name="changed" handler="on_activation_key_entry_changed" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="purpose_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">end</property>
- <property name="label" translatable="yes">Purpose</property>
- <property name="justify">right</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkRevealer" id="system_purpose_revealer">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkGrid" id="system_purpose_grid">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="row_spacing">4</property>
- <property name="column_spacing">4</property>
- <child>
- <object class="GtkLabel" id="usage_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">Usage</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="role_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">Role</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="sla_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">SLA</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkComboBoxText" id="system_purpose_role_combobox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <signal name="changed" handler="on_system_purpose_role_combobox_changed" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkComboBoxText" id="system_purpose_sla_combobox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <signal name="changed" handler="on_system_purpose_sla_combobox_changed" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkComboBoxText" id="system_purpose_usage_combobox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <signal name="changed" handler="on_system_purpose_usage_combobox_changed" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">4</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="system_purpose_checkbox">
- <property name="label" translatable="yes" context="GUI|Subscription|Set System Purpose">Set System Purpose</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_system_purpose_checkbox_toggled" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="insights_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">end</property>
- <property name="label" translatable="yes">Insights</property>
- <property name="justify">right</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">5</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="insights_checkbox">
- <property name="label" translatable="yes" context="GUI|Subscription|Red Hat Insights">Connect to Red Hat _Insights</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="tooltip_text" translatable="yes">Red Hat Insights aims to increase your IT efficiency and speed across hybrid infrastructures by identifying and prioritizing risks, managing vulnerabilities, and compliance, and analyzing costs. For more information, visit the Red Hat Insights information page.</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">5</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkExpander" id="options_expander">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkGrid" id="options_grid">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="row_spacing">4</property>
- <property name="column_spacing">4</property>
- <child>
- <object class="GtkCheckButton" id="custom_rhsm_baseurl_checkbox">
- <property name="label" translatable="yes">Custom base URL</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_custom_rhsm_baseurl_checkbox_toggled" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">4</property>
- </packing>
- </child>
- <child>
- <object class="GtkRevealer" id="custom_rhsm_baseurl_revealer">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkEntry" id="custom_rhsm_baseurl_entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <signal name="changed" handler="on_custom_rhsm_baseurl_entry_changed" swapped="no"/>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">5</property>
- </packing>
- </child>
- <child>
- <object class="GtkRevealer" id="custom_server_hostname_revealer">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkEntry" id="custom_server_hostname_entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <signal name="changed" handler="on_custom_server_hostname_entry_changed" swapped="no"/>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="custom_server_hostname_checkbox">
- <property name="label" translatable="yes">Custom server URL</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_custom_server_hostname_checkbox_toggled" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="http_proxy_checkbox">
- <property name="label" translatable="yes">Use HTTP proxy</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="on_http_proxy_checkbox_toggled" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkRevealer" id="http_proxy_revealer">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkGrid" id="http_proxy_grid">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="row_spacing">4</property>
- <property name="column_spacing">4</property>
- <child>
- <object class="GtkLabel" id="http_proxy_location_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">Location</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="http_proxy_username_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">User name</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="http_proxy_password_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">Password</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="http_proxy_location_entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hexpand">True</property>
- <property name="placeholder_text" translatable="yes">hostname:port</property>
- <signal name="changed" handler="on_http_proxy_location_entry_changed" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="http_proxy_username_entry">
- <property name="width_request">250</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <signal name="changed" handler="on_http_proxy_username_entry_changed" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="http_proxy_password_entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="visibility">False</property>
- <property name="invisible_char">●</property>
- <signal name="changed" handler="on_http_proxy_password_entry_changed" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- </object>
- </child>
- <child type="label">
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Options</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="registration_status_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_top">8</property>
- <property name="margin_bottom">8</property>
- <property name="label" translatable="yes">The system is currently not registered.</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="register_button">
- <property name="label" translatable="yes" context="GUI|Subscription|Register">_Register</property>
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="halign">center</property>
- <property name="use_underline">True</property>
- <signal name="clicked" handler="on_register_button_clicked" swapped="no"/>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">3</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child type="tab">
- <placeholder/>
- </child>
- <child>
- <object class="GtkBox" id="subscription_status_box">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_top">8</property>
- <property name="orientation">vertical</property>
- <property name="spacing">4</property>
- <child>
- <object class="GtkBox" id="status_box">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">4</property>
- <child>
- <object class="GtkBox" id="top_level_status_box">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">4</property>
- <child>
- <object class="GtkLabel" id="properly_subscribed_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">The system has been properly subscribed</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- <attribute name="scale" value="1.2"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="unregister_button">
- <property name="label" translatable="yes" context="GUI|Subscription|Unregister">_Unregister</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="halign">center</property>
- <property name="use_underline">True</property>
- <signal name="clicked" handler="on_unregister_button_clicked" swapped="no"/>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="padding">8</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkGrid" id="status_grid">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="margin_top">8</property>
- <property name="row_spacing">4</property>
- <property name="column_spacing">8</property>
- <child>
- <object class="GtkLabel" id="method_label">
- <property name="name">method_label</property>
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">end</property>
- <property name="label" translatable="yes">Method</property>
- <property name="justify">right</property>
- <attributes>
- <attribute name="weight" value="semibold"/>
- </attributes>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="system_purpose_label">
- <property name="name">system_purpose_label</property>
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">end</property>
- <property name="label" translatable="yes">System Purpose</property>
- <property name="justify">right</property>
- <attributes>
- <attribute name="weight" value="semibold"/>
- </attributes>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="method_status_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label">lorem ipsum</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="role_status_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label">lorem ipsum</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="sla_status_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label">lorem ipsum</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="another_insights_label">
- <property name="name">insights_label</property>
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">end</property>
- <property name="label" translatable="yes">Insights</property>
- <property name="justify">right</property>
- <attributes>
- <attribute name="weight" value="semibold"/>
- </attributes>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">4</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="insights_status_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label">lorem ipsum</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">4</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="usage_status_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="label">lorem ipsum</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">3</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="attached_subscriptions_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">start</property>
- <property name="margin_top">16</property>
- <property name="margin_bottom">4</property>
- <property name="label" translatable="yes">No subscriptions have been attached to the system</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- <attribute name="scale" value="1.2"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="subscriptions_scrolled_window">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="vexpand">True</property>
- <child>
- <object class="GtkViewport" id="subscriptions_viewport">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="shadow_type">none</property>
- <child>
- <object class="GtkListBox" id="subscriptions_listbox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="selection_mode">none</property>
- <style>
- <class name="subscriptions_listbox"/>
- </style>
- </object>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- <child type="tab">
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child type="tab">
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- </child>
- <child internal-child="accessible">
- <object class="AtkObject" id="subscription_window-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">SYSTEM PURPOSE</property>
- </object>
- </child>
- </object>
-</interface>
diff --git a/pyanaconda/ui/gui/spokes/subscription.py b/pyanaconda/ui/gui/spokes/subscription.py
deleted file mode 100644
index 4661cf4..0000000
--- a/pyanaconda/ui/gui/spokes/subscription.py
+++ /dev/null
@@ -1,1163 +0,0 @@
-# Subscription spoke class
-#
-# Copyright (C) 2020 Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details. You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-
-from enum import IntEnum
-
-from pyanaconda.flags import flags
-from pyanaconda.threading import threadMgr, AnacondaThread
-
-from pyanaconda.core.i18n import _, CN_
-from pyanaconda.core.constants import SECRET_TYPE_HIDDEN, \
- SUBSCRIPTION_REQUEST_TYPE_USERNAME_PASSWORD, SUBSCRIPTION_REQUEST_TYPE_ORG_KEY, \
- THREAD_SUBSCRIPTION, THREAD_PAYLOAD, SOURCE_TYPES_OVERRIDEN_BY_CDN, \
- THREAD_SUBSCRIPTION_SPOKE_INIT
-from pyanaconda.core.payload import ProxyString, ProxyStringError
-from pyanaconda.ui.lib.subscription import register_and_subscribe, \
- unregister, SubscriptionPhase
-from pyanaconda.core.async_utils import async_action_wait
-
-from pyanaconda.modules.common.constants.services import SUBSCRIPTION, NETWORK
-from pyanaconda.modules.common.structures.subscription import SystemPurposeData, \
- SubscriptionRequest, AttachedSubscription
-from pyanaconda.modules.common.util import is_module_available
-from pyanaconda.modules.common.task import sync_run_task
-
-from pyanaconda.ui.gui.spokes import NormalSpoke
-from pyanaconda.ui.gui.spokes.lib.subscription import fill_combobox, \
- populate_attached_subscriptions_listbox
-from pyanaconda.ui.categories.software import SoftwareCategory
-from pyanaconda.ui.communication import hubQ
-from pyanaconda.ui.lib.subscription import username_password_sufficient, org_keys_sufficient, \
- check_cdn_is_installation_source
-
-from pyanaconda.anaconda_loggers import get_module_logger
-log = get_module_logger(__name__)
-
-__all__ = ["SubscriptionSpoke"]
-
-
-# the integers correspond to the order of options
-# in the authentication mode combo box
-class AuthenticationMethod(IntEnum):
- USERNAME_PASSWORD = 0
- ORG_KEY = 1
-
-
-class SubscriptionSpoke(NormalSpoke):
- """Subscription spoke provides the Connect to Red Hat screen."""
- builderObjects = ["subscription_window"]
-
- mainWidgetName = "subscription_window"
- uiFile = "spokes/subscription.glade"
- help_id = "SubscriptionSpoke"
-
- category = SoftwareCategory
-
- icon = "application-certificate-symbolic"
- title = CN_("GUI|Spoke", "_Connect to Red Hat")
-
- # main notebook pages
- REGISTRATION_PAGE = 0
- SUBSCRIPTION_STATUS_PAGE = 1
-
- @classmethod
- def should_run(cls, environment, data):
- """The Subscription spoke should run only if the Subscription module is available."""
- return is_module_available(SUBSCRIPTION)
-
- def __init__(self, *args):
- super().__init__(*args)
-
- # connect to the Subscription DBus module API
- self._subscription_module = SUBSCRIPTION.get_proxy()
-
- # connect to the Network DBus module API
- self._network_module = NETWORK.get_proxy()
-
- # get initial data from the Subscription module
- self._subscription_request = self._get_subscription_request()
- self._system_purpose_data = self._get_system_purpose_data()
- # Keep a copy of system purpose data that has been last applied to
- # the installation environment.
- # That way we can check if the main copy of the system purposed data
- # changed since it was applied (for example due to user input)
- # and needs to be reapplied.
- # By default this variable is None and will only be set to a
- # SystemPurposeData instance when first system purpose data is
- # applied to the installation environment.
- self._last_applied_system_purpose_data = None
-
- self._authentication_method = AuthenticationMethod.USERNAME_PASSWORD
-
- self._registration_error = ""
- self._registration_phase = None
- self._registration_controls_enabled = True
-
- # Red Hat Insights should be enabled by default for non-kickstart installs.
- #
- # For kickstart installations we will use the value from the module, which
- # False by default & can be set to True via the rhsm kickstart command.
- if not flags.automatedInstall:
- self._subscription_module.SetInsightsEnabled(True)
-
- # previous visit network connectivity tracking
- self._network_connected_previously = False
-
- # overriden source tracking
- self._overridden_source_type = None
-
- self._spoke_initialized = False
-
- # common spoke properties
-
- @property
- def ready(self):
- """The subscription spoke is ready once the spoke initialization thread finishes.
-
- The spoke initialization thread waits for the subscription and payload initialization
- threads, to avoid the Subscription spoke being set mandatory in cases
- where the current installation source is the CDN, but payload refresh is still
- running and it might change the installation source to CDROM later on.
-
- NOTE: We don't actually wait for the spoke initialization thread to finish, we check
- a variable it sets instead. This is due to the thread also sending the hub refresh
- signal, which would trigger a race condition if the hub refresh is processed before
- the spoke initialization thread finishes. Setting the variable and *then* sending
- the hub refresh signal avoids this issue.
- """
- return self._spoke_initialized
-
-
- @property
- def status(self):
- # The spoke status message:
- # - shows registration phases when registration + subscription
- # or unregistration is ongoing
- # - otherwise shows not-registered/registered/error
- return self._get_status_message()
-
- @property
- def mandatory(self):
- """The subscription spoke is mandatory if Red Hat CDN is set as installation source."""
- return check_cdn_is_installation_source(self.payload)
-
- @property
- def completed(self):
- return self.subscription_attached
-
- @property
- def sensitive(self):
- # the Subscription spoke should be always accessible
- return True
-
- # common spoke methods
-
- def apply(self):
- log.debug("Subscription GUI: apply() running")
- self._set_data_to_module()
-
- def refresh(self):
- log.debug("Subscription GUI: refresh() running")
- # update spoke state based on up-to-date data from the Subscription module
- # (this also takes care of updating the two properties holding subscription
- # request as well as system purpose data)
- self._update_spoke_state()
- # check if network connectivity is available
- # - without network connectivity the spoke is pretty much unusable
- # - also, no need to check if registration/unregistration is in progress
- if not self.registration_phase:
- self._check_connectivity()
-
- # DBus structure mirrors
-
- @property
- def subscription_request(self):
- """A mirror of the subscription request from the Subscription DBus module.
-
- Should be always set and is periodically updated on refresh().
-
- :return: up to date subscription request
- :rtype: SubscriptionRequest instance
- """
- return self._subscription_request
-
- @property
- def system_purpose_data(self):
- """A mirror of system purpose data from the Subscription DBus module.
-
- Should be always set and is periodically updated on refresh().
-
- :return: up to date system purpose data
- :rtype: SystemPurposeData instance
- """
- return self._system_purpose_data
-
- # placeholder control
-
- def enable_http_proxy_password_placeholder(self, show_placeholder):
- """Show a placeholder on the HTTP proxy password field.
-
- The placeholder notifies the user about HTTP proxy password
- being set in the DBus module.
-
- The placeholder will be only shown if there is no
- actual text in the entry field.
- """
- if show_placeholder:
- self._http_proxy_password_entry.set_placeholder_text(_("Password set."))
- else:
- self._http_proxy_password_entry.set_placeholder_text("")
-
- def enable_password_placeholder(self, show_placeholder):
- """Show a placeholder on the red hat account password field.
-
- The placeholder notifies the user about activation
- key being set in the DBus module.
-
- The placeholder will be only shown if there is no
- actual text in the entry field.
- """
- if show_placeholder:
- self._password_entry.set_placeholder_text(_("Password set."))
- else:
- self._password_entry.set_placeholder_text("")
-
- def enable_activation_key_placeholder(self, show_placeholder):
- """Show a placeholder on the activation key field.
-
- The placeholder notifies the user about activation
- key being set in the DBus module.
-
- The placeholder will be only shown if there is no
- actual text in the entry field.
- """
- if show_placeholder:
- self._activation_key_entry.set_placeholder_text(_("Activation key set."))
- else:
- self._activation_key_entry.set_placeholder_text("")
-
- # properties controlling visibility of options that can be hidden
-
- @property
- def custom_server_hostname_visible(self):
- return self._custom_server_hostname_checkbox.get_active()
-
- @custom_server_hostname_visible.setter
- def custom_server_hostname_visible(self, visible):
- self._custom_server_hostname_checkbox.set_active(visible)
-
- @property
- def http_proxy_visible(self):
- return self._http_proxy_checkbox.get_active()
-
- @http_proxy_visible.setter
- def http_proxy_visible(self, visible):
- self._http_proxy_checkbox.set_active(visible)
-
- @property
- def custom_rhsm_baseurl_visible(self):
- return self._custom_rhsm_baseurl_checkbox.get_active()
-
- @custom_rhsm_baseurl_visible.setter
- def custom_rhsm_baseurl_visible(self, visible):
- self._custom_rhsm_baseurl_checkbox.set_active(visible)
-
- @property
- def account_visible(self):
- return self._account_radio_button.get_active()
-
- @account_visible.setter
- def account_visible(self, visible):
- self._account_radio_button.set_active(visible)
-
- @property
- def activation_key_visible(self):
- return self._activation_key_radio_button.get_active()
-
- @activation_key_visible.setter
- def activation_key_visible(self, visible):
- self._activation_key_radio_button.set_active(visible)
-
- @property
- def system_purpose_visible(self):
- return self._system_purpose_checkbox.get_active()
-
- @system_purpose_visible.setter
- def system_purpose_visible(self, visible):
- self._system_purpose_checkbox.set_active(visible)
-
- @property
- def options_visible(self):
- return self._options_expander.get_expanded()
-
- @options_visible.setter
- def options_visible(self, visible):
- self._options_expander.set_expanded(visible)
-
- # properties - element sensitivity
-
- def set_registration_controls_sensitive(self, sensitive, include_register_button=True):
- """Set sensitivity of the registration controls.
-
- We set these value individually so that the registration status label
- that is between the controls will not become grayed out due to setting
- the top level container insensitive.
- """
- self._registration_grid.set_sensitive(sensitive)
- self._options_expander.set_sensitive(sensitive)
- self._registration_controls_enabled = sensitive
- self._update_registration_state()
-
- # authentication related signals
-
- def on_account_radio_button_toggled(self, radio):
- self._account_revealer.set_reveal_child(radio.get_active())
- if radio.get_active():
- self.authentication_method = AuthenticationMethod.USERNAME_PASSWORD
-
- def on_activation_key_radio_button_toggled(self, radio):
- self._activation_key_revealer.set_reveal_child(radio.get_active())
- if radio.get_active():
- self.authentication_method = AuthenticationMethod.ORG_KEY
-
- def on_username_entry_changed(self, editable):
- self.subscription_request.account_username = editable.get_text()
- self._update_registration_state()
-
- def on_password_entry_changed(self, editable):
- entered_text = editable.get_text()
- if entered_text:
- self.enable_password_placeholder(False)
- self.subscription_request.account_password.set_secret(entered_text)
- self._update_registration_state()
-
- def on_organization_entry_changed(self, editable):
- self.subscription_request.organization = editable.get_text()
- self._update_registration_state()
-
- def on_activation_key_entry_changed(self, editable):
- entered_text = editable.get_text()
- keys = None
- if entered_text:
- self.enable_activation_key_placeholder(False)
- keys = entered_text.split(',')
- # keys == None clears keys in the module, so deleting keys
- # in the keys field will also clear module data on apply()
- self.subscription_request.activation_keys.set_secret(keys)
- self._update_registration_state()
-
- # system purpose related signals
-
- def on_system_purpose_checkbox_toggled(self, checkbox):
- active = checkbox.get_active()
- self._system_purpose_revealer.set_reveal_child(active)
- if active:
- # make sure data in the system purpose comboboxes
- # are forwarded to the system purpose data structure
- # in case something was set before they were hidden
- self.on_system_purpose_role_combobox_changed(self._system_purpose_role_combobox)
- self.on_system_purpose_sla_combobox_changed(self._system_purpose_sla_combobox)
- self.on_system_purpose_usage_combobox_changed(self._system_purpose_usage_combobox)
- else:
- # system purpose combo boxes have been hidden, clear the corresponding
- # data from the system purpose data structure, but keep it in the combo boxes
- # in case the user tries to show them again before next spoke entry clears them
- self.system_purpose_data.role = ""
- self.system_purpose_data.sla = ""
- self.system_purpose_data.usage = ""
-
- def on_system_purpose_role_combobox_changed(self, combobox):
- self.system_purpose_data.role = combobox.get_active_id()
-
- def on_system_purpose_sla_combobox_changed(self, combobox):
- self.system_purpose_data.sla = combobox.get_active_id()
-
- def on_system_purpose_usage_combobox_changed(self, combobox):
- self.system_purpose_data.usage = combobox.get_active_id()
-
- # HTTP proxy signals
-
- def on_http_proxy_checkbox_toggled(self, checkbox):
- active = checkbox.get_active()
- self._http_proxy_revealer.set_reveal_child(active)
- if active:
- # make sure data in the HTTP proxy entries
- # are forwarded to the subscription request structure
- # in case something was entered before they were hidden
- self.on_http_proxy_location_entry_changed(self._http_proxy_location_entry)
- self.on_http_proxy_username_entry_changed(self._http_proxy_username_entry)
- self.on_http_proxy_password_entry_changed(self._http_proxy_password_entry)
- else:
- # HTTP proxy entries have been hidden, clear the corresponding data from
- # the subscription request structure, but keep it in the entries in case
- # the user tries to show them again before next spoke entry clears them
- self._subscription_request.server_proxy_hostname = ""
- self._subscription_request.server_proxy_port = -1
- self._subscription_request.server_proxy_user = ""
- self._subscription_request.server_proxy_password.set_secret(None)
-
- def on_http_proxy_location_entry_changed(self, editable):
- # Incorrect hostnames, including empty strings, will
- # throw an exception we need to catch and switch
- # to defaults. This can happen often as the user
- # types the hostname to the field.
- try:
- proxy_obj = ProxyString(url=editable.get_text())
- hostname = proxy_obj.host
- if proxy_obj.port:
- # the DBus API expects an integer
- port = int(proxy_obj.port)
- except ProxyStringError:
- hostname = ""
- port = -1 # not set == -1
- # set the resulting values to the DBus structure
- self.subscription_request.server_proxy_hostname = hostname
- self.subscription_request.server_proxy_port = port
-
- def on_http_proxy_username_entry_changed(self, editable):
- self.subscription_request.server_proxy_user = editable.get_text()
-
- def on_http_proxy_password_entry_changed(self, editable):
- password = editable.get_text()
- # if password is set in the field, set it, or set None to clear the password
- self.subscription_request.server_proxy_password.set_secret(password or None)
-
- # custom server hostname and rhsm baseurl signals
-
- def on_custom_server_hostname_checkbox_toggled(self, checkbox):
- active = checkbox.get_active()
- self._custom_server_hostname_revealer.set_reveal_child(active)
- if active:
- # make sure data in the server hostname entry
- # is forwarded to the subscription request structure
- # in case something was entered before the entry was
- # hidden
- self.on_custom_server_hostname_entry_changed(self._custom_server_hostname_entry)
- else:
- # the entry was hidden, clear the data from subscription request but
- # keep it in the entry in case user decides to show the entry again
- # before next spoke entry clears it
- self.subscription_request.server_hostname = ""
-
- def on_custom_server_hostname_entry_changed(self, editable):
- self.subscription_request.server_hostname = editable.get_text()
-
- def on_custom_rhsm_baseurl_checkbox_toggled(self, checkbox):
- active = checkbox.get_active()
- self._custom_rhsm_baseurl_revealer.set_reveal_child(active)
- if active:
- # make sure data in the rhsm baseurl entry
- # is forwarded to the subscription request structure
- # in case something was entered before the entry was
- # hidden
- self.on_custom_rhsm_baseurl_entry_changed(self._custom_rhsm_baseurl_entry)
- else:
- # the entry was hidden, clear the data from subscription request but
- # keep it in the entry in case user decides to show the entry again
- # before next spoke entry clears it
- self.subscription_request.rhsm_baseurl = ""
-
- def on_custom_rhsm_baseurl_entry_changed(self, editable):
- self.subscription_request.rhsm_baseurl = editable.get_text()
-
- # button signals
-
- def on_register_button_clicked(self, button):
- log.debug("Subscription GUI: register button clicked")
- self._register()
-
- def on_unregister_button_clicked(self, button):
- """Handle registration related tasks."""
- log.debug("Subscription GUI: unregister button clicked")
- self._unregister()
-
- # properties - general properties
-
- @property
- def registration_phase(self):
- """Reports what phase the registration procedure is in.
-
- Only valid if a registration thread is running.
- """
- return self._registration_phase
-
- @registration_phase.setter
- def registration_phase(self, phase):
- self._registration_phase = phase
-
- @property
- def subscription_attached(self):
- """Was a subscription entitlement successfully attached ?"""
- return self._subscription_module.IsSubscriptionAttached
-
- @property
- def network_connected(self):
- """Does it look like that we have network connectivity ?
-
- Network connectivity is required for subscribing a system.
- """
- return self._network_module.Connected
-
- @property
- def authentication_method(self):
- """Report which authentication method is in use."""
- return self._authentication_method
-
- @authentication_method.setter
- def authentication_method(self, method):
- self._authentication_method = method
- if method == AuthenticationMethod.USERNAME_PASSWORD:
- self.activation_key_visible = False
- self.account_visible = True
- self.subscription_request.type = SUBSCRIPTION_REQUEST_TYPE_USERNAME_PASSWORD
- elif method == AuthenticationMethod.ORG_KEY:
- self.activation_key_visible = True
- self.account_visible = False
- self.subscription_request.type = SUBSCRIPTION_REQUEST_TYPE_ORG_KEY
-
- @property
- def options_set(self):
- """Report if at least one option in the Options section has been set."""
- return self.http_proxy_visible or self.custom_server_hostname_visible or \
- self.custom_rhsm_baseurl_visible
-
- @property
- def registration_error(self):
- return self._registration_error
-
- @registration_error.setter
- def registration_error(self, error_message):
- self._registration_error = error_message
- # also set the spoke warning banner
- self.show_warning_message(error_message)
-
- def initialize(self):
- NormalSpoke.initialize(self)
- self.initialize_start()
-
- # get object references from the builders
- self._main_notebook = self.builder.get_object("main_notebook")
-
- # * the registration tab * #
-
- # container for the main registration controls
- self._registration_grid = self.builder.get_object("registration_grid")
-
- # authentication
- self._account_radio_button = self.builder.get_object("account_radio_button")
- self._activation_key_radio_button = self.builder.get_object("activation_key_radio_button")
-
- # authentication - account
- self._account_revealer = self.builder.get_object("account_revealer")
- self._username_entry = self.builder.get_object("username_entry")
- self._password_entry = self.builder.get_object("password_entry")
-
- # authentication - activation key
- self._activation_key_revealer = self.builder.get_object("activation_key_revealer")
- self._organization_entry = self.builder.get_object("organization_entry")
- self._activation_key_entry = self.builder.get_object("activation_key_entry")
-
- # system purpose
- self._system_purpose_checkbox = self.builder.get_object("system_purpose_checkbox")
- self._system_purpose_revealer = self.builder.get_object("system_purpose_revealer")
- self._system_purpose_role_combobox = self.builder.get_object(
- "system_purpose_role_combobox"
- )
- self._system_purpose_sla_combobox = self.builder.get_object(
- "system_purpose_sla_combobox"
- )
- self._system_purpose_usage_combobox = self.builder.get_object(
- "system_purpose_usage_combobox"
- )
-
- # insights
- self._insights_checkbox = self.builder.get_object("insights_checkbox")
-
- # options expander
- self._options_expander = self.builder.get_object("options_expander")
-
- # HTTP proxy
- self._http_proxy_checkbox = self.builder.get_object("http_proxy_checkbox")
- self._http_proxy_revealer = self.builder.get_object("http_proxy_revealer")
- self._http_proxy_location_entry = self.builder.get_object("http_proxy_location_entry")
- self._http_proxy_username_entry = self.builder.get_object("http_proxy_username_entry")
- self._http_proxy_password_entry = self.builder.get_object("http_proxy_password_entry")
-
- # RHSM baseurl
- self._custom_rhsm_baseurl_checkbox = self.builder.get_object(
- "custom_rhsm_baseurl_checkbox"
- )
- self._custom_rhsm_baseurl_revealer = self.builder.get_object(
- "custom_rhsm_baseurl_revealer"
- )
- self._custom_rhsm_baseurl_entry = self.builder.get_object(
- "custom_rhsm_baseurl_entry"
- )
-
- # server hostname
- self._custom_server_hostname_checkbox = self.builder.get_object(
- "custom_server_hostname_checkbox"
- )
- self._custom_server_hostname_revealer = self.builder.get_object(
- "custom_server_hostname_revealer"
- )
- self._custom_server_hostname_entry = self.builder.get_object(
- "custom_server_hostname_entry"
- )
-
- # status label
- self._registration_status_label = self.builder.get_object("registration_status_label")
-
- # register button
- self._register_button = self.builder.get_object("register_button")
-
- # * the subscription status tab * #
-
- # general status
- self._method_status_label = self.builder.get_object("method_status_label")
- self._role_status_label = self.builder.get_object("role_status_label")
- self._sla_status_label = self.builder.get_object("sla_status_label")
- self._usage_status_label = self.builder.get_object("usage_status_label")
- self._insights_status_label = self.builder.get_object("insights_status_label")
-
- # attached subscriptions
- self._attached_subscriptions_label = self.builder.get_object(
- "attached_subscriptions_label"
- )
- self._subscriptions_listbox = self.builder.get_object("subscriptions_listbox")
-
- # unregister button
- self._unregister_revealer = self.builder.get_object("unregister_revealer")
- self._unregister_button = self.builder.get_object("unregister_button")
-
- # setup spoke state based on data from the Subscription DBus module
- self._update_spoke_state()
-
- # start the rest of spoke initialization which might take some time
- # (mainly due to waiting for various initialization threads to finish)
- # in a separate thread
- threadMgr.add(AnacondaThread(name=THREAD_SUBSCRIPTION_SPOKE_INIT,
- target=self._initialize))
-
- def _initialize(self):
- # wait for subscription thread to finish (if any)
- threadMgr.wait(THREAD_SUBSCRIPTION)
- # also wait for the payload thread, which migh still be processing
- # a CDROM source, to avoid the Subscription being mandatory by mistake
- # due to CDN still being default at the time of evaulation
- threadMgr.wait(THREAD_PAYLOAD)
-
- # update overall state
- self._update_registration_state()
- self._update_subscription_state()
-
- # we are done, mark the spoke as initialized
- self._spoke_initialized = True
-
- # Send ready signal to main event loop,
- # which among other things refreshes the hub to make
- # sure the Connect to Red Hat spokes shows up as ready.
- hubQ.send_ready(self.__class__.__name__, False)
-
- # report that we are done
- self.initialize_done()
-
- # private methods
-
- def _update_spoke_state(self):
- """Setup spoke state based on Subscription DBus module state.
-
- Subscription DBus module state is represented by the SubscriptionRequest and
- SystemPurposeData DBus structures. We first update their local mirrors from
- the DBus module and then set all the controls in the spoke to values
- represented in the DBus structures.
-
- NOTE: There are a couple special cases where we need to do some special precessing,
- such as for fields holding sensitive data. If we blindly set those based
- on DBus structure data, we would effectively clear them as the Subscription
- DBus module never returns previously set sensitive data in plain text.
-
- """
- # start by pulling in fresh data from the Subscription DBus module
- self._subscription_request = self._get_subscription_request()
- self._system_purpose_data = self._get_system_purpose_data()
-
- # next update the authentication part of the UI
- self._update_authetication_ui()
-
- # check if system purpose part of the spoke should be visible
- self.system_purpose_visible = self.system_purpose_data.check_data_available()
-
- # NOTE: the fill_combobox() function makes sure to remove old data from the
- # combo box before filling it
-
- # role
- fill_combobox(self._system_purpose_role_combobox,
- self.system_purpose_data.role,
- self._subscription_module.GetValidRoles())
- # SLA
- fill_combobox(self._system_purpose_sla_combobox,
- self.system_purpose_data.sla,
- self._subscription_module.GetValidSLAs())
- # usage
- fill_combobox(self._system_purpose_usage_combobox,
- self.system_purpose_data.usage,
- self._subscription_module.GetValidUsageTypes())
-
- # Insights
- self._insights_checkbox.set_active(self._subscription_module.InsightsEnabled)
-
- # update the HTTP proxy part of the UI
- self._update_http_proxy_ui()
-
- # set custom server hostname
- self.custom_server_hostname_visible = bool(self.subscription_request.server_hostname)
- self._custom_server_hostname_entry.set_text(self.subscription_request.server_hostname)
-
- # set custom rhsm baseurl
- self.custom_rhsm_baseurl_visible = bool(self.subscription_request.rhsm_baseurl)
- self._custom_rhsm_baseurl_entry.set_text(self.subscription_request.rhsm_baseurl)
-
- # if there is something set in the Options section, expand the expander
- # - this needs to go last, after all the values in option section are set/not set
- if self.options_set:
- self.options_visible = True
-
- # now that we updated the spoke with fresh data from the module, we can run the
- # general purpose update functions that make sure the two parts of the spoke
- # (the registration part and the subscription part) are both valid
- self._update_registration_state()
- self._update_subscription_state()
-
- def _update_authetication_ui(self):
- """Update the authentication part of the spoke.
-
- - SubscriptionRequest always has type set
- - username + password is the default
- For the related password and activation keys entry holding sensitive data
- we need to reconcile the data held in the spoke from previous entry with
- data set in the DBus module previously:
- - data in module and entry empty -> set placeholder
- - data in module and entry populated -> keep text in entry,
- we assume it is the same as what is in module
- - no data in module and entry populated -> clear entry & any placeholders
- (data cleared over DBus API)
- - no data in module and entry empty -> do nothing
- """
- if self.subscription_request.type == SUBSCRIPTION_REQUEST_TYPE_USERNAME_PASSWORD:
- self.authentication_method = AuthenticationMethod.USERNAME_PASSWORD
- self._username_entry.set_text(self.subscription_request.account_username)
- set_in_entry = bool(self._password_entry.get_text())
- set_in_module = self.subscription_request.account_password.type == SECRET_TYPE_HIDDEN
- if set_in_module:
- if not set_in_entry:
- self.enable_password_placeholder(True)
- else:
- self._password_entry.set_text("")
- self.enable_password_placeholder(False)
- elif self.subscription_request.type == SUBSCRIPTION_REQUEST_TYPE_ORG_KEY:
- self.authentication_method = AuthenticationMethod.ORG_KEY
- self._organization_entry.set_text(self.subscription_request.organization)
- set_in_entry = bool(self._activation_key_entry.get_text())
- set_in_module = self.subscription_request.activation_keys.type == SECRET_TYPE_HIDDEN
- if set_in_module:
- if not set_in_entry:
- self.enable_activation_key_placeholder(True)
- else:
- self._activation_key_entry.set_text("")
- self.enable_activation_key_placeholder(False)
-
- def _update_http_proxy_ui(self):
- """Update the HTTP proxy configuration part of the spoke."""
- proxy_hostname = self.subscription_request.server_proxy_hostname
- proxy_port = self.subscription_request.server_proxy_port
- proxy_port_set = proxy_port >= 0
- proxy_username = self.subscription_request.server_proxy_user
- proxy_password_secret = self.subscription_request.server_proxy_password
- proxy_password_set = proxy_password_secret.type == SECRET_TYPE_HIDDEN
- self.http_proxy_visible = proxy_hostname or proxy_username or proxy_password_set
- if proxy_hostname:
- proxy_url = proxy_hostname
- if proxy_port_set:
- proxy_url = "{}:{}".format(proxy_url, proxy_port)
- self._http_proxy_location_entry.set_text(proxy_url)
- # HTTP proxy username
- self._http_proxy_username_entry.set_text(proxy_username)
- # HTTP proxy password
- set_in_entry = bool(self._http_proxy_password_entry.get_text())
- secret_type = self.subscription_request.server_proxy_password.type
- set_in_module = secret_type == SECRET_TYPE_HIDDEN
- if set_in_module:
- if not set_in_entry:
- self.enable_http_proxy_password_placeholder(True)
- else:
- self._http_proxy_password_entry.set_text("")
- self.enable_http_proxy_password_placeholder(False)
-
- def _set_data_to_module(self):
- """Set system purpose data to the DBus module.
-
- Called either on apply() or right before a subscription
- attempt.
- """
- self._set_system_purpose_data()
- # Set data about Insights to the DBus module.
- self._set_insights()
- # Set subscription request to the DBus module.
- self._set_subscription_request()
-
- def _get_system_purpose_data(self):
- """Get SystemPurposeData from the Subscription module."""
- struct = self._subscription_module.SystemPurposeData
- return SystemPurposeData.from_structure(struct)
-
- def _set_system_purpose_data(self):
- """Set system purpose data to the Subscription DBus module."""
- self._subscription_module.SetSystemPurposeData(
- SystemPurposeData.to_structure(self.system_purpose_data)
- )
- # also apply the data (only applies when needed)
- self._apply_system_purpose_data()
-
- def _apply_system_purpose_data(self):
- """Apply system purpose data to the installation environment.
-
- Apply system purpose data to the installation environment, provided that:
- - system purpose data has not yet been applied to the system
- or
- - current system purpose data is different from the data last applied to the system
-
- Due to that we keep a copy of the last applied system purpose data so that we can
- check for difference.
-
- If the last applied data is the same as current system purpose data, nothing is done.
- """
- if self._last_applied_system_purpose_data != self.system_purpose_data:
- log.debug("Subscription GUI: applying system purpose data to installation environment")
- task_path = self._subscription_module.SetSystemPurposeWithTask()
- task_proxy = SUBSCRIPTION.get_proxy(task_path)
- sync_run_task(task_proxy)
- self._last_applied_system_purpose_data = self.system_purpose_data
-
- def _get_subscription_request(self):
- """Get SubscriptionRequest from the Subscription module."""
- struct = self._subscription_module.SubscriptionRequest
- return SubscriptionRequest.from_structure(struct)
-
- def _set_subscription_request(self):
- """Set subscription request to the Subscription DBus module."""
- self._subscription_module.SetSubscriptionRequest(
- SubscriptionRequest.to_structure(self.subscription_request)
- )
-
- def _set_insights(self):
- """Configure Insights in DBus module based on GUI state."""
- self._subscription_module.SetInsightsEnabled(self._insights_checkbox.get_active())
-
- def _register(self):
- """Try to register a system."""
- # update data in the Subscription DBUS module
- self._set_data_to_module()
-
- # disable controls
- self.set_registration_controls_sensitive(False)
-
- # wait for the previous subscription thread to finish
- threadMgr.wait(THREAD_SUBSCRIPTION)
-
- # check if the current installation source will be overriden
- # and remember it if it is the case
- source_type = self.payload.source_type
- if source_type is not None and source_type in SOURCE_TYPES_OVERRIDEN_BY_CDN:
- self._overridden_source_type = source_type
- else:
- # no override will happen, so clear the variable
- self._overridden_source_type = None
-
- # try to register
- log.debug("Subscription GUI: attempting to register")
- threadMgr.add(
- AnacondaThread(
- name=THREAD_SUBSCRIPTION,
- target=register_and_subscribe,
- kwargs={
- "payload": self.payload,
- "progress_callback": self._subscription_progress_callback,
- "error_callback": self._subscription_error_callback,
- "restart_payload": True
- }
- )
- )
-
- def _unregister(self):
- """Try to unregister a system."""
- # update data in the Subscription DBUS module
- self._set_data_to_module()
-
- # disable controls
- self.set_registration_controls_sensitive(False)
-
- # wait for the previous subscription thread to finish
- threadMgr.wait(THREAD_SUBSCRIPTION)
-
- # try to unregister
- log.debug("Subscription GUI: attempting to unregister")
- threadMgr.add(
- AnacondaThread(
- name=THREAD_SUBSCRIPTION,
- target=unregister,
- kwargs={
- "payload": self.payload,
- "overridden_source_type": self._overridden_source_type,
- "progress_callback": self._subscription_progress_callback,
- "error_callback": self._subscription_error_callback,
- "restart_payload": True
- }
- )
- )
-
- @async_action_wait
- def _subscription_progress_callback(self, phase):
- """Progress handling for subscription thread.
-
- Used both for both registration + attaching subscription
- and for unregistration.
-
- NOTE: Using the @async_action_wait decorator as this is
- called from the subscription thread. We need to do
- that as GTK does bad things if non main threads
- interact with it.
- """
- # clear error message from a previous attempt (if any)
- self.registration_error = ""
- # set registration phase
- self.registration_phase = phase
-
- # set spoke status according to subscription thread phase
- if phase == SubscriptionPhase.DONE:
- log.debug("Subscription GUI: registration & attach done")
- # we are done, clear the phase
- self.registration_phase = None
- # update registration and subscription parts of the spoke
- self._update_registration_state()
- self._update_subscription_state()
- # enable controls
- self.set_registration_controls_sensitive(True)
- # notify hub
- hubQ.send_ready(self.__class__.__name__, False)
- else:
- # processing still ongoing, set the phase
- self.registration_phase = phase
- # notify hub
- hubQ.send_ready(self.__class__.__name__, False)
- # update spoke state
- self._update_registration_state()
-
- @async_action_wait
- def _subscription_error_callback(self, error_message):
- log.debug("Subscription GUI: registration & attach failed")
- # store the error message
- self.registration_error = error_message
- # even if we fail, we are technically done,
- # so clear the phase
- self.registration_phase = None
- # update registration and subscription parts of the spoke
- self._update_registration_state()
- self._update_subscription_state()
- # re-enable controls, so user can try again
- self.set_registration_controls_sensitive(True)
- # notify hub
- hubQ.send_ready(self.__class__.__name__, False)
-
- def _get_status_message(self):
- """Get status message describing current spoke state.
-
- The registration phase is taken into account (if any)
- as well as possible error state and subscription
- being or not being attached.
-
- NOTE: This method is used both for the spoke status message
- as well as for the in-spoke status label.
- """
- phase = self.registration_phase
- if phase:
- if phase == SubscriptionPhase.UNREGISTER:
- return _("Unregistering...")
- elif phase == SubscriptionPhase.REGISTER:
- return _("Registering...")
- elif phase == SubscriptionPhase.ATTACH_SUBSCRIPTION:
- return _("Attaching subscription...")
- elif phase == SubscriptionPhase.DONE:
- return _("Subscription attached.")
- elif self.registration_error:
- return _("Registration failed.")
- elif self.subscription_attached:
- return _("Registered.")
- else:
- return _("Not registered.")
-
- @async_action_wait
- def _update_registration_state(self):
- """Update state of the registration related part of the spoke.
-
- Hopefully this method is not too inefficient as it is running basically
- on every keystroke in the username/password/organization/key entry.
- """
- subscription_attached = self.subscription_attached
- if subscription_attached:
- self._main_notebook.set_current_page(self.SUBSCRIPTION_STATUS_PAGE)
- else:
- self._main_notebook.set_current_page(self.REGISTRATION_PAGE)
-
- # update registration status label
- self._registration_status_label.set_text(self._get_status_message())
-
- # update button states
- self._update_register_button_state()
- self._update_unregister_button_state()
-
- @async_action_wait
- def _update_subscription_state(self):
- """Update state of the subscription related part of the spoke.
-
- Update state of the part of the spoke, that shows data about the
- currently attached subscriptions.
- """
- # authentication method
- if self.authentication_method == AuthenticationMethod.USERNAME_PASSWORD:
- method_string = _("Registered with account {}").format(
- self.subscription_request.account_username
- )
- else: # org + key
- method_string = _("Registered with organization {}").format(
- self.subscription_request.organization
- )
- self._method_status_label.set_text(method_string)
-
- # final syspurpose data
-
- # role
- final_role_string = _("Role: {}").format(self.system_purpose_data.role)
- self._role_status_label.set_text(final_role_string)
-
- # SLA
- final_sla_string = _("SLA: {}").format(self.system_purpose_data.sla)
- self._sla_status_label.set_text(final_sla_string)
-
- # usage
- final_usage_string = _("Usage: {}").format(self.system_purpose_data.usage)
- self._usage_status_label.set_text(final_usage_string)
-
- # Insights
- # - this strings are referring to the desired target system state,
- # the installation environment itself is not expected to be
- # connected to Insights
- if self._subscription_module.InsightsEnabled:
- insights_string = _("Connected to Red Hat Insights")
- else:
- insights_string = _("Not connected to Red Hat Insights")
- self._insights_status_label.set_text(insights_string)
-
- # get attached subscriptions as a list of structs
- attached_subscriptions = self._subscription_module.AttachedSubscriptions
- # turn the structs to more useful AttachedSubscription instances
- attached_subscriptions = AttachedSubscription.from_structure_list(attached_subscriptions)
-
- # check how many we have & set the subscription status string accordingly
- subscription_count = len(attached_subscriptions)
- if subscription_count == 0:
- if self._subscription_module.IsSimpleContentAccessEnabled:
- subscription_string = _("Subscribed in Simple Content Access mode.")
- else:
- subscription_string = _("No subscriptions are attached to the system")
- elif subscription_count == 1:
- subscription_string = _("1 subscription attached to the system")
- else:
- subscription_string = _("{} subscriptions attached to the system").format(
- subscription_count
- )
-
- self._attached_subscriptions_label.set_text(subscription_string)
-
- # populate the attached subscriptions listbox
- populate_attached_subscriptions_listbox(
- self._subscriptions_listbox,
- attached_subscriptions
- )
-
- def _check_connectivity(self):
- """Check network connectivity is available.
-
- Network connectivity is required for using the Subscription spoke
- for obvious reasons (eq. for communication with the remote
- Candlepin instance & CDN).
-
- If network is already available, this method makes the registration
- controls sensitive and clears any previous connectivity warnings.
-
- If network is not available it makes the registration controls
- insensitive and displays a warning to the user.
- """
- network_connected = self.network_connected
- if network_connected:
- # make controls sensitive, unless processing is ongoing
- self.set_registration_controls_sensitive(True)
- if not self._network_connected_previously:
- # clear previous connectivity warning
- # - we only do this on connectivity state change so that we don't clear
- # registration error related warnings
- log.debug("Subscription GUI: clearing connectivity warning")
- self.clear_info()
- else:
- # make controls insensitive
- self.set_registration_controls_sensitive(False)
- # set a warning
- log.debug("Subscription GUI: setting connectivity warning")
- self.show_warning_message(
- _("Please enable network access before connecting to Red Hat.")
- )
- # remember state
- self._network_connected_previously = network_connected
-
- def _update_register_button_state(self):
- """Update register button state.
-
- The button is only sensitive if no processing is ongoing
- and we either have enough authentication data to register
- or the system is subscribed, so we can unregister it.
- """
- button_sensitive = False
- if self._registration_controls_enabled:
- # if we are subscribed, we can always unregister
- if self.subscription_attached:
- button_sensitive = True
- # check if credentials are sufficient for registration
- elif self.authentication_method == AuthenticationMethod.USERNAME_PASSWORD:
- button_sensitive = username_password_sufficient(self.subscription_request)
- elif self.authentication_method == AuthenticationMethod.ORG_KEY:
- button_sensitive = org_keys_sufficient(self.subscription_request)
- self._register_button.set_sensitive(button_sensitive)
-
- def _update_unregister_button_state(self):
- """Update unregister button state.
-
- Make sure the Unregister button follows status of the
- _registration_controls_enabled variable.
- """
- self._unregister_button.set_sensitive(self._registration_controls_enabled)
diff --git a/pyanaconda/ui/lib/subscription.py b/pyanaconda/ui/lib/subscription.py
deleted file mode 100644
index 87633d7..0000000
--- a/pyanaconda/ui/lib/subscription.py
+++ /dev/null
@@ -1,421 +0,0 @@
-#
-# Subscription related helper functions.
-#
-# Copyright (C) 2020 Red Hat, Inc. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from enum import Enum
-
-from pyanaconda.threading import threadMgr
-
-from pyanaconda.core.constants import THREAD_WAIT_FOR_CONNECTING_NM, \
- SUBSCRIPTION_REQUEST_TYPE_USERNAME_PASSWORD, SUBSCRIPTION_REQUEST_TYPE_ORG_KEY, \
- SOURCE_TYPE_HDD, SOURCE_TYPE_CDN, SOURCE_TYPES_OVERRIDEN_BY_CDN
-from pyanaconda.core.i18n import _
-from pyanaconda.core.constants import PAYLOAD_TYPE_DNF
-from pyanaconda.ui.lib.payload import create_source, set_source, tear_down_sources
-from pyanaconda.ui.lib.storage import unmark_protected_device
-from pyanaconda.payload.manager import payloadMgr
-from pyanaconda.errors import errorHandler, ERROR_RAISE
-
-from pyanaconda.modules.common.constants.services import SUBSCRIPTION
-from pyanaconda.modules.common import task
-from pyanaconda.modules.common.structures.subscription import SubscriptionRequest
-from pyanaconda.modules.common.structures.secret import SECRET_TYPE_HIDDEN, \
- SECRET_TYPE_TEXT
-from pyanaconda.modules.common.errors.subscription import RegistrationError, \
- UnregistrationError, SubscriptionError
-
-from pyanaconda.anaconda_loggers import get_module_logger
-log = get_module_logger(__name__)
-
-# The following secret types mean a secret has been set
-# (and it is either in plaintext or hidden in the module).
-SECRET_SET_TYPES = (SECRET_TYPE_TEXT, SECRET_TYPE_HIDDEN)
-
-# Asynchronous subscription state tracking
-class SubscriptionPhase(Enum):
- UNREGISTER = 1
- REGISTER = 2
- ATTACH_SUBSCRIPTION = 3
- DONE = 4
-
-# temporary methods for Subscription/CDN related source switching
-
-
-def _tear_down_existing_source(payload):
- """Tear down existing payload, so we can set a new one.
-
- :param payload: Anaconda payload instance
- """
- source_proxy = payload.get_source_proxy()
-
- if source_proxy.Type == SOURCE_TYPE_HDD and source_proxy.Partition:
- unmark_protected_device(source_proxy.Partition)
-
- tear_down_sources(payload.proxy)
-
-
-def switch_source(payload, source_type):
- """Switch to an installation source.
-
- :param payload: Anaconda payload instance
- :param source_type: installation source type
- """
- _tear_down_existing_source(payload)
-
- new_source_proxy = create_source(source_type)
- set_source(payload.proxy, new_source_proxy)
-
-
-def _do_payload_restart(payload):
- """Restart the Anaconda payload.
-
- This should be done after changing the installation sorce,
- such as when switching to and from the CDN.
-
- :param payload: Anaconda payload instance
- """
- # restart payload
- payloadMgr.restart_thread(payload,
- fallback=False,
- checkmount=False,
- onlyOnChange=False)
-
-
-def check_cdn_is_installation_source(payload):
- """Check if Red Hat CDN is the current installation source.
-
- :param payload: Anaconda payload instance
- """
- if payload.type == PAYLOAD_TYPE_DNF:
- source_proxy = payload.get_source_proxy()
- return source_proxy.Type == SOURCE_TYPE_CDN
- else:
- # the CDN source pretty much only supports
- # DNF payload at the moment
- return False
-
-
-# Kickstart error handling
-
-class KickstartRegistrationError(Exception):
- """Registration attempt from kickstart failed."""
- pass
-
-
-def kickstart_error_handler(message):
- """Helper function which raises exception if kickstart triggered registration fails."""
- exn = KickstartRegistrationError(message)
- if errorHandler.cb(exn) == ERROR_RAISE:
- raise exn
-
-# Asynchronous registration + subscription & unregistration handling
-#
-# The Red Hat subscription related tasks communicate over network and might
-# take some time to finish (up to tens of seconds). We definitely don't want
-# to block either automated installation or the UI before they finish.
-#
-# These tasks (register + attach subscription and unregister) need to run in
-# threads and these threads need to be started from at least two places:
-# - from early startup code for automated installations
-# - from Subscription spoke based on user interaction
-#
-# Also in some cases, multiple individual DBus tasks will need to be run
-# in sequence with any errors handled accordingly.
-#
-# Anaconda modularity is not yet advanced enough to handle this in a generic
-# manner, so we need simple scheduler living in the context of the main Anaconda
-# thread. The simple scheduler hosts the code that starts the respective subscription
-# handling thread, which assures appropriate tasks are run.
-#
-# As the scheduler code than can be run either during early startup or in reaction to user
-# interaction in the Subscription spoke we avoid code duplication.
-
-
-def dummy_progress_callback(subscription_phase):
- """Dummy progress reporting function used if no custom callback is set."""
- pass
-
-
-def dummy_error_callback(error_message):
- """Dummy error reporting function used if no custom callback is set."""
- pass
-
-
-def org_keys_sufficient(subscription_request=None):
- """Report if sufficient credentials are set for org & keys registration attempt.
-
- :param subscription_request: an subscription request, if None a fresh subscription request
- will be fetched from the Subscription module over DBus
- :type subscription_request: SubscriptionRequest instance
- :return: True if sufficient, False otherwise
- :rtype: bool
- """
- if subscription_request is None:
- subscription_proxy = SUBSCRIPTION.get_proxy()
- subscription_request_struct = subscription_proxy.SubscriptionRequest
- subscription_request = SubscriptionRequest.from_structure(subscription_request_struct)
- organization_set = bool(subscription_request.organization)
- key_set = subscription_request.activation_keys.type in SECRET_SET_TYPES
- return organization_set and key_set
-
-
-def username_password_sufficient(subscription_request=None):
- """Report if sufficient credentials are set for username & password registration attempt.
-
- :param subscription_request: an subscription request, if None a fresh subscription request
- will be fetched from the Subscription module over DBus
- :type subscription_request: SubscriptionRequest instance
- :return: True if sufficient, False otherwise
- :rtype: bool
- """
- if subscription_request is None:
- subscription_proxy = SUBSCRIPTION.get_proxy()
- subscription_request_struct = subscription_proxy.SubscriptionRequest
- subscription_request = SubscriptionRequest.from_structure(subscription_request_struct)
- username_set = bool(subscription_request.account_username)
- password_set = subscription_request.account_password.type in SECRET_SET_TYPES
- return username_set and password_set
-
-
-def register_and_subscribe(payload, progress_callback=None, error_callback=None,
- restart_payload=False):
- """Try to register and subscribe the installation environment.
-
- :param payload: Anaconda payload instance
- :param progress_callback: progress callback function, takes one argument, subscription phase
- :type progress_callback: callable(subscription_phase)
- :param error_callback: error callback function, takes one argument, the error message
- :type error_callback: callable(error_message)
- :param bool restart_payload: should payload restart be attempted if it appears necessary ?
-
- NOTE: The restart_payload attribute controls if the subscription helper function should
- attempt to restart the payload thread if it deems it necessary (DVD -> CDN switch,
- registration with CDN source, etc.). If restart_payload is True, it might restart
- the payload. If it is False, it well never try to do that.
-
- The main usecase of this at the moment is when the subscription helper function
- is invoked during early Anaconda kickstart installation. At this stage the initial
- payload restart has not yet been run and starting it too early could lead to various
- issues. At this stage we don't want the helper function to restart payload, so we keep
- restart_payload at default value (False). Later on during manual user interaction we
- definitely want payload to be restarted as needed (the initial restart long done)
- and so we pass restart_payload=True.
- """
-
- # assign dummy callback functions if none were provided by caller
- if progress_callback is None:
- progress_callback = dummy_progress_callback
- if error_callback is None:
- error_callback = dummy_error_callback
-
- # connect to the Subscription DBus module
- subscription_proxy = SUBSCRIPTION.get_proxy()
-
- # First make sure network connectivity is available
- # by waiting for the connectivity check thread
- # to finish, in case it is running, usually early
- # during Anaconda startup.
- threadMgr.wait(THREAD_WAIT_FOR_CONNECTING_NM)
-
- # Next we make sure to set RHSM config options
- # to be in sync with the current subscription request.
- task_path = subscription_proxy.SetRHSMConfigWithTask()
- task_proxy = SUBSCRIPTION.get_proxy(task_path)
- task.sync_run_task(task_proxy)
-
- # Then check if we are not already registered.
- #
- # In some fairly bizarre cases it is apparently
- # possible that registration & attach will succeed,
- # but the attached subscription will be incomplete
- # and/or invalid. These cases will be caught by
- # the subscription token check and marked as failed
- # by Anaconda.
- #
- # It is also possible that registration succeeds,
- # but attach fails.
- #
- # To make recovery and another registration attempt
- # possible, we need to first unregister the already
- # registered system, as a registration attempt on
- # an already registered system would fail.
- if subscription_proxy.IsRegistered:
- log.debug("subscription thread: system already registered, unregistering")
- progress_callback(SubscriptionPhase.UNREGISTER)
- task_path = subscription_proxy.UnregisterWithTask()
- task_proxy = SUBSCRIPTION.get_proxy(task_path)
- try:
- task.sync_run_task(task_proxy)
- except UnregistrationError as e:
- log.debug("subscription thread: unregistration failed: %s", e)
- # Failing to unregister the system is an unrecoverable error,
- # so we end there.
- error_callback(str(e))
- return
- log.debug("Subscription GUI: unregistration succeeded")
-
- # Try to register.
- #
- # If we got this far the system was either not registered
- # or was unregistered successfully.
- log.debug("subscription thread: attempting to register")
- progress_callback(SubscriptionPhase.REGISTER)
- # check authentication method has been set and credentials seem to be
- # sufficient (though not necessarily valid)
- subscription_request_struct = subscription_proxy.SubscriptionRequest
- subscription_request = SubscriptionRequest.from_structure(subscription_request_struct)
- task_path = None
- if subscription_request.type == SUBSCRIPTION_REQUEST_TYPE_USERNAME_PASSWORD:
- if username_password_sufficient():
- task_path = subscription_proxy.RegisterUsernamePasswordWithTask()
- elif subscription_request.type == SUBSCRIPTION_REQUEST_TYPE_ORG_KEY:
- if org_keys_sufficient():
- task_path = subscription_proxy.RegisterOrganizationKeyWithTask()
-
- if task_path:
- task_proxy = SUBSCRIPTION.get_proxy(task_path)
- try:
- task.sync_run_task(task_proxy)
- except RegistrationError as e:
- log.debug("subscription thread: registration attempt failed: %s", e)
- log.debug("subscription thread: skipping auto attach due to registration error")
- error_callback(str(e))
- return
- log.debug("subscription thread: registration succeeded")
- else:
- log.debug("subscription thread: credentials insufficient, skipping registration attempt")
- error_callback(_("Registration failed due to insufficient credentials."))
- return
-
- # try to attach subscription
- log.debug("subscription thread: attempting to auto attach an entitlement")
- progress_callback(SubscriptionPhase.ATTACH_SUBSCRIPTION)
- task_path = subscription_proxy.AttachSubscriptionWithTask()
- task_proxy = SUBSCRIPTION.get_proxy(task_path)
- try:
- task.sync_run_task(task_proxy)
- except SubscriptionError as e:
- log.debug("subscription thread: failed to attach subscription: %s", e)
- error_callback(str(e))
- return
-
- # parse attached subscription data
- log.debug("subscription thread: parsing attached subscription data")
- task_path = subscription_proxy.ParseAttachedSubscriptionsWithTask()
- task_proxy = SUBSCRIPTION.get_proxy(task_path)
- task.sync_run_task(task_proxy)
-
- # check if the current installation source should be overridden by
- # the CDN source we can now use
- # - at the moment this is true only for the CDROM source
- source_proxy = payload.get_source_proxy()
- if payload.type == PAYLOAD_TYPE_DNF:
- if source_proxy.Type in SOURCE_TYPES_OVERRIDEN_BY_CDN:
- log.debug("subscription thread: overriding current installation source by CDN")
- switch_source(payload, SOURCE_TYPE_CDN)
- # If requested, also restart the payload if CDN is the installation source
- # The CDN either already was the installation source or we just switched to it.
- #
- # Make sure to get fresh source proxy as the old one might be stale after
- # after a source switch.
- source_proxy = payload.get_source_proxy()
- if restart_payload and source_proxy.Type == SOURCE_TYPE_CDN:
- log.debug("subscription thread: restarting payload after registration")
- _do_payload_restart(payload)
-
- # and done, report attaching subscription was successful
- log.debug("subscription thread: auto attach succeeded")
- progress_callback(SubscriptionPhase.DONE)
-
-
-def unregister(payload, overridden_source_type, progress_callback=None, error_callback=None,
- restart_payload=False):
- """Try to unregister the installation environment.
-
- NOTE: Unregistering also removes any attached subscriptions and
- if an installation source has been overridden, switches
- back to it.
-
- :param payload: Anaconda payload instance
- :param overridden_source_type: type of the source that was overridden by the CDN source at
- registration time (if any)
- :param progress_callback: progress callback function, takes one argument, subscription phase
- :type progress_callback: callable(subscription_phase)
- :param error_callback: error callback function, takes one argument, the error message
- :type error_callback: callable(error_message)
- :param bool restart_payload: should payload restart be attempted if it appears necessary ?
-
- NOTE: For more information about the restart_payload attribute, see the
- register_and_subscribe() function doc string.
- """
-
- # assign dummy callback functions if none were provided by caller
- if progress_callback is None:
- progress_callback = dummy_progress_callback
- if error_callback is None:
- error_callback = dummy_error_callback
-
- # connect to the Subscription DBus module
- subscription_proxy = SUBSCRIPTION.get_proxy()
-
- if subscription_proxy.IsRegistered:
- log.debug("subscription thread: unregistering the system")
- # Make sure to set RHSM config options to be in sync
- # with the current subscription request in the unlikely
- # case of someone doing a valid change in the subscription
- # request since we registered.
- task_path = subscription_proxy.SetRHSMConfigWithTask()
- task_proxy = SUBSCRIPTION.get_proxy(task_path)
- task.sync_run_task(task_proxy)
- progress_callback(SubscriptionPhase.UNREGISTER)
- task_path = subscription_proxy.UnregisterWithTask()
- task_proxy = SUBSCRIPTION.get_proxy(task_path)
- try:
- task.sync_run_task(task_proxy)
- except UnregistrationError as e:
- log.debug("subscription thread: unregistration failed: %s", e)
- error_callback(str(e))
- return
-
- # If the CDN overrode an installation source we should revert that
- # on unregistration, provided CDN is the current source.
- source_proxy = payload.get_source_proxy()
- switched_source = False
- if payload.type == PAYLOAD_TYPE_DNF:
- if source_proxy.Type == SOURCE_TYPE_CDN and overridden_source_type:
- log.debug(
- "subscription thread: rolling back CDN installation source override"
- )
- switch_source(payload, overridden_source_type)
- switched_source = True
-
- # If requested, also restart the payload if:
- # - installation source switch occured
- # - the current source is CDN, which can no longer be used
- # after unregistration, so we need to refresh the Source
- # and Software spokes
- if restart_payload and (source_proxy.Type == SOURCE_TYPE_CDN or switched_source):
- log.debug("subscription thread: restarting payload after unregistration")
- _do_payload_restart(payload)
-
- log.debug("Subscription GUI: unregistration succeeded")
- progress_callback(SubscriptionPhase.DONE)
- else:
- log.warning("subscription thread: not registered, so can't unregister")
- progress_callback(SubscriptionPhase.DONE)
- return
2.27.0
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。