kiwi-el8/kiwi/container/setup/base.py
Igor Raits 1f547d6bb9
Stop copying /dev files statically into the OCI container
In containers (nspawn) where part of the /dev filesystem is bind-mounted
from outside system, kiwi fails to do the rsync (in creation of the
nodes).

There is no reason to actually copy whole tree inside so let's just
not do it (as it does not seem to be needed at all).
2022-10-22 08:09:46 +02:00

176 lines
5.3 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 collections
import os
# project
from kiwi.command import Command
from kiwi.exceptions import (
KiwiContainerSetupError
)
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)
def post_init(self, custom_args):
"""
Post initialization method
Implementation in specialized container setup class
:param list custom_args: unused
"""
pass
def setup(self):
"""
Setup container metadata
Implementation in specialized bootloader class required
"""
raise NotImplementedError
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"'
}
)
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"'
}
)
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:
Command.run(
['ln', '-s', '-f', '/dev/null', service_file]
)
except Exception as e:
raise KiwiContainerSetupError(
'Failed to deactivate service %s: %s' %
(name, format(e))
)
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'
}
)
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 = config.read().rsplit('\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))