app/status: also check for timer state

I spent quite some time trying to figure out why the last run timestamp
of the autoupdate service wasn't showing up in `status`. It turned out
to be that systemd only keeps that information around if an associated
timer unit is active.

Thinking more, I think it makes sense to split out the case where the
timer isn't even running explicitly, rather than just reporting "no runs
since boot".

Closes: #1242
Approved by: cgwalters
This commit is contained in:
Jonathan Lebon 2018-02-13 14:25:20 +00:00 committed by Atomic Bot
parent 92029de009
commit aa87fe7d1a

View File

@ -39,6 +39,8 @@
#include <libglnx.h>
#define RPMOSTREE_AUTOMATIC_TIMER_OBJPATH \
"/org/freedesktop/systemd1/unit/rpm_2dostreed_2dautomatic_2etimer"
#define RPMOSTREE_AUTOMATIC_SERVICE_OBJPATH \
"/org/freedesktop/systemd1/unit/rpm_2dostreed_2dautomatic_2eservice"
@ -172,37 +174,62 @@ gv_nevra_to_evr (GString *buffer,
PKG_NEVRA_FLAGS_EPOCH_VERSION_RELEASE);
}
typedef enum {
AUTO_UPDATE_SDSTATE_TIMER_UNKNOWN,
AUTO_UPDATE_SDSTATE_TIMER_INACTIVE,
AUTO_UPDATE_SDSTATE_SERVICE_FAILED,
AUTO_UPDATE_SDSTATE_OK,
} AutoUpdateSdState;
static gboolean
get_last_auto_update_run (GDBusConnection *connection,
char **out_last_run,
gboolean *out_fail,
GCancellable *cancellable,
GError **error)
get_last_auto_update_run (GDBusConnection *connection,
AutoUpdateSdState *out_state,
char **out_last_run,
GCancellable *cancellable,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR ("Querying systemd for last auto-update run", error);
g_autoptr(GDBusProxy) unit_proxy =
/* Check if the timer is running, otherwise systemd won't even keep timestamp info on dead
* services. Also good to tell users if the policy is not none, but timer is off (though
* we don't print it as an error; e.g. the timer might have been explicitly masked). */
g_autoptr(GDBusProxy) timer_unit_proxy =
g_dbus_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, NULL,
"org.freedesktop.systemd1", RPMOSTREE_AUTOMATIC_SERVICE_OBJPATH,
"org.freedesktop.systemd1", RPMOSTREE_AUTOMATIC_TIMER_OBJPATH,
"org.freedesktop.systemd1.Unit", cancellable, error);
if (!unit_proxy)
if (!timer_unit_proxy)
return FALSE;
g_autoptr(GVariant) state_val =
g_dbus_proxy_get_cached_property (unit_proxy, "ActiveState");
g_autoptr(GVariant) timer_state_val =
g_dbus_proxy_get_cached_property (timer_unit_proxy, "ActiveState");
/* let's not error out if we can't msg systemd (e.g. bad sepol); just mark as unknown */
if (state_val == NULL)
if (timer_state_val == NULL)
{
*out_fail = FALSE;
*out_last_run = g_strdup ("unknown");
*out_state = AUTO_UPDATE_SDSTATE_TIMER_UNKNOWN;
return TRUE; /* NB early return */
}
const char *state = g_variant_get_string (state_val, NULL);
if (g_str_equal (state, "failed"))
const char *timer_state = g_variant_get_string (timer_state_val, NULL);
if (g_str_equal (timer_state, "inactive"))
{
*out_fail = TRUE;
*out_state = AUTO_UPDATE_SDSTATE_TIMER_INACTIVE;
return TRUE; /* NB early return */
}
g_autoptr(GDBusProxy) service_unit_proxy =
g_dbus_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, NULL,
"org.freedesktop.systemd1", RPMOSTREE_AUTOMATIC_SERVICE_OBJPATH,
"org.freedesktop.systemd1.Unit", cancellable, error);
if (!service_unit_proxy)
return FALSE;
g_autoptr(GVariant) service_state_val =
g_dbus_proxy_get_cached_property (service_unit_proxy, "ActiveState");
const char *service_state = g_variant_get_string (service_state_val, NULL);
if (g_str_equal (service_state, "failed"))
{
*out_state = AUTO_UPDATE_SDSTATE_SERVICE_FAILED;
return TRUE; /* NB early return */
}
@ -228,7 +255,7 @@ get_last_auto_update_run (GDBusConnection *connection,
}
}
*out_fail = FALSE;
*out_state = AUTO_UPDATE_SDSTATE_OK;
*out_last_run = g_steal_pointer (&last_run);
return TRUE;
}
@ -258,22 +285,47 @@ print_daemon_state (RPMOSTreeSysroot *sysroot_proxy,
g_print ("(%s)\n", policy);
else
{
gboolean failed;
AutoUpdateSdState state;
g_autofree char *last_run = NULL;
GDBusConnection *connection =
g_dbus_proxy_get_connection (G_DBUS_PROXY (sysroot_proxy));
if (!get_last_auto_update_run (connection, &last_run, &failed, cancellable, error))
if (!get_last_auto_update_run (connection, &state, &last_run, cancellable, error))
return FALSE;
if (failed)
g_print ("(%s; %s%slast run failed%s%s)\n", policy,
get_red_start (), get_bold_start (), get_bold_end (), get_red_end ());
else if (last_run)
/* e.g. "last check 4h 32min ago" */
g_print ("(%s; last run %s)\n", policy, last_run);
else
g_print ("(%s; no runs since boot)\n", policy);
switch (state)
{
case AUTO_UPDATE_SDSTATE_TIMER_UNKNOWN:
{
g_print ("(%s; unknown timer state)\n", policy);
break;
}
case AUTO_UPDATE_SDSTATE_TIMER_INACTIVE:
{
g_print ("(%s; timer inactive)\n", policy);
break;
}
case AUTO_UPDATE_SDSTATE_SERVICE_FAILED:
{
g_print ("(%s; %s%slast run failed%s%s)\n", policy,
get_red_start (), get_bold_start (),
get_bold_end (), get_red_end ());
break;
}
case AUTO_UPDATE_SDSTATE_OK:
{
if (last_run)
/* e.g. "last check 4h 32min ago" */
g_print ("(%s; last run %s)\n", policy, last_run);
else
g_print ("(%s; no runs since boot)\n", policy);
break;
}
default:
{
g_assert_not_reached ();
}
}
}
}