Commit graph

376 commits

Author SHA1 Message Date
Christian Kellner
ba0acf7ff8 samples: example for legacy boot but gpt partition
An example demonstrating the use of the BIOS boot partition to
enable legacy grub2 boot (i.e. non-efi boot) with a GPT partition
layout.
2020-01-09 01:43:56 +01:00
Christian Kellner
9e929d3db6 assembler/qemu: refactor grub2 boot image patching
As noted in earlier commits the grub2 boot image needs to be patched
to contain the position of the grub2 core. By default, the location
in the boot image is hard-coded to be the mbr gap (sector 1) but for
GPT partition schemes a separate BIOS boot partition is used that is
located at a "random" location. Refactor the code to generalize the
boot image patching, where the default mbr gap location is just a
special case of the general.
2020-01-09 01:43:56 +01:00
Christian Kellner
814cb4eb80 assembler/qemu: gpt support for grub legacy
The GRUB2 bootloader in legacy mode, i.e. non-EFI mode, consists of
several stages. The fist one place in the in the Master Boot Record
of the disk will load and execute the next, second stage, consisting
of core modules and the grub kernel. The first bit is also known as
'boot' and the second as 'core'. When the 'MBR' partition layout is
being used, there is a gap between the Master Boot Record (MBR) and
the first partition (for historical and performance reasons). The
core image normally is placed into this gap (call the MBR gap).
When the partition layout is 'gpt' there is no standard gap that can
be used, instead a special partition ("BIOS boot" [1]) needs to be
created that can store the grub2 core image. Additionally, the 'boot'
image need to modified to point the sector of that partition. The
core image itself also needs to be modified with the information of
the location its own second sector. The location of the pointers
were taken from the grub2 source ([2] at commit [3]). For the 'boot'
image it is 'GRUB_BOOT_MACHINE_KERNEL_SECTOR' (0x5c) from 'pc/boot.h'
and for the core image "0x200 - GRUB_BOOT_MACHINE_LIST_SIZE (12)" to
be found in 'pc/diskboot.S'.

[1] https://en.wikipedia.org/wiki/BIOS_boot_partition
[2] https://github.com/rhboot/grub2
[3] 2a2e10c1b39672de3d5da037a50d5c371f49b40d
2020-01-09 01:43:56 +01:00
Christian Kellner
c83019a264 assembler/qemu: extract grub2 boot image writing
Extract the small piece of code that writes the grub2's boot image,
i.e. the first stage of the bootloader that will in turn jump to
the second stage. Currently the position of the core is hard-coded
to be the MBR gap, i.e. the gap between the MBR and the start of
the first partition. This is not a necessity, e.g. when using a
dedicated BIOS boot partition on GPT partition layouts. This re-
factoring should make it easier to add code dealing with such
situations.
2020-01-09 01:43:56 +01:00
Lars Karlitski
b9b2f99123 osbuild: create API sockets in the thread they're used in
This might (hopefully) fix a race in destructing the asyncio.EventLoop
that's used in all API classes, which leads to warnings about unhandled
exceptions on CI.

This also puts their creation closer to where the client-side sockets
are created.
2019-12-25 17:48:26 +01:00
Christian Kellner
57b2c1e12d samples: include ppc64le sample
Include a example of a ppc64le (open firmware) pipeline based on
f30-s390x. It includes changes to the grub2 stage (selecting the
platform), the partition table contains the PReP partition needed
to store the grub2 core image.
2019-12-24 15:42:24 +01:00
Christian Kellner
1da71ebbb4 assembler/qemu: support for ppc64le (open firmware)
Introduce support for ppc64le (Open Firmware). The main difference
to x86 legacy, i.e. non-efi, is that no stage 1 is required because
the core image is stored on a special 'PReP' partition, which must
be marked as bootable. The firmware then looks for that partition
and directly loads the core from there and executes it.
Introduce a `platform` parameter for the grub installer code which
controls various platform depended aspects, including a) the path
for the modules, b) what modules are compiled into the core, c) if
the boot image is written to the MBR and 4) where to write the core
image, i.e. mbr-gap or PReP partition.
2019-12-24 15:42:24 +01:00
Christian Kellner
ccf9994ba6 assembler/qemu: extra func for writing grub core
Extract the function that writes the grub2 core to the image file.
The only supported location currently is the MBR gap, which is the
gap between the Master Boot Record and the first partition, which
for historical and performance reasons was aligned to a certain
sector (used to be 64 but now is even larger with 2048). In the
future other locations for the grub2 core will be supported such
as the PReP partition (ppc64le) or bios-boot (GPT hybrid booting).
2019-12-24 15:42:24 +01:00
Christian Kellner
8fcf7d5c45 assembler/qemu: explicit bootloader selection
Make the bootloader selection explicit by introducing a new option
called `bootloader`, which is an object, containing the `type` and
options belonging to the bootloader. For now only boot-loader that
is supported is "grub2".
2019-12-24 15:42:24 +01:00
Christian Kellner
e12667914a assembler/qemu: dynamically determine grub2 prefix
Instead of hard-coding "msdos1", determine this partition id
dynamically based on the partition table type and the index
of the partition that contains /boot/grub2, which normally is
either a separate boot partition or the root partition. In
order to be able to do so, set the index of each Partition
when the partition information is read back via `sfdisk`.
NB: partition indexes start at 1 for grub2.
2019-12-24 15:42:24 +01:00
Christian Kellner
33078bf1df assembler/qemu: we want the boot fs type for grub2
The filesystem module that grub2 needs to have in the core image
is the filesystem containing the grub modules, specifically the
"normal.mod", as well as the grub configuration. In the standard
case, which is also what osbuild uses, this is /boot/grub2; thus
we actually do want the filesystem containing that directory and
its type not the root filesystem.
2019-12-24 15:42:24 +01:00
Christian Kellner
c57da5722f assembler/qemu: clarify module usage for grub2
Explain the concept and reason behind the grub2 core as well as the
details behind the selection of the core  modules that get included.
Also elaborate a bit on the MBR gap. For more details about this see
https://en.wikipedia.org/wiki/GNU_GRUB#Version_2_(GRUB_2)
NB: This commit also changes the order of the grub modules, which in
turn changes the layout of the core.img and thus the hash value used
in the test; adapt those value to reflect the changed core.img.
2019-12-24 15:42:24 +01:00
Christian Kellner
828b568734 stage/grub2: support for non i386-pc platforms
Change the `legacy` option (keeping compatibility) from a boolean
to a string, specifying the target platform the legacy modules
are being installed for.
2019-12-24 15:42:24 +01:00
Lars Karlitski
08b7a1a6b5 stages/dnf: don't show repo id in checksum error
repoid was based on index in the "repos" array from options. Now that we
fetch repository configuration from a source, the order might be
different.
2019-12-23 01:12:38 +01:00
Lars Karlitski
510e2b1e94 osbuild: introduce sources
Pipelines encode which source content they need in the form of
repository metadata checksums (or rpm checksums). In addition, they
encode where they fetch that source content from in the form of URLs.
This is overly specific and doesn't have to be in the pipeline's hash:
the checksum is enough to specify an image.

In practice, this precluded using alternative ways of getting at source
packages, such as local mirrors, which could speed up development.

Introduce a new osbuild API: sources. With it, a stage can query for a
way to fetch source content based on checksums.

The first such source is `org.osbuild.dnf`, which returns repository
configuration for a metadata checksum. Note that the dnf stage continues
to verify that the content it received matches the checksum it expects.

Sources are implemented as programs, living in a `sources` directory.
They are run on the host (i.e., uncontained) right now. Each source gets
passed options, which are taken from a new command line argument to
osbuild, and an array of checksums for which to return content.

This API is only available to stages right now.
2019-12-23 01:12:38 +01:00
Lars Karlitski
b81a11800d test: merge duplicate dnf stages 2019-12-23 01:12:38 +01:00
Tom Gundersen
1f7766596f stages/dnf: log more clearly in case the repo metadata changes
This is an expected error case, so we should not assert, but log
and return failure. In the future we should probably also return
the error as structured data.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-12-18 22:18:33 +01:00
Christian Kellner
f67a649805 assembler/qemu: support partition names (gpt)
The GPT (GUID Partition Table) standard for partition layout supports
giving partition a name in the Partition object as well as in the
option for the qemu stage when specifying the partition layout.
2019-12-18 20:45:54 +01:00
Christian Kellner
1ea04d803f assembler/qemu: mkfs_for_type → Filesystem.make_at
Make mkfs_for_type a member of Filesystem (as 'make').
2019-12-18 20:45:54 +01:00
Christian Kellner
dc25fb3e42 assembler/qemu: helper to root fs partition
Introduce a method on the PartitionTable that returns the partition
containing the root filesystem. NB: this does not have to be the
first partition (which could be the EFI partition, or something
else), so we have to iterate through the partitions until we find
it.
2019-12-18 20:45:54 +01:00
Christian Kellner
5ee68aef30 assembler/qemu: Partition{Table} & Filesystem objs
Instead of having dictionaries representing the partition table,
partitions and filesystems together with some functions operating
on them, have proper python objects with methods. In the future
these objects could be extract and properly tested as well.
2019-12-18 20:45:54 +01:00
Christian Kellner
83c3f9608d samples: add a simple error example
Uses the org.osbuild.error stage to test error behavior and handling.
2019-12-18 12:45:59 +01:00
Christian Kellner
6333d1c3bd stage/error: new simple stage always erroring out
A simple stage like 'noop' that will return with `returncode` or
255 if nothing is specified. Like 'noop' it might be useful for
testing, debugging, and wasting time.
2019-12-18 12:45:59 +01:00
Christian Kellner
ede3f6baeb pipeline: proper object cleanup on errors
The recent changes removed the {Assembler,Stage}Failed exceptions,
which includes them being thrown from Stage.run and Assembler.run.
Instead result dictionaries are returned even on errors. But the
object store, used as a context manager, relies on exceptions to
detect the error case and thus needs them to cleanup the temporary
objects. Without those exceptions the temporary objects end up in
the store even when the sage or assembler failed.
Restore the old behavior by throwing a generic BuildError exception
from the Stage and Assembler, which will be caught directly in the
pipeline and converted to a result dict.
2019-12-18 12:45:59 +01:00
Lars Karlitski
9350e868a7 test: don't capture stderr when running osbuild
stdout is expected to be JSON.
2019-12-18 11:12:37 +01:00
Lars Karlitski
f09a0c2a69 test/assemblers: don't delete output in the store
To fix running the test multiple times with OSBUILD_TEST_STORE.
2019-12-18 11:12:37 +01:00
Lars Karlitski
e7c939b9e1 test/assembler: use static uuids
To keep the pipelines unique when using OSBUILD_TEST_STORE.
2019-12-18 11:12:37 +01:00
Lars Karlitski
59bdca86ac test/assembler: fix nbd race
The nbd device might not be ready after `qemu-nbd --connect` returns,
leading to access errors such as this further down:

    sfdisk: cannot open /dev/nbd12: Inappropriate ioctl for device

Fix this by polling the device with `nbd-client --check <device>`.

Also, the nbd device might not be released after `qemu-nbd --disconnect`
returns. Fix this by using `nbd-client --disconnect`, which waits.

This introduces a new test dependency on nbd-client (in the ndb package
on Fedora).
2019-12-18 11:12:37 +01:00
Lars Karlitski
5b77048e97 7 2019-12-16 01:17:25 +01:00
Lars Karlitski
e0bb65dd71 api and remoteloop: don't close the passed-in socket
The socket that the osbuild and loop apis should talk on are passed into
their `__init__` function. The caller should be responsible for closing
those sockets.

This already happens in all current callers.

This fixes a non-fatal error on RHEL's python 3.6, because it was
calling `socket.close` on an already-closed socket:

    Traceback (most recent call last):
      File "/usr/lib64/python3.6/asyncio/base_events.py", line 529, in __del__
        self.close()
      File "/usr/lib64/python3.6/asyncio/unix_events.py", line 63, in close
        super().close()
      File "/usr/lib64/python3.6/asyncio/selector_events.py", line 99, in close
        self._close_self_pipe()
      File "/usr/lib64/python3.6/asyncio/selector_events.py", line 109, in _close_self_pipe
        self._remove_reader(self._ssock.fileno())
      File "/usr/lib64/python3.6/asyncio/selector_events.py", line 268, in _remove_reader
        key = self._selector.get_key(fd)
      File "/usr/lib64/python3.6/selectors.py", line 189, in get_key
        return mapping[fileobj]
      File "/usr/lib64/python3.6/selectors.py", line 70, in __getitem__
        fd = self._selector._fileobj_lookup(fileobj)
      File "/usr/lib64/python3.6/selectors.py", line 224, in _fileobj_lookup
        return _fileobj_to_fd(fileobj)
      File "/usr/lib64/python3.6/selectors.py", line 41, in _fileobj_to_fd
        raise ValueError("Invalid file descriptor: {}".format(fd))
    ValueError: Invalid file descriptor: -1
2019-12-15 12:05:14 +01:00
Lars Karlitski
61e32ff3ef pipeline: return new-style result from build pipeline
Commit 82a2be53d introduced a new return type from `Pipeline.run()`. It
changed the caller in `__main__.py`, but missed that the build pipeline
uses the same function.
2019-12-15 12:03:43 +01:00
Lars Karlitski
82a2be53d4 pipeline: return logs in --json mode
A pipeline run only returned logs in the `StageFailed` and
`AssemblerFailed` exceptions. Remove those and always return structured
data instead.

It only returns data for stages that actually ran (i.e., didn't come
from the cache). This is similar to the output in interactive mode.

Also change osbuildtest to be able to deal with output that is larger
than the pipe buffer by using subprocess.communicate().
2019-12-14 13:49:24 +01:00
Christian Kellner
f1b9361837 editorconfig: add one matching current style
Add a editorconfig (https://editorconfig.org/) config file so most
editors can, by default, get the right indent settings.
2019-12-13 18:15:08 +01:00
Christian Kellner
24f41495d9 loop: fix a few typos
Some minor spelling corrections and a correction to the API doc in
one place.
2019-12-13 18:15:08 +01:00
Christian Kellner
c77313079b assembler/qemu: add filesystem label support
Add a (optional) property call `label` to the `filesystem` object to
support labeling the filesystem. Add the label for the ESP to both
UEFI examples.
2019-12-12 17:25:47 +01:00
Christian Kellner
5cae5283d7 samples/f30-aarch64: 64bit ARM examples
Based on the UEFI sample (f30-base-uefi.json). NB: the inclusion
of the dracut-config-generic is needed to disable "host-only" for
dracut so the initramfs will include the virtio_blk block device
driver that is needed to mount the root file system when running
the image in qemu.
2019-12-12 17:25:47 +01:00
Brian C. Lane
4a44fdf317 samples/f30-base-uefi.json: UEFI x86_64 example
Include a basic example to generate a x84_64 UEFI image.
2019-12-12 17:25:47 +01:00
Christian Kellner
accef40124 assembler/qemu: support ESP partitions
Add mkfs_vfat and hook it up into the generic mkfs_for_type()
dispatcher function. Install grub2 to the MBR only if the partition
table is of type "MBR".
2019-12-12 17:25:47 +01:00
Christian Kellner
5eb4ceff2f assembler/qemu: support generic partition layouts
Introduce two new assembler options `pttype` and `partitions` to
allow fine grained control over how the partition table is created.
The first one controls the partition type, either `mbr` (default,
when the key is missing) or `gpt`; if specified the `partitions`
key must contain a list of objects describing the individual
partitions (`start`, `size`, `type`) together with a `filesystem`
object describing the filesystem (`type`, `uuid`, `mountpoint`) to
be created on that partition.
In the case the `pttype` option is missing, the legacy mode is used
where `root_fs_uuid` and `root_fs_type` need to be specified.
2019-12-12 17:25:47 +01:00
Christian Kellner
9688859acf assembler/qemu: install_grub uses partitions
Use the newly available partition information in the install_grub2
method: detect which module to use for the root filesystem and
assert the second stage fits between the MBR and the first partition.
2019-12-12 17:25:47 +01:00
Christian Kellner
9863b5ad10 assembler/qemu: refactor fs creation & mounting
Introduce a generic mkfs_for_type() function that will dispatch
to the correct mkfs function depending on the type. Additionally
refactor the partition creation and mounting code to handle more
than one partition.
2019-12-12 17:25:47 +01:00
Christian Kellner
9b9c604ab7 assembler/qemu: refactor partition table code
Part of the refactoring to support uefi/gpt: the method that creates
the partition table now returns an array of dictionaries corresponding
to the individual partitions that have been created together with the
information for the filesystem that this partition should end up with.
2019-12-12 17:25:47 +01:00
Christian Kellner
b85e8ea673 assembler/qemu: refactor to prepare for uefi/gpt
Prepare the stage for uefi/gpt support by extracting the code that
installs GRUB and creates the partitions into its own functions.
Should not have any effect on the actual data written to the image.
2019-12-12 17:25:47 +01:00
Christian Kellner
ce5f3c4331 stages/grub: add uefi support (optional)
Introduce two new configuration options: `legacy` and `uefi`. The
first one being a boolean (default: True) that controls if GRUB
modules, fonts and the configuration is installed in the right
locations to support legacy boot mode.
The `uefi` option (of type object with a single `vendor` property)
enables UEFI support by writing the configuration into the correct
EFI directory, "/boot/efi/EFI/<vendor>/grub.cfg", where vendor is
taken from said `vendor` property.
2019-12-12 17:25:47 +01:00
Christian Kellner
1f5853a27f stages/grub: extract code to write grub config
Part of refactoring the grub2 stage to be able the handle UEFI. No
semantic change.
2019-12-12 17:25:47 +01:00
Christian Kellner
b6da6418c1 stages/grub: extract font copying code
Part of refactoring the grub2 stage to be able the handle UEFI. No
semantic change.
2019-12-12 17:25:47 +01:00
Christian Kellner
1c0f00e37c stages/grub: extract module copying code
Part of refactoring the grub2 module so it can also handle UEFI.
No semantic change.
2019-12-12 17:25:47 +01:00
Christian Kellner
d1d27567e8 buildroot: dyld workaround also on ppc64le
The workaround of manually linking /lib64 -> /usr/lib64 inside the
container that is needed on s390 is also required on ppc64 because
here the dynamic linker is set to /lib64/ld64.so.2 and the /lib64
link is not created.
2019-12-12 13:16:05 +01:00
Christian Kellner
575039db29 buildroot: work around s390x linker + nspawn issue
Work around a combination of systemd not creating the link from
/lib64 -> /usr/lib64 (see systemd issue #14311) and the dynamic
linker is being set to (/lib/ld64.so.1 -> /lib64/ld64.so.1)
Therefore we manually create the link before calling nspawn
2019-12-12 13:16:05 +01:00
Lars Karlitski
e590dee93b assemblers/tar: fix compression
Commit 283281f broke compression by appending the argument last to the
tar command line. It needs to appear before the file.

Fix that and add a test.

[teg: add minor fix]
2019-12-10 12:07:08 +01:00