Commit graph

424 commits

Author SHA1 Message Date
Christian Kellner
e3956ac831 gitignore: ignore IDE files
Ignore files related VS Code, PyCharm and gdb.
2020-02-05 15:53:34 +01:00
Christian Kellner
4cbbcdba87 samples: fix types for fstab.{freq, passno}
The schema demands that these are of type integer not string.
2020-01-29 18:03:24 +01:00
Christian Kellner
beb24a38b0 assembler/qemu: schema: 'dos' option for 'pttype'
Reflect the actual code by allowing 'dos' as pttype, which is as an
alias for 'mbr'.
2020-01-29 18:03:24 +01:00
Christian Kellner
ed8b71da36 assembler/qemu: fix 'size' schema type
It is an integer not a string.
2020-01-29 18:03:24 +01:00
Christian Kellner
2a3e5107f4 assembler/rawfs: fix schema type for 'size'
It is supposed to be an integer not a string.
2020-01-29 18:03:24 +01:00
Christian Kellner
4f72036efa stages/grub2: fix schema entry for 'legacy'
The 'legacy' option can either be of type boolean (the old version
kept for compatibility reasons) or 'string'. Adjust the schema to
account for that.
2020-01-29 18:03:24 +01:00
Christian Kellner
56a8586bab test: verify all stage options are valid json
Load all stages and assemblers and verify that the json in
STAGE_OPTS is actually valid json.
2020-01-28 13:10:14 +01:00
Christian Kellner
a3b9b55682 stages/grub2: fix json for stage options
Extra data: line 49 column 1 (char 1350) caused by an extra "}" at
the end of the data.
2020-01-28 13:10:14 +01:00
Christian Kellner
c084d51e3e stages/error: fix json for stage options
Expecting ',' delimiter: line 5 column 5 (char 88) caused by a
missing ','.
2020-01-28 13:10:14 +01:00
Christian Kellner
b261cb071e stages/dnf: fix json for stage options
Expecting property name enclosed in double quotes: line 81
column 1 (char 2272), caused by a trailing ",".
2020-01-28 13:10:14 +01:00
Tom Gundersen
ee86b57392 pipeline: back var by the store
This makes sure all disk access is backed by the same disk. We may
want this for performance reasons (avoiding moving across disks), but
also to experiment with different backing stores for all disk access.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2020-01-27 15:51:47 +01:00
Tom Gundersen
2837604bf8 buildroot: allow customizing the backing store for /var
Currently /var was always backed by /var/tmp, but we may want to
control exactly what it is backed by. The default is the same, so
this is not a behavioral change.
2020-01-27 15:51:47 +01:00
Major Hayden
2691acefeb Add the first gitlab ci YAML
This is the first test of connecting gitlab CI to the github
repository.

Signed-off-by: Major Hayden <major@redhat.com>
2020-01-24 00:41:12 +01:00
Christian Kellner
cf9c9946e0 pipeline: bind mount the osbuild module for the stages
The dnf stage wants to import `osbuild.sources` but currently the
osbuild module is not available in the stages. Apply the same hack
done in the Assembler also in for the stages, i.e. bind mount the
osbuild module to the stages/osbuild.
2020-01-23 00:49:11 +01:00
Christian Kellner
e7b989a08d osbuild.spec: actually install runners symlinks
The Fedora 31 and Fedora 32 runners are symlinks but the spec file
only looked for files and not symlinks. Fix that.

Follow up by 6a14ba40f7. Found by
Lars.
2020-01-23 00:47:57 +01:00
Christian Kellner
eab3414f00 samples: add hybrid boot with extra boot partition
Add a new sample that supports hybrid boot, i.e. legacy boot and
UEFI, like f30-hybrid-qcow2, but with a separate boot partition.
The latter means that 'fix-bls' as well as the 'grub2' stage need
to be adapted for it: 'fix-bls' needs have the prefix set to "/"
and grub2 needs to have a 'boot_fs_uuid' option pointing to the
uuid of the filesystem for the boot partition.
2020-01-19 23:01:36 +01:00
Christian Kellner
eb71e3d85c assembler/qemu: grub prefix relative to mountpoint
The grub prefix ("/boot/grub2") should be defined as relative to the
mountpoint of the filesystem containing it, i.e. /boot/grub2 if it is
on the root filesystem or /grub2 if boot is on a separate partition.
2020-01-19 23:01:36 +01:00
Christian Kellner
abfc4d6b5a stages/fix-bls: support for different prefix
The paths for the kernel and the initrd in the BLS snippets are
meant to be relative to the root of the filesystem they are on.
The current code assumes that kernel and initrd are installed
under '/boot' and that '/boot' is on the root file system and
thus all paths get fixed up to start with '/boot/…'. But the
'/boot' directory can be on a separate partition and thus file
system, and then paths need to be relative to that and should
be fixed up with '/…'. Introduce a new option 'prefix' that
can be used to manually specify the prefix after the fixup,
defaulting to '/boot' for backwards compatibility.
NB: The canonical Boot Loader Specification[1] requires that
a separate partition is used boot related files and it will
be mounted at '/boot' (or '/efi').

[1] https://systemd.io/BOOT_LOADER_SPECIFICATION/
2020-01-19 23:01:36 +01:00
Christian Kellner
b3ae34b07e stages/grub2: make $boot just an alias for $root
Up until now the grub config theoretically supported having different
values for 'root' (via grubenv's $GRUB2_ROOT_FS_UUID) and 'boot' (via
grubenv's $GRUB2_BOOT_FS_UUID). 'boot' is a leftover from the initial
implementation when grub was looking for BLS snippets also in the ESP,
and will be removed in the future.
In our and also the canonical Fedora/RHEL grub configurations the BLS
are in the very same location for UEFI and legacy and thus 'boot' is
always 'root'.
Therefore we get rid of the extra grubenv variable refering to 'boot'
and just set 'boot' to 'root' after that was discovered.
2020-01-19 23:01:36 +01:00
Christian Kellner
92e2961090 stages/grub2: support for separate boot partition
Add a new `boot_fs_uuid` option for when a separate partition is
being used for '/boot' with the indicated uuid. This will then be
used for the grub2 "root" and "boot" variables. Additionally, in
the redirect config, need to refer to files and directories paths
relative to the partition they are contained, i.e. /boot/grub2 if
/boot is on root ('/') or /grub2 if /boot is on a extra dedicated
partition.
2020-01-19 23:01:36 +01:00
Lars Karlitski
7bb06d2334 loop: handle set_status returning EBUSY
This happens rarely when the same loop device is used in rapid
succession. The kernel flushes the page cache asynchronously, which
means that it might not be cleared yet when a new file is bound.
`set_status` checks if the cache is clear (`set_fd` doesn't).

Handle this by trying a different device when `set_status` returns
`EBUSY`.

Fixes #177
2020-01-19 22:19:25 +01:00
Lars Karlitski
b487126bb8 loop: explicitly close fds to loop devices
Don't wait until python's garbage collector closes the file descriptors
to loop devices. Close them when the `LoopServer` context manager exits,
after an assembler has finished running.
2020-01-19 22:19:25 +01:00
Lars Karlitski
47dc1b5b92 loop: don't leak open fd to /dev
Close the file descriptor to `/dev` when we opened it.
2020-01-19 22:19:25 +01:00
Lars Karlitski
977f0a465b loop: fix typo in LoopInfo member 2020-01-19 22:19:25 +01:00
Christian Kellner
2d6fa9564c samples/f30-s390x: use new stlye sources for dnf
Instead of directly encoding the repo configuration make use of the
new sources api. The corresponding entry in samples/sources.json
which is referenced here ("sha256:450d4c0…") was added with the
previous commit ("92cfc57d720…").

    "it's the future! 🛸" - Lars Karlitski
2020-01-13 20:05:10 +01:00
Christian Kellner
8d7cd7c871 samples/sources: add f30 on s390x dnf repo
Add the repo source for the org.osbuild.dnf stage for fedora 30 on
s390x.
2020-01-13 20:05:10 +01:00
Christian Kellner
d53787be66 samples/f30-s390x.json: example for s390x
Bare bones example for image creation on s390x with MBR partition
layout and zipl bootloader. The kernel command line is configured
via the new org.osbuild.kernel-cmdline stage which needs to be run
before the dnf stage.
2020-01-13 20:05:10 +01:00
Christian Kellner
49e1b91d47 assembler/qemu: support for zipl bootloader
Support the s390x bootloader zipl (z Initial Program Loader). We
supply the parameters for the kernel+initrd as well es the target,
i.e. the boot partition where the bootmap is creating, the device,
here called 'targetbase', to install the bootloader on, including
parameters describing the device (type, blocksize) and also the
offset of the partition containing the target from the start of
device (in sectors).
The kernel and initrd are found via the bootloader entry, ignoring
the rescue kernel.
Since zipl needs the device as well as access to the boot partition
the image is bound to a loopback device. Also keep the filesystem
tree mounted during the execution of the zipl installation.
2020-01-13 20:05:10 +01:00
Christian Kellner
a32c30d06c test: add simple check for kernel-cmdline stage
Add a stage test to check that the new kopts stage is creating the
target file /etc/kernel/cmdline with the right content. Since tree
diff currently seems to lack support for content hashing new files
we work around this by creating first an empty /etc/kernel/cmdline
file and then get a content diff with the desired options set.
2020-01-13 20:05:10 +01:00
Christian Kellner
7a8c76cb1c stages/kopts: new stage to set the kernel cmdline
The canonical way to set the kernel commandline, which is used by
the kernel post install scripts, see kernel-install(8), is the
file /etc/kernel/cmdline, or in the case this does not exist,
/proc/cmdline. The new stages offers a way to write this file in a
more "type-safe" way, by providing explicit options for certain
well known params (for now only `root_fs_uuid`). Additional params
are specified via `kernel_opts`. This follows the grub2 stage name
convention.
2020-01-13 20:05:10 +01:00
Christian Kellner
40096e189b test: new test to check zipl stage
The zipl stage is a fairly simple stage that just creates a file
in /etc called zipl.conf with a single configurable option, which
is called `timeout`. Check the file gets properly created with
the desired hash and verify that setting the timeout works.
2020-01-13 20:05:10 +01:00
Christian Kellner
fc9108e16e stage/zipl: new stage to configure zipl
Write a default config for the z Initial Program Loader to work
correctly. Parameters taken from anaconda[1].

[1] 2e793483b4/pyanaconda/bootloader/zipl.py (L132)
2020-01-13 20:05:10 +01:00
Christian Kellner
64addbe2d2 buildroot: allow creating device nodes on s390x
The z Initial Program Loader (zipl) when creating the bootmap in
bootmap_creat (src/zipl/bootmap.c) wants to create a device node
via misc_temp_dev (bootmap_create:1141) for the device that it
is installing the bootloader to[1]. Currently access to loopback
devices is allowed from within the container (it is used to mount
the image), but only read/write access. On s390x also allow the
creation of device nodes, so zipl can do its work and install
the bootloader stages on the "disk".

[1] zipl source at commit dcce14923c3e9615df53773d1d8a3a22cbb23b96
2020-01-13 20:05:10 +01:00
Christian Kellner
bf41326ac6 remoteloop: don't use O_DIRECT on s390x
Using O_DIRECT to open the image partition and then using that fd
for the backing of the loopback device will break the mounting of
the formatted partition, i.e mount will fail with:

  mount: /tmp/looptest-6qrtkp5e/mountpoint-root: wrong fs type,
  bad option, bad superblock on /dev/loop0, missing codepage or
  helper program, or other error.

Reproducible with the follow small-ish python script, executed via
'env PYTHONPATH=$(pwd) python3 looptest.py':

---- 8< ---- 8< ---- [ looptest.py ] ---- 8< ---- 8< ----

import contextlib
import json
import os
import subprocess
import stat
import tempfile

from osbuild import loop

@contextlib.contextmanager
def mount(source, dest):
    subprocess.run(["mount", source, dest], check=True)
    try:
        yield dest
    finally:
        subprocess.run(["umount", "-R", dest], check=True)

@contextlib.contextmanager
def os_open(path, flags):
    fd = os.open(path, flags)
    try:
        yield fd
    finally:
        os.close(fd)

def main():
    size = 512 * 1024 * 1024
    ptuuid = "0x14fc63d2"

    with contextlib.ExitStack() as cm:
        tmpdir = cm.enter_context(tempfile.TemporaryDirectory(prefix="looptest-"))
        print(f"Temporary directory at {tmpdir}")

        devdir = os.path.join(tmpdir, "dev")
        os.makedirs(devdir, exist_ok=True)
        dir_fd = cm.enter_context(os_open(devdir, os.O_DIRECTORY))

        image = os.path.join(tmpdir, "image")
        subprocess.run(["truncate", "--size", str(size), image], check=True)
        table = f"label: mbr\nlabel-id: {ptuuid}\nbootable, type=83"
        subprocess.run(["sfdisk", image], input=table, encoding='utf-8',
                       check=True)
        # read it back
        r = subprocess.run(["sfdisk", "--json", image],
                           stdout=subprocess.PIPE,
                           encoding='utf-8', check=True)
        table = json.loads(r.stdout)["partitiontable"]
        partitions = table["partitions"]
        start = partitions[0]["start"] * 512
        size = partitions[0]["size"] * 512

        # fails here with os.O_DIRECT
        image_fd = cm.enter_context(os_open(image, os.O_RDWR | os.O_DIRECT))

        control = loop.LoopControl()
        minor = control.get_unbound()
        lo = loop.Loop(minor)
        lo.set_fd(image_fd)
        lo.set_status(offset=start, sizelimit=size, autoclear=True)
        lo.mknod(dir_fd)
        loopdev = f"/dev/loop{minor}"

        # loopdev = os.path.join(devdir, lo.devname)
        # os.chmod(loopdev, os.stat(loopdev).st_mode | stat.S_IRGRP)

        subprocess.run(["ls", "-la", f"{devdir}"], check=True)
        subprocess.run(["mkfs.ext4", loopdev],
                       input="y", encoding='utf-8', check=True)

        subprocess.run(["blkid", loopdev], check=True)

        mountpoint = os.path.join(tmpdir, "mountpoint-root")
        os.makedirs(mountpoint, exist_ok=True)
        cm.enter_context(mount(loopdev, mountpoint))
        subprocess.run(["ls", "-la", tmpdir], check=True)
        subprocess.run(["ls", "-la", mountpoint], check=True)
        subprocess.run(["mount"], check=True)

if __name__ == '__main__':
    main()
2020-01-13 20:05:10 +01:00
Christian Kellner
65996d1370 assembler/qemu: declare bootloader options
Include the `bootloader` options in the STAGE_OPTS json schema.
Commit 8fcf7d5c4… introduce the `bootloader` option but the
corresponding schema entry was omitted.
2020-01-13 20:05:10 +01:00
Martin Sehnoutka
6a14ba40f7 Create Fedora 31 and Fedora 32 runners 2020-01-10 18:27:55 +01:00
Christian Kellner
b79a215659 README: add information about 'sources'
Update the command line options help text as well as the sample
command line to build the `base-qcow2.json` to include the new
sources command line option.
2020-01-10 18:26:12 +01:00
Christian Kellner
20399a57ee samples: add hybrid boot example
Add a example demonstrating hybrid boot. The main ingredients are:
 - grub2 stage has `uefi` and `legacy` options
 - GPT partition layout
 - BIOS boot partition so that core image for grub2 legacy can
   be stored (small, 1MB, type 21686148-6449-6E6F-744E-656564454649)
 - ESP partition so UEFI can load grub*.efi (via the shim)
2020-01-10 18:25:35 +01:00
Christian Kellner
4804632268 stages/grub2: support for hybrid booting
In the case that the image should support booting via EFI *and*
legacy grub, i.e. hybrid booting, the canonical grub config is
stored in /boot/grub2 just as for normal legacy booting. The
config file for efi grub is a very small one that will just look
for the partition containing the /boot/grub2/grub.cfg file and use
then set the prefix accordingly and load that file. In the hybrid
case grubenv file also will just be located in /boot/grub2 and
not in the ESP therefore the symlink that was created by the
package needs to be removed.
2020-01-10 18:25:35 +01:00
Christian Kellner
b50193f289 assemblers/qemu: fix backward compat for grub2
With the introduction of the `bootloader` option, grub2 legacy
installation setting changed. Before, grub2 legacy installation
was dependent on the partition scheme, i.e. only when dos/mbr
layout was used grub2 got installed. After the change the default
is to install it unless `bootloader.type" is explicitly set, even
if the partition layout is GPT. But a legacy grub2 installation
on GPT requires a BIOS boot partition, so the new default is not
right for the case of pure (non-hyrid) UEFI images.
Therefore revert to the old behavior of only defaulting to grub2
legacy if the option is not explicitly set *and* the partition
layout is "dos"/"mbr".
Adapt the f30-qcow2-gpt sample, which is non-uefi grub2 legacy
but with GPT and a bios boot partition, to explicitly request
the grub2 bootloader.
2020-01-10 15:48:27 +01:00
Christian Kellner
42a4176a9f stages/grub2: fix auto bool to platform conversion
In the case that legacy is of type bool it is automatically converted
to the platform string ("i386-legacy"). This is mainly done to keep
backwards comparability as it was just a boolean before. But the auto
conversion did not take the actual *value* of the boolean into account
meaning "legacy: False" would be turned into "legacy: i386-pc" and
thus effectively changing the value from False to True.
2020-01-10 15:48:27 +01:00
Lars Karlitski
3a73d589d2 stages/dnf: don't ignore unavailable repositories
dnf skips unavailable repositories by default, which only leads to
harder understand errors later. Configure it to fail when any of the
passed repositories cannot be reached.
2020-01-09 23:55:43 +01:00
Lars Karlitski
84a948bcd7 stages/dnf: don't print repository data
It may contain secrets now, which we don't want in the logs.
2020-01-09 23:55:43 +01:00
Lars Karlitski
59ffebaff0 stages,sources/dnf: allow passing certificate data
Add support for dnf's sslcacert, sslclientcert, and sslclientkey
options. The latter two are passed as secrets (clientcert as well
because it might be a pem file that also includes the private key).

Sources run on the host, so their options may contain paths to the host
file system. Make use of that by accepting only paths in those options,
because it allows using tools to deal with certificate files.

Also make sure that the dnf source only returns options it knows about.
2020-01-09 23:55:43 +01:00
Lars Karlitski
12b5c6aaa4 sources: bump maximum message size to 64k
These messages contain certificate data, which is quite large.

We should probably use streaming sockets in the future.
2020-01-09 23:55:43 +01:00
Lars Karlitski
e123715bc6 osbuild: introduce secrets
Add a new command line option `--secrets`, which accepts a JSON file
that is structured similarly to a source file. It is should contain data
that is necessary to fetch content, but shouldn't appear in any logs.
2020-01-09 23:55:43 +01:00
Lars Karlitski
02ad4e3810 sources: fail gracefully when a source returns invalid JSON
Include the actual output of the source to help debugging.
2020-01-09 23:55:43 +01:00
Lars Karlitski
ef7f17d95b osbuild.spec: install sources directory
Missed it in 510e2b1e94.
2020-01-09 23:55:20 +01:00
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