Source code for kiwi.container.setup.base

# 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
# 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 <>
import collections
import os

# project
from kiwi.command import Command
from kiwi.utils.sync import DataSync

from kiwi.exceptions import (

[docs]class ContainerSetupBase: """ Base class for setting up the root system to create a container image from for e.g docker. The methods here are generic to linux systems following the FHS standard and modern enough e.g based on systemd Attributes * :attr:`root_dir` root directory path name * :attr:`custom_args` dict of custom arguments """ def __init__(self, root_dir, custom_args=None): if not os.path.exists(root_dir): raise KiwiContainerSetupError( 'Container root directory %s does not exist' % root_dir ) self.root_dir = root_dir self.custom_args = custom_args or {} if 'container_name' not in self.custom_args: self.custom_args['container_name'] = 'system-container' self.post_init(custom_args)
[docs] def post_init(self, custom_args): """ Post initialization method Implementation in specialized container setup class :param list custom_args: unused """ pass
[docs] def setup(self): """ Setup container metadata Implementation in specialized bootloader class required """ raise NotImplementedError
[docs] def deactivate_bootloader_setup(self): """ Container bootloader setup Tell the system there is no bootloader configuration it needs to care for. A container does not boot """ bootloader_setup = self.root_dir + '/etc/sysconfig/bootloader' if os.path.exists(bootloader_setup): self._update_config( bootloader_setup, { 'LOADER_LOCATION': 'LOADER_LOCATION="none"', 'LOADER_TYPE': 'LOADER_TYPE="none"' } )
[docs] def deactivate_root_filesystem_check(self): """ Container filesystem check setup The root filesystem of a container could be an overlay or a mapped device. In any case it should not be checked for consistency as this is should be done by the container infrastructure """ boot_setup = self.root_dir + '/etc/sysconfig/boot' if os.path.exists(boot_setup): self._update_config( boot_setup, { 'ROOTFS_BLKDEV': 'ROOTFS_BLKDEV="/dev/null"' } )
[docs] def deactivate_systemd_service(self, name): """ Container system services setup Init systems among others also controls services which starts at boot time. A container does not really boot. Thus some services needs to be deactivated :param string name: systemd service name """ service_file = self.root_dir + '/usr/lib/systemd/system/' + name if os.path.exists(service_file): try: ['ln', '-s', '-f', '/dev/null', service_file] ) except Exception as e: raise KiwiContainerSetupError( 'Failed to deactivate service %s: %s' % (name, format(e)) )
[docs] def setup_root_console(self): """ Container console setup /dev/console should be allowed to login by root """ securetty = self.root_dir + '/etc/securetty' if not os.path.exists(securetty): with open(securetty, 'w'): pass self._update_config( securetty, { 'console': 'console' } )
[docs] def setup_static_device_nodes(self): """ Container device node setup Without subsystems like udev running in a container it is required to provide a set of device nodes to let the system in the container function correctly. This is done by syncing the host system nodes to the container. That this will also create device nodes which are not necessarily present in the container later is a know limitation of this method and considered harmless """ try: data = DataSync('/dev/', self.root_dir + '/dev/') data.sync_data( options=['-a', '-x', '--devices', '--specials'] ) except Exception as e: raise KiwiContainerSetupError( 'Failed to create static container nodes %s' % format(e) )
[docs] def get_container_name(self): """ Container name :return: name :rtype: str """ return self.custom_args['container_name']
def _update_config(self, filename, update_record): data = [] with open(filename, 'r') as config: data ='\n') sorted_record = collections.OrderedDict( sorted(update_record.items()) ) for current_value, new_value in list(sorted_record.items()): entry_found = False for index in range(0, len(data)): line = data[index] if line.startswith(current_value): entry_found = True data[index] = new_value if not entry_found: data.append(new_value) with open(filename, 'w') as config: config.write('%s\n' % '\n'.join(data))