Skip to content

Commit

Permalink
Creating categories dbus API for installation phases
Browse files Browse the repository at this point in the history
  • Loading branch information
adamkankovsky committed Dec 7, 2023
1 parent f921b0c commit 859ec17
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 21 deletions.
9 changes: 9 additions & 0 deletions pyanaconda/core/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,3 +506,12 @@ class DisplayModes(Enum):

# FIPS mode minimum LUKS passphrase length
FIPS_PASSPHRASE_MIN_LENGTH = 8


# Installation categories
CATEGORY_UNDEFINED = "UNDEFINED"
CATEGORY_ENVIRONMENT = "ENVIRONMENT_CONFIGURATION"
CATEGORY_STORAGE = "STORAGE_CONFIGURATION"
CATEGORY_SOFTWARE = "SOFTWARE_INSTALLATION"
CATEGORY_BOOTLOADER = "BOOTLOADER_INSTALLATION"
CATEGORY_SYSTEM = "SYSTEM_CONFIGURATION"
64 changes: 44 additions & 20 deletions pyanaconda/installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
#
from pyanaconda.core.dbus import DBus
from pyanaconda.core.configuration.anaconda import conf
from pyanaconda.core.constants import PAYLOAD_LIVE_TYPES, PAYLOAD_TYPE_DNF
from pyanaconda.core.constants import PAYLOAD_LIVE_TYPES, PAYLOAD_TYPE_DNF, CATEGORY_SYSTEM, CATEGORY_BOOTLOADER, \
CATEGORY_ENVIRONMENT, CATEGORY_STORAGE, CATEGORY_SOFTWARE
from pyanaconda.modules.boss.install_manager.installation_category_interface import CategoryReportTaskInterface
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
Expand Down Expand Up @@ -50,7 +52,6 @@ def _writeKS(ksdata):
f.write("# Generated by Anaconda {}\n".format(util.get_anaconda_version_string()))
f.write(str(ksdata))


class RunInstallationTask(InstallationTask):
"""Task to run the installation queue."""

Expand Down Expand Up @@ -82,8 +83,13 @@ def run(self):
ksdata=self._ksdata,
)

def for_publication(self):
"""Return a DBus representation."""
return CategoryReportTaskInterface(self)

def _queue_started_cb(self, task):
"""The installation queue was started."""
self.report_category(task.task_category)
self.report_progress(task.status_message)

def _task_completed_cb(self, task):
Expand All @@ -107,7 +113,8 @@ def _prepare_configuration(self, payload, ksdata):
# we only run the tasks if the Subscription module is available
subscription_config = TaskQueue(
"Subscription configuration",
_("Configuring Red Hat subscription")
_("Configuring Red Hat subscription"),
CATEGORY_SYSTEM
)
subscription_proxy = SUBSCRIPTION.get_proxy()
subscription_dbus_tasks = subscription_proxy.InstallWithTasks()
Expand All @@ -117,7 +124,8 @@ def _prepare_configuration(self, payload, ksdata):
# schedule the execute methods of ksdata that require an installed system to be present
os_config = TaskQueue(
"Installed system configuration",
_("Configuring installed system")
_("Configuring installed system"),
CATEGORY_SYSTEM
)

# add installation tasks for the Security DBus module
Expand Down Expand Up @@ -158,7 +166,8 @@ def _prepare_configuration(self, payload, ksdata):
overwrite = payload.type in PAYLOAD_LIVE_TYPES
network_config = TaskQueue(
"Network configuration",
_("Writing network configuration")
_("Writing network configuration"),
CATEGORY_SYSTEM
)
network_config.append(Task(
"Network configuration",
Expand All @@ -171,7 +180,8 @@ def _prepare_configuration(self, payload, ksdata):
if is_module_available(USERS):
user_config = TaskQueue(
"User creation",
_("Creating users")
_("Creating users"),
CATEGORY_SYSTEM
)
users_proxy = USERS.get_proxy()
users_dbus_tasks = users_proxy.InstallWithTasks()
Expand All @@ -181,7 +191,8 @@ def _prepare_configuration(self, payload, ksdata):
# Anaconda addon configuration
addon_config = TaskQueue(
"Anaconda addon configuration",
_("Configuring addons")
_("Configuring addons"),
CATEGORY_SYSTEM
)

boss_proxy = BOSS.get_proxy()
Expand All @@ -194,7 +205,8 @@ def _prepare_configuration(self, payload, ksdata):
# Initramfs generation
generate_initramfs = TaskQueue(
"Initramfs generation",
_("Generating initramfs")
_("Generating initramfs"),
CATEGORY_BOOTLOADER
)
bootloader_proxy = STORAGE.get_proxy(BOOTLOADER)

Expand Down Expand Up @@ -236,7 +248,8 @@ def run_generate_initramfs():
if flags.flags.kexec:
kexec_setup = TaskQueue(
"Kexec setup",
_("Setting up kexec")
_("Setting up kexec"),
CATEGORY_BOOTLOADER
)
kexec_setup.append(Task(
"Setup kexec",
Expand All @@ -247,7 +260,8 @@ def run_generate_initramfs():
# write anaconda related configs & kickstarts
write_configs = TaskQueue(
"Write configs and kickstarts",
_("Storing configuration files and kickstarts")
_("Storing configuration files and kickstarts"),
CATEGORY_SYSTEM
)

# Write the kickstart file to the installed system (or, copy the input
Expand All @@ -267,7 +281,8 @@ def run_generate_initramfs():

post_scripts = TaskQueue(
"Post installation scripts",
_("Running post-installation scripts")
_("Running post-installation scripts"),
CATEGORY_SYSTEM
)
post_scripts.append(Task(
"Run post installation scripts",
Expand Down Expand Up @@ -315,7 +330,8 @@ def _prepare_installation(self, payload, ksdata):
# setup the installation environment
setup_environment = TaskQueue(
"Installation environment setup",
_("Setting up the installation environment")
_("Setting up the installation environment"),
CATEGORY_ENVIRONMENT
)

boss_proxy = BOSS.get_proxy()
Expand All @@ -341,7 +357,8 @@ def _prepare_installation(self, payload, ksdata):
storage_proxy = STORAGE.get_proxy()
early_storage = TaskQueue(
"Early storage configuration",
_("Configuring storage")
_("Configuring storage"),
CATEGORY_STORAGE
)
early_storage.append_dbus_tasks(STORAGE, storage_proxy.InstallWithTasks())

Expand All @@ -354,7 +371,8 @@ def _prepare_installation(self, payload, ksdata):
# Run %pre-install scripts with the filesystem mounted and no packages
pre_install_scripts = TaskQueue(
"Pre-install scripts",
_("Running pre-installation scripts")
_("Running pre-installation scripts"),
CATEGORY_ENVIRONMENT
)
pre_install_scripts.append(Task(
"Run %pre-install scripts",
Expand All @@ -367,7 +385,8 @@ def _prepare_installation(self, payload, ksdata):
# - check for possibly needed additional packages.
pre_install = TaskQueue(
"Pre install tasks",
_("Running pre-installation tasks")
_("Running pre-installation tasks"),
CATEGORY_SOFTWARE
)

if is_module_available(SECURITY):
Expand All @@ -391,7 +410,8 @@ def _prepare_installation(self, payload, ksdata):

payload_install = TaskQueue(
"Payload installation",
_("Installing the software")
_("Installing the software"),
CATEGORY_SOFTWARE
)
payload_install.append(Task(
"Install the payload",
Expand All @@ -403,7 +423,8 @@ def _prepare_installation(self, payload, ksdata):
if payload.type != PAYLOAD_TYPE_DNF:
late_storage = TaskQueue(
"Late storage configuration",
_("Configuring storage")
_("Configuring storage"),
CATEGORY_STORAGE,
)
conf_task = storage_proxy.WriteConfigurationWithTask()
late_storage.append_dbus_tasks(STORAGE, [conf_task])
Expand All @@ -413,7 +434,8 @@ def _prepare_installation(self, payload, ksdata):
bootloader_proxy = STORAGE.get_proxy(BOOTLOADER)
bootloader_install = TaskQueue(
"Bootloader installation",
_("Installing boot loader")
_("Installing boot loader"),
CATEGORY_BOOTLOADER
)

def run_configure_bootloader():
Expand Down Expand Up @@ -446,7 +468,8 @@ def run_install_bootloader():

post_install = TaskQueue(
"Post-installation setup tasks",
_("Performing post-installation setup tasks")
_("Performing post-installation setup tasks"),
CATEGORY_SYSTEM
)
post_install.append(Task(
"Run post-installation setup tasks",
Expand All @@ -460,7 +483,8 @@ def run_install_bootloader():
if snapshot_proxy.IsRequested(SNAPSHOT_WHEN_POST_INSTALL):
snapshot_creation = TaskQueue(
"Creating post installation snapshots",
_("Creating snapshots")
_("Creating snapshots"),
CATEGORY_STORAGE
)
snapshot_task = snapshot_proxy.CreateWithTask(SNAPSHOT_WHEN_POST_INSTALL)
snapshot_creation.append_dbus_tasks(STORAGE, [snapshot_task])
Expand Down
17 changes: 16 additions & 1 deletion pyanaconda/installation_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,9 @@ class TaskQueue(BaseTask):
TaskQueues and Tasks can be mixed in a single TaskQueue.
"""

def __init__(self, name, status_message=None):
def __init__(self, name, status_message=None, task_category=None):
super().__init__(name)
self._task_category = task_category
self._status_message = status_message
# the list backing this TaskQueue instance
self._queue = []
Expand All @@ -103,6 +104,20 @@ def __init__(self, name, status_message=None):
self.task_started = Signal()
self.task_completed = Signal()

@property
def task_category(self):
"""A category describing the Queue is trying to achieve.
Eq. "Converting all foo into bar."
The current main usecase is to set the ProgressHub status message when
a TaskQueue is started.
:returns: a task category
:rtype: str
"""
return self._task_category

@property
def status_message(self):
"""A status message describing the Queue is trying to achieve.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# DBus installation task category interface.
#
# API specification of task category interface.
#
# Copyright (C) 2017 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 dasbus.server.interface import dbus_interface, dbus_signal
from pyanaconda.modules.common.constants.interfaces import TASK_CATEGORY
from dasbus.typing import * # pylint: disable=wildcard-import
from pyanaconda.modules.common.task import TaskInterface

__all__ = ['CategoryReportTaskInterface']


@dbus_interface(TASK_CATEGORY.interface_name)
class CategoryReportTaskInterface(TaskInterface):
"DBus interface for a task category report"

def connect_signals(self):
super().connect_signals()
self.implementation.category_changed_signal.connect(self.CategoryChanged)

@dbus_signal
def CategoryChanged(self, category: Str):
"""Signal making progress for this task.
:param category: Number of the category. See pyanaconda/core/constants.py
InstallationCategories for info about a category indexes.
"""
pass
5 changes: 5 additions & 0 deletions pyanaconda/modules/common/constants/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
basename="Task"
)

TASK_CATEGORY = DBusInterfaceIdentifier(
namespace=ANACONDA_NAMESPACE,
basename="TaskCategory"
)

DEVICE_TREE_VIEWER = DBusInterfaceIdentifier(
namespace=DEVICE_TREE_NAMESPACE,
basename="Viewer"
Expand Down
20 changes: 20 additions & 0 deletions pyanaconda/modules/common/task/progress.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ class ProgressReporter(ABC):
def __init__(self):
super().__init__()
self._progress_changed_signal = Signal()
self._category_changed_signal = Signal()

self.__progress_lock = Lock()
self.__progress_step = 0
self.__progress_category = None
self.__progress_msg = ""

@property
Expand All @@ -55,6 +57,24 @@ def progress_changed_signal(self):
"""Signal emits when the progress of the task changes."""
return self._progress_changed_signal

@property
def category_changed_signal(self):
"""Signal emits when the category of the task changes."""
return self._category_changed_signal

@async_action_nowait
def report_category(self, category):
current_category = self.__progress_category
if category is None:
return
else:
category_value = category.value
if current_category is None:
self.__progress_category = category_value
current_category = category_value
self._category_changed_signal.emit(current_category)


@async_action_nowait
def report_progress(self, message, step_number=None, step_size=None):
"""Report a progress change.
Expand Down

0 comments on commit 859ec17

Please sign in to comment.