pungi/pungi/phases/test.py
Haibo Lin 477b43d4e9 Split repoclosure into separate phase
Move repoclosure out from test phase into its own phase and
run parallel with image building phases(osbs, imagebuild, ...)
to speed things up.

JIRA: RHELCMP-8
Signed-off-by: Haibo Lin <hlin@redhat.com>
2020-04-14 09:25:57 +08:00

122 lines
3.9 KiB
Python

# -*- coding: utf-8 -*-
# This program 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; version 2 of the License.
#
# This program 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 Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <https://gnu.org/licenses/>.
import os
from pungi.phases.base import PhaseBase
from pungi.util import failable, get_arch_variant_data
class TestPhase(PhaseBase):
name = "test"
def run(self):
check_image_sanity(self.compose)
def check_image_sanity(compose):
"""
Go through all images in manifest and make basic sanity tests on them. If
any check fails for a failable deliverable, a message will be printed and
logged. Otherwise the compose will be aborted.
"""
im = compose.im
for variant in compose.get_variants():
if variant.uid not in im.images:
continue
for arch in variant.arches:
if arch not in im.images[variant.uid]:
continue
for img in im.images[variant.uid][arch]:
check_sanity(compose, variant, arch, img)
check_size_limit(compose, variant, arch, img)
def check_sanity(compose, variant, arch, image):
path = os.path.join(compose.paths.compose.topdir(), image.path)
deliverable = getattr(image, "deliverable")
can_fail = getattr(image, "can_fail", False)
with failable(
compose, can_fail, variant, arch, deliverable, subvariant=image.subvariant
):
with open(path, "rb") as f:
iso = is_iso(f)
if image.format == "iso" and not iso:
raise RuntimeError("%s does not look like an ISO file" % path)
if (
image.arch in ("x86_64", "i386")
and image.bootable
and not has_mbr(f)
and not has_gpt(f)
and not (iso and has_eltorito(f))
):
raise RuntimeError(
"%s is supposed to be bootable, but does not have MBR nor "
"GPT nor is it a bootable ISO" % path
)
# If exception is raised above, failable may catch it, in which case
# nothing else will happen.
def _check_magic(f, offset, bytes):
"""Check that the file has correct magic number at correct offset."""
f.seek(offset)
return f.read(len(bytes)) == bytes
def is_iso(f):
return _check_magic(f, 0x8001, b"CD001")
def has_mbr(f):
return _check_magic(f, 0x1FE, b"\x55\xAA")
def has_gpt(f):
return _check_magic(f, 0x200, b"EFI PART")
def has_eltorito(f):
return _check_magic(f, 0x8801, b"CD001\1EL TORITO SPECIFICATION")
def check_size_limit(compose, variant, arch, img):
"""If a size of the ISO image is over the configured limit, report a
warning. Do nothing for other types of images.
"""
if img.format != "iso":
return
limits = get_arch_variant_data(compose.conf, "createiso_max_size", arch, variant)
if not limits and not getattr(img, "_max_size", None):
return
# For ISOs created in extra_isos phase we add an attribute with the limit,
# and there is a global option otherwise.
limit = getattr(img, "_max_size", None) or limits[0]
if img.size > limit:
is_strict = get_arch_variant_data(
compose.conf, "createiso_max_size_is_strict", arch, variant
)
msg = "ISO %s is too big. Expected max %dB, got %dB" % (
img.path,
limit,
img.size,
)
if any(is_strict):
raise RuntimeError(msg)
else:
compose.log_warning(msg)