discover_system_state refactor in C++

This commit refactors the system state discovery
script from openbmc/skeleton in C++ in order to
use the sdbusplus library.

Change-Id: Ie431b147cbdcd92ac8cf20916235011b6a5a3f4c
Signed-off-by: Michael Tritz <mtritz@us.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index 53de608..64b1b82 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,7 +3,8 @@
 sbin_PROGRAMS = \
 	phosphor-host-state-manager \
 	phosphor-chassis-state-manager \
-	phosphor-bmc-state-manager
+	phosphor-bmc-state-manager \
+	phosphor-discover-system-state
 
 phosphor_host_state_manager_SOURCES = \
 	host_state_manager.cpp \
@@ -17,6 +18,9 @@
 	bmc_state_manager.cpp \
 	bmc_state_manager_main.cpp
 
+phosphor_discover_system_state_SOURCES = \
+	discover_system_state.cpp
+
 generic_cxxflags = $(SYSTEMD_CFLAGS) $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) $(SDBUSPLUS_CFLAGS)
 generic_ldflags = $(SYSTEMD_LIBS) $(PHOSPHOR_DBUS_INTERFACES_LIBS) $(SDBUSPLUS_LIBS)
 
@@ -28,3 +32,6 @@
 
 phosphor_bmc_state_manager_CXXFLAGS = $(generic_cxxflags)
 phosphor_bmc_state_manager_LDFLAGS = $(generic_ldflags)
+
+phosphor_discover_system_state_CXXFLAGS = $(generic_cxxflags)
+phosphor_discover_system_state_LDFLAGS = $(generic_ldflags)
diff --git a/discover_system_state.cpp b/discover_system_state.cpp
new file mode 100644
index 0000000..3989b3f
--- /dev/null
+++ b/discover_system_state.cpp
@@ -0,0 +1,150 @@
+#include <iostream>
+#include <map>
+#include <string>
+#include <config.h>
+#include <systemd/sd-bus.h>
+#include <sdbusplus/server.hpp>
+#include <phosphor-logging/log.hpp>
+#include "chassis_state_manager.hpp"
+#include "host_state_manager.hpp"
+
+namespace phosphor
+{
+namespace state
+{
+namespace manager
+{
+
+using namespace phosphor::logging;
+
+constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
+constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
+constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
+
+constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
+
+constexpr auto HOST_PATH = "/xyz/openbmc_project/state/host0";
+
+constexpr auto SETTINGS_PATH = "/org/openbmc/settings/host0";
+constexpr auto SETTINGS_INTERFACE = "org.openbmc.settings.Host";
+
+constexpr auto CHASSIS_PATH = "/xyz/openbmc_project/state/chassis0";
+
+std::string getService(sdbusplus::bus::bus& bus, std::string path,
+                       std::string interface)
+{
+    auto mapper = bus.new_method_call(MAPPER_BUSNAME,
+                                      MAPPER_PATH,
+                                      MAPPER_INTERFACE,
+                                      "GetObject");
+
+    mapper.append(path, std::vector<std::string>({interface}));
+    auto mapperResponseMsg = bus.call(mapper);
+
+    if (mapperResponseMsg.is_method_error())
+    {
+        log<level::ERR>("Error in mapper call",
+                        entry("PATH=%s", path.c_str()),
+                        entry("INTERFACE=%s", interface.c_str()));
+        throw std::runtime_error("Error in mapper call");
+    }
+
+    std::map<std::string, std::vector<std::string>> mapperResponse;
+    mapperResponseMsg.read(mapperResponse);
+    if (mapperResponse.empty())
+    {
+        log<level::ERR>("Error reading mapper response",
+                        entry("PATH=%s", path.c_str()),
+                        entry("INTERFACE=%s", interface.c_str()));
+        throw std::runtime_error("Error reading mapper response");
+    }
+
+    return mapperResponse.begin()->first;
+}
+
+std::string getProperty(sdbusplus::bus::bus& bus, std::string path,
+                        std::string interface, std::string propertyName)
+{
+    sdbusplus::message::variant<std::string> property;
+    std::string service = getService(bus, path, interface);
+
+    auto method = bus.new_method_call(service.c_str(),
+                                      path.c_str(),
+                                      PROPERTY_INTERFACE,
+                                      "Get");
+
+    method.append(interface, propertyName);
+    auto reply = bus.call(method);
+
+    if (reply.is_method_error())
+    {
+        log<level::ERR>("Error in property Get",
+                        entry("PROPERTY=%s", propertyName.c_str()));
+        throw std::runtime_error("Error in property Get");
+    }
+
+    reply.read(property);
+
+    if (sdbusplus::message::variant_ns::get<std::string>(property).empty())
+    {
+        log<level::ERR>("Error reading property response",
+                        entry("PROPERTY=%s", propertyName.c_str()));
+        throw std::runtime_error("Error reading property response");
+    }
+
+    return sdbusplus::message::variant_ns::get<std::string>(property);
+}
+
+void setProperty(sdbusplus::bus::bus& bus, std::string path,
+                 std::string interface, std::string property, std::string value)
+{
+    sdbusplus::message::variant<std::string> variantValue = value;
+    std::string service = getService(bus, path, interface);
+
+    auto method = bus.new_method_call(service.c_str(),
+                                      path.c_str(),
+                                      PROPERTY_INTERFACE,
+                                      "Set");
+
+    method.append(interface, property, variantValue);
+    bus.call_noreply(method);
+
+    return;
+}
+
+} // namespace manager
+} // namespace state
+} // namepsace phosphor
+
+int main()
+{
+    auto bus = sdbusplus::bus::new_default();
+
+    using namespace phosphor::state::manager;
+    namespace server = sdbusplus::xyz::openbmc_project::State::server;
+
+    std::string currentPowerState = getProperty(bus, CHASSIS_PATH,
+                                                CHASSIS_BUSNAME,
+                                                "CurrentPowerState");
+
+    if(currentPowerState == convertForMessage(server::Chassis::PowerState::Off))
+    {
+        std::string power_policy = getProperty(bus, SETTINGS_PATH,
+                                               SETTINGS_INTERFACE,
+                                               "power_policy");
+
+        log<level::INFO>("Host power is off, checking power policy",
+                         entry("POWER_POLICY=%s", power_policy.c_str()));
+
+        if (power_policy == "ALWAYS_POWER_ON")
+        {
+            log<level::INFO>("power_policy=ALWAYS_POWER_ON, powering host on");
+            setProperty(bus, HOST_PATH, HOST_BUSNAME,
+                        "RequestedHostTransition",
+                        convertForMessage(server::Host::Transition::On));
+        }
+
+    }
+
+    return 0;
+}