xref: /openbmc/openpower-occ-control/utils.cpp (revision 37abe9be91df2bb173c9642a2740a425904d7921)
1  #include "utils.hpp"
2  
3  #include <systemd/sd-event.h>
4  #include <unistd.h>
5  
6  #include <phosphor-logging/elog-errors.hpp>
7  #include <phosphor-logging/lg2.hpp>
8  #include <sdbusplus/bus.hpp>
9  #include <xyz/openbmc_project/Common/error.hpp>
10  #include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
11  #include <xyz/openbmc_project/State/Host/server.hpp>
12  
13  #include <string>
14  namespace open_power
15  {
16  namespace occ
17  {
18  namespace utils
19  {
20  // For throwing exceptions
21  using namespace phosphor::logging;
22  using InternalFailure =
23      sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
24  
25  using BootProgress = sdbusplus::xyz::openbmc_project::State::Boot::server::
26      Progress::ProgressStages;
27  constexpr auto HOST_STATE_OBJ_PATH = "/xyz/openbmc_project/state/host0";
28  
getService(const std::string & path,const std::string & interface)29  const std::string getService(const std::string& path,
30                               const std::string& interface)
31  {
32      using InterfaceList = std::vector<std::string>;
33      std::map<std::string, std::vector<std::string>> mapperResponse;
34  
35      auto& bus = getBus();
36  
37      auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
38                                        MAPPER_IFACE, "GetObject");
39      mapper.append(path, InterfaceList({interface}));
40  
41      auto mapperResponseMsg = bus.call(mapper);
42      mapperResponseMsg.read(mapperResponse);
43      if (mapperResponse.empty())
44      {
45          lg2::error("ERROR reading mapper response: path={PATH}, I/F={INTF}",
46                     "PATH", path, "INTF", interface);
47  
48          elog<InternalFailure>();
49      }
50  
51      // the value here will be the service name
52      return mapperResponse.cbegin()->first;
53  }
54  
getProperty(const std::string & objectPath,const std::string & interface,const std::string & propertyName)55  const PropertyValue getProperty(const std::string& objectPath,
56                                  const std::string& interface,
57                                  const std::string& propertyName)
58  {
59      PropertyValue value{};
60  
61      auto& bus = getBus();
62      auto service = getService(objectPath, interface);
63      if (service.empty())
64      {
65          return value;
66      }
67  
68      auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
69                                        DBUS_PROPERTY_IFACE, "Get");
70      method.append(interface, propertyName);
71  
72      auto reply = bus.call(method);
73      reply.read(value);
74  
75      return value;
76  }
77  
78  /**
79   * @brief Sets a given object's property value
80   *
81   * @param[in] objectPath - Name of the object containing the property
82   * @param[in] interface - Interface name containing the property
83   * @param[in] propertyName - Property name
84   * @param[in] value - Property value
85   */
setProperty(const std::string & objectPath,const std::string & interface,const std::string & propertyName,PropertyValue && value)86  void setProperty(const std::string& objectPath, const std::string& interface,
87                   const std::string& propertyName, PropertyValue&& value)
88  {
89      using namespace std::literals::string_literals;
90      PropertyValue varValue(std::forward<PropertyValue>(value));
91  
92      try
93      {
94          auto& bus = getBus();
95          auto service = getService(objectPath, interface);
96          if (service.empty())
97          {
98              return;
99          }
100  
101          auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
102                                            DBUS_PROPERTY_IFACE, "Set");
103          method.append(interface, propertyName, varValue);
104  
105          auto reply = bus.call(method);
106          if (reply.is_method_error())
107          {
108              lg2::error("util::setProperty: Failed to set property {PROP}",
109                         "PROP", propertyName);
110          }
111      }
112      catch (const std::exception& e)
113      {
114          auto error = errno;
115          lg2::error("setProperty: failed to Set {PROP}, errno={ERR}, what={MSG}",
116                     "PROP", propertyName, "ERR", error, "PROP", e.what());
117      }
118  }
119  
getSubtreePaths(const std::vector<std::string> & interfaces,const std::string & path)120  std::vector<std::string> getSubtreePaths(
121      const std::vector<std::string>& interfaces, const std::string& path)
122  {
123      std::vector<std::string> paths;
124  
125      auto& bus = getBus();
126      auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
127                                        MAPPER_IFACE, "GetSubTreePaths");
128      method.append(path, 0, interfaces);
129  
130      auto reply = bus.call(method);
131      reply.read(paths);
132  
133      return paths;
134  }
135  
136  // Get the service and object path for an interface
getServiceUsingSubTree(const std::string & interface,std::string & path)137  std::string getServiceUsingSubTree(const std::string& interface,
138                                     std::string& path)
139  {
140      using Path = std::string;
141      using Intf = std::string;
142      using Serv = std::string;
143      using Intfs = std::vector<Intf>;
144      using Objects = std::map<Path, std::map<Serv, Intfs>>;
145      Serv service;
146      Objects rspObjects;
147  
148      auto& bus = getBus();
149      auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_OBJ_PATH,
150                                        MAPPER_IFACE, "GetSubTree");
151      method.append(path, 0, std::vector{interface});
152  
153      auto mapperResponseMsg = bus.call(method);
154      mapperResponseMsg.read(rspObjects);
155      if (rspObjects.empty())
156      {
157          lg2::error(
158              "util::getServiceUsingSubTree: Failed getSubTree({PATH},0,{INTF})",
159              "PATH", path, "INTF", interface);
160      }
161      else
162      {
163          path = rspObjects.begin()->first;
164          if (!rspObjects.begin()->second.empty())
165          {
166              service = rspObjects.begin()->second.begin()->first;
167          }
168          else
169          {
170              lg2::error(
171                  "getServiceUsingSubTree: service not found for interface {INTF} (path={PATH})",
172                  "INTF", interface, "PATH", path);
173          }
174      }
175  
176      return service;
177  }
178  
getStateValue(const std::string & intf,const std::string & objPath,const std::string & state)179  std::string getStateValue(const std::string& intf, const std::string& objPath,
180                            const std::string& state)
181  {
182      std::string stateVal;
183      try
184      {
185          auto& bus = getBus();
186          auto service = getService(objPath, intf);
187          if (service.empty())
188          {
189              throw std::runtime_error("getStateValue: Failed to get service");
190          }
191  
192          auto method =
193              bus.new_method_call(service.c_str(), objPath.c_str(),
194                                  "org.freedesktop.DBus.Properties", "Get");
195  
196          method.append(intf, state);
197  
198          auto reply = bus.call(method);
199  
200          std::variant<std::string> propertyVal;
201  
202          reply.read(propertyVal);
203  
204          stateVal = std::get<std::string>(propertyVal);
205      }
206      catch (const sdbusplus::exception_t& e)
207      {
208          lg2::error("D-Bus call exception, OBJPATH({PATH}), "
209                     "INTERFACE({INTF}), PROPERTY({PROP}) EXCEPTION({ERR})",
210                     "PATH", objPath, "INTF", intf, "PROP", state, "ERR",
211                     e.what());
212          throw std::runtime_error("Failed to get host state property");
213      }
214      catch (const std::bad_variant_access& e)
215      {
216          lg2::error(
217              "Exception raised while read host state({STATE}) property "
218              "value,  OBJPATH({PATH}), INTERFACE({INTF}), EXCEPTION({ERR})",
219              "STATE", state, "PATH", objPath, "INTF", intf, "ERR", e.what());
220          throw std::runtime_error("Failed to get host state property");
221      }
222  
223      return stateVal;
224  }
225  
getBootProgress()226  BootProgress getBootProgress()
227  {
228      BootProgress bootProgessStage;
229      constexpr auto bootProgressInterface =
230          "xyz.openbmc_project.State.Boot.Progress";
231      std::string value = getStateValue(bootProgressInterface,
232                                        HOST_STATE_OBJ_PATH, "BootProgress");
233      bootProgessStage = sdbusplus::xyz::openbmc_project::State::Boot::server::
234          Progress::convertProgressStagesFromString(value);
235      return bootProgessStage;
236  }
237  
isHostRunning()238  bool isHostRunning()
239  {
240      BootProgress bootProgressStatus = getBootProgress();
241      if ((bootProgressStatus == BootProgress::SystemInitComplete) ||
242          (bootProgressStatus == BootProgress::SystemSetup) ||
243          (bootProgressStatus == BootProgress::OSRunning))
244      {
245          return true;
246      }
247      return false;
248  }
249  
250  } // namespace utils
251  } // namespace occ
252  } // namespace open_power
253