Cedric Bosdonnat wrote: > Could anyone have a look at this one? > Sure :). > -- > Cedric > > On Thu, 2014-04-03 at 14:20 +0200, Cédric Bosdonnat wrote: > >> This uses the dbus api of systemd to check the power management >> capabilities of the node. >> --- >> Diff with v3: >> * Added unit tests vir virSystemdCan* helpers >> * Make the default for with-pm-utils depending on dbus and systemd detection >> * Changed the implementation of the helpers to return true for >> 'yes' and 'challenge' responses, we shouldn't get a 'no' given libvirtd runs >> as privileged user... but who knows. >> >> configure.ac | 24 +++++++++++ >> libvirt.spec.in | 9 +++++ >> src/libvirt_private.syms | 3 ++ >> src/util/virnodesuspend.c | 75 ++++++++++++++++++++++++++-------- >> src/util/virsystemd.c | 59 +++++++++++++++++++++++++++ >> src/util/virsystemd.h | 6 +++ >> tests/virsystemdmock.c | 22 ++++++++++ >> Needs rebased after 4607168e, which removed this file. >> tests/virsystemdtest.c | 100 +++++++++++++++++++++++++++++++++++++++++++++- >> 8 files changed, 281 insertions(+), 17 deletions(-) >> >> diff --git a/configure.ac b/configure.ac >> index 73efffa..34e5ec2 100644 >> --- a/configure.ac >> +++ b/configure.ac >> @@ -563,6 +563,10 @@ AC_ARG_WITH([chrdev-lock-files], >> [location for UUCP style lock files for character devices >> (use auto for default paths on some platforms) @<:@default=auto@:>@])]) >> m4_divert_text([DEFAULTS], [with_chrdev_lock_files=auto]) >> +AC_ARG_WITH([pm-utils], >> + [AS_HELP_STRING([--with-pm-utils], >> + [use pm-utils for power management @<:@default=yes@:>@])]) >> +m4_divert_text([DEFAULTS], [with_pm_utils=check]) >> >> dnl >> dnl in case someone want to build static binaries >> @@ -1621,6 +1625,25 @@ fi >> >> AM_CONDITIONAL([WITH_PHYP],[test "$with_phyp" = "yes"]) >> >> +dnl >> +dnl Should we build with pm-utils support? >> +dnl >> +set -x >> Left-over debug? >> +if test "$with_pm_utils" = "check"; then >> + with_pm_utils=yes >> + if test "$with_dbus" = "yes"; then >> + if test "$init_systemd" = "yes"; then >> + with_pm_utils=no >> + fi >> + fi >> +fi >> + >> +if test "$with_pm_utils" = "yes"; then >> + AC_DEFINE_UNQUOTED([WITH_PM_UTILS], 1, [whether to use pm-utils]) >> +fi >> +AM_CONDITIONAL([WITH_PM_UTILS], [test "$with_pm_utils" = "yes"]) >> +set +x >> Same. >> + >> dnl virsh libraries >> VIRSH_LIBS="$VIRSH_LIBS $READLINE_LIBS" >> AC_SUBST([VIRSH_LIBS]) >> @@ -2845,6 +2868,7 @@ AC_MSG_NOTICE([ rbd: $LIBRBD_LIBS]) >> else >> AC_MSG_NOTICE([ rbd: no]) >> fi >> +AC_MSG_NOTICE([pm-utils: $with_pm_utils]) >> >> AC_MSG_NOTICE([]) >> AC_MSG_NOTICE([Test suite]) >> diff --git a/libvirt.spec.in b/libvirt.spec.in >> index eab9b23..5c20955 100644 >> --- a/libvirt.spec.in >> +++ b/libvirt.spec.in >> @@ -132,6 +132,7 @@ >> %define with_libssh2 0%{!?_without_libssh2:0} >> %define with_wireshark 0%{!?_without_wireshark:0} >> %define with_systemd_daemon 0%{!?_without_systemd_daemon:0} >> +%define with_pm_utils 1 >> >> # Non-server/HV driver defaults which are always enabled >> %define with_sasl 0%{!?_without_sasl:1} >> @@ -182,6 +183,7 @@ >> %if 0%{?fedora} >= 17 || 0%{?rhel} >= 7 >> %define with_systemd 1 >> %define with_systemd_daemon 1 >> + %define with_pm_utils 0 >> %endif >> >> # Fedora 18 / RHEL-7 are first where firewalld support is enabled >> @@ -1138,8 +1140,10 @@ Requires: nc >> Requires: gettext >> # Needed by virt-pki-validate script. >> Requires: gnutls-utils >> +%if %{with_pm_utils} >> # Needed for probing the power management features of the host. >> Requires: pm-utils >> +%{endif} >> %if %{with_sasl} >> Requires: cyrus-sasl >> # Not technically required, but makes 'out-of-box' config >> @@ -1395,6 +1399,10 @@ driver >> %define _without_systemd_daemon --without-systemd-daemon >> %endif >> >> +%if ! %{with_pm_utils} >> + %define _without_pm_utils --without-pm-utils >> +%endif >> + >> %define when %(date +"%%F-%%T") >> %define where %(hostname) >> %define who %{?packager}%{!?packager:Unknown} >> @@ -1471,6 +1479,7 @@ rm -f po/stamp-po >> %{?_with_firewalld} \ >> %{?_without_wireshark} \ >> %{?_without_systemd_daemon} \ >> + %{?_without_pm_utils} \ >> %{with_packager} \ >> %{with_packager_version} \ >> --with-qemu-user=%{qemu_user} \ >> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms >> index 38fbf63..ce51bdf 100644 >> --- a/src/libvirt_private.syms >> +++ b/src/libvirt_private.syms >> @@ -1879,6 +1879,9 @@ virSysinfoSetup; >> >> >> # util/virsystemd.h >> +virSystemdCanHibernate; >> +virSystemdCanHybridSleep; >> +virSystemdCanSuspend; >> virSystemdCreateMachine; >> virSystemdMakeMachineName; >> virSystemdMakeScopeName; >> diff --git a/src/util/virnodesuspend.c b/src/util/virnodesuspend.c >> index 8088931..b1eddff 100644 >> --- a/src/util/virnodesuspend.c >> +++ b/src/util/virnodesuspend.c >> @@ -22,6 +22,7 @@ >> #include <config.h> >> #include "virnodesuspend.h" >> >> +# include "virsystemd.h" >> #include "vircommand.h" >> #include "virthread.h" >> #include "datatypes.h" >> @@ -245,23 +246,9 @@ int nodeSuspendForDuration(unsigned int target, >> return ret; >> } >> >> - >> -/** >> - * virNodeSuspendSupportsTarget: >> - * @target: The power management target to check whether it is supported >> - * by the host. Values could be: >> - * VIR_NODE_SUSPEND_TARGET_MEM >> - * VIR_NODE_SUSPEND_TARGET_DISK >> - * VIR_NODE_SUSPEND_TARGET_HYBRID >> - * @supported: set to true if supported, false otherwise >> - * >> - * Run the script 'pm-is-supported' (from the pm-utils package) >> - * to find out if @target is supported by the host. >> - * >> - * Returns 0 if the query was successful, -1 on failure. >> - */ >> +#ifdef WITH_PM_UTILS >> static int >> -virNodeSuspendSupportsTarget(unsigned int target, bool *supported) >> +virNodeSuspendSupportsTargetPMUtils(unsigned int target, bool *supported) >> { >> virCommandPtr cmd; >> int status; >> @@ -300,6 +287,62 @@ virNodeSuspendSupportsTarget(unsigned int target, bool *supported) >> virCommandFree(cmd); >> return ret; >> } >> +#endif >> + >> +static int >> +virNodeSuspendSupportsTargetSystemd(unsigned int target, bool *supported) >> +{ >> + int ret = -1; >> + >> + if (virNodeSuspendInitialize() < 0) >> + return -1; >> + >> + *supported = false; >> + >> + switch (target) { >> + case VIR_NODE_SUSPEND_TARGET_MEM: >> + ret = virSystemdCanSuspend(supported); >> + break; >> + case VIR_NODE_SUSPEND_TARGET_DISK: >> + ret = virSystemdCanHibernate(supported); >> + break; >> + case VIR_NODE_SUSPEND_TARGET_HYBRID: >> + ret = virSystemdCanHybridSleep(supported); >> + break; >> + default: >> + return ret; >> + } >> + >> + return ret; >> +} >> + >> +/** >> + * virNodeSuspendSupportsTarget: >> + * @target: The power management target to check whether it is supported >> + * by the host. Values could be: >> + * VIR_NODE_SUSPEND_TARGET_MEM >> + * VIR_NODE_SUSPEND_TARGET_DISK >> + * VIR_NODE_SUSPEND_TARGET_HYBRID >> + * @supported: set to true if supported, false otherwise >> + * >> + * Run the script 'pm-is-supported' (from the pm-utils package) >> + * to find out if @target is supported by the host. >> + * >> + * Returns 0 if the query was successful, -1 on failure. >> + */ >> +static int >> +virNodeSuspendSupportsTarget(unsigned int target, bool *supported) >> +{ >> + int ret; >> + >> + ret = virNodeSuspendSupportsTargetSystemd(target, supported); >> +#ifdef WITH_PM_UTILS >> + if (ret < 0) >> + ret = virNodeSuspendSupportsTargetPMUtils(target, supported); >> +#endif >> + >> + return ret; >> +} >> >> /** >> * virNodeSuspendGetTargetMask: >> diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c >> index 93b3f9c..e9ca564 100644 >> --- a/src/util/virsystemd.c >> +++ b/src/util/virsystemd.c >> @@ -325,3 +325,62 @@ virSystemdNotifyStartup(void) >> sd_notify(0, "READY=1"); >> #endif >> } >> + >> +static int >> +virSystemdPMSupportTarget(const char *methodName, bool *result) >> +{ >> + int ret; >> + DBusConnection *conn; >> + DBusMessage *message = NULL; >> + char *response; >> + >> + ret = virDBusIsServiceEnabled("org.freedesktop.login1"); >> + if (ret < 0) >> + return ret; >> + >> + if ((ret = virDBusIsServiceRegistered("org.freedesktop.login1")) < 0) >> + return ret; >> + >> + if (!(conn = virDBusGetSystemBus())) >> + return -1; >> + >> + ret = -1; >> + >> + if (virDBusCallMethod(conn, >> + &message, >> + NULL, >> + "org.freedesktop.login1", >> + "/org/freedesktop/login1", >> + "org.freedesktop.login1.Manager", >> + methodName, >> + NULL) < 0) >> + return ret; >> + >> + if ((ret = virDBusMessageRead(message, "s", &response)) < 0) >> + goto cleanup; >> + >> + *result = STREQ("yes", response) || STREQ("challenge", response); >> + >> + ret = 0; >> + >> + cleanup: >> + dbus_message_unref(message); >> + VIR_FREE(response); >> + >> + return ret; >> +} >> + >> +int virSystemdCanSuspend(bool *result) >> +{ >> + return virSystemdPMSupportTarget("CanSuspend", result); >> +} >> + >> +int virSystemdCanHibernate(bool *result) >> +{ >> + return virSystemdPMSupportTarget("CanHibernate", result); >> +} >> + >> +int virSystemdCanHybridSleep(bool *result) >> +{ >> + return virSystemdPMSupportTarget("CanHybridSleep", result); >> +} >> diff --git a/src/util/virsystemd.h b/src/util/virsystemd.h >> index 7fed456..491c9b7 100644 >> --- a/src/util/virsystemd.h >> +++ b/src/util/virsystemd.h >> @@ -48,4 +48,10 @@ int virSystemdTerminateMachine(const char *name, >> >> void virSystemdNotifyStartup(void); >> >> +int virSystemdCanSuspend(bool *result); >> + >> +int virSystemdCanHibernate(bool *result); >> + >> +int virSystemdCanHybridSleep(bool *result); >> + >> #endif /* __VIR_SYSTEMD_H__ */ >> diff --git a/tests/virsystemdmock.c b/tests/virsystemdmock.c >> index 23167db..cc385ec 100644 >> --- a/tests/virsystemdmock.c >> +++ b/tests/virsystemdmock.c >> @@ -76,10 +76,21 @@ DBusMessage *dbus_connection_send_with_reply_and_block(DBusConnection *connectio >> } else { >> reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); >> } >> + } else if (STREQ(service, "org.freedesktop.login1")) { >> + char *supported = getenv("RESULT_SUPPORT"); >> + DBusMessageIter iter; >> + reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); >> + dbus_message_iter_init_append(reply, &iter); >> + >> + if (!dbus_message_iter_append_basic(&iter, >> + DBUS_TYPE_STRING, >> + &supported)) >> + goto error; >> } else if (STREQ(service, "org.freedesktop.DBus") && >> STREQ(member, "ListActivatableNames")) { >> const char *svc1 = "org.foo.bar.wizz"; >> const char *svc2 = "org.freedesktop.machine1"; >> + const char *svc3 = "org.freedesktop.login1"; >> DBusMessageIter iter, sub; >> reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); >> dbus_message_iter_init_append(reply, &iter); >> @@ -95,11 +106,17 @@ DBusMessage *dbus_connection_send_with_reply_and_block(DBusConnection *connectio >> DBUS_TYPE_STRING, >> &svc2)) >> goto error; >> + if (!getenv("FAIL_NO_SERVICE") && >> + !dbus_message_iter_append_basic(&sub, >> + DBUS_TYPE_STRING, >> + &svc3)) >> + goto error; >> dbus_message_iter_close_container(&iter, &sub); >> } else if (STREQ(service, "org.freedesktop.DBus") && >> STREQ(member, "ListNames")) { >> const char *svc1 = "org.foo.bar.wizz"; >> const char *svc2 = "org.freedesktop.systemd1"; >> + const char *svc3 = "org.freedesktop.login1"; >> DBusMessageIter iter, sub; >> reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); >> dbus_message_iter_init_append(reply, &iter); >> @@ -115,6 +132,11 @@ DBusMessage *dbus_connection_send_with_reply_and_block(DBusConnection *connectio >> DBUS_TYPE_STRING, >> &svc2)) >> goto error; >> + if ((!getenv("FAIL_NO_SERVICE") && !getenv("FAIL_NOT_REGISTERED")) && >> + !dbus_message_iter_append_basic(&sub, >> + DBUS_TYPE_STRING, >> + &svc3)) >> + goto error; >> dbus_message_iter_close_container(&iter, &sub); >> } else { >> reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); >> diff --git a/tests/virsystemdtest.c b/tests/virsystemdtest.c >> index 4fc5137..a9583e7 100644 >> --- a/tests/virsystemdtest.c >> +++ b/tests/virsystemdtest.c >> @@ -205,7 +205,6 @@ static int testCreateBadSystemd(const void *opaque ATTRIBUTE_UNUSED) >> return 0; >> } >> >> - >> Spurious whitespace change. Looks good otherwise. You addressed all the comments from previous versions. Regards, Jim >> struct testScopeData { >> const char *name; >> const char *partition; >> @@ -237,6 +236,86 @@ testScopeName(const void *opaque) >> return ret; >> } >> >> +typedef int (*virSystemdCanHelper)(bool * result); >> +struct testPMSupportData { >> + virSystemdCanHelper tested; >> +}; >> + >> +static int testPMSupportHelper(const void *opaque) >> +{ >> + int rv; >> + bool result; >> + size_t i; >> + const char *results[4] = {"yes", "no", "na", "challenge"}; >> + int expected[4] = {1, 0, 0, 1}; >> + const struct testPMSupportData *data = opaque; >> + >> + for (i = 0; i < 4; i++) { >> + setenv("RESULT_SUPPORT", results[i], 1); >> + if ((rv = data->tested(&result)) < 0) { >> + fprintf(stderr, "%s", "Unexpected canSuspend error\n"); >> + return -1; >> + } >> + >> + if (result != expected[i]) { >> + fprintf(stderr, "Unexpected result for answer '%s'\n", results[i]); >> + goto error; >> + } >> + unsetenv("RESULT_SUPPORT"); >> + } >> + >> + return 0; >> +error: >> + unsetenv("RESULT_SUPPORT"); >> + return -1; >> +} >> + >> +static int testPMSupportHelperNoSystemd(const void *opaque) >> +{ >> + int rv; >> + bool result; >> + const struct testPMSupportData *data = opaque; >> + >> + setenv("FAIL_NO_SERVICE", "1", 1); >> + >> + if ((rv = data->tested(&result)) == 0) { >> + unsetenv("FAIL_NO_SERVICE"); >> + fprintf(stderr, "%s", "Unexpected canSuspend success\n"); >> + return -1; >> + } >> + unsetenv("FAIL_NO_SERVICE"); >> + >> + if (rv != -2) { >> + fprintf(stderr, "%s", "Unexpected canSuspend error\n"); >> + return -1; >> + } >> + >> + return 0; >> +} >> + >> +static int testPMSupportSystemdNotRunning(const void *opaque) >> +{ >> + int rv; >> + bool result; >> + const struct testPMSupportData *data = opaque; >> + >> + setenv("FAIL_NOT_REGISTERED", "1", 1); >> + >> + if ((rv = data->tested(&result)) == 0) { >> + unsetenv("FAIL_NOT_REGISTERED"); >> + fprintf(stderr, "%s", "Unexpected canSuspend success\n"); >> + return -1; >> + } >> + unsetenv("FAIL_NOT_REGISTERED"); >> + >> + if (rv != -2) { >> + fprintf(stderr, "%s", "Unexpected canSuspend error\n"); >> + return -1; >> + } >> + >> + return 0; >> +} >> + >> static int >> mymain(void) >> { >> @@ -275,6 +354,25 @@ mymain(void) >> TEST_SCOPE("demo", "/machine/eng-dept/testing!stuff", >> "machine-eng\\x2ddept-testing\\x21stuff-lxc\\x2ddemo.scope"); >> >> +# define TESTS_PM_SUPPORT_HELPER(name, function) \ >> + do { \ >> + struct testPMSupportData data = { \ >> + function \ >> + }; \ >> + if (virtTestRun("Test " name " ", testPMSupportHelper, &data) < 0) \ >> + ret = -1; \ >> + if (virtTestRun("Test " name " no systemd ", \ >> + testPMSupportHelperNoSystemd, &data) < 0) \ >> + ret = -1; \ >> + if (virtTestRun("Test systemd " name " not running ", \ >> + testPMSupportSystemdNotRunning, &data) < 0) \ >> + ret = -1; \ >> + } while (0) >> + >> + TESTS_PM_SUPPORT_HELPER("canSuspend", &virSystemdCanSuspend); >> + TESTS_PM_SUPPORT_HELPER("canHibernate", &virSystemdCanHibernate); >> + TESTS_PM_SUPPORT_HELPER("canHybridSleep", &virSystemdCanHybridSleep); >> + >> return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; >> >> } >> >> > > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list