-
Notifications
You must be signed in to change notification settings - Fork 375
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
Add dbus-announce plugin #1255
Add dbus-announce plugin #1255
Conversation
I'm starting to think we might actually be better off without sending notifications for individual packages, because this will be noisy, and doubly so since the psm hooks can get called multiple times per package as you noted. Just announce that transaction is in progress and when it ends. Which makes me wonder if we couldn't actually merge this with the inhibit plugin somehow, as then beginning and end of the transaction is the most interesting thing there. |
...noisy and like you said in the ticket, we don't want people to start building their own triggers outside rpm. Information about the contents of a transaction in progress is probably best limited to the invoking process. |
Yeah, I had the package info as a separate patch, but I figured it'd be easier to just delete the functions than splitting all the changes and fixes. |
Having slept over it: the thing is that the packages aren't actually installed/removed and the result code until the transaction is over, we really must not advertise the inconsistent state to others. The syslog plugin gets this wrong too... I'd really prefer starting with just the transaction begin/end signals, the case for individual package signals is much muddier. It's always much easier to add than remove. |
Split the package signals into a separate patch as they need some deeper discussion on how the plugin hooks should actually work and what new we need to add (see #1254). |
Is there any coordination between this and the work to add dbus to libdnf in rpm-software-management/libdnf#941 for example? For rpm-ostree we are already a DBus daemon, and having multiple other libraries in the stack also going out and talking to DBus is going to be a bit problematic. Binding this to the systemd-inhibit plugin makes sense because we already turn that off for rpm-ostree (because it's transactional, there's no reason to inhibit). |
Well, we add this on request of the DNF team that need to be notified if something else (rpm cli) changes the rpmdb underneath their daemon. Note that this is very different from the lib dnf thing even if it also uses DBus. RPM will not offer a DBUS interface that can be queried or send commands to. All this does is sending out signals that notify who ever is interested that the rpmdb is changing.
So this is going to be a plugin that can be disabled or just plainly not be installed in the first place. We will probably not integrate this into the systemd-inhibit plugin but have it as a separate plugin that is very similar and comes in it's own sub package. Can you please elaborate on why sending some DBus signals should be problematic? |
plugins/dbus_announce.c
Outdated
|
||
state->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err); | ||
if (dbus_error_is_set(&err)) { | ||
fprintf(stderr, "Connection Error (%s)\n", err.message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be filtered out in case dbus isn't running to begin with, similarly to what commit 708e613 does. Also, rpmlog() should be used instead of fprintf().
plugins/dbus_announce.c
Outdated
} | ||
} | ||
|
||
return RPMRC_NOTFOUND; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return code logic is confusing, with multiple returns in space of just a few lines.
plugins/dbus_announce.c
Outdated
dbcookie = _free(dbcookie); | ||
|
||
if (!dbus_connection_send(state->bus, msg, &serial)) { | ||
return RPMRC_FAIL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, failing the entire transaction if dbus announce fails seems a bit dramatic. Then again, if people are actually relying on these signals...
plugins/dbus_announce.c
Outdated
|
||
dbcookie = rpmdbCookie(rpmtsGetRdb(ts)); | ||
if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &dbcookie)) { | ||
return RPMRC_FAIL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This leaks memory in the failure case.
In general, the "goto err" idiom with a single exit point for cleanup is preferred over multiple returns, exactly for reasons like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably should also add the transaction ID to these messages.
Ah, I see. Well, nothing else can/should be changing the rpmdb on rpm-ostree based systems (see also coreos/rpm-ostree#1789 where rpm-ostree will start wrapping
OK that seems fine, then we can not install it in the container image and rpm-ostree based systems.
A few things. First, rpm-ostree updates are offline (generating a new root) by default - so anything listening and responding to these DBus signals would be confused because it's not affecting the current rpm database but a new one it can't see. Second, and related to that - which exact component would be listening to these signals? Would it be Do we really need DBus for this versus just e.g. having interested processes use |
This isn't just for dnf's benefit. It's a mechanism that anybody who needs to do so is free to listen, and everybody else can ignore. |
Speaking as a former DBus maintainer upstream here and I have written many DBus APIs... It seems dramatically simpler to me to go with the inotify approach, the requirement is basically for librpm to And most crucially it avoids creating a new API for things to try to query/monitor the rpm database state. There's already an API for that via librpm. This signal isn't extensible - if e.g. a new field (say something related to modules) becomes interesting then we'd have to define a new one. Handling that requires going down to a "bag of properties" i.e. A DBus API is a serious commitment, particularly once you have things listening to it. That said a particular strength of DBus (really the reason it was created) is to be able to to cross privilege boundaries by having unprivileged processes (originally the desktop) sanely monitor and interact with system services. But in this case since the consumer is (theoretically) dnf they're in the same privilege level (and in fact the same process!), so that doesn't apply. FWIW here's the libostree code to bump mtime: https://github.com/ostreedev/ostree/blob/62632511f149adfc186da7f0e976006845591c8f/src/libostree/ostree-sysroot.c#L357 And here's where rpm-ostree uses it: https://github.com/coreos/rpm-ostree/blob/e6907d209b258388339b26e58a6da8cd022d1081/src/daemon/rpmostreed-sysroot.c#L788 That's how rpm-ostreed gets notified if e.g. an admin directly runs |
@cgwalters , the use-case is not dnf itself but a daemon which will need to refresh it's view of rpmdb whenever someone else changes the rpmdb. See #1124 for some background. Also one thing worth remembering is that inotify is a Linux-specific interface, but rpm is portable software. While adding system-specific features is okay, exposing them via public API creates its own set of problems. Thanks for the insights on DBus. |
(Colin, see issue #1124 for a solution using a named pipe) |
One important aspect of dbus vs librpm API is that not everybody wants to link to librpm, which imposes its own signal handling on users when the db is open, and our ABI hasn't been particularly stable historically, dbus library itself is much more stable AIUI. |
Can turn that off since 56f49d7 right?
Maintaining C shared libraries is indeed extremely hard. I've messed up in the past and only just barely caught it before releases etc. That said there are nice tools now like libabigail - should be easy to set that up on CI here right?
Yeah, libdbus as a C shared library has been fine and will continue to be so, but exposing an API over DBus is a separate thing with long term commitments. If we're effectively saying most projects shouldn't be using librpm to read the rpm database effectively (that seems like what you're implying) that's a rather radical thing right? Maybe I am misunderstanding though. |
API users turning off signal handling is not a solution, it's a problem in its own right.
librpm ABI stability or lack of thereof has little to do about it being difficult, it's merely that rpm has historically exported all manner of crap that it never should have, and it's not possible to get rid off it all in one go, unfortunately. So for 12+ years we've done staged "exit accumulated crap, bump soname" releases every now and then, rpm soname bumps are an absolute PITA.
Eh, no kidding?
I said no such thing. Different users have different priorities and needs, projects should (be able to) use what works best for them. Linking to librpm comes with heavy and hard to understand babbage and is way too intimate (think "bare metal") for various "casual" users. A DBus API puts a much needed insulation layer between the process that actually accesses rpmdb and the unsuspecting piece of software wanting to know something about packages on the system. With the existing librpm API, very weird things happen in dark corners such as gdb running as root on a 32bit process on a 64bit system does an rpmdb query for debuginfo discovery. |
From dnf-daemon point of view this plugin looks good and definitely useful. I've just build rpm with this plugin enabled and I'm going to test how it works. Thanks Florian! |
I did some testing in dnfdaemon and the patch is working for us. Just (as Panu mentioned) for consistency I'd like to change CompleteTransaction signal name to EndTransaction - the signal is emitted regardless the transaction was successful and "Complete" in the name suggests the success. |
b38344a
to
c434c33
Compare
There are quite a few unaddressed review issues from the previous round still present. |
c434c33
to
68afa6d
Compare
While many smaller things are fixed now. This still needs a run through the error handling. |
OK, now there should be all issues raised so far being addressed. The plugin now only gives a warning via |
plugins/dbus_announce.c
Outdated
if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &dbcookie)) { | ||
goto err; | ||
} | ||
dbcookie = _free(dbcookie); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dbcookie will leak if dbus_message_append_args() fails. The generally fail-safe strategy is to initialize to NULL and free at central exit point than try be clever with local allocations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plugged the leak. Still not a text book example of the central exit point pattern...
plugins/dbus_announce.c
Outdated
state->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err); | ||
if (dbus_error_is_set(&err)) { | ||
goto err; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no strict guideline whether to use {} on a one-liner block, but please pick a strategy and use it consistently. There are multiple cases where braces are not used (eg a few lines above), and many cases where they are not, throughout this file.
I personally tend to avoid the the excess {} unless it's needed for readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deleted lots of { and }.
Rebased to current master |
plugins/dbus_announce.c
Outdated
goto err; | ||
|
||
dbcookie = rpmdbCookie(rpmtsGetRdb(ts)); | ||
if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &dbcookie)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for not realizing this earlier: we really should add transaction ID to these messages.
{ | ||
int rc; | ||
|
||
rc = open_dbus(plugin, ts); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just cosmetics, but you could save a couple of lines by initializing on the declaration line.
The plugin announces start and end of transactions
Added transaction id to the message and added a description of the data send in the man page. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we've stared at the code long enough, lets get some real-world experience next...
The plugin announces start and completion of transactions and
the installation and erasure of packages.
The patch still needs some polishing:
Resolves: #1249