Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd: implement manifest command #6

Merged
merged 9 commits into from
Dec 16, 2024
Merged

Conversation

mvo5
Copy link
Collaborator

@mvo5 mvo5 commented Dec 2, 2024

This commit implements the manifest command for image-builder.
It will generate an osbuild manifest based on the given inputs,
e.g.:

$ ./image-builder manifest --blueprint /path/to/blueprint.toml centos-9 qcow2
{"version":"2","pipelines":[{"name":"build","runner":",...

Note that there is an integration test but because of the depsolve
it will be slow. It will be skipped when doing go test -short.

Integration tests for ostree commit, this is because ostree commit integration tests will need "build" first because the way this is tested today is that first an edge-commit is created, then an edge-ami based on this commit is generated. But "build" is currently missing

Note that this has no README.md update for manifest because manifest is considered an internal command, once "build" is added (which is easy once manifest is there) "build" will be documented.

@mvo5 mvo5 requested a review from achilleas-k December 2, 2024 12:49
@mvo5 mvo5 marked this pull request as ready for review December 2, 2024 14:28
@mvo5 mvo5 requested a review from ondrejbudai December 2, 2024 15:37
@mvo5 mvo5 mentioned this pull request Dec 3, 2024
HACKING.md Outdated Show resolved Hide resolved
HACKING.md Outdated Show resolved Hide resolved
HACKING.md Outdated Show resolved Hide resolved
HACKING.md Outdated Show resolved Hide resolved
HACKING.md Outdated Show resolved Hide resolved
internal/manifestgen/manifestgen.go Show resolved Hide resolved
internal/manifestgen/manifestgen.go Outdated Show resolved Hide resolved
internal/manifestgen/manifestgen.go Show resolved Hide resolved
@@ -69,6 +104,17 @@ operating sytsems like centos and RHEL with easy customizations support.`,
listImagesCmd.Flags().String("output", "", "Output in a specific format (text, json)")
rootCmd.AddCommand(listImagesCmd)

manifestCmd := &cobra.Command{
Use: "manifest <distro> <image-type> [<arch>]",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be nicer if the architecture was a flag option (--arch)?
That way we could make blueprint an optional positional argument, which I think would be a more common usage. Switching the arch would probably be less common.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that is an interesting idea. The reason for current layout is that it's designed to be copy/paste friendly from list-iamges. I.e.

$ image-builder list-images
...
rhel-10.0 type:oci arch:x86_64
$ image-builder manifest rhel-10.0 type:oci arch:x86_64
...

so we could tweak the list output to

$ image-builder list-images
...
rhel-10.0 type:vhd --arch x86_64
rhel-10.0 type:vmdk --arch x86_64
rhel-10.0 type:oci --arch x86_64
$ image-builder manifest rhel-10.0 type:oci --arch x86_64
...

(which looks a bit uneven but not too bad and for scripts we provide --json output).

Or we could drop this property (copy/pastable). Or we make the third argument fuzzy, i.e. if it starts with "arch:" we consider it an architecture and otherwise its a blueprint. (or something else I forgot?)

WDYT?

Copy link
Member

@achilleas-k achilleas-k Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we could tweak the list output to

$ image-builder list-images
...
rhel-10.0 type:vhd --arch x86_64
rhel-10.0 type:vmdk --arch x86_64
rhel-10.0 type:oci --arch x86_64
$ image-builder manifest rhel-10.0 type:oci --arch x86_64
...

Eeeeeeeh... no. That's too weird.

Or we could drop this property (copy/pastable).

It's a nice property but yes I don't think it's important enough to make the output of another command so unusual.

Or we make the third argument fuzzy, i.e. if it starts with "arch:" we consider it an architecture and otherwise its a blueprint.

Not a bad idea.

(or something else I forgot?)

Perhaps something more uniform?

$ image-builder list-images
...
distro:rhel-10.0 type:vhd arch:x86_64
distro:rhel-10.0 type:vmdk arch:x86_64
distro:rhel-10.0 type:oci arch:x86_64

$ image-builder manifest distro:rhel-10.0 type:oci arch:x86_64

While that makes typing out a manifest or build command by hand a tiny bit more tedious, it also makes it nice that the args aren't positional anymore and opens up the way to make distro optional too.

So you could do:

$ image-builder manifest type:qcow2

which would imply distro:$hostdistro,arch:$hostarch, and blueprint:/dev/null (empty).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While that makes typing out a manifest or build command by hand a tiny bit more tedious, it also makes it nice that the args aren't positional anymore and opens up the way to make distro optional too.

One issue with this is that we're inventing a new convention for non-positional arguments with option:value instead of the standard --option=value ...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[..]

Or we could drop this property (copy/pastable).

It's a nice property but yes I don't think it's important enough to make the output of another command so unusual.
[..]

Let's do that then, it's the most simple and straightforward change. I am a little bit sad about it because now:

$ image-builder manifest distro:rhel-10.0 type:oci arch:x86_64
error: cannot find blueprint "arch:x86_64"

$ image-builder build distro:rhel-10.0 type:oci arch:x86_64
error: cannot find blueprint "arch:x86_64"

We could change the default for image-builder-cli list-image to only show same arch images by default and hint at something like "--all" to see all, then we would have preserved the copy/paste property again (at least by default) and it's nicer for the "build" case. Open for ideas of course but that seems a reasonable path forward(?).

Copy link
Collaborator Author

@mvo5 mvo5 Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed this tweak now in a "fixup!" commit for easier review and squash them all at the end:

$ image-builder manifest centos-9 qcow2 
...
$ image-builder manifest centos-9 qcow2 ./path/to/blueprint
...
image-builder manifest --arch s390x centos-9 qcow2 /path/to/blueprint
...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be nicer if the architecture was a flag option (--arch)? That way we could make blueprint an optional positional argument, which I think would be a more common usage. Switching the arch would probably be less common.

I'd agree that this would be the more common usage but for the build command, not the manifest. My reasoning is that we will most probably end up generating manifests on a host that may not have the desired architecture. For "internal" usage, I'd be fine with BP being the an option instead.

There's no perfect solution here, as I can make an argument for any combination of BP and arch (not) being a positional argument.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fwiw, I have no strong opinion, I like the copy/paste property of the original design and "bib" also rquires an argument (currently) to pass a blueprint. Going back to the previous way is as easy as removing the last commit :) But I'm more interested in a way forward right now than which way it is :) (I would love to get this in before EOY)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This had some more (offline) discussion with Ondrej and Achilleas and the latest agreement is:

This commit tweaks the argument handling based on the suggestion
by Achilleas and Ondrej (thanks!). Now it takes

$ image-builder manifest qcow2 ./path/to/blueprint
...
$ image-builder manifest --arch s390x --distro centos-9 qcow2
...

If no arch is specified the hostname arch is used. If no distro
is specified in either the blueprint or the commandline it is
auto-detected based on the host.

Note that if the distro from the comandline and the blueprint
diverge an error is raised. We can relax this rule and just
add precedence, e.g. commandline always overrides the blueprint
but ideally we would have a clear use-case here so we start
conservative and can always relax this rule later (the inverse
is much harder).

This means it is no longer copy/paste friendly from `list-images`
by default but instead we can provide a new
`list-images --output=shell` option that outputs in exactly the
format that `image-builder [manifest|build]` need.

cmd/image-builder/main.go Outdated Show resolved Hide resolved
@mvo5 mvo5 force-pushed the add-manifest-2 branch 2 times, most recently from df44603 to 82e057f Compare December 4, 2024 09:34
@mvo5 mvo5 requested a review from achilleas-k December 4, 2024 09:35
@mvo5 mvo5 force-pushed the add-manifest-2 branch 2 times, most recently from d4101ef to d46d430 Compare December 4, 2024 09:54
@thozza thozza self-requested a review December 6, 2024 11:59
Copy link
Member

@thozza thozza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work. I've added a few comments.

HACKING.md Outdated
The go source code of image-builder-cli is under
`./cmd/image-builder`. It uses the
[images](https://github.com/osbuild/images) library internally to
generate the imagess. Unit tests (and integration tests where it makes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: imagess

// PipelineNamesFrom will return all pipeline names from an osbuild
// json manifest. It will error on missing pipelines.
//
// XXX: move to images:pkg/manifesttest? or something
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO yes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this as a TODO

Comment on lines +32 to +34
depsolvedSets[name] = res.Packages
repoSets[name] = res.Repos
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be good to note here that the code discards the SBOM part of res.

internal/manifestgen/manifestgen.go Show resolved Hide resolved
@@ -69,6 +104,17 @@ operating sytsems like centos and RHEL with easy customizations support.`,
listImagesCmd.Flags().String("output", "", "Output in a specific format (text, json)")
rootCmd.AddCommand(listImagesCmd)

manifestCmd := &cobra.Command{
Use: "manifest <distro> <image-type> [<arch>]",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be nicer if the architecture was a flag option (--arch)? That way we could make blueprint an optional positional argument, which I think would be a more common usage. Switching the arch would probably be less common.

I'd agree that this would be the more common usage but for the build command, not the manifest. My reasoning is that we will most probably end up generating manifests on a host that may not have the desired architecture. For "internal" usage, I'd be fine with BP being the an option instead.

There's no perfect solution here, as I can make an argument for any combination of BP and arch (not) being a positional argument.

internal/blueprintload/blueprintload.go Show resolved Hide resolved
Copy link
Member

@ondrejbudai ondrejbudai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great. I would like to have an answer for the seeding, other comments are nitpicks. :)

if err != nil {
return nil, err
}
// strip prefixes to make ib copy/paste friendly when pastring output
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pastring -> pasting

for name, pkgSet := range packageSets {
res, err := solver.Depsolve(pkgSet, sbom.StandardTypeNone)
if err != nil {
return nil, nil, err
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how much this is worth since we really need a shared helper, but still: I think this error should be wrapper with name.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I wrapped all errors from the default*Resolver now

if err != nil {
return err
}
preManifest, warnings, err := imgType.Manifest(bp, *imgOpts, repos, 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the seed here? I think the we should make it random by default. A fixed seed should be opt-in.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, (very) nice catch and urg for missing this.

Thinking a bit about it I wonder^Wthink we should look into images and tweak the API here, it seems in almost all "real" use-cases one would want a non-zero seed here so maybe this could become either a pointer (and on nil we just pick a random seed) or keep as is but assign a random value if we get "0" in images. Obviously followup material and I fixed this instance of the issue here but thinking about the future/a followup, wdyt?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened osbuild/images#1107 as an RFC

mvo5 added 5 commits December 13, 2024 09:22
This commit adds a helper to find exactly a single image from a
given disto/type/arch description. This will be used in `manifest`,
`build` and potentially more. It is meant to support copy/paste
from the `image-builder list-images` output, so: "distro:centos-9"
is support just like "centos-9" (same for distro/imgType/arch).
This commit adds a basic HACKING.md that explains the bare mimimum
to get started, including `go test -short` to skip the expensive
tests.

Contains also a drive-by rename of the test dependency install
for the GH action.
This commit adds a new `manifesttest` that helps sharing code
when testing generated osbuild manifests.
This commit adds a new generic `manifestgen` package that can be
used to generate osbuild manifests. It works on a higher level
then the low-level `manifest` package from `images` and provides
plugable resolvers and a streamlined API.

This package is meant to be moved to the `images` library eventually.
This commit implements the `manifest` command for `image-builder`.
It will generate an osbuild manifest based on the given inputs,
e.g.:
```
$ ./image-builder manifest centos-9 qcow2
{"version":"2","pipelines":[{"name":"build","runner":",...
```

Note that there is an integration test but because of the depsolve
it will be slow. It will be skipped when doing `go test -short`.
Copy link
Member

@ondrejbudai ondrejbudai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this very much. Some minor issues inline.

Short: "Build manifest for the given distro/image-type, e.g. centos-9 qcow2",
RunE: cmdManifest,
SilenceUsage: true,
Args: cobra.MinimumNArgs(2),
Args: cobra.MinimumNArgs(1),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't cobra have RangeArgs(1, 2)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, TIL!

internal/blueprintload/blueprintload.go Outdated Show resolved Hide resolved
cmd/image-builder/main.go Outdated Show resolved Hide resolved
cmd/image-builder/distro.go Outdated Show resolved Hide resolved
mvo5 added 3 commits December 13, 2024 16:33
This commit provides a `blueprintload` package that can be used
to load blueprints from json/toml from a path. This will be used
in `bootc-image-builder` and `image-builder-cli` and should
eventually be merged into `images`.
This commit adds support to pass a blueprint to the manifest
generation.
This commit adds an integration test for the container resolving
when generating a manifest. This is sadly quite indirect right now
because `manifestgen` needs some more support from `images` and
the `distro_test` code there (that will hopefully come soon(ish)).
This commit tweaks the argument handling based on the suggestion
by Achilleas and Ondrej (thanks!). Now it takes
```console
$ image-builder manifest qcow2 ./path/to/blueprint
...
$ image-builder manifest --arch s390x --distro centos-9 qcow2
...
```
If no arch is specified the hostname arch is used. If no distro
is specified in either the blueprint or the commandline it is
auto-detected based on the host.

Note that if the distro from the comandline and the blueprint
diverge an error is raised. We can relax this rule and just
add precedence, e.g. commandline always overrides the blueprint
but ideally we would have a clear use-case here so we start
conservative and can always relax this rule later (the inverse
is much harder).

This means it is no longer copy/paste friendly from `list-images`
by default but instead we can provide a new
`list-images --output=shell` option that outputs in exactly the
format that `image-builder [manifest|build]` need.
Copy link
Member

@ondrejbudai ondrejbudai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good from my PoV

@supakeen supakeen added this pull request to the merge queue Dec 16, 2024
Merged via the queue into osbuild:main with commit 4b8bff8 Dec 16, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants