xref: /openbmc/openpower-occ-control/utils.cpp (revision 37abe9be91df2bb173c9642a2740a425904d7921)
1f3b7514eSGeorge Liu #include "utils.hpp"
2f3b7514eSGeorge Liu 
3bae4d07eSChris Cain #include <systemd/sd-event.h>
4bae4d07eSChris Cain #include <unistd.h>
536f9cdedSChris Cain 
630e329adSVishwanatha Subbanna #include <phosphor-logging/elog-errors.hpp>
7*37abe9beSChris Cain #include <phosphor-logging/lg2.hpp>
894df8c90SGunnar Mills #include <sdbusplus/bus.hpp>
930e329adSVishwanatha Subbanna #include <xyz/openbmc_project/Common/error.hpp>
10bae4d07eSChris Cain #include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
11bae4d07eSChris Cain #include <xyz/openbmc_project/State/Host/server.hpp>
12b5ca1015SGeorge Liu 
13b5ca1015SGeorge Liu #include <string>
1430e329adSVishwanatha Subbanna namespace open_power
1530e329adSVishwanatha Subbanna {
1630e329adSVishwanatha Subbanna namespace occ
1730e329adSVishwanatha Subbanna {
18f3b7514eSGeorge Liu namespace utils
19f3b7514eSGeorge Liu {
2030e329adSVishwanatha Subbanna // For throwing exceptions
2130e329adSVishwanatha Subbanna using namespace phosphor::logging;
2294df8c90SGunnar Mills using InternalFailure =
2394df8c90SGunnar Mills     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
2430e329adSVishwanatha Subbanna 
25bae4d07eSChris Cain using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::server::
26bae4d07eSChris Cain     Progress::ProgressStages;
27bae4d07eSChris Cain constexpr auto HOST_STATE_OBJ_PATH = "/xyz/openbmc_project/state/host0";
28bae4d07eSChris Cain 
getService(const std::string & path,const std::string & interface)29f3b7514eSGeorge Liu const std::string getService(const std::string& path,
30f3b7514eSGeorge Liu                              const std::string& interface)
3130e329adSVishwanatha Subbanna {
32f3b7514eSGeorge Liu     using InterfaceList = std::vector<std::string>;
33f3b7514eSGeorge Liu     std::map<std::string, std::vector<std::string>> mapperResponse;
3430e329adSVishwanatha Subbanna 
35f3b7514eSGeorge Liu     auto& bus = getBus();
3630e329adSVishwanatha Subbanna 
37f3b7514eSGeorge Liu     auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
38f3b7514eSGeorge Liu                                       MAPPER_IFACE, "GetObject");
39f3b7514eSGeorge Liu     mapper.append(path, InterfaceList({interface}));
40f3b7514eSGeorge Liu 
41f3b7514eSGeorge Liu     auto mapperResponseMsg = bus.call(mapper);
4230e329adSVishwanatha Subbanna     mapperResponseMsg.read(mapperResponse);
43f3b7514eSGeorge Liu     if (mapperResponse.empty())
4430e329adSVishwanatha Subbanna     {
45*37abe9beSChris Cain         lg2::error("ERROR reading mapper response: path={PATH}, I/F={INTF}",
46*37abe9beSChris Cain                    "PATH", path, "INTF", interface);
4730e329adSVishwanatha Subbanna 
4830e329adSVishwanatha Subbanna         elog<InternalFailure>();
4930e329adSVishwanatha Subbanna     }
50f3b7514eSGeorge Liu 
51f3b7514eSGeorge Liu     // the value here will be the service name
52f3b7514eSGeorge Liu     return mapperResponse.cbegin()->first;
5330e329adSVishwanatha Subbanna }
5430e329adSVishwanatha Subbanna 
getProperty(const std::string & objectPath,const std::string & interface,const std::string & propertyName)55f3b7514eSGeorge Liu const PropertyValue getProperty(const std::string& objectPath,
56f3b7514eSGeorge Liu                                 const std::string& interface,
57f3b7514eSGeorge Liu                                 const std::string& propertyName)
58f3b7514eSGeorge Liu {
59f3b7514eSGeorge Liu     PropertyValue value{};
60f3b7514eSGeorge Liu 
61f3b7514eSGeorge Liu     auto& bus = getBus();
62f3b7514eSGeorge Liu     auto service = getService(objectPath, interface);
63f3b7514eSGeorge Liu     if (service.empty())
64f3b7514eSGeorge Liu     {
65f3b7514eSGeorge Liu         return value;
66f3b7514eSGeorge Liu     }
67f3b7514eSGeorge Liu 
68f3b7514eSGeorge Liu     auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
69f3b7514eSGeorge Liu                                       DBUS_PROPERTY_IFACE, "Get");
70f3b7514eSGeorge Liu     method.append(interface, propertyName);
71f3b7514eSGeorge Liu 
72f3b7514eSGeorge Liu     auto reply = bus.call(method);
73f3b7514eSGeorge Liu     reply.read(value);
74f3b7514eSGeorge Liu 
75f3b7514eSGeorge Liu     return value;
76f3b7514eSGeorge Liu }
77f3b7514eSGeorge Liu 
7836f9cdedSChris Cain /**
7936f9cdedSChris Cain  * @brief Sets a given object's property value
8036f9cdedSChris Cain  *
811be4337bSChris Cain  * @param[in] objectPath - Name of the object containing the property
8236f9cdedSChris Cain  * @param[in] interface - Interface name containing the property
831be4337bSChris Cain  * @param[in] propertyName - Property name
8436f9cdedSChris Cain  * @param[in] value - Property value
8536f9cdedSChris Cain  */
setProperty(const std::string & objectPath,const std::string & interface,const std::string & propertyName,PropertyValue && value)8636f9cdedSChris Cain void setProperty(const std::string& objectPath, const std::string& interface,
875d66a0aaSChris Cain                  const std::string& propertyName, PropertyValue&& value)
8836f9cdedSChris Cain {
8936f9cdedSChris Cain     using namespace std::literals::string_literals;
905d66a0aaSChris Cain     PropertyValue varValue(std::forward<PropertyValue>(value));
9136f9cdedSChris Cain 
921be4337bSChris Cain     try
931be4337bSChris Cain     {
9436f9cdedSChris Cain         auto& bus = getBus();
9536f9cdedSChris Cain         auto service = getService(objectPath, interface);
9636f9cdedSChris Cain         if (service.empty())
9736f9cdedSChris Cain         {
9836f9cdedSChris Cain             return;
9936f9cdedSChris Cain         }
10036f9cdedSChris Cain 
10136f9cdedSChris Cain         auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
10236f9cdedSChris Cain                                           DBUS_PROPERTY_IFACE, "Set");
10336f9cdedSChris Cain         method.append(interface, propertyName, varValue);
10436f9cdedSChris Cain 
10536f9cdedSChris Cain         auto reply = bus.call(method);
10636f9cdedSChris Cain         if (reply.is_method_error())
10736f9cdedSChris Cain         {
108*37abe9beSChris Cain             lg2::error("util::setProperty: Failed to set property {PROP}",
109*37abe9beSChris Cain                        "PROP", propertyName);
11036f9cdedSChris Cain         }
11136f9cdedSChris Cain     }
1121be4337bSChris Cain     catch (const std::exception& e)
1131be4337bSChris Cain     {
1141be4337bSChris Cain         auto error = errno;
115*37abe9beSChris Cain         lg2::error("setProperty: failed to Set {PROP}, errno={ERR}, what={MSG}",
116*37abe9beSChris Cain                    "PROP", propertyName, "ERR", error, "PROP", e.what());
1171be4337bSChris Cain     }
1181be4337bSChris Cain }
11936f9cdedSChris Cain 
getSubtreePaths(const std::vector<std::string> & interfaces,const std::string & path)120d7542c83SPatrick Williams std::vector<std::string> getSubtreePaths(
121d7542c83SPatrick Williams     const std::vector<std::string>& interfaces, const std::string& path)
1225901abdaSMatt Spinler {
1235901abdaSMatt Spinler     std::vector<std::string> paths;
1245901abdaSMatt Spinler 
1255901abdaSMatt Spinler     auto& bus = getBus();
1265901abdaSMatt Spinler     auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
1275901abdaSMatt Spinler                                       MAPPER_IFACE, "GetSubTreePaths");
1285901abdaSMatt Spinler     method.append(path, 0, interfaces);
1295901abdaSMatt Spinler 
1305901abdaSMatt Spinler     auto reply = bus.call(method);
1315901abdaSMatt Spinler     reply.read(paths);
1325901abdaSMatt Spinler 
1335901abdaSMatt Spinler     return paths;
1345901abdaSMatt Spinler }
1351be4337bSChris Cain 
1361be4337bSChris Cain // Get the service and object path for an interface
getServiceUsingSubTree(const std::string & interface,std::string & path)1371be4337bSChris Cain std::string getServiceUsingSubTree(const std::string& interface,
1381be4337bSChris Cain                                    std::string& path)
1391be4337bSChris Cain {
1401be4337bSChris Cain     using Path = std::string;
1411be4337bSChris Cain     using Intf = std::string;
1421be4337bSChris Cain     using Serv = std::string;
1431be4337bSChris Cain     using Intfs = std::vector<Intf>;
1441be4337bSChris Cain     using Objects = std::map<Path, std::map<Serv, Intfs>>;
1451be4337bSChris Cain     Serv service;
1461be4337bSChris Cain     Objects rspObjects;
1471be4337bSChris Cain 
1481be4337bSChris Cain     auto& bus = getBus();
1491be4337bSChris Cain     auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
1501be4337bSChris Cain                                       MAPPER_IFACE, "GetSubTree");
1511be4337bSChris Cain     method.append(path, 0, std::vector{interface});
1521be4337bSChris Cain 
1531be4337bSChris Cain     auto mapperResponseMsg = bus.call(method);
1541be4337bSChris Cain     mapperResponseMsg.read(rspObjects);
1551be4337bSChris Cain     if (rspObjects.empty())
1561be4337bSChris Cain     {
157*37abe9beSChris Cain         lg2::error(
158*37abe9beSChris Cain             "util::getServiceUsingSubTree: Failed getSubTree({PATH},0,{INTF})",
159*37abe9beSChris Cain             "PATH", path, "INTF", interface);
1601be4337bSChris Cain     }
1611be4337bSChris Cain     else
1621be4337bSChris Cain     {
1631be4337bSChris Cain         path = rspObjects.begin()->first;
1641be4337bSChris Cain         if (!rspObjects.begin()->second.empty())
1651be4337bSChris Cain         {
1661be4337bSChris Cain             service = rspObjects.begin()->second.begin()->first;
1671be4337bSChris Cain         }
1681be4337bSChris Cain         else
1691be4337bSChris Cain         {
170*37abe9beSChris Cain             lg2::error(
171*37abe9beSChris Cain                 "getServiceUsingSubTree: service not found for interface {INTF} (path={PATH})",
172*37abe9beSChris Cain                 "INTF", interface, "PATH", path);
1731be4337bSChris Cain         }
1741be4337bSChris Cain     }
1751be4337bSChris Cain 
1761be4337bSChris Cain     return service;
1771be4337bSChris Cain }
1781be4337bSChris Cain 
getStateValue(const std::string & intf,const std::string & objPath,const std::string & state)179bae4d07eSChris Cain std::string getStateValue(const std::string& intf, const std::string& objPath,
180bae4d07eSChris Cain                           const std::string& state)
181bae4d07eSChris Cain {
182bae4d07eSChris Cain     std::string stateVal;
183bae4d07eSChris Cain     try
184bae4d07eSChris Cain     {
185bae4d07eSChris Cain         auto& bus = getBus();
186bae4d07eSChris Cain         auto service = getService(objPath, intf);
187bae4d07eSChris Cain         if (service.empty())
188bae4d07eSChris Cain         {
189bae4d07eSChris Cain             throw std::runtime_error("getStateValue: Failed to get service");
190bae4d07eSChris Cain         }
191bae4d07eSChris Cain 
192d7542c83SPatrick Williams         auto method =
193d7542c83SPatrick Williams             bus.new_method_call(service.c_str(), objPath.c_str(),
194d7542c83SPatrick Williams                                 "org.freedesktop.DBus.Properties", "Get");
195bae4d07eSChris Cain 
196bae4d07eSChris Cain         method.append(intf, state);
197bae4d07eSChris Cain 
198bae4d07eSChris Cain         auto reply = bus.call(method);
199bae4d07eSChris Cain 
200bae4d07eSChris Cain         std::variant<std::string> propertyVal;
201bae4d07eSChris Cain 
202bae4d07eSChris Cain         reply.read(propertyVal);
203bae4d07eSChris Cain 
204bae4d07eSChris Cain         stateVal = std::get<std::string>(propertyVal);
205bae4d07eSChris Cain     }
206af40808fSPatrick Williams     catch (const sdbusplus::exception_t& e)
207bae4d07eSChris Cain     {
208*37abe9beSChris Cain         lg2::error("D-Bus call exception, OBJPATH({PATH}), "
209*37abe9beSChris Cain                    "INTERFACE({INTF}), PROPERTY({PROP}) EXCEPTION({ERR})",
210*37abe9beSChris Cain                    "PATH", objPath, "INTF", intf, "PROP", state, "ERR",
211*37abe9beSChris Cain                    e.what());
212bae4d07eSChris Cain         throw std::runtime_error("Failed to get host state property");
213bae4d07eSChris Cain     }
214bae4d07eSChris Cain     catch (const std::bad_variant_access& e)
215bae4d07eSChris Cain     {
216*37abe9beSChris Cain         lg2::error(
217*37abe9beSChris Cain             "Exception raised while read host state({STATE}) property "
218*37abe9beSChris Cain             "value,  OBJPATH({PATH}), INTERFACE({INTF}), EXCEPTION({ERR})",
219*37abe9beSChris Cain             "STATE", state, "PATH", objPath, "INTF", intf, "ERR", e.what());
220bae4d07eSChris Cain         throw std::runtime_error("Failed to get host state property");
221bae4d07eSChris Cain     }
222bae4d07eSChris Cain 
223bae4d07eSChris Cain     return stateVal;
224bae4d07eSChris Cain }
225bae4d07eSChris Cain 
getBootProgress()226bae4d07eSChris Cain BootProgress getBootProgress()
227bae4d07eSChris Cain {
228bae4d07eSChris Cain     BootProgress bootProgessStage;
229bae4d07eSChris Cain     constexpr auto bootProgressInterface =
230bae4d07eSChris Cain         "xyz.openbmc_project.State.Boot.Progress";
231bae4d07eSChris Cain     std::string value = getStateValue(bootProgressInterface,
232bae4d07eSChris Cain                                       HOST_STATE_OBJ_PATH, "BootProgress");
233bae4d07eSChris Cain     bootProgessStage = sdbusplus::xyz::openbmc_project::State::Boot::server::
234bae4d07eSChris Cain         Progress::convertProgressStagesFromString(value);
235bae4d07eSChris Cain     return bootProgessStage;
236bae4d07eSChris Cain }
237bae4d07eSChris Cain 
isHostRunning()238bae4d07eSChris Cain bool isHostRunning()
239bae4d07eSChris Cain {
240bae4d07eSChris Cain     BootProgress bootProgressStatus = getBootProgress();
241bae4d07eSChris Cain     if ((bootProgressStatus == BootProgress::SystemInitComplete) ||
242bae4d07eSChris Cain         (bootProgressStatus == BootProgress::SystemSetup) ||
243bae4d07eSChris Cain         (bootProgressStatus == BootProgress::OSRunning))
244bae4d07eSChris Cain     {
245bae4d07eSChris Cain         return true;
246bae4d07eSChris Cain     }
247bae4d07eSChris Cain     return false;
248bae4d07eSChris Cain }
249bae4d07eSChris Cain 
250f3b7514eSGeorge Liu } // namespace utils
25130e329adSVishwanatha Subbanna } // namespace occ
25230e329adSVishwanatha Subbanna } // namespace open_power
253