xref: /openbmc/phosphor-pid-control/dbus/dbuspassiveredundancy.cpp (revision f8b6e55147148c3cfb42327ff267197a460b411c)
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 #include <sdbusplus/exception.hpp>
22 #include <sdbusplus/message.hpp>
23 
24 #include <array>
25 #include <iostream>
26 #include <set>
27 #include <string>
28 #include <unordered_map>
29 #include <variant>
30 #include <vector>
31 
32 namespace pid_control
33 {
34 
35 namespace properties
36 {
37 
38 constexpr const char* interface = "org.freedesktop.DBus.Properties";
39 constexpr const char* get = "Get";
40 constexpr const char* getAll = "GetAll";
41 
42 } // namespace properties
43 
44 namespace redundancy
45 {
46 
47 constexpr const char* collection = "Collection";
48 constexpr const char* status = "Status";
49 constexpr const char* interface = "xyz.openbmc_project.Control.FanRedundancy";
50 
51 } // namespace redundancy
52 
DbusPassiveRedundancy(sdbusplus::bus_t & bus)53 DbusPassiveRedundancy::DbusPassiveRedundancy(sdbusplus::bus_t& bus) :
54     match(bus,
55           "type='signal',member='PropertiesChanged',arg0namespace='" +
56               std::string(redundancy::interface) + "'",
57 
58           [this](sdbusplus::message_t& message) {
59               std::string objectName;
60               std::unordered_map<
61                   std::string,
62                   std::variant<std::string, std::vector<std::string>>>
63                   result;
64               try
65               {
66                   message.read(objectName, result);
67               }
68               catch (const sdbusplus::exception_t&)
69               {
70                   std::cerr << "Error reading match data";
71                   return;
72               }
73               auto findStatus = result.find("Status");
74               if (findStatus == result.end())
75               {
76                   return;
77               }
78               std::string status = std::get<std::string>(findStatus->second);
79 
80               auto methodCall = passiveBus.new_method_call(
81                   message.get_sender(), message.get_path(),
82                   properties::interface, properties::get);
83               methodCall.append(redundancy::interface, redundancy::collection);
84               std::variant<std::vector<std::string>> collection;
85 
86               try
87               {
88                   auto reply = passiveBus.call(methodCall);
89                   reply.read(collection);
90               }
91               catch (const sdbusplus::exception_t&)
92               {
93                   std::cerr << "Error reading match data";
94                   return;
95               }
96 
97               auto data = std::get<std::vector<std::string>>(collection);
98               if (status.rfind("Failed") != std::string::npos)
99               {
100                   failed.insert(data.begin(), data.end());
101               }
102               else
103               {
104                   for (const auto& d : data)
105                   {
106                       failed.erase(d);
107                   }
108               }
109           }),
110     passiveBus(bus)
111 {
112     populateFailures();
113 }
114 
populateFailures(void)115 void DbusPassiveRedundancy::populateFailures(void)
116 {
117     auto mapper = passiveBus.new_method_call(
118         "xyz.openbmc_project.ObjectMapper",
119         "/xyz/openbmc_project/object_mapper",
120         "xyz.openbmc_project.ObjectMapper", "GetSubTree");
121     mapper.append("/", 0, std::array<const char*, 1>{redundancy::interface});
122     std::unordered_map<
123         std::string, std::unordered_map<std::string, std::vector<std::string>>>
124         respData;
125     try
126     {
127         auto resp = passiveBus.call(mapper);
128         resp.read(respData);
129     }
130     catch (const sdbusplus::exception_t&)
131     {
132         std::cerr << "Populate Failures Mapper Error\n";
133         return;
134     }
135 
136     /*
137      * The subtree response looks like:
138      * {path :
139      *     {busname:
140      *        {interface, interface, interface, ...}
141      *     }
142      * }
143      *
144      * This loops through this structure to pre-populate the already failed
145      * items
146      */
147 
148     for (const auto& [path, interfaceDict] : respData)
149     {
150         for (const auto& [owner, _] : interfaceDict)
151         {
152             auto call = passiveBus.new_method_call(
153                 owner.c_str(), path.c_str(), properties::interface,
154                 properties::getAll);
155             call.append(redundancy::interface);
156 
157             std::unordered_map<
158                 std::string,
159                 std::variant<std::string, std::vector<std::string>>>
160                 getAll;
161             try
162             {
163                 auto data = passiveBus.call(call);
164                 data.read(getAll);
165             }
166             catch (const sdbusplus::exception_t&)
167             {
168                 std::cerr << "Populate Failures Mapper Error\n";
169                 return;
170             }
171             std::string status =
172                 std::get<std::string>(getAll[redundancy::status]);
173             if (status.rfind("Failed") == std::string::npos)
174             {
175                 continue;
176             }
177             std::vector<std::string> collection =
178                 std::get<std::vector<std::string>>(
179                     getAll[redundancy::collection]);
180             failed.insert(collection.begin(), collection.end());
181         }
182     }
183 }
184 
getFailed()185 const std::set<std::string>& DbusPassiveRedundancy::getFailed()
186 {
187     return failed;
188 }
189 
190 } // namespace pid_control
191