kiwi-el8/kiwi/boot/image/base.py
2016-10-14 08:31:41 +02:00

283 lines
8.7 KiB
Python

# Copyright (c) 2015 SUSE Linux GmbH. All rights reserved.
#
# This file is part of kiwi.
#
# kiwi 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 3 of the License, or
# (at your option) any later version.
#
# kiwi 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 kiwi. If not, see <http://www.gnu.org/licenses/>
#
import os
import platform
import pickle
from tempfile import mkdtemp
# project
from ...defaults import Defaults
from ...xml_description import XMLDescription
from ...xml_state import XMLState
from ...logger import log
from ...path import Path
from ...exceptions import (
KiwiTargetDirectoryNotFound,
KiwiConfigFileNotFound,
KiwiBootImageDumpError
)
class BootImageBase(object):
"""
Base class for boot image(initrd) task
Attributes
* :attr:`xml_state`
Instance of XMLState of the system image description
* :attr:`target_dir`
target dir to store the initrd
* :attr:`initrd_filename`
initrd file name
* :attr:`temp_boot_root_directory`
temporary directory to create the initrd system
* :attr:`boot_xml_state`
Instance of XMLState of the boot image description
"""
def __init__(self, xml_state, target_dir, root_dir=None):
self.xml_state = xml_state
self.target_dir = target_dir
self.initrd_filename = None
self.boot_xml_state = None
self.setup = None
self.temp_directories = []
self.call_destructor = True
self.boot_root_directory = root_dir
if not self.boot_root_directory:
self.boot_root_directory = mkdtemp(
prefix='kiwi_boot_root.', dir=self.target_dir
)
self.temp_directories.append(
self.boot_root_directory
)
if not os.path.exists(target_dir):
raise KiwiTargetDirectoryNotFound(
'target directory %s not found' % target_dir
)
self.initrd_file_name = ''.join(
[
self.target_dir, '/',
self.xml_state.xml_data.get_name(),
'.' + platform.machine(),
'-' + self.xml_state.get_image_version(),
'.initrd'
]
)
def dump(self, filename):
"""
Pickle dump this instance to a file. If the object dump
is requested the destructor code will also be disabled
in order to preserve the generated data
:param string filename: file path name
"""
try:
with open(filename, 'wb') as boot_image:
pickle.dump(self, boot_image)
self.disable_cleanup()
except Exception as e:
raise KiwiBootImageDumpError(
'Failed to pickle dump boot image: %s' % format(e)
)
def disable_cleanup(self):
self.call_destructor = False
def enable_cleanup(self):
self.call_destructor = True
def prepare(self):
"""
Prepare new root system to create initrd from. Implementation
is only needed if there is no other root system available
"""
raise NotImplementedError
def create_initrd(self, mbrid=None):
"""
Implements creation of the initrd
:param object mbrid: instance of ImageIdentifier
"""
raise NotImplementedError
def is_prepared(self):
"""
Check if initrd system is prepared
:return: initrd system preparation status
:rtype: bool
"""
return os.listdir(self.boot_root_directory)
def load_boot_xml_description(self):
"""
Load the boot image description referenced by the system image
description boot attribute
"""
log.info('Loading Boot XML description')
boot_description_directory = self.get_boot_description_directory()
boot_config_file = boot_description_directory + '/config.xml'
if not os.path.exists(boot_config_file):
raise KiwiConfigFileNotFound(
'no Boot XML description found in %s' %
boot_description_directory
)
boot_description = XMLDescription(
description=boot_config_file,
derived_from=self.xml_state.xml_data.description_dir
)
boot_image_profile = self.xml_state.build_type.get_bootprofile()
if not boot_image_profile:
boot_image_profile = 'default'
boot_kernel_profile = self.xml_state.build_type.get_bootkernel()
if not boot_kernel_profile:
boot_kernel_profile = 'std'
self.boot_xml_state = XMLState(
boot_description.load(), [boot_image_profile, boot_kernel_profile]
)
log.info('--> loaded %s', boot_config_file)
if self.boot_xml_state.build_type:
log.info(
'--> Selected build type: %s',
self.boot_xml_state.get_build_type_name()
)
if self.boot_xml_state.profiles:
log.info(
'--> Selected boot profiles: image: %s, kernel: %s',
boot_image_profile, boot_kernel_profile
)
def import_system_description_elements(self):
"""
Copy information from the system image relevant to create the
boot image to the boot image state XML description
"""
self.xml_state.copy_displayname(
self.boot_xml_state
)
self.xml_state.copy_name(
self.boot_xml_state
)
self.xml_state.copy_repository_sections(
target_state=self.boot_xml_state,
wipe=True
)
self.xml_state.copy_drivers_sections(
self.boot_xml_state
)
strip_description = XMLDescription(
Defaults.get_boot_image_strip_file()
)
strip_xml_state = XMLState(strip_description.load())
strip_xml_state.copy_strip_sections(
self.boot_xml_state
)
preferences_subsection_names = [
'bootloader_theme',
'bootsplash_theme',
'locale',
'packagemanager',
'rpm_check_signatures',
'rpm_excludedocs',
'showlicense'
]
self.xml_state.copy_preferences_subsections(
preferences_subsection_names, self.boot_xml_state
)
self.xml_state.copy_bootincluded_packages(
self.boot_xml_state
)
self.xml_state.copy_bootincluded_archives(
self.boot_xml_state
)
self.xml_state.copy_bootdelete_packages(
self.boot_xml_state
)
type_attributes = [
'bootkernel',
'bootloader',
'bootloader_console',
'bootprofile',
'boottimeout',
'btrfs_root_is_snapshot',
'gpt_hybrid_mbr',
'devicepersistency',
'filesystem',
'firmware',
'fsmountoptions',
'hybrid',
'hybridpersistent',
'hybridpersistent_filesystem',
'initrd_system',
'installboot',
'installprovidefailsafe',
'kernelcmdline',
'ramonly',
'target_removable',
'vga',
'wwid_wait_timeout'
]
self.xml_state.copy_build_type_attributes(
type_attributes, self.boot_xml_state
)
self.xml_state.copy_systemdisk_section(
self.boot_xml_state
)
self.xml_state.copy_machine_section(
self.boot_xml_state
)
self.xml_state.copy_oemconfig_section(
self.boot_xml_state
)
def get_boot_description_directory(self):
"""
Provide path to the boot image XML description
:return: path name
:rtype: string
"""
boot_description = self.xml_state.build_type.get_boot()
if boot_description:
if not boot_description[0] == '/':
boot_description = \
Defaults.get_boot_image_description_path() + '/' + \
boot_description
return boot_description
def __del__(self):
if self.call_destructor:
log.info('Cleaning up %s instance', type(self).__name__)
for directory in self.temp_directories:
if directory and os.path.exists(directory):
Path.wipe(directory)