kiwi-el8/kiwi/system/root_import/base.py
Marcus Schäfer d4d39e481a
Drop insecure and unsupported md5 digest
Decommission the Checksum.md5() method and move all places
in code to sha256(). The md5 digest is considered insecure
and has also been removed from hashlib as a supported digest.
This Fixes #2696
2024-12-19 11:26:07 +01:00

190 lines
6.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 logging
import pathlib
from typing import (
Dict, List, Optional
)
# project
from kiwi.xml_state import XMLState
from kiwi.defaults import Defaults
from kiwi.system.setup import SystemSetup
from kiwi.path import Path
from kiwi.system.uri import Uri
from kiwi.command import Command
from kiwi.mount_manager import MountManager
from kiwi.utils.checksum import Checksum
from kiwi.exceptions import (
KiwiRootImportError,
KiwiUriTypeUnknown
)
log = logging.getLogger('kiwi')
class RootImportBase:
"""
Imports the root system from an already packed image.
* :attr:`root_dir`
root directory path name
* :attr:`image_uris`
Uri object(s) to store source location(s)
* :attr:`custom_args`
Dictonary to set specialized class specific configuration values
"""
def __init__(
self, root_dir: str, image_uris: List[Uri],
custom_args: Dict[str, str] = {}
):
self.raw_urls: List[str] = []
self.image_files: List[str] = []
self.overlay: Optional[MountManager] = None
self.root_dir = root_dir
for image_uri in image_uris:
try:
if image_uri.is_remote():
raise KiwiRootImportError(
'Only local imports are supported'
)
image_file = image_uri.translate()
self.image_files.append(image_file)
if not os.path.exists(image_file):
raise KiwiRootImportError(
f'Could not stat base image file: {image_file}'
)
except KiwiUriTypeUnknown:
# Let specialized class handle unknown uri schemes
raw_url = image_uri.uri
log.warning(
f'Unkown URI type for the base image: {raw_url}'
)
self.raw_urls.append(raw_url)
self.post_init(custom_args)
def post_init(self, custom_args):
"""
Initialization of the specialized import class
Implementation in specialized root import class
"""
pass
def overlay_finalize(self, xml_state: XMLState) -> None:
"""
Umount the overlay root, delete lower and work directories
and move the upper (delta) to represent the final root_dir.
All files that got deleted will be reported in a metadata
file named Defaults.get_removed_files_name(). This information
can be used by other tools to know about actively deleted
files and bring them back at a later point in time.
:param XMLState xml_state: Instance of XML state
"""
if self.overlay:
pinch_reference = f'{self.root_dir}_cow_before_pinch'
removed = f'{self.root_dir}/{Defaults.get_removed_files_name()}'
systemfiles = f'{self.root_dir}/{Defaults.get_system_files_name()}'
system = SystemSetup(xml_state, self.root_dir)
# Run config-overlay.sh
system.call_config_overlay_script()
# Run config-host-overlay.sh
system.call_config_host_overlay_script(
working_directory=self.root_dir
)
# Include system files if requested
if xml_state.build_type.get_require_system_files():
with open(systemfiles, 'a') as systemfiles_fd:
# copy on write makes this file to become part of the delta
systemfiles_fd.write(os.linesep)
# Umount and rename upper to be the new root
self.overlay.umount()
Path.wipe(self.root_dir)
log.debug("renaming %s -> %s", self.overlay.upper, self.root_dir)
pathlib.Path(self.overlay.upper).replace(self.root_dir)
# Create removed files metadata
if not os.path.isdir(pinch_reference):
Path.create(pinch_reference)
exclude_options = []
removed_files = []
for item in Defaults.get_exclude_list_for_removed_files_detection():
exclude_options.append('--exclude')
exclude_options.append(item)
get_removed = [
'rsync', '-av', '--dry-run', '--out-format=%n'
] + exclude_options + [
f'{pinch_reference}/', f'{self.root_dir}/'
]
for item in Command.run(get_removed).output.split(os.linesep):
entry = f'{pinch_reference}/{item}'
if item and os.path.exists(entry) and not os.path.isdir(entry):
removed_files.append(item)
Path.wipe(pinch_reference)
if removed_files:
with open(removed, 'w') as removed_fd:
for filename in removed_files:
removed_fd.write(filename)
removed_fd.write(os.linesep)
# delete character device nodes from delta tree.
# (c) device nodes are used to track deleted files
# and directories from the lower path of the overlayfs
# tree. Since we extract the upper path of the overlay
# any changes to the lower tree cannot be tracked.
Command.run(
[
'find', self.root_dir, '-type', 'c', '-delete'
]
)
Path.wipe(self.overlay.lower)
Path.wipe(self.overlay.work)
def overlay_data(self):
"""
Synchronize data from the given base image to the target root
directory as an overlayfs mounted target.
Implementation in specialized root import class
"""
raise NotImplementedError
def sync_data(self):
"""
Synchronizes the root system of `image_file` into the root_dir
Implementation in specialized root import class
"""
raise NotImplementedError
def _make_checksum(self, image):
checksum = Checksum(image)
checksum.sha256(''.join([image, '.sha256']))