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