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