# # 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 . # 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)