xref: /openbmc/phosphor-pid-control/dbus/dbuspassiveredundancy.cpp (revision 2922eebe4ddc565062eef84082519c094cb99f6e)
1 /*
2 // Copyright (c) 2019 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 
17 #include "dbuspassiveredundancy.hpp"
18 
19 #include <sdbusplus/bus.hpp>
20 #include <sdbusplus/bus/match.hpp>
21 
22 #include <iostream>
23 #include <set>
24 #include <unordered_map>
25 #include <variant>
26 
27 namespace pid_control
28 {
29 
30 namespace properties
31 {
32 
33 constexpr const char* interface = "org.freedesktop.DBus.Properties";
34 constexpr const char* get = "Get";
35 constexpr const char* getAll = "GetAll";
36 
37 } // namespace properties
38 
39 namespace redundancy
40 {
41 
42 constexpr const char* collection = "Collection";
43 constexpr const char* status = "Status";
44 constexpr const char* interface = "xyz.openbmc_project.Control.FanRedundancy";
45 
46 } // namespace redundancy
47 
DbusPassiveRedundancy(sdbusplus::bus_t & bus)48 DbusPassiveRedundancy::DbusPassiveRedundancy(sdbusplus::bus_t& bus) :
49     match(bus,
50           "type='signal',member='PropertiesChanged',arg0namespace='" +
51               std::string(redundancy::interface) + "'",
52 
53           [this](sdbusplus::message_t& message) {
54               std::string objectName;
55               std::unordered_map<
56                   std::string,
57                   std::variant<std::string, std::vector<std::string>>>
58                   result;
59               try
60               {
61                   message.read(objectName, result);
62               }
63               catch (const sdbusplus::exception_t&)
64               {
65                   std::cerr << "Error reading match data";
66                   return;
67               }
68               auto findStatus = result.find("Status");
69               if (findStatus == result.end())
70               {
71                   return;
72               }
73               std::string status = std::get<std::string>(findStatus->second);
74 
75               auto methodCall = passiveBus.new_method_call(
76                   message.get_sender(), message.get_path(),
77                   properties::interface, properties::get);
78               methodCall.append(redundancy::interface, redundancy::collection);
79               std::variant<std::vector<std::string>> collection;
80 
81               try
82               {
83                   auto reply = passiveBus.call(methodCall);
84                   reply.read(collection);
85               }
86               catch (const sdbusplus::exception_t&)
87               {
88                   std::cerr << "Error reading match data";
89                   return;
90               }
91 
92               auto data = std::get<std::vector<std::string>>(collection);
93               if (status.rfind("Failed") != std::string::npos)
94               {
95                   failed.insert(data.begin(), data.end());
96               }
97               else
98               {
99                   for (const auto& d : data)
100                   {
101                       failed.erase(d);
102                   }
103               }
104           }),
105     passiveBus(bus)
106 {
107     populateFailures();
108 }
109 
populateFailures(void)110 void DbusPassiveRedundancy::populateFailures(void)
111 {
112     auto mapper = passiveBus.new_method_call(
113         "xyz.openbmc_project.ObjectMapper",
114         "/xyz/openbmc_project/object_mapper",
115         "xyz.openbmc_project.ObjectMapper", "GetSubTree");
116     mapper.append("/", 0, std::array<const char*, 1>{redundancy::interface});
117     std::unordered_map<
118         std::string, std::unordered_map<std::string, std::vector<std::string>>>
119         respData;
120     try
121     {
122         auto resp = passiveBus.call(mapper);
123         resp.read(respData);
124     }
125     catch (const sdbusplus::exception_t&)
126     {
127         std::cerr << "Populate Failures Mapper Error\n";
128         return;
129     }
130 
131     /*
132      * The subtree response looks like:
133      * {path :
134      *     {busname:
135      *        {interface, interface, interface, ...}
136      *     }
137      * }
138      *
139      * This loops through this structure to pre-poulate the already failed items
140      */
141 
142     for (const auto& [path, interfaceDict] : respData)
143     {
144         for (const auto& [owner, _] : interfaceDict)
145         {
146             auto call = passiveBus.new_method_call(
147                 owner.c_str(), path.c_str(), properties::interface,
148                 properties::getAll);
149             call.append(redundancy::interface);
150 
151             std::unordered_map<
152                 std::string,
153                 std::variant<std::string, std::vector<std::string>>>
154                 getAll;
155             try
156             {
157                 auto data = passiveBus.call(call);
158                 data.read(getAll);
159             }
160             catch (const sdbusplus::exception_t&)
161             {
162                 std::cerr << "Populate Failures Mapper Error\n";
163                 return;
164             }
165             std::string status =
166                 std::get<std::string>(getAll[redundancy::status]);
167             if (status.rfind("Failed") == std::string::npos)
168             {
169                 continue;
170             }
171             std::vector<std::string> collection =
172                 std::get<std::vector<std::string>>(
173                     getAll[redundancy::collection]);
174             failed.insert(collection.begin(), collection.end());
175         }
176     }
177 }
178 
getFailed()179 const std::set<std::string>& DbusPassiveRedundancy::getFailed()
180 {
181     return failed;
182 }
183 
184 } // namespace pid_control
185