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