Commit graph

227 commits

Author SHA1 Message Date
Achilleas Koutsou
1a2dfb0070 test: add tests for new monitor and its components
Signed-off-by: Achilleas Koutsou <achilleas@koutsou.net>
2024-03-12 16:44:12 +01:00
Michael Vogt
2f0ed8c755 osbuild: ensure a usable /var/tmp is available inside the buildroot
Colin asked for this in
https://github.com/osbuild/bootc-image-builder/issues/223 and
it's easy enough.
2024-03-11 13:09:28 +01:00
Gianluca Zuccarelli
6c0973238d utils/mnt: fix mount permissions
This is a follow up to #1550 where we enabled a `rw` permissions mode,
which is not ideal since it would theoretically be possible to set both
`ro` and `rw` modes at the same time. This commit fixes the issue by only
allowing one option at a time.

Fixes #1588
2024-03-07 13:01:47 +00:00
Michael Vogt
d38665a2af util: tweak bls.options_append() support no/multiple options
The BLS specification [0] says the `options` field is optional and
can also appear multiple times. This commit tweaks the code to
deal with these corner cases and also adds tests that ensure that
this works correctly.

It also tweaks the file handling to be atomic.

[0] https://uapi-group.org/specifications/specs/boot_loader_specification/
2024-02-28 10:37:01 +01:00
Michael Vogt
7b5d6e4bd9 testutil: add new mock_command context manager
The new `testutil.mock_command` context manager can be used to
mock commands in PATH and replace them with arbitrary shell
scripts. This is useful in testing to e.g. simulate exact error
conditions that would be hard to trigger otherwise or to replace
long running commands with faked results.

Example:
```
fake_cmd = textwrap.dedent("""\
do-something
""")
with mock_command("some-cmd", fake_cmd):
   your_code
```
2024-02-12 17:41:21 -08:00
Dusty Mabe
e1cbf92673 ostree: add convenience function for using default OSTree deployment
This adds a `default: true` option for all cases where OSTree
information is specified in schemas and allows for the information
to be picked up from the filesystem.

This is a safe operation because when building disk images there is
no known case where having two deployments makes sense. In the case
there ever were a case then the osname, ref, and serial options still
exist and can be used.

Co-authored-by: Luke Yang <luyang@redhat.com>
Co-authored-by: Michael Vogt <michael.vogt@gmail.com>
2024-02-07 18:50:38 -05:00
Michael Vogt
6b8c1872f6 fscache: use remove_lru() to reclaim space when the cache is full
This commit adds code that will remove the least recently used
entries when a store() operation does not succeeds because the
cache is full. To be more efficient it will try to free
twice the requested size (this can be configured in the code).
2024-02-06 17:16:48 +01:00
Michael Vogt
6096f999f3 fscache: add FsCache._remove_lru() to remove entries
The FsCache._remove_lru() removes the least recently used entry
from the cache.
2024-02-06 17:16:48 +01:00
Michael Vogt
b2a82beb75 fscache: add new `FsCache._last_used_objs()' helper
This commit adds a helper that can be used to get a sorted list
of cache entries. The list includes the name and the last_used
information.
2024-02-06 17:16:48 +01:00
Michael Vogt
a56afcb280 test: add new testutil.assert_jsonschema_error_contains() helper
This commit adds a new helper `assert_jsonschema_error_contains()`
to `testutil` and uses it everywhere where we check errors from
jsonschema.
2024-01-23 12:00:59 +01:00
Michael Vogt
f5d6d11f1d osbuild: error when {Device,Mount} is modified after creation
This is a drive-by change after spending some quality time with the
mount code. The `id` field of `Mount` is calculated only once and
only when creating a `Mount`. This seems slightly dangerous as
any change to an attribute after creation will not update the
id. This means two options:
1. dynamically update the `id` on changes
2. forbid changes after the `id` is calculcated

I went with (2) but happy to discuss of course but it seems more
the spirit of the class.

It also does the same change for "devices.Device"
2024-01-19 02:54:26 +01:00
Michael Vogt
fd2079be60 test: fix test_libc_futimes_works
The test_libc_futimes_works() is failing under RHEL/Centos right
now. To make it more robust a tiny sleep and rounding of the
timestamps is introduced to ensure that we are not run into
floating point comaparison funnines.

The second part of the fix is to open the stamp_file in read-only
mode to ensure that the mtime is not modified by the open itself
which is what lead to the actual test failure.
2024-01-18 08:44:25 +01:00
Michael Vogt
73ec3122f2 stages,test: update tests for new selinux.setfiles() calling 2024-01-11 10:23:25 +01:00
Michael Vogt
ad8fd2f532 testutil: extrace new make_fake_tree() helper
Extract a new helper `make_fake_tree()` that generalizes the existing
helper `make_fake_input_tree()`. The later will always create the
content under `{basedir}/tree` which is convinient for input tree
based tests but too specialized when using it in different contexts.

The existing `make_fake_input_tree()` is preserved unchanged and
becomes just a tiny wrapper.
2024-01-03 11:25:48 -08:00
Michael Vogt
8c95bd9dd7 test: fix autopep8 issues 2024-01-02 19:31:31 +01:00
Michael Vogt
530afa566f test: fix isort issues 2024-01-02 19:31:31 +01:00
Michael Vogt
57b5c7994e test: fix all pylint issues 2024-01-02 19:31:31 +01:00
Michael Vogt
1b297ad0ba test: add more output when ensure_mtime() assert fails 2023-12-22 19:46:48 +01:00
Michael Vogt
e76e0e92d6 osbuild: take partition into account in calc_id and add test 2023-12-22 10:18:29 -05:00
Michael Vogt
651a0ff047 test: add test that checks that partition are added to mount stage 2023-12-22 10:18:29 -05:00
Michael Vogt
827b238764 format/v2: add new "partition" field to "describe_mount" 2023-12-22 10:18:29 -05:00
Michael Vogt
2d72dc125d test: rename TestFileSystemMountService->FakeFileSystemMountService
The rename avoids warnings from pytest. It confuses this for
a unittest class apparently. And it's really a `Fake` service
anyway.
2023-12-21 16:07:35 +01:00
Michael Vogt
e35d841509 objectstore: add new skip_preserve_owner to Object.export()
This commit allows to exclude preserving ownership from an object
export. This is required to fix the issue that on macOS the an
podman based workflow cannot export objects with preserving
ownerships.

Originally this was a `no_preserve: Optional[List[str]] = None)`
to be super flexible in what we pass to `cp` but then I felt like
YAGNI - if we need more we can trivially change this (internal)
API again :)
2023-12-20 09:28:39 +01:00
Michael Vogt
caddf0adfb fscache: add new FsCache._last_used() helper
This helper can be used to implement a strategy to find the oldest
cache entries and evict them when the cache is full.

The implementation uses the `atime` of the per object `cache.lock`
file and ensures in `load()` that it's actually updated.
2023-12-12 22:57:21 +01:00
Michael Vogt
f52cabc3c1 osutil: add Libc.futimens() wrapper for futimens() call
Python has no wrapper for a futime*() call so we need to implement
it in the `util.linux` package.
2023-12-12 22:57:21 +01:00
Michael Vogt
ca9f4038c8 util: add test that validates cache update strategy 2023-12-12 22:57:21 +01:00
Brian C. Lane
9eb9f7f7f2 test: Move make_fake_input_tree to testutil
This is useful for other stage tests, move it and add a test.
2023-12-12 19:45:04 +01:00
Michael Vogt
5416028f2d osbuild: include std{out,err} in FileSystemMountService.mount() errors
This commit adds mount output to the error raised by
FileSystemMountService.mount(). This is useful when running into
mount failures during osbuild runs.

The issue was discovered while debugging a mount failure for
osbuild-composer PR#3820. Initially osbuild PR#1490 was meant
to fix it but it turned out there is a third mount helper in
the code that was originally overlooked (sorry for that!).
2023-12-12 16:25:35 +01:00
Michael Vogt
4026d4dc10 test: add test that ensures mount output is part of the exception
While debugging a failure of osbuild-composer [0] on fc39 it was
noticed that a mount failure does not include the output of
the mount command:
```
  File "/usr/lib/python3.12/site-packages/osbuild/mounts.py", line 78, in mount
    path = client.call("mount", args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/osbuild/host.py", line 348, in call
    ret, _ = self.call_with_fds(method, args)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/osbuild/host.py", line 384, in call_with_fds
    raise error
osbuild.host.RemoteError: CalledProcessError: Command '['mount', '-t', 'xfs', '-o', 'ro,norecovery', '--source', '/dev/rootvg/applv', '--target', '/tmp/tmpjtfmth56/app']' returned non-zero exit status 32.
   File "/usr/lib/python3.12/site-packages/osbuild/host.py", line 268, in serve
    reply, reply_fds = self._handle_message(msg, fds)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/osbuild/host.py", line 301, in _handle_message
    ret, fds = self.dispatch(name, args, fds)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/osbuild/mounts.py", line 111, in dispatch
    r = self.mount(args)
        ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/osbuild/mounts.py", line 160, in mount
    subprocess.run(
  File "/usr/lib64/python3.12/subprocess.py", line 571, in run
    raise CalledProcessError(retcode, process.args,
```
which makes diagnostic errors harder of course. This commit adds
a test that ensures that mount output is visbile and also changes
the code to include it.

[0] https://github.com/osbuild/osbuild-composer/pull/3820
2023-12-11 11:24:17 +01:00
Michael Vogt
158acaac78 osbuild: ensure loop.Loop() has the required device node
When loop.Loop() is called and a new loop device must be allocated
there is no gurantee that the correct device node is available on
the system. In containers /dev is often just a tmpfs with static
device nodes. So when /dev/loopN is not available when the
container is created the device node will be missing even if
`get_unbound()` create a new loop device for us.

This commit ensures that the device node is available. It creates
it unconditionally and ignores any EEXIST errors to ensure there
is no TOCTOU issue.

Note that the test could have passed a `Loop(dir_fd=open(tmpdir))`
instead of creating/patching loop.DEV_PATH but it seems slightly
nicer to test the flow without a custom dir_path as this is what
the real code that creates a loop device is also using.
2023-11-24 16:05:52 +01:00
Michael Vogt
edbf409a40 osbuild: fix missing initialization of fd in osbuild.loop.Loop
When osbuild.loop.Loop calls `__init__()` it assigns the `self.fd`
on open. However if that open call fails for whatever reason
(not found, permissions) the cleanup in `__del__` will fail in
confusing ways because `self.fd` is not initialized yet. It
also prevents the correct error from getting reported. A tiny
test is added to ensure this does not regress.
2023-11-23 14:01:53 +01:00
Michael Vogt
1374faa488 tests: remove custom tmpdir() fixtures and use tmp_path
This commit removes some unnecessary custom tmpdir() fixtures
and uses the pytest buildin tmp_path instead.

Some custom tmpdir fixtures are left in place as they configure
the tmp location to be under `/var/tmp` which is not trivial to
do with pytests `tmp_path`. Not sure or not if the is a deep
reason there for using /var/tmp. I assume it's to ensure that
the tests run on a real FS not on a potential tmpfs but I don't
have the full background so didn't want to change anything.
2023-11-23 13:09:25 +01:00
Michael Vogt
9d7bbd674f tests: remove custom tempdir_fixture
There is no need for a handcrafted tempdir fixture, pytest already
provides a build-in `tmp_path`.
2023-11-22 12:46:19 +01:00
Michael Vogt
4b69d2e1c4 util: tweak _calculate_size() to _calculate_space()
Update the naming, docstring and tweak the tests.

Thanks to bcl and dustymabe!
2023-11-22 10:28:08 +01:00
Michael Vogt
061501d4c2 osbuild: add new testutil.imports module to help test stages
This commit adds `osbuild.testutil.imports.import_module_from_path`
that can be used to import arbitrary python source files. This
allows importing files from the stages directory that have a
non python friendly filename like `org.osbuild.kickstart`.
2023-11-07 15:12:08 +01:00
Brian C. Lane
44c28c8c16 autopep8: Update with changes to make autopep8 -a -a -a happy 2023-08-10 13:04:14 +02:00
Tomáš Hozza
5946a013ee Test: some tests depending on rpm-ostree were not checking its presence
Add conditional skip to some tests that depend on rpm-ostree
availability, but were not checking for its presence. These tests would
previously fail if rpm-ostree is not available. They will be skipped
now.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
2023-04-28 22:02:35 +02:00
Simon de Vlieger
162587724a test: this test requires to be able to bindmount 2023-03-20 16:32:47 +01:00
Christian Kellner
d466d5d66a test/objectstore: use os.stat instead Path.stat
Instead of using `Path.stat` use `os.stat` since the former only
gained the `follow_symlinks` argument in 3.10 but we still need
to support Python 3.6 for RHEL 7 and 8.
Additionally, reduce the precision by converting timestamps to an
integer to avoid false negatives due to floating point arithmetic.
2022-12-28 11:35:37 +01:00
David Rheinsberg
18c69d2620 util/fscache: add cachedir-tag support
The cachedir-tag specification defines how to mark directories as
cache-directories. This allows tools like `tar` to ignore those
directories if desired (e.g., see `tar --ignore-caches`). This is very
useful to avoid huge cache-directories in backups and remote
synchronizations.

The spec simply defines a file called `CACHEDIR.TAG` with the first 43
bytes to be: "Signature: 8a477f597d28d172789f06886806bc55" (which
happens to be the MD5-checksum of ".IsCacheDirectory". Further content
is to be ignored. Any such files marks the directory in question as a
cache-directory.

The cachedir-tag has been successfully deployed in tools like `cargo`
and `VLC`, and is currently discussed to be implemented in Firefox. More
information is available here: https://bford.info/cachedir/

Signed-off-by: David Rheinsberg <david.rheinsberg@gmail.com>
2022-12-20 16:56:43 +01:00
David Rheinsberg
a3e49df619 test/fscache-coherency: add coherency tests
Add an extension to the FsCache tests which verifies cache coherency and
atomicity of the FsCache implementation. Additionally, if available, it
utilizes a cache on NFS storage to test network-support.

Unfortunately, the stress-tests keep triggering kernel-oopses in the NFS
client driver, so they are disabled for now. However, once investigated,
we can re-enable them.

Signed-off-by: David Rheinsberg <david.rheinsberg@gmail.com>
2022-12-20 16:56:32 +01:00
David Rheinsberg
8a9efa89fc util/fscache: provide store_tree() helper
Add a helper that copies an entire directory tree including all metadata
into the cache. Use it in the ObjectStore to commit entries.

Unlike FsCache.store() this does not require entering the context from
the call-site. Instead, all data is directly passed to the cache and the
operation is under full control of the cache.

The ObjectStore is adjusted to make use of this. This requires exposing
the root-path (rather than the tree-path) to be accessible for
individual objects, hence a `path`-@property is added alongside the
`tree`-@property. Note that `__fspath__` still refers to the tree-path,
since this is the only path really required for outside access other
than from the object-manager itself.

Signed-off-by: David Rheinsberg <david.rheinsberg@gmail.com>
2022-12-20 16:56:32 +01:00
Christian Kellner
76197c70c4 objectstore: support source_epoch for Object
Add a new `source_epoch` attribute that if set, will lead to all
mtimes that are newer or equal to the creation date being clamped
to the specified `source_epoch` time when the object is finalized.
2022-12-15 13:10:35 +00:00
Christian Kellner
39d38d33fd util/path: new clamp mtime function
New utility function to clamp all mtimes of a given path to a
certain timestamp. Clamp here means that any timestamp later
than the specified upper bound will be set to the upper bound.
2022-12-15 13:10:35 +00:00
David Rheinsberg
ef20b40faa util/fscache: introduce versioning
Add a new field to the cache-information called `version`, which is a
simple integer that is incremented on any backward-incompatible change.

The cache-implementation is modified to avoid any access to the cache
except for `<cache>/staging/`. This means, changes to the staging area
must be backwards compatible at all cost. Furthermore, it means we can
always successfully run osbuild even on possibly incompatible caches,
because we can always just ignore the cache and fully rely on the
staging area being accessible.

The `load()` method will always return cache-misses. The `store()`
method simply discards the entry instead of storing it. Note that
`store()` needs to provide a context to the caller, hence this
implementation simply creates another staging-context to provide to the
caller and then discard. This is non-optimal, but keeps the API simple
and avoids raising an exception to the caller (but this can be changed
if it turns out to be problematic or unwanted).

Lastly, the `cache.info` field behaves as usual, since this is also the
field used to read the cache-version. However, this file is never
written to improve resiliency and allow blacklisting buggy versions from
the past.

Signed-off-by: David Rheinsberg <david.rheinsberg@gmail.com>
2022-12-15 08:55:39 +01:00
Christian Kellner
fdd9e859dc test: convert objectstore test to pytest
Port the existing object store tests from `unittest` to `pytest`.
Allow all tests that can run without root privileges to do so. No
functional change of the test itself.
2022-12-14 13:50:28 +01:00
Christian Kellner
ae0680da11 osbuid: integrate FsCache into ObjectStore
Integrate the recently added file system cache `FsCache` into our
object store `ObjectStore`. NB: This changes the semantics of it:
previously a call to `ObjectStore.commit` resulted in the object
being in the cache (i/o errors aside). But `FsCache.store`, which
is now the backing store for objects, will only commit objects if
there is enough space left. Thus we cannot rely that objects are
present for reading after a call to `FsCache.store`. To cope with
this we now always copy the object into the cache, even for cases
where we previously moved it: for the case where commit is called
with `object_id` matching `Object.id`, which is the case for when
`commit` is called for last stage in the pipeline. We could keep
this optimization but then we would have to special case it and
not call `commit` for these cases but only after we exported all
objects; or in other words, after we are sure we will never read
from any committed object again. The extra complexity seems not
worth it for the little gain of the optimization.
Convert all the tests for the new semantic and also remove a lot
of them that make no sense under this new paradigm.

Add a new command line option `--cache-max-size` which will set
the maximum size of the cache, if specified.
2022-12-09 12:03:40 +01:00
Christian Kellner
1e0e1fa2c2 util: add helper to parse size strings
Code is based on `common.DataSizeToUint64` in Composer, with a
modification to allow `unlimited` so that the result is compatible
with `fscache.MaximumSizeType`.

[1] f4aed3e6e2/internal/common/helpers.go (L46)
2022-12-09 12:03:40 +01:00
Christian Kellner
e2c687e363 test/objectstore: properly enter store context
In the `store_server` test, pass the store to `enter_context`,
instead of the `stack`; the latter is an interesting form of
recursion, and totally not what we want.
2022-12-09 12:03:40 +01:00
Christian Kellner
809c9e7828 pipeline,api: write metadata directly
Instead of transmitting stage metadata over a socket and then
writing it via `Object.meta.write`, use the latter and bind
mount the corresponding file into the stage so it can directly
be written to from the stage. Change `api.metadata` to do so,
which means that this change is transparent for the stages.
2022-12-09 12:03:40 +01:00