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

DnfContext: fix handling of default module profiles #1278

Merged

Conversation

jlebon
Copy link
Contributor

@jlebon jlebon commented Jun 21, 2021

Currently, default profiles are encoded in modulemd-defaults, which are
separate from the modulemd spec. E.g. in Fedora, it's in:
https://pagure.io/releng/fedora-module-defaults

The ModulePackage::getDefaultProfile() function only queried for the
modulemd data, not modulemd-defaults data. Eventually, once MBS learns
about defaults in modulemds Fedora may start using it, but until then
and regardless we need to support defaults in modulemd-defaults, i.e.
using container->getDefaultProfiles(), just like dnf does.

@jlebon
Copy link
Contributor Author

jlebon commented Jun 21, 2021

/cc @sgallagher for commit message accuracy

Eventually, once MBS learns about defaults in modulemds Fedora may start using it

Is there a link tracking this work BTW? If so, I'll throw the link in there. I looked in https://pagure.io/fm-orchestrator/issues but didn't find anything.

Currently, default profiles are encoded in modulemd-defaults, which are
separate from the modulemd spec. E.g. in Fedora, it's in:
https://pagure.io/releng/fedora-module-defaults

The `ModulePackage::getDefaultProfile()` function only queried for the
modulemd data, not modulemd-defaults data. Eventually, once MBS learns
about defaults in modulemds Fedora may start using it, but until then
and regardless we need to support defaults in modulemd-defaults, i.e.
using `container->getDefaultProfiles()`, just like `dnf` does.
@jlebon jlebon force-pushed the pr/default-profiles branch from 0b54a22 to d5933e9 Compare June 22, 2021 19:37
@jlebon
Copy link
Contributor Author

jlebon commented Jun 23, 2021

Now passing CI! 🎉

@sgallagher
Copy link

sgallagher commented Jun 23, 2021

Sorry, I'm on training this week so I'm just now seeing this. The defaults in the repositories will NOT be included in the modulemd-stream metadata, they will still be delivered as modulemd-defaults documents in the repository YAML.

The change was packager-side only: you can specify the defaults in the modulemd-packager v3 documents and MBS will convert that into an appropriate modulemd-defaults document.

It was done this way specifically to avoid needing to change how DNF interprets the data.

@jlebon
Copy link
Contributor Author

jlebon commented Jun 23, 2021

Ack thanks. So it sounds like we could rip out ModulePackage::getDefaultProfiles entirely in that case.

jlebon added a commit to jlebon/libdnf that referenced this pull request Jun 23, 2021
Even once modulemds support defaults, they won't be part of the repo
data. Instead, MBS will transparently convert them to modulemd-defaults
as usual for backwards compatibility. Therefore, there's no need for us
to inspect it. Let's match `dnf` and rely only on modulemd-defaults.

See: rpm-software-management#1278 (comment)
@jlebon jlebon force-pushed the pr/default-profiles branch from d5933e9 to b74270d Compare June 23, 2021 13:34
@jlebon
Copy link
Contributor Author

jlebon commented Jun 23, 2021

Updated second commit now to just drop that functionality!

@j-mracek
Copy link
Contributor

Thank you very much for the patch. I did not know that we have ModuleProfile getDefaultProfile() for module package, because it is not used in dnf. Unfortunately we cannot remove it because we have to keep compatibility and ModulePackage is exposed in Python bindings. May I ask you to replace https://github.com/rpm-software-management/libdnf/pull/1278/commits/b74270dc3821b44dde31472568d4b4dcea93a68c by note or recommendation to use getDefaultProfile() from ModuleContainer. Thanks a lot. The rest looks good.

The function is misguided in two ways:
1. It returns default profiles found in the modulemd itself, rather than
   the modulemd-defaults, which is more likely what users want. In
   Fedora, once the former is supported, MBS will automatically convert
   it into the latter so that clients shouldn't actually have to change
   anyway.
2. It returns a single profile, whereas if we actually wanted this info,
   it would be more correct to return a vector of profiles, since there
   can be more than one default profile.

Document this and stop using it in `dnf_context_module_install()`.
@jlebon jlebon force-pushed the pr/default-profiles branch from b74270d to 8e43a53 Compare June 28, 2021 13:33
@jlebon
Copy link
Contributor Author

jlebon commented Jun 28, 2021

@j-mracek Thanks for the feedback, I updated the PR!

if (profiles.empty()) {
profiles.push_back(latest->getDefaultProfile());
throw std::runtime_error("No default profile found for " + latest->getFullIdentifier());
Copy link
Contributor

Choose a reason for hiding this comment

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

I see that throw std::runtime_error is using in the method several times. But this is C API and with GError ** error, therefore I would prefer that it will directly sets GError. At the end it sets GError because it catches std::runtime_error and transforms it into GError. What's your opinion?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason we throw and catch here is to match dnf's semantics of processing all the inputs before throwing an error. This also matches what functions like dnf_context_module_enable do, where messages are queued up during each iteration if we encounter errors. (And actually, this is what we're doing here too, where in the catch block we queue up a message.)

Copy link
Contributor

Choose a reason for hiding this comment

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

I am really sorry, I get it now. You throw std::runtime_error because you don't want to set g_error (std::runtime_error in not catched by following macro).

#define CATCH_TO_GERROR(RET)                                                   \
catch (const libdnf::Goal::Error& e) {                                       \
    g_set_error_literal(error, DNF_ERROR, e.getErrCode(), e.what());           \
    return RET;                                                                \
} catch (const libdnf::Error& e) {                                             \
    g_set_error_literal(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR, e.what()); \
    return RET;                                                                \
}

But this is a wrong approach. gboolean dnf_context_module_install() is C API function therefore it must not thow any C++ exception. For people that uses C++ it is not a problem because the can catch it, but for C users it is unsolvable.

I propose to replace throw std::runtime_error("No default profile found for " + latest->getFullIdentifier());
by

g_set_error_literal();
return FALSE; 

Copy link
Contributor

Choose a reason for hiding this comment

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

It is true that dnf_context_module_enable trow an error, but it happen only when the internal logic of the code would be incorrect. Therefore I expect to terminate program without possibility to catch it when it happen. It is possible to use assert() instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But this is a wrong approach. gboolean dnf_context_module_install() is C API function therefore it must not thow any C++ exception. For people that uses C++ it is not a problem because the can catch it, but for C users it is unsolvable.

The exceptions we throw here never actually bubble to the caller. They're immediately caught and converted to messages.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's more like we're using exceptions for flow control. We could equivalently inline the messages.emplace_back() and continue at each site where we currently throw if you prefer, though that would make things more verbose.

@jlebon
Copy link
Contributor Author

jlebon commented Jul 5, 2021

@j-mracek Any more thoughts on this? Would like to have the rpm-ostree side of this merged this week hopefully. :)

@j-mracek
Copy link
Contributor

LGTM

@j-mracek j-mracek merged commit 478be6c into rpm-software-management:dnf-4-master Jul 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants