Get rid of debootstrap

Replace debootstrap with an apt-get based pre-download of
packages followed by a dpkg-deb extraction.
This Fixes #2599
This commit is contained in:
Marcus Schäfer 2024-07-30 12:50:54 +02:00
parent 6be3fc5195
commit d149ab09db
No known key found for this signature in database
GPG Key ID: A16C1128698C8CAC
69 changed files with 234 additions and 416 deletions

View File

@ -208,10 +208,10 @@ class KiwiDataStructureError(KiwiError):
"""
class KiwiDebootstrapError(KiwiError):
class KiwiDebianBootstrapError(KiwiError):
"""
Exception raised if not enough user data to call debootstrap
were provided or the debootstrap has failed.
Exception raised if the bootstrap installation for Debian
based systems has failed
"""

View File

@ -30,11 +30,12 @@ from kiwi.path import Path
from kiwi.package_manager.base import PackageManagerBase
from kiwi.system.root_bind import RootBind
from kiwi.repository.apt import RepositoryApt
from kiwi.utils.temporary import Temporary
import kiwi.defaults as defaults
from kiwi.exceptions import (
KiwiDebootstrapError,
KiwiDebianBootstrapError,
KiwiRequestError,
KiwiFileNotFound
)
@ -131,12 +132,11 @@ class PackageManagerApt(PackageManagerBase):
) -> CommandCallT:
"""
Process package install requests for bootstrap phase (no chroot)
Either debootstrap or a prebuilt bootstrap package can be used
to bootstrap a new system.
Either a manual unpacking strategy or a prebuilt bootstrap
package can be used to bootstrap a new system.
:param object root_bind:
instance of RootBind to manage kernel file systems before
debootstrap call
unused
:param str bootstrap_package:
package name of a bootstrap package
@ -149,9 +149,7 @@ class PackageManagerApt(PackageManagerBase):
bootstrap_package
)
else:
return self._process_install_requests_bootstrap_debootstrap(
root_bind
)
return self._process_install_requests_bootstrap()
def _process_install_requests_bootstrap_prebuild_root(
self, bootstrap_package: str
@ -205,117 +203,78 @@ class PackageManagerApt(PackageManagerBase):
# Install eventual bootstrap packages as standard system install
return self.process_install_requests()
def _process_install_requests_bootstrap_debootstrap(
self, root_bind: RootBind = None
) -> CommandCallT:
def _process_install_requests_bootstrap(self) -> CommandCallT:
"""
Process package install requests for bootstrap phase (no chroot)
The debootstrap program is used to bootstrap a new system
Process package install requests for bootstrap phase (no chroot).
:param object root_bind: instance of RootBind to manage kernel
file systems before debootstrap call
:raises KiwiDebootstrapError: if no main distribution repository
is configured, if the debootstrap script is not found or if the
debootstrap script execution fails
:raises KiwiDebianBootstrapError
:return: process results in command type
:rtype: namedtuple
:rtype: CommandCallT
"""
if not self.distribution:
raise KiwiDebootstrapError(
'No main distribution repository is configured'
)
bootstrap_script = '/usr/share/debootstrap/scripts/' + \
self.distribution
if not os.path.exists(bootstrap_script):
raise KiwiDebootstrapError(
'debootstrap script for %s distribution not found' %
self.distribution
)
# APT package manager does not support bootstrapping. To circumvent
# this limitation there is the debootstrap tool for APT based distros.
# Because of that there is a little overlap between KIWI and
# debootstrap. Debootstrap manages itself the kernel file systems for
# chroot environment, thus we need to umount the kernel file systems
# before calling debootstrap and remount them afterwards.
if root_bind:
root_bind.umount_kernel_file_systems()
# debootsrap will create its own dev/fd devices
debootstrap_device_node_conflicts = [
'dev/fd',
'dev/pts'
]
for node in debootstrap_device_node_conflicts:
Path.wipe(os.path.normpath(os.sep.join([self.root_dir, node])))
if 'apt' in self.package_requests:
# debootstrap takes care to install apt
self.package_requests.remove('apt')
# we invoke apt-get install to download all the essential packages.
# With DPkg::Pre-Install-Pkgs, we specify a shell command that will
# receive the list of packages that will be installed on stdin.
# By configuring Debug::pkgDpkgPm=1, apt-get install will not
# actually execute any dpkg commands, so all it does is download
# the essential debs and tell us their full in the apt cache without
# actually installing them.
try:
cmd = ['debootstrap']
if self.repository.unauthenticated == 'false' and \
os.path.exists(self.repository.keyring):
cmd.append('--keyring={}'.format(self.repository.keyring))
else:
cmd.append('--no-check-gpg')
if self.deboostrap_minbase:
cmd.append('--variant=minbase')
if self.package_requests:
cmd.append(
'--include={}'.format(','.join(self.package_requests))
)
if self.repository.components:
cmd.append(
'--components={0}'.format(
','.join(self.repository.components)
if 'apt' not in self.package_requests:
self.package_requests.append('apt')
update_cache = [
'apt-get'
] + self.apt_get_args + self.custom_args + [
'update'
]
result = Command.run(
update_cache, self.command_env
)
log.debug(
'Apt update: {0} {1}'.format(result.output, result.error)
)
package_names = Temporary(prefix='kiwi_debs_').new_file()
package_extract = Temporary(prefix='kiwi_bootstrap_').new_file()
download_bootstrap = [
'apt-get'
] + self.apt_get_args + self.custom_args + [
'install',
'-oDebug::pkgDPkgPm=1',
f'-oDPkg::Pre-Install-Pkgs::=cat >{package_names.name}',
'?essential',
'?exact-name(usr-is-merged)'
] + self.package_requests
result = Command.run(
download_bootstrap, self.command_env
)
log.debug(
'Apt download: {0} {1}'.format(result.output, result.error)
)
with open(package_extract.name, 'w') as install:
install.write(
'while read -r deb;do echo "{0}";{1}|{2};done <{3}'.format(
'Unpacking $deb',
'dpkg-deb --fsys-tarfile $deb',
f'tar -C {self.root_dir} -x',
package_names.name
)
)
self.cleanup_requests()
cmd.extend(
[self.distribution, self.root_dir, self.distribution_path]
result = Command.run(
['bash', package_extract.name], self.command_env
)
log.debug(
'Apt extract: {0} {1}'.format(result.output, result.error)
)
self.cleanup_requests()
return Command.call(
update_cache, self.command_env
)
return Command.call(cmd, self.command_env)
except Exception as e:
raise KiwiDebootstrapError(
raise KiwiDebianBootstrapError(
'%s: %s' % (type(e).__name__, format(e))
)
def get_error_details(self) -> str:
"""
Provide further error details
Read the debootstrap log if available
:rtype: str
"""
debootstrap_log_file = os.path.join(
self.root_dir, 'debootstrap/debootstrap.log'
)
if os.path.exists(debootstrap_log_file):
with open(debootstrap_log_file) as log_fd:
return log_fd.read() or 'logfile is empty'
return f'logfile {debootstrap_log_file!r} does not exist'
def post_process_install_requests_bootstrap(
self, root_bind: RootBind = None, delta_root: bool = False
) -> None:
"""
Mounts the kernel file systems to the chroot environment is
ready after the bootstrap procedure
:param object root_bind:
instance of RootBind to manage kernel file systems
:param bool delta_root:
root is derived from a base system
"""
if root_bind:
root_bind.mount_kernel_file_systems(delta_root)
def process_install_requests(self) -> CommandCallT:
"""
Process package install requests for image phase (chroot)

View File

@ -72,7 +72,6 @@ class RepositoryApt(RepositoryBase):
self.distribution: str = ''
self.distribution_path: str = ''
self.debootstrap_repo_set = False
self.repo_names: List = []
self.components: List = []
@ -139,8 +138,7 @@ class RepositoryApt(RepositoryBase):
prio: int = None, dist: str = None, components: str = None,
user: str = None, secret: str = None, credentials_file: str = None,
repo_gpgcheck: bool = None, pkg_gpgcheck: bool = None,
sourcetype: str = None, use_for_bootstrap: bool = False,
customization_script: str = None
sourcetype: str = None, customization_script: str = None
) -> None:
"""
Add apt_get repository
@ -157,8 +155,6 @@ class RepositoryApt(RepositoryBase):
:param bool repo_gpgcheck: enable repository signature validation
:param bool pkg_gpgcheck: unused
:param str sourcetype: unused
:param bool use_for_bootstrap: use this repository for the
debootstrap call
:param str customization_script:
custom script called after the repo file was created
"""
@ -190,10 +186,8 @@ class RepositoryApt(RepositoryBase):
else:
# create a debian distributon repository setup for the
# specified distributon name and components
if not self.debootstrap_repo_set:
self.distribution = dist
self.distribution_path = uri
self.debootstrap_repo_set = use_for_bootstrap
self.distribution = dist
self.distribution_path = uri
repo_details += 'Suites: ' + dist + os.linesep
repo_details += 'Components: ' + components + os.linesep
if repo_gpgcheck is False:

View File

@ -77,7 +77,7 @@ class RepositoryBase:
self, name: str, uri: str, repo_type: str, prio: int, dist: str,
components: str, user: str, secret: str, credentials_file: str,
repo_gpgcheck: bool, pkg_gpgcheck: bool, sourcetype: str,
use_for_bootstrap: bool = False, customization_script: str = None
customization_script: str = None
) -> None:
"""
Add repository
@ -96,7 +96,6 @@ class RepositoryBase:
:param bool repo_gpgcheck: unused
:param bool pkg_gpgcheck: unused
:param str sourcetype: unused
:param bool use_for_bootstrap: unused
:param str customization_script: unused
"""
raise NotImplementedError

View File

@ -51,8 +51,7 @@ class RepositoryDnf(RepositoryBase):
prio: int = None, dist: str = None, components: str = None,
user: str = None, secret: str = None, credentials_file: str = None,
repo_gpgcheck: bool = False, pkg_gpgcheck: bool = False,
sourcetype: str = None, use_for_bootstrap: bool = False,
customization_script: str = None
sourcetype: str = None, customization_script: str = None
) -> None:
pass # pragma: no cover

View File

@ -192,8 +192,7 @@ class RepositoryDnf4(RepositoryBase):
prio: int = None, dist: str = None, components: str = None,
user: str = None, secret: str = None, credentials_file: str = None,
repo_gpgcheck: bool = False, pkg_gpgcheck: bool = False,
sourcetype: str = None, use_for_bootstrap: bool = False,
customization_script: str = None
sourcetype: str = None, customization_script: str = None
) -> None:
"""
Add dnf repository
@ -211,7 +210,6 @@ class RepositoryDnf4(RepositoryBase):
:param bool pkg_gpgcheck: enable package signature validation
:param str sourcetype:
source type, one of 'baseurl', 'metalink' or 'mirrorlist'
:param bool use_for_bootstrap: unused
:param str customization_script:
custom script called after the repo file was created
"""

View File

@ -192,8 +192,7 @@ class RepositoryDnf5(RepositoryBase):
prio: int = None, dist: str = None, components: str = None,
user: str = None, secret: str = None, credentials_file: str = None,
repo_gpgcheck: bool = False, pkg_gpgcheck: bool = False,
sourcetype: str = None, use_for_bootstrap: bool = False,
customization_script: str = None
sourcetype: str = None, customization_script: str = None
) -> None:
"""
Add dnf repository
@ -211,7 +210,6 @@ class RepositoryDnf5(RepositoryBase):
:param bool pkg_gpgcheck: enable package signature validation
:param str sourcetype:
source type, one of 'baseurl', 'metalink' or 'mirrorlist'
:param bool use_for_bootstrap: unused
:param str customization_script:
custom script called after the repo file was created
"""

View File

@ -115,8 +115,7 @@ class RepositoryPacman(RepositoryBase):
prio: int = None, dist: str = None, components: str = None,
user: str = None, secret: str = None, credentials_file: str = None,
repo_gpgcheck: bool = False, pkg_gpgcheck: bool = False,
sourcetype: str = None, use_for_bootstrap: bool = False,
customization_script: str = None
sourcetype: str = None, customization_script: str = None
) -> None:
"""
Add pacman repository
@ -133,7 +132,6 @@ class RepositoryPacman(RepositoryBase):
:param bool repo_gpgcheck: enable database signature validation
:param bool pkg_gpgcheck: enable package signature validation
:param str sourcetype: unused
:param bool use_for_bootstrap: unused
:param str customization_script:
custom script called after the repo file was created
"""

View File

@ -29,6 +29,7 @@ class PackageManagerTemplateAptGet:
# kiwi generated apt-get config file
Dir "/";
Dir::State "${apt_shared_base}/";
Dir::State::status "/var/lib/dpkg/status.kiwi";
Dir::Cache "${apt_shared_base}/";
Dir::Etc "${apt_shared_base}/";
''').strip() + os.linesep

View File

@ -252,8 +252,7 @@ class RepositoryZypper(RepositoryBase):
prio: int = None, dist: str = None, components: str = None,
user: str = None, secret: str = None, credentials_file: str = None,
repo_gpgcheck: bool = False, pkg_gpgcheck: bool = False,
sourcetype: str = None, use_for_bootstrap: bool = False,
customization_script: str = None
sourcetype: str = None, customization_script: str = None
) -> None:
"""
Add zypper repository
@ -270,7 +269,6 @@ class RepositoryZypper(RepositoryBase):
:param bool repo_gpgcheck: enable repository signature validation
:param bool pkg_gpgcheck: enable package signature validation
:param str sourcetype: unused
:param boot use_for_bootstrap: unused
:param str customization_script:
custom script called after the repo file was created
"""

View File

@ -66,7 +66,7 @@ div {
attribute xsi:schemaLocation { xsd:anyURI }
k.image.schemaversion.attribute =
## The allowed Schema version (fixed value)
attribute schemaversion { "8.1" }
attribute schemaversion { "8.2" }
k.image.id =
## An identification number which is represented in a file
## named /etc/ImageID
@ -1135,25 +1135,6 @@ div {
attribute sourcetype {
"baseurl" | "metalink" | "mirrorlist"
}
k.repository.use_for_bootstrap.attribute =
## Specify whether this repository should be the one used for
## bootstrapping or not. False by default. Only a single repository
## is allowed to be used for bootstrapping. If none is set the
## last one is picked.
attribute use_for_bootstrap { xsd:boolean }
>> sch:pattern [ id = "use_for_bootstrap" is-a = "repo_type"
sch:param [ name = "attr" value = "use_for_bootstrap" ]
sch:param [ name = "types" value = "apt-deb" ]
]
>> sch:pattern [ id = "single_deboostrap_repo"
sch:rule [ context = "image"
sch:assert [
test = "count(repository[@use_for_bootstrap='true'])<=1"
"There can only be a single repository set for "
"bootstrap ('use_for_bootstrap' attribute)"
]
]
]
k.repository.attlist =
k.repository.type.attribute? &
k.repository.profiles.attribute? &
@ -1171,8 +1152,7 @@ div {
k.repository.package_gpgcheck.attribute? &
k.repository.priority.attribute? &
k.repository.password.attribute? &
k.repository.username.attribute? &
k.repository.use_for_bootstrap.attribute?
k.repository.username.attribute?
k.repository =
## The Name of the Repository
element repository {
@ -3545,7 +3525,7 @@ div {
## The tarball will be unpacked and used as the bootstrap
## rootfs to begin with. The feature is currently only
## available with the apt package manager to allow an
## alternative bootstrap method for debootstrap
## alternative bootstrap method
attribute bootstrap_package { text }
>> sch:pattern [ id = "bootstrap_package" is-a = "packages_type"
sch:param [ name = "attr" value = "bootstrap_package" ]

View File

@ -150,7 +150,7 @@ second the location of the XSD Schema
<define name="k.image.schemaversion.attribute">
<attribute name="schemaversion">
<a:documentation>The allowed Schema version (fixed value)</a:documentation>
<value>8.1</value>
<value>8.2</value>
</attribute>
</define>
<define name="k.image.id">
@ -1728,24 +1728,6 @@ be a simple repository url</a:documentation>
</choice>
</attribute>
</define>
<define name="k.repository.use_for_bootstrap.attribute">
<attribute name="use_for_bootstrap">
<a:documentation>Specify whether this repository should be the one used for
bootstrapping or not. False by default. Only a single repository
is allowed to be used for bootstrapping. If none is set the
last one is picked.</a:documentation>
<data type="boolean"/>
</attribute>
<sch:pattern id="use_for_bootstrap" is-a="repo_type">
<sch:param name="attr" value="use_for_bootstrap"/>
<sch:param name="types" value="apt-deb"/>
</sch:pattern>
<sch:pattern id="single_deboostrap_repo">
<sch:rule context="image">
<sch:assert test="count(repository[@use_for_bootstrap='true'])&lt;=1">There can only be a single repository set for bootstrap ('use_for_bootstrap' attribute)</sch:assert>
</sch:rule>
</sch:pattern>
</define>
<define name="k.repository.attlist">
<interleave>
<optional>
@ -1793,9 +1775,6 @@ last one is picked.</a:documentation>
<optional>
<ref name="k.repository.username.attribute"/>
</optional>
<optional>
<ref name="k.repository.use_for_bootstrap.attribute"/>
</optional>
</interleave>
</define>
<define name="k.repository">
@ -5354,7 +5333,7 @@ in /var/cache/kiwi/bootstrap/PACKAGE_NAME.ARCH.tar.xz
The tarball will be unpacked and used as the bootstrap
rootfs to begin with. The feature is currently only
available with the apt package manager to allow an
alternative bootstrap method for debootstrap</a:documentation>
alternative bootstrap method</a:documentation>
</attribute>
<sch:pattern id="bootstrap_package" is-a="packages_type">
<sch:param name="attr" value="bootstrap_package"/>

View File

@ -170,8 +170,6 @@ class SystemPrepare:
xml_repo
)
repo_sourcetype = xml_repo.get_sourcetype()
repo_use_for_bootstrap = \
True if xml_repo.get_use_for_bootstrap() else False
log.info(
'Setting up repository %s', Uri.print_sensitive(repo_source)
)
@ -211,8 +209,7 @@ class SystemPrepare:
repo_type, repo_priority, repo_dist, repo_components,
repo_user, repo_secret, uri.credentials_file_name(),
repo_repository_gpgcheck, repo_package_gpgcheck,
repo_sourcetype, repo_use_for_bootstrap,
repo_customization_script
repo_sourcetype, repo_customization_script
)
if clear_cache:
repo.delete_repo_cache(repo_alias)

View File

@ -161,7 +161,6 @@ class SystemSetup:
xml_repo
)
repo_sourcetype = xml_repo.get_sourcetype()
repo_use_for_bootstrap = False
uri = Uri(repo_source, repo_type)
repo_source_translated = uri.translate(
check_build_environment=False
@ -185,8 +184,7 @@ class SystemSetup:
repo_type, repo_priority, repo_dist, repo_components,
repo_user, repo_secret, uri.credentials_file_name(),
repo_repository_gpgcheck, repo_package_gpgcheck,
repo_sourcetype, repo_use_for_bootstrap,
repo_customization_script
repo_sourcetype, repo_customization_script
)
def import_cdroot_files(self, target_dir: str) -> None:

View File

@ -128,9 +128,6 @@ from kiwi.system.prepare import SystemPrepare
from kiwi.system.setup import SystemSetup
from kiwi.defaults import Defaults
from kiwi.system.profile import Profile
from kiwi.command import Command
from kiwi.exceptions import KiwiCommandError
log = logging.getLogger('kiwi')
@ -252,29 +249,9 @@ class SystemPrepareTask(CliTask):
] + self.xml_state.get_repositories_signing_keys(),
self.global_args['--target-arch']
) as manager:
run_bootstrap = True
if self.xml_state.get_package_manager() == 'apt' and \
self.command_args['--allow-existing-root']:
# try to call apt-get inside of the existing root.
# If the call succeeds we skip calling debootstrap again
# and assume the root to be ok to proceed with apt-get
# if it fails, treat the root as dirty and give the
# bootstrap a try
try:
Command.run(
['chroot', abs_root_path, 'apt-get', '--version']
)
run_bootstrap = False
log.warning(
'debootstrap will only be called once, skipped'
)
except KiwiCommandError:
run_bootstrap = True
if run_bootstrap:
system.install_bootstrap(
manager, self.command_args['--add-bootstrap-package']
)
system.install_bootstrap(
manager, self.command_args['--add-bootstrap-package']
)
setup = SystemSetup(
self.xml_state, abs_root_path

View File

@ -2442,7 +2442,7 @@ class repository(k_source):
"""The Name of the Repository"""
subclass = None
superclass = k_source
def __init__(self, source=None, type_=None, profiles=None, arch=None, alias=None, sourcetype=None, components=None, distribution=None, imageinclude=None, imageonly=None, repository_gpgcheck=None, customize=None, package_gpgcheck=None, priority=None, password=None, username=None, use_for_bootstrap=None):
def __init__(self, source=None, type_=None, profiles=None, arch=None, alias=None, sourcetype=None, components=None, distribution=None, imageinclude=None, imageonly=None, repository_gpgcheck=None, customize=None, package_gpgcheck=None, priority=None, password=None, username=None):
self.original_tagname_ = None
super(repository, self).__init__(source, )
self.type_ = _cast(None, type_)
@ -2460,7 +2460,6 @@ class repository(k_source):
self.priority = _cast(int, priority)
self.password = _cast(None, password)
self.username = _cast(None, username)
self.use_for_bootstrap = _cast(bool, use_for_bootstrap)
def factory(*args_, **kwargs_):
if CurrentSubclassModule_ is not None:
subclass = getSubclassFromModule_(
@ -2502,8 +2501,6 @@ class repository(k_source):
def set_password(self, password): self.password = password
def get_username(self): return self.username
def set_username(self, username): self.username = username
def get_use_for_bootstrap(self): return self.use_for_bootstrap
def set_use_for_bootstrap(self, use_for_bootstrap): self.use_for_bootstrap = use_for_bootstrap
def validate_arch_name(self, value):
# Validate type arch-name, a restriction on xs:token.
if value is not None and Validate_simpletypes_:
@ -2593,9 +2590,6 @@ class repository(k_source):
if self.username is not None and 'username' not in already_processed:
already_processed.add('username')
outfile.write(' username=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.username), input_name='username')), ))
if self.use_for_bootstrap is not None and 'use_for_bootstrap' not in already_processed:
already_processed.add('use_for_bootstrap')
outfile.write(' use_for_bootstrap="%s"' % self.gds_format_boolean(self.use_for_bootstrap, input_name='use_for_bootstrap'))
def exportChildren(self, outfile, level, namespaceprefix_='', name_='repository', fromsubclass_=False, pretty_print=True):
super(repository, self).exportChildren(outfile, level, namespaceprefix_, name_, True, pretty_print=pretty_print)
def build(self, node):
@ -2695,15 +2689,6 @@ class repository(k_source):
if value is not None and 'username' not in already_processed:
already_processed.add('username')
self.username = value
value = find_attr_value_('use_for_bootstrap', node)
if value is not None and 'use_for_bootstrap' not in already_processed:
already_processed.add('use_for_bootstrap')
if value in ('true', '1'):
self.use_for_bootstrap = True
elif value in ('false', '0'):
self.use_for_bootstrap = False
else:
raise_parse_error(node, 'Bad boolean attribute')
super(repository, self).buildAttributes(node, attrs, already_processed)
def buildChildren(self, child_, node, nodeName_, fromsubclass_=False):
super(repository, self).buildChildren(child_, node, nodeName_, True)

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"
indent="yes" omit-xml-declaration="no" encoding="utf-8"/>
<!-- default rule -->
<xsl:template match="*" mode="conv81to82">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates mode="conv81to82"/>
</xsl:copy>
</xsl:template>
<!-- version update -->
<para xmlns="http://docbook.org/ns/docbook">
Changed attribute <tag class="attribute">schemaversion</tag>
to <tag class="attribute">schemaversion</tag> from
<literal>8.1</literal> to <literal>8.2</literal>.
</para>
<xsl:template match="image" mode="conv81to82">
<xsl:choose>
<!-- nothing to do if already at 8.2 -->
<xsl:when test="@schemaversion > 8.1">
<xsl:copy-of select="/"/>
</xsl:when>
<!-- otherwise apply templates -->
<xsl:otherwise>
<image schemaversion="8.2">
<xsl:copy-of select="@*[local-name() != 'schemaversion']"/>
<xsl:apply-templates mode="conv81to82"/>
</image>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- delete use_for_bootstrap attribute from repository -->
<para xmlns="http://docbook.org/ns/docbook">
Delete obsolete use_for_bootstrap attribute from repository
</para>
<xsl:template match="repository" mode="conv81to82">
<repository>
<xsl:copy-of select="@*[not(local-name(.) = 'use_for_bootstrap')]"/>
<xsl:apply-templates mode="conv81to82"/>
</repository>
</xsl:template>
</xsl:stylesheet>

View File

@ -10,6 +10,7 @@
<xsl:import href="convert75to76.xsl"/>
<xsl:import href="convert76to80.xsl"/>
<xsl:import href="convert80to81.xsl"/>
<xsl:import href="convert81to82.xsl"/>
<xsl:import href="pretty.xsl"/>
<xsl:output encoding="utf-8"/>
@ -35,8 +36,12 @@
<xsl:apply-templates select="exslt:node-set($v80)" mode="conv80to81"/>
</xsl:variable>
<xsl:variable name="v82">
<xsl:apply-templates select="exslt:node-set($v81)" mode="conv81to82"/>
</xsl:variable>
<xsl:apply-templates
select="exslt:node-set($v81)" mode="pretty"
select="exslt:node-set($v82)" mode="pretty"
/>
</xsl:template>

View File

@ -125,13 +125,11 @@ Provides: kiwi-image:tbz
# tools conditionally used by kiwi
%if 0%{?fedora} || 0%{?rhel} >= 8
Recommends: gnupg2
Recommends: debootstrap
Recommends: apt
Recommends: dpkg
%endif
%if 0%{?suse_version}
Recommends: gpg2
Recommends: debootstrap
Recommends: dpkg
%if 0%{?suse_version} >= 1650
Recommends: dnf
%endif
@ -158,7 +156,7 @@ Requires: zypper
Provides: kiwi-packagemanager:zypper
%endif
%if 0%{?debian} || 0%{?ubuntu}
Requires: debootstrap
Requires: apt
Requires: dpkg
Requires: gnupg
%endif

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS" displayname="Bob">
<image schemaversion="8.2" name="LimeJeOS" displayname="Bob">
<drivers>
<file name="crypto/*"/>
<file name="drivers/acpi/*"/>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS" displayname="Bob">
<image schemaversion="8.2" name="LimeJeOS" displayname="Bob">
<drivers>
<file name="crypto/*"/>
<file name="drivers/acpi/*"/>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="apt-testing">
<image schemaversion="8.2" name="apt-testing">
<description type="system">
<author>Bob</author>
<contact>user@example.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS" displayname="Bob">
<image schemaversion="8.2" name="LimeJeOS" displayname="Bob">
<drivers>
<file name="crypto/*"/>
<file name="drivers/acpi/*"/>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS" displayname="Bob">
<image schemaversion="8.2" name="LimeJeOS" displayname="Bob">
<drivers>
<file name="crypto/*"/>
<file name="drivers/acpi/*"/>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="TestPartitions">
<image schemaversion="8.2" name="TestPartitions">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="TestPartitions">
<image schemaversion="8.2" name="TestPartitions">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="JeOS">
<image schemaversion="8.2" name="JeOS">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2" displayname="schäfer">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2" displayname="schäfer">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LiveImage" displayname="Live">
<image schemaversion="8.2" name="LiveImage" displayname="Live">
<description type="system">
<author>Marcus Schäfer</author>
<contact>bob@example.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS">
<image schemaversion="8.2" name="LimeJeOS">
<description type="system">
<author>Marcus</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS">
<image schemaversion="8.2" name="LimeJeOS">
<description type="system">
<author>Marcus</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="JeOS">
<image schemaversion="8.2" name="JeOS">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="Some">
<image schemaversion="8.2" name="Some">
<description type="system">
<author>Marcus Schäfer</author>
<contact>some@some.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="custom-root-volume-setup">
<image schemaversion="8.2" name="custom-root-volume-setup">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2" displayname="Bob">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2" displayname="Bob">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="TestPartitions">
<image schemaversion="8.2" name="TestPartitions">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="JeOS">
<image schemaversion="8.2" name="JeOS">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS-openSUSE-13.2" displayname="Bob">
<image schemaversion="8.2" name="LimeJeOS-openSUSE-13.2" displayname="Bob">
<drivers>
<file name="crypto/*"/>
<file name="drivers/acpi/*"/>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="TypeConflict">
<image schemaversion="8.2" name="TypeConflict">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.de</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="JeOS">
<image schemaversion="8.2" name="JeOS">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="JeOS">
<image schemaversion="8.2" name="JeOS">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="JeOS">
<image schemaversion="8.2" name="JeOS">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="JeOS">
<image schemaversion="8.2" name="JeOS">
<description type="system">
<author>Marcus Schäfer</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS" displayname="Bob">
<image schemaversion="8.2" name="LimeJeOS" displayname="Bob">
<description type="system">
<author>Marcus</author>
<contact>ms@suse.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="initrd-isoboot-suse-13.2">
<image schemaversion="8.2" name="initrd-isoboot-suse-13.2">
<description type="boot">
<author>Marcus Schaefer</author>
<contact>ms@novell.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="initrd-isoboot-suse-13.2">
<image schemaversion="8.2" name="initrd-isoboot-suse-13.2">
<description type="boot">
<author>Marcus Schaefer</author>
<contact>ms@novell.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="initrd-oemboot-suse-13.2">
<image schemaversion="8.2" name="initrd-oemboot-suse-13.2">
<description type="boot">
<author>Marcus Schaefer</author>
<contact>ms@novell.com</contact>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="8.0" name="LimeJeOS" displayname="Bob">
<image schemaversion="8.2" name="LimeJeOS" displayname="Bob">
<drivers>
<file name="crypto/*"/>
<file name="drivers/acpi/*"/>

View File

@ -1,6 +1,7 @@
import logging
import io
from unittest.mock import (
patch, call, Mock
patch, call, Mock, MagicMock
)
from pytest import (
raises, fixture
@ -11,7 +12,7 @@ from kiwi.package_manager.apt import PackageManagerApt
import kiwi.defaults as defaults
from kiwi.exceptions import (
KiwiDebootstrapError,
KiwiDebianBootstrapError,
KiwiRequestError,
KiwiFileNotFound
)
@ -100,119 +101,55 @@ class TestPackageManagerApt:
bootstrap_package='bootstrap-package'
)
def test_process_install_requests_bootstrap_debootstrap_no_dist(self):
self.manager.distribution = None
with raises(KiwiDebootstrapError):
self.manager.process_install_requests_bootstrap()
@patch('os.path.exists')
def test_process_install_requests_bootstrap_debootstrap_no_script(
self, mock_exists
):
mock_exists.return_value = False
with raises(KiwiDebootstrapError):
self.manager.process_install_requests_bootstrap()
@patch('kiwi.command.Command.call')
@patch('kiwi.package_manager.apt.os.path.exists')
@patch('kiwi.package_manager.apt.Path.wipe')
def test_process_install_requests_bootstrap_debootstrap_failed(
self, mock_wipe, mock_exists, mock_call
@patch('kiwi.command.Command.run')
def test_process_install_requests_bootstrap_failed(
self, mock_Command_run, mock_Command_call
):
self.manager.request_package('apt')
mock_call.side_effect = Exception
mock_exists.return_value = True
mock_root_bind = Mock()
with raises(KiwiDebootstrapError):
self.manager.process_install_requests_bootstrap(mock_root_bind)
@patch('kiwi.package_manager.apt.os.path.exists')
def test_get_error_details(self, mock_exists):
mock_exists.return_value = True
with patch('builtins.open', create=True) as mock_open:
file_handle = mock_open.return_value.__enter__.return_value
file_handle.read.return_value = 'log-data'
assert self.manager.get_error_details() == \
file_handle.read.return_value
mock_open.assert_called_once_with(
'root-dir/debootstrap/debootstrap.log'
)
@patch('kiwi.package_manager.apt.os.path.exists')
def test_get_error_details_no_log_file(self, mock_exists):
mock_exists.return_value = False
assert self.manager.get_error_details() == \
"logfile 'root-dir/debootstrap/debootstrap.log' does not exist"
@patch('kiwi.package_manager.apt.os.path.exists')
def test_get_error_details_logfile_is_empty(self, mock_exists):
mock_exists.return_value = True
with patch('builtins.open', create=True) as mock_open:
file_handle = mock_open.return_value.__enter__.return_value
file_handle.read.return_value = ''
assert self.manager.get_error_details() == \
'logfile is empty'
mock_Command_call.side_effect = Exception
with patch('builtins.open', create=True):
with raises(KiwiDebianBootstrapError):
self.manager.process_install_requests_bootstrap()
@patch('kiwi.command.Command.run')
@patch('kiwi.command.Command.call')
@patch('kiwi.package_manager.apt.Path.wipe')
@patch('kiwi.package_manager.apt.os.path.exists')
def test_process_install_requests_bootstrap_debootstrap(
self, mock_exists, mock_wipe, mock_call
@patch('kiwi.package_manager.apt.Temporary.new_file')
def test_process_install_requests_bootstrap(
self, mock_Temporary_new_file, mock_Command_call, mock_Command_run
):
self.manager.request_package('apt')
mock_Temporary_new_file.return_value.name = 'temporary'
self.manager.request_package('vim')
call_result = Mock()
call_result.process.communicate.return_value = ('stdout', 'stderr')
mock_call.return_value = call_result
mock_root_bind = Mock()
mock_exists.return_value = True
self.manager.process_install_requests_bootstrap(mock_root_bind)
mock_call.assert_called_once_with(
[
'debootstrap', '--keyring=trusted.gpg',
'--variant=minbase', '--include=vim',
'--components=main,restricted', 'xenial',
'root-dir', 'xenial_path'
], ['env']
)
assert mock_wipe.call_args_list == [
call('root-dir/dev/fd'),
call('root-dir/dev/pts')
mock_Command_call.return_value = call_result
with patch('builtins.open', create=True) as mock_open:
mock_open.return_value = MagicMock(spec=io.IOBase)
file_handle = mock_open.return_value.__enter__.return_value
self.manager.process_install_requests_bootstrap()
file_handle.write.assert_called_once_with(
'while read -r deb;do echo "Unpacking $deb";dpkg-deb'
' --fsys-tarfile $deb|tar -C root-dir -x;done <temporary'
)
assert mock_Command_run.call_args_list == [
call(
['apt-get', '-c', 'apt.conf', '-y', 'update'], ['env']
),
call(
[
'apt-get', '-c', 'apt.conf', '-y', 'install',
'-oDebug::pkgDPkgPm=1',
'-oDPkg::Pre-Install-Pkgs::=cat >temporary',
'?essential',
'?exact-name(usr-is-merged)',
'vim',
'apt'
], ['env']
),
call(
['bash', 'temporary'], ['env']
)
]
mock_root_bind.umount_kernel_file_systems.assert_called_once_with()
def test_post_process_install_requests_bootstrap(self):
mock_root_bind = Mock()
self.manager.post_process_install_requests_bootstrap(mock_root_bind)
mock_root_bind.mount_kernel_file_systems.assert_called_once_with(False)
@patch('kiwi.command.Command.call')
@patch('kiwi.package_manager.apt.Path.wipe')
@patch('kiwi.package_manager.apt.os.path.exists')
def test_process_install_requests_bootstrap_debootstrap_no_gpg_check(
self, mock_exists, mock_wipe, mock_call
):
self.manager.request_package('apt')
self.manager.request_package('vim')
call_result = Mock()
call_result.process.communicate.return_value = ('stdout', 'stderr')
mock_root_bind = Mock()
mock_call.return_value = call_result
mock_exists.side_effect = lambda x: True if 'xenial' in x else False
self.manager.process_install_requests_bootstrap(mock_root_bind)
mock_call.assert_called_once_with(
[
'debootstrap', '--no-check-gpg',
'--variant=minbase', '--include=vim',
'--components=main,restricted', 'xenial',
'root-dir', 'xenial_path'
], ['env']
)
assert mock_wipe.call_args_list == [
call('root-dir/dev/fd'),
call('root-dir/dev/pts')
]
mock_root_bind.umount_kernel_file_systems.assert_called_once_with()
@patch('kiwi.command.Command.call')
@patch('kiwi.command.Command.run')

View File

@ -287,12 +287,12 @@ class TestSystemPrepare:
call(
'uri-alias', 'uri', None, 42,
None, None, None, None, 'credentials-file', None, None,
'baseurl', False, None
'baseurl', None
),
call(
'uri-alias', 'uri', 'rpm-md', None,
None, None, None, None, 'credentials-file', None, None,
None, False, '../data/script'
None, '../data/script'
)
]
assert repo.delete_repo_cache.call_args_list == [

View File

@ -1678,7 +1678,7 @@ class TestSystemSetup:
self.setup_with_real_xml.import_repositories_marked_as_imageinclude()
assert repo.add_repo.call_args_list[0] == call(
'uri-alias', 'uri', 'rpm-md', None, None, None, None, None,
'kiwiRepoCredentials', None, None, None, False, '../data/script'
'kiwiRepoCredentials', None, None, None, '../data/script'
)
@patch('os.path.exists')

View File

@ -10,8 +10,6 @@ import kiwi
from ..test_helper import argv_kiwi_tests
from kiwi.exceptions import KiwiCommandError
from kiwi.tasks.system_prepare import SystemPrepareTask
@ -181,33 +179,6 @@ class TestSystemPrepareTask:
)
assert system_prepare.clean_package_manager_leftovers.called
@patch('kiwi.xml_state.XMLState.get_package_manager')
@patch('kiwi.tasks.system_prepare.SystemPrepare')
def test_process_system_prepare_run_debootstrap_only_once(
self, mock_SystemPrepare, mock_get_package_manager
):
manager = MagicMock()
system_prepare = Mock()
system_prepare.setup_repositories = Mock(
return_value=manager
)
mock_SystemPrepare.return_value.__enter__.return_value = system_prepare
self._init_command_args()
mock_get_package_manager.return_value = 'apt'
self.task.command_args['--allow-existing-root'] = True
# debootstrap must be called if chroot with apt-get failed
self.command.run.side_effect = KiwiCommandError('error')
self.task.process()
assert system_prepare.install_bootstrap.called
# debootstrap must not be called if chroot looks good
self.command.run.side_effect = None
system_prepare.install_bootstrap.reset_mock()
with self._caplog.at_level(logging.WARNING):
self.task.process()
assert not system_prepare.install_bootstrap.called
@patch('kiwi.xml_state.XMLState.get_repositories_signing_keys')
@patch('kiwi.tasks.system_prepare.SystemPrepare')
def test_process_system_prepare_add_package(