217 lines
7.1 KiB
Python
217 lines
7.1 KiB
Python
#
|
|
# Base object of all payloads.
|
|
#
|
|
# Copyright (C) 2019 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 abc import ABCMeta, abstractmethod
|
|
|
|
from dasbus.server.publishable import Publishable
|
|
|
|
from pyanaconda.core.signal import Signal
|
|
from pyanaconda.modules.common.errors.general import UnavailableValueError
|
|
from pyanaconda.modules.common.errors.payload import IncompatibleSourceError, SourceSetupError
|
|
from pyanaconda.modules.common.base import KickstartBaseModule
|
|
from pyanaconda.modules.payloads.base.initialization import SetUpSourcesTask, TearDownSourcesTask
|
|
from pyanaconda.modules.payloads.constants import SourceState
|
|
|
|
from pyanaconda.anaconda_loggers import get_module_logger
|
|
log = get_module_logger(__name__)
|
|
|
|
|
|
class PayloadBase(KickstartBaseModule, Publishable, metaclass=ABCMeta):
|
|
"""Base class for all the payload modules.
|
|
|
|
This will contain all API specific to payload which will be called
|
|
by the base payload module.
|
|
"""
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._sources = []
|
|
self.sources_changed = Signal()
|
|
self._kernel_version_list = None
|
|
|
|
@property
|
|
@abstractmethod
|
|
def type(self):
|
|
"""Type of this payload.
|
|
|
|
:return: value of the payload.base.constants.PayloadType enum
|
|
"""
|
|
return None
|
|
|
|
@property
|
|
@abstractmethod
|
|
def default_source_type(self):
|
|
"""Type of the default source.
|
|
|
|
:return SourceType: a default source type
|
|
"""
|
|
return None
|
|
|
|
@property
|
|
@abstractmethod
|
|
def supported_source_types(self):
|
|
"""Get list of supported source types.
|
|
|
|
:return [SourceType]: a list of supported source types
|
|
"""
|
|
return []
|
|
|
|
@property
|
|
def sources(self):
|
|
"""Get list of sources attached to this payload.
|
|
|
|
:return: list of source objects attached to this payload
|
|
:rtype: [instance of PayloadSourceBase class]
|
|
"""
|
|
return self._sources
|
|
|
|
def _get_source(self, source_type):
|
|
"""Get an attached source object of the specified type.
|
|
|
|
:param SourceType source_type: a type of the source
|
|
:return: a source object or None
|
|
"""
|
|
for source in self.sources:
|
|
if source.type == source_type:
|
|
return source
|
|
|
|
return None
|
|
|
|
def set_sources(self, sources):
|
|
"""Set a new list of sources to this payload.
|
|
|
|
Before setting the sources, please make sure the sources are not initialized otherwise
|
|
the SourceSetupError exception will be raised. Payload have to cleanup after itself.
|
|
|
|
..NOTE:
|
|
The SourceSetupError is a reasonable effort to solve the race condition. However,
|
|
there is still a possibility that the task to initialize sources (`SetupSourcesWithTask()`)
|
|
was created with the old list but not run yet. In that case this check will not work and
|
|
the initialization task will run with the old list.
|
|
|
|
:param sources: set a new sources
|
|
:type sources: instance of pyanaconda.modules.payloads.source.source_base.PayloadSourceBase
|
|
:raise: IncompatibleSourceError when source is not a supported type
|
|
SourceSetupError when attached sources are initialized
|
|
"""
|
|
for source in sources:
|
|
if source.type not in self.supported_source_types:
|
|
raise IncompatibleSourceError("Source type {} is not supported by this payload."
|
|
.format(source.type.value))
|
|
|
|
if any(source.get_state() == SourceState.READY for source in self.sources):
|
|
raise SourceSetupError("Can't change list of sources if there is at least one source "
|
|
"initialized! Please tear down the sources first.")
|
|
|
|
self._sources = sources
|
|
log.debug("New sources %s were added.", sources)
|
|
self.sources_changed.emit()
|
|
|
|
def add_source(self, source):
|
|
"""Module scope API for easier adding of sources.
|
|
|
|
:param source: Source we want to add.
|
|
"""
|
|
sources = list(self.sources)
|
|
sources.append(source)
|
|
self.set_sources(sources)
|
|
|
|
def is_network_required(self):
|
|
"""Do the sources require a network?
|
|
|
|
:return: True or False
|
|
"""
|
|
for source in self.sources:
|
|
if source.network_required:
|
|
return True
|
|
|
|
return False
|
|
|
|
def calculate_required_space(self):
|
|
"""Calculate space required for the installation.
|
|
|
|
:return: required size in bytes
|
|
:rtype: int
|
|
"""
|
|
total = 0
|
|
|
|
for source in self.sources:
|
|
total += source.required_space
|
|
|
|
return total
|
|
|
|
def get_kernel_version_list(self):
|
|
"""Get the kernel versions list.
|
|
|
|
The kernel version list doesn't have to be available
|
|
before the payload installation.
|
|
|
|
:return: a list of kernel versions
|
|
:raises UnavailableValueError: if the list is not available
|
|
"""
|
|
if self._kernel_version_list is None:
|
|
raise UnavailableValueError("The kernel version list is not available.")
|
|
|
|
return self._kernel_version_list
|
|
|
|
def set_kernel_version_list(self, kernels):
|
|
"""Set the kernel versions list.
|
|
|
|
This function should be called by one of the installation tasks.
|
|
|
|
:param kernels: a list of kernel versions
|
|
"""
|
|
self._kernel_version_list = kernels
|
|
log.debug("The kernel version list is set to: %s", kernels)
|
|
|
|
@abstractmethod
|
|
def install_with_tasks(self):
|
|
"""Install the payload.
|
|
|
|
:return: list of tasks
|
|
"""
|
|
pass
|
|
|
|
def post_install_with_tasks(self):
|
|
"""Execute post installation steps.
|
|
|
|
:return: list of tasks
|
|
"""
|
|
return []
|
|
|
|
def set_up_sources_with_task(self):
|
|
"""Set up installation sources."""
|
|
return SetUpSourcesTask(self.sources)
|
|
|
|
def tear_down_sources_with_task(self):
|
|
"""Tear down installation sources."""
|
|
return TearDownSourcesTask(self.sources)
|
|
|
|
def tear_down_with_tasks(self):
|
|
"""Returns teardown tasks for this payload.
|
|
|
|
Clean up everything after this payload.
|
|
|
|
:return: a list of tasks
|
|
"""
|
|
tasks = []
|
|
|
|
if self.sources:
|
|
tasks.append(self.tear_down_sources_with_task())
|
|
|
|
return tasks
|