anaconda/anaconda-40.22.3.13/pyanaconda/modules/boss/kickstart_manager/kickstart_manager.py
2024-11-14 21:39:56 -08:00

176 lines
6 KiB
Python

#
# Distributing kickstart to anaconda modules.
#
# Copyright (C) 2017 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 pykickstart.errors import KickstartError
from pykickstart.version import makeVersion
from pyanaconda.anaconda_loggers import get_module_logger
from pyanaconda.modules.boss.kickstart_manager.parser import SplitKickstartParser,\
VALID_SECTIONS_ANACONDA
from pyanaconda.modules.common.constants.services import BOSS
from pyanaconda.modules.common.structures.kickstart import KickstartReport, KickstartMessage
log = get_module_logger(__name__)
__all__ = ['KickstartManager']
class KickstartManager(object):
"""Distributes kickstart to modules and collects it back."""
def __init__(self):
self._module_observers = []
@property
def module_observers(self):
"""Get all module observers for kickstart distribution."""
return self._module_observers
def on_module_observers_changed(self, observers):
"""Set module observers for kickstart distribution."""
self._module_observers = list(observers)
def read_kickstart_file(self, path):
"""Read the specified kickstart file.
:param path: a path to a file
:returns: a kickstart report
"""
report = KickstartReport()
try:
elements = self._split_to_elements(path)
reports = self._distribute_to_modules(elements)
except KickstartError as e:
data = KickstartMessage.for_error(e)
data.module_name = BOSS.service_name
data.file_name = path
report.error_messages.append(data)
else:
self._merge_module_reports(report, reports)
return report
def _split_to_elements(self, path):
"""Split the kickstart given by path into elements."""
handler = makeVersion()
parser = SplitKickstartParser(handler, valid_sections=VALID_SECTIONS_ANACONDA)
return parser.split(path)
def _distribute_to_modules(self, elements):
"""Distribute split kickstart to modules synchronously.
:returns: list of (Line number, Message) errors reported by modules when
distributing kickstart
:rtype: list of kickstart reports
"""
reports = []
for observer in self._module_observers:
if not observer.is_service_available:
log.warning("Module %s not available!", observer.service_name)
continue
commands = observer.proxy.KickstartCommands
sections = observer.proxy.KickstartSections
addons = observer.proxy.KickstartAddons
log.info("%s handles commands %s sections %s addons %s.",
observer.service_name, commands, sections, addons)
module_elements = elements.get_and_process_elements(
commands=commands,
sections=sections,
addons=addons
)
module_kickstart = elements.get_kickstart_from_elements(
module_elements
)
if not module_kickstart:
log.info("There are no kickstart data for %s.", observer.service_name)
continue
module_report = KickstartReport.from_structure(
observer.proxy.ReadKickstart(module_kickstart)
)
line_references = elements.get_references_from_elements(
module_elements
)
for message in module_report.get_messages():
line_number, file_name = line_references[message.line_number]
message.line_number = line_number
message.file_name = file_name
message.module_name = observer.service_name
reports.append(module_report)
return reports
def _merge_module_reports(self, report, module_reports):
"""Merge the module reports into the final report."""
for module_report in module_reports:
report.error_messages.extend(module_report.error_messages)
report.warning_messages.extend(module_report.warning_messages)
def generate_kickstart(self):
"""Return a kickstart representation of modules.
:return: a kickstart string
"""
kickstarts = self._generate_from_modules()
return self._merge_module_kickstarts(kickstarts)
def _generate_from_modules(self):
"""Generate kickstart from modules.
:return: a map of module names and kickstart strings
"""
result = {}
for observer in self._module_observers:
if not observer.is_service_available:
log.warning("Module %s not available!", observer.service_name)
continue
module_name = observer.service_name
module_kickstart = observer.proxy.GenerateKickstart()
result[module_name] = module_kickstart
return result
def _merge_module_kickstarts(self, module_kickstarts):
"""Merge kickstart from modules
:param module_kickstarts: a map of modules names and kickstart strings
:return: a complete kickstart string
"""
parts = []
for name in sorted(module_kickstarts):
part = module_kickstarts[name].strip()
if not part:
continue
parts.append(part)
return "\n\n".join(parts)