Commit graph

74 commits

Author SHA1 Message Date
Tomas Hozza
a4e6531565 worker: define job types as constants
Define supported job type names as constants and use them in all places,
instead of string literals.

There are multiple benefits of this approach. Using constants removed
the room for typos in the string literals. One can use autocompletion in
IDE for job types. Using constant makes it easier to find all references
where it is used and thus all places that are handling a specific job
type.
2022-06-10 14:48:18 +01:00
Achilleas Koutsou
9fda1ff55f dnfjson: cache cleanup
Added CleanCache() method to the solver that deletes all the caches if
the total size grows above a certain (configurable) limit
(default: 500 MiB).

The function is called externally to handle errors (usually log or
ignore completely) and to avoid calling multiple times for multiple
depsolves of a single request.

The cleanup is extremely simple and is meant as a placeholder for more
sophisticated cache management.  The goal is to simply avoid ballooning
cache sizes that might cause issues for users or our own services.
2022-06-01 11:36:52 +01:00
Achilleas Koutsou
7a70a5e69b dnfjson: drop repo checksums
The repository checksums in the response from dnf-json aren't used
anywhere.  Since we're making changes to dnf-json and depsolving, now is
a good opportunity to drop them completely.
2022-06-01 11:36:52 +01:00
Achilleas Koutsou
c092783a70 simplify package set chain handling
Move package set chain collation to the distro package and add
repositories to the package sets while returning the package sets from
their source, i.e., the ImageType.PackageSets() method.

This also removes the concept of "base repositories".  There are no
longer repositories that are added implicitly to all package sets but
instead each package set needs to specify *all* the repositories it will
be depsolved against.

This paves the way for the requirement we have for building RHEL 7
images with a RHEL 8 build root.  The build root package set has to be
depsolved against RHEL 8 repositories without any "base repos" included.
This is now possible since package sets and repositories are explicitly
associated from the start and there is no implicit global repository
set.

The change requires adding a list of PackageSet names to the core
rpmmd.RepoConfig.  In the cloud API, repositories that are limited to
specific package sets already contain the correct package set names and
these are now copied to the internal RepoConfig when converting types in
genRepoConfig().
The user-specified repositories are only associated with the payload
package sets like before.
2022-06-01 11:36:52 +01:00
Achilleas Koutsou
b56ff56189 tests: use TestMain() instead of Init() to compile mock-dnf-json
Lets us have teardown code so we can clean up the temporary directory
where the binary was built.
2022-06-01 11:36:52 +01:00
Achilleas Koutsou
86536f11e7 rpmmd: add Repositories list to PackageSet struct
Attach the repository configurations that are specific to a package set
directly on the PackageSet object.  This simplifies the Depsolve()
signature and avoids requiring a `nil` when no additional repositories
are required.  More importantly, it makes associating repositories to
package sets explicit, no longer relying on matching array indices or
map keys.
2022-06-01 11:36:52 +01:00
Achilleas Koutsou
61d7c465af dnfjson: remove single Depsolve function and command
Remove the single Depsolve function from the dnfjson package and the
depsolve command from the dnf-json tool.  The new ChainDepsolve
functions and chain-depsolve command can handle single depsolves in the
same way so there's no need to keep (and have to maintain) two versions
of very similar code.

The ChainDepsolve function (in Go) and chain-depsolve command (in
Python) have been renamed to plain Depsolve and depsolve respectively,
since they are now general purpose depsolve functions.
2022-06-01 11:36:52 +01:00
Achilleas Koutsou
8518488028 kojiapi: double word typo fixes in error messages 2022-06-01 11:36:52 +01:00
Achilleas Koutsou
177ea1b08f Replace all rpmmd.Depsolve() calls with dnfjson
All calls to rpmmd.Depsolve() are now replaced with the equivalent call
to solver.Depsolve() (or dnfjson.Depsolve() for one-off calls).

Attached an unconfigured dnfjson.BaseSolver to all APIs and server
configurations where rpmmd.RPMMD used to be.  This BaseSolver instance
loads the repository credentials from the system and carries the cache
directory, much like the RPMMD field used to do.  The BaseSolver is used
to create an initialised (configured) solver with the platform variables
(module platform ID, release ver, and arch) before running a Depsolve()
or FetchMetadata() using the NewWithConfig() method.

The FillDependencies() call in the modulesInfoHandler() of the weldr API
has been replaced by a direct call to the Depsolve() function.  This
rpmmd function was only used here.  Replacing the rpmmd.Depsolve() call
in rpmmd.FillDependencies() with dnfjson.Depsolve() would have created
an import cycle.  The FillDependencies() function could have been moved
to dnfjson, but since it's only used in one place, moving the one-line
function body into the caller is ok.

For testing:

The mock-dnf-json is compiled to a temporary directory during test
initialisation and used for each Depsolve() or FetchMetadata() call.

The weldr API tests now use the mock dnfjson.  Each rpmmd_mock.Fixture
now also has a dnfjson_mock.ResponseGenerator.

All API calls in the tests use the proper functions from dnfjson and
only the dnf-json script is mocked.  Because of this, some of the
expected results in responses_test had to be changed to match correct
behaviour:
- The "builds" array of each package in the result of a module or
  project list is now sorted by version number (ascending) because we
  sort the package list in the result of dnfjson by NVR.
- 'check_gpg: true' is added to the expected response of the depsolve
  test.  The repository configs in the test weldr API specify 'CheckGPG:
  True', but the mock responses returned it as false, so the expected
  result didn't need to include it.  Since now we're using the actual
  dnfjson code to convert the mock response to the internal structure,
  the repository settings are correctly used to set flag to true for
  each package associated with that repository.
- The word "occurred" was mistyped as "occured" in rpmmd and is now
  fixed in dnfjson.
2022-06-01 11:36:52 +01:00
Tomas Hozza
b92196a056 kojiapi: use DepsolvePackageSets instead of Depsolve 2022-04-28 14:42:49 +02:00
Eng Zer Jun
00ea3eb285 test: use T.TempDir to create temporary test directory
The directory created by `T.TempDir` is automatically removed when the
test and all its subtests complete.

Reference: https://pkg.go.dev/testing#T.TempDir
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2022-04-05 09:27:43 +02:00
Ondřej Budai
7bfcee36f8 jobqueue: introduce the concept of channels
Channels are a concept similar to job types. Callers must specify a channel
name when queueing a new job. A list of channels is also specified when
dequeueing a job. The dequeued job's channel will always be from one of the
specified channel. Of course, the job types are also respected. The dequeued
job will also always be from one of the specified type.

Currently, all calls to jobqueue were changed so all queue operations use
an empty channel name and all dequeue operations use a list containing
an empty channel.

Thus, this is a non-functional change.

Signed-off-by: Ondřej Budai <ondrej@budai.cz>
2022-03-08 12:07:00 +01:00
Tom Gundersen
b32ab36e1d worker/server: typesafe Job and JobStatus
Replace Job() and JobStatus() with typesafe versions, and introduce JobType()
for the rare instances where we don't know the type up front.

Additionally, catch a few more error cases:
 - if OSBuildResult is nil, then we failed to invoke osbuild
 - make sure the same JobResult handling is done for osbuild-koji, as for osbuild
2022-02-01 20:28:40 +00:00
Christian Kellner
5e2617ed49 kojiapi: successful osbuild jobs must have output
When we compute the overall status of a koji compose, the individual
build jobs are checked. Currently, a job is considered a failure, if
a build job has output (`OSBuildOutput`) and the output's `Success`
field is `false`. But `OSBuildOutput` will be `nil` when osbuild
crashed or refused the manifest input. Therefore the job status is
a failure if `OSBuildOutput` is `nil`, since if osbuild was run,
and the run was successful we must have a non-`OSBuildOutput` field.
2022-01-28 20:37:23 +00:00
Gianluca Zuccarelli
88b5529cc4 osbuild-worker: test error backwards compatability
Since the workers will use structured error messages
going forward, it is necessary to maintain backwards
compatability for there errors in composer. Tests have
been added to the various apis to ensure that each api
checks for both kinds of errors, old and new.
2022-01-27 16:45:14 +01:00
Gianluca Zuccarelli
cc981b887a osbuild-worker: implement structured errors
Implement the structured errors as defined by the worker client.
Every error for each of the job types now returns a structured
error with a reason and a specific error code.  This will make
it possible to differentiate between 4xx errors and 5xx errors.

This commit refactors the way errors are implemented in the workers,
but maintains backwards compatability in composer by checking for
both kinds of errors.
2022-01-27 16:45:14 +01:00
sanne
a83cf95d5b go.mod: Update oapi-codegen and kin-openapi 2022-01-12 11:35:06 +01:00
Ondřej Budai
c55ec88505 api/koji: fix /compose/log route
We have been actually unmarshalling into a wrong datatype for a year, by
fixing this, we should get much more logging in Brew.

Signed-off-by: Ondřej Budai <ondrej@budai.cz>
2021-11-30 18:14:10 +01:00
Achilleas Koutsou
9aef7bfc47 osbuild-worker: attach pipeline names to jobs
Pipeline names are added to each job before adding to the queue. When a
job is finished, the names are copied to the Result object as well. This
is done for both OSBuild and Koji jobs.

The pipeline names in the result are primarily used to separate package
lists into build and payload/image packages in two cases:
1. Koji builds: for reporting the build root and image package lists to
   Koji (in Koji finalize).
2. Cloud API (v1 and v2): for reporting the payload packages in the
   metadata request.

The pipeline names are also used to print the system log output in the
order in which pipelines are executed. This still isn't used when
printing the OSBuild Result (osbuild2.Result.Write()) and we still rely
on sorting by pipeline name
(see https://github.com/osbuild/osbuild-composer/pull/1330).
2021-11-16 09:49:37 +01:00
Achilleas Koutsou
682fc245e5 kojiapi: use osbuild2.Result in test
Signed-off-by: Achilleas Koutsou <achilleas@koutsou.net>
2021-11-16 09:49:37 +01:00
sanne
2f328b0e97 workers: Backwards compatible api.openshift.com spec compliance
The main changes are:
- Kind, Href, Id fields for every object returned
- Attach operationIds to each request, return it for errors
- Errors are predefined and queryable
2021-09-27 13:10:05 +01:00
Martin Sehnoutka
1ada606ed8 internal/rhsm: introduce package that handles subscriptions
The problem: osbuild-composer used to have a rather uncomplete logic for
selecting client certificates and keys while fetching data from
repositories that use the "subscription model". In this scenario, every
repo requires the user to use a client-side TLS certificate. The problem
is that every repo can use its own CA and require a different pair of
a certificate and a key. This case wasn't handled at all in composer.

Furthermore, osbuild-composer can use remote workers which complicates
things even more.

Assumptions: The problem outlined above is hard to solve in the general
case, but Red Hat Subscription Manager places certain limitations on how
subscriptions might be used. For example, a subscription must be tight to
a host system, so there is no way to use such a repository in osbuild-composer
without it being available on the host system as well.

Also, if a user wishes to use a certain repository in osbuild-composer it
must be available on both hosts: the composer and the worker. It will come
with different pair of a client certificate and a key but otherwise, its
configuration remains the same.

The solution: Expect all the subscriptions to be registered in the
/etc/yum.repos.d/redhat.repo file. Read the mapping of URLs to certificates
and keys from there and use it. Don't change the manifest format and let
osbuild guess the appropriate subscription to use.
2021-08-09 12:40:23 +02:00
sanne
0fcb44e617 worker: Move job tokens to the queue itself
This removes state from the worker server, as it no longer contains the
list of running jobs. Instead only the queue knows if jobs are running
or not.
2021-07-08 21:14:38 +01:00
Achilleas Koutsou
1a3447ed38 kojiapi: include image type exports in Koji job args
Koji image request handling now reads the exports defined by each image
type. All APIs now support reading the exports defined by each image
type. The worker still falls back to "assembler" in case the call comes
from an older version of composer.
2021-06-18 14:02:09 +01:00
Tomas Hozza
f7f064274a Tests: remove fedoratest and replace it with test_distro
fedoratest was yet another dummy distribution used by unit tests. After
the rework of test_distro, there is no reason to not use it as the only
distro implementation for testing purposes.

Remove fedoratest distro and replace it with test_distro in all affected
tests.

Signed-off-by: Tomas Hozza <thozza@redhat.com>
2021-05-14 15:43:00 +02:00
Achilleas Koutsou
8090621300 osbuild: rename package to osbuild1
Preparing for version 2 of the manifest schema, which will be
implemented in a separate package (osbuild2) alongside the original.
2021-03-17 18:12:17 +00:00
Ondřej Budai
dd4db353e2 distro: move Registry to its own distroregistry package
My goal is to add a method to distroregistry to return Registry with
all supported distributions. This way, all supported distributions
would be defined only on one place.

To achieve this, the Registry must live outside the distro package
because the distro implementation depends on it and this would create
a circular dependency unsupported by Go.

Signed-off-by: Ondřej Budai <ondrej@budai.cz>
2021-03-12 08:29:30 +01:00
Tom Gundersen
9e2e009ac8 distro: introduce PackageSets
This replaces Packages() and BuildPackages() by returning a map of
package sets, the semantics of which is up to the distro to define.

They are meant to be depsolved and the result returned back as a
map to Manifest(), with the same keys.

No functional change.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2021-03-10 11:52:05 +00:00
Achilleas Koutsou
487299f09c kojiapi: Job not found should return 404
Not Found (404) is a more appropriate code for requesting a valid
(correctly formatted) UUID that doesn't exist in the job queue.
2021-01-19 10:37:51 +01:00
Achilleas Koutsou
9d3d4dcdea kojiapi/test: Make calls with init, build job IDs
Send requests to the compose/{id}, compose/{id}/logs, and
compose/{id}/manifests using job IDs for non-finalize type jobs to test
the type verification.
2021-01-19 10:37:51 +01:00
Achilleas Koutsou
e59e07a09a kojiapi: Check job type (job status and logs)
The type verification introduced in the previous commit is now also used
when retrieving the job status (GET /compose/{id}) and the logs (GET
/compose/{id}/logs).

In these cases, job retrieval needs to be performed twice:
1. First the job parameters are retrieved (Job()) to check the type.
2. Then the job result is retrieved (JobStatus()) for the status or
   logs.

This makes it unlikely (essentially impossible) that the retrieval will
fail with "not found" on the second retrieval (JobStatus()), but it's
still a good sanity check for the system.

Verifies the Koji job types when retrieving Init and Build jobs as well.
2021-01-19 10:37:51 +01:00
Achilleas Koutsou
a2c4622930 kojiapi: Check job type when retrieving from queue
When a job's arguments are retrieved (for the /manifests API endpoint),
the incoming ID should correspond to a Finalize Job.  The new
worker.Job() method helps us verify the type and produce an error if the
wrong type is found.
Similarly, the dependencies of a Finalize Job should be in order (Init
Job first followed by Build Jobs).  The types are validated while
iterating the dependency list.

Added convenience functions that check the retrieved job type and return
the initialised struct or an error if the ID is not found or does not
match the type.

Currently the getInitJob() function isn't used but it will be useful
later.
2021-01-19 10:37:51 +01:00
Achilleas Koutsou
668fb003ef jobqueue: Replace JobArgs() with Job()
JobArgs() function replaced with more general Job() function that
returns all the parameters used to originally define a job during
Enqueue(). This new function enables access to the type of a job in the
queue, which wasn't available until now (except when Dequeueing).
2021-01-19 10:37:51 +01:00
Achilleas Koutsou
75a96bd99d test: Job args/manifests retrieval
1. Test retrieving the job arguments from the worker using an
   OSBuildJob.
   Very basic test with an empty manifest.
2. Test retrieving job manifests through the Koji API. Uses the existing
   TestCompose test. The returned manifests are empty for all cases.
2021-01-16 13:39:30 +01:00
Achilleas Koutsou
8f4c72b0a3 kojiapi: Fix common typo in comments 2021-01-16 13:39:30 +01:00
Achilleas Koutsou
7ec084fa56 kojiapi: Add endpoint for retrieving job manifest
Add and implement an API endpoint that returns the manifests for a given
osbuild-koji job. The route returns an array of manifests, one for each
image in the request.

Retrieves the arguments of each Build Job to extract the Manifest.
2021-01-16 13:39:30 +01:00
Lars Karlitski
90e15da032 kojiapi/test: use the worker of the fixture
No need to create a second one.
2021-01-12 12:19:25 +01:00
Jacob Kozol
da6f5ba701 kojiapi,cloudapi: exclude packages when depsolving
When rpmmd's Depsolve function is called we need to pass in the image
type's excluded packages. These excluded packages are retrieved when we
get the packages we include from each image type.
2021-01-06 21:34:37 +01:00
Ondřej Budai
1dd4eb7e38 composer: seed the random number generator
I thought rand in Go is auto-seeded but I was wrong, see [1].
This commit adds seed initialization.

[1]: https://golang.org/pkg/math/rand/#Seed

Signed-off-by: Ondřej Budai <ondrej@budai.cz>
2020-12-15 21:26:40 +01:00
Ondřej Budai
973639d372 distro/rhel84: use a random uuid for XFS partition
Imagine this situation: You have a RHEL system booted from an image produced
by osbuild-composer. On this system, you want to use osbuild-composer to
create another image of RHEL.

However, there's currently something funny with partitions:

All RHEL images built by osbuild-composer contain a root xfs partition. The
interesting bit is that they all share the same xfs partition UUID. This might
sound like a good thing for reproducibility but it has a quirk.

The issue appears when osbuild runs the qemu assembler: it needs to mount all
partitions of the future image to copy the OS tree into it.

Imagine that osbuild-composer is running on a system booted from an imaged
produced by osbuild-composer. This means that its root xfs partition has this
uuid:

efe8afea-c0a8-45dc-8e6e-499279f6fa5d

When osbuild-composer builds an image on this system, it runs osbuild that
runs the qemu assembler at some point. As I said previously, it will mount
all partitions of the future image. That means that it will also try to
mount the root xfs partition with this uuid:

efe8afea-c0a8-45dc-8e6e-499279f6fa5d

Do you remember this one? Yeah, it's the same one as before. However, the xfs
kernel driver doesn't like that. It contains a global table[1] of all xfs
partitions that forbids to mount 2 xfs partitions with the same uuid.

I mean... uuids are meant to be unique, right?

This commit changes the way we build RHEL 8.4 images: Each one now has a
unique uuid. It's now literally a unique universally unique identifier. haha

[1]: a349e4c659/fs/xfs/xfs_mount.c (L51)
2020-12-15 16:43:39 +01:00
Ondřej Budai
3d465a4778 api/koji: invert the compose status condition
This is just easier to grasp.

Signed-off-by: Ondřej Budai <ondrej@budai.cz>
2020-12-02 10:27:31 +01:00
Ondřej Budai
00cd4cb346 api/koji: return pending status until all jobs are finished
Previously, the compose status returned failure as soon as possible.
koji-osbuild considers the job as done when its status == failure and proceeds
with uploading the logs to koji and marking the job as failed. However, not
all osbuild-composer jobs might be done at this point so the logs might be
incomplete making the debugging hard.

This commit changes the behaviour: Now, the compose status is pending until
ALL jobs belonging to it are finished.

Signed-off-by: Ondřej Budai <ondrej@budai.cz>
2020-12-02 10:27:31 +01:00
Ondřej Budai
e10a7f1ccc {koji,worker}/server: log errors returned from handlers
Previously, we had no clue what errors were catched by the default echo's
error handler. Thus, in the case of an error, we were basically blind. Let's
log all errors so we can investigate them later.

Signed-off-by: Ondřej Budai <ondrej@budai.cz>
2020-12-02 08:52:27 +01:00
Ondřej Budai
978e309153 worker/server: move it to the style of koji server
The previous code was smelling a bit (e.g. Server.server field) so I decided
to rewrite it in the style of the much nicer koji server.

Not a functional change.

Signed-off-by: Ondřej Budai <ondrej@budai.cz>
2020-11-19 17:39:24 +00:00
Tom Gundersen
bf86e8ad79 workerapi: serialize koji errors as strings
Serializing an interface does not work, let us simply use the string
representation and treat the empty string as no error. This is
compatible with the current API in the success case, and fixes the
error case, which is currently broken.

Also extend the test matrix for the kojiapi to ensure that all the
different kinds of errors can be serialized correctly and leads to
the correct status being returned.

Fixes #1079 and #1080.
2020-11-13 09:39:55 +01:00
Ondřej Budai
a6df2877a3 fsjobqueue: accept jobs of any type
Soon, we want to begin tagging the jobs with the name of its submitter.
The simplest way to add a tag to a job is to put it into its type string.
However, as we don't know (and don't want to know) the submitters' names when
osbuild-composer is initialized, we need to be able to push arbitrary job
types into the jobqueue.

This commit therefore lifts the restriction that a jobqueue accepts only
a predefined set of job types. Now, jobqueue clients can push jobs of
arbitrary names.

Signed-off-by: Ondřej Budai <ondrej@budai.cz>
2020-11-12 15:30:30 +00:00
Tom Gundersen
f9af1e3e13 kojiapi/logs: adjust for multi-build composes
Return the full array of image build logs, as well as logs for the
init and import tasks.
2020-11-11 18:16:42 +01:00
Tom Gundersen
a99127aed9 kojiapi: add basic test
This test schedules a compose, pops the jobs off the queue, marks each
as done and verifies that the compose is correctly marked as successful.
2020-11-11 18:16:42 +01:00
Tom Gundersen
5dac422b9c cmd/composer: drop koji configuration
Now that all interaciton with the koji API happens in the workers
we can drop koji configuration from composer itself. This means
that composer no longer needs to be provisioned with kerberos
credentials, and does not need to know about which koji servers
the workers support.
2020-11-11 18:16:42 +01:00
Tom Gundersen
654daf96c1 kojiapi: return BuildID from status route
This is no longer returned when creating a compose, as it is obtained
asynchronously.

The TaskID is still returned, and is always set to 0. This is not right,
and should either be fixed or dropped. The caller should know the TaskID
(if they have one), so this is redundant and currently unused.
2020-11-11 18:16:42 +01:00