blob: f7f82ddc2cefd2533ede8b14906d26e97825bff6 [file] [log] [blame]
/*
// Copyright (c) 2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/
#include "dbuspassiveredundancy.hpp"
#include <sdbusplus/bus.hpp>
#include <sdbusplus/bus/match.hpp>
#include <iostream>
#include <set>
#include <unordered_map>
#include <variant>
namespace pid_control
{
namespace properties
{
constexpr const char* interface = "org.freedesktop.DBus.Properties";
constexpr const char* get = "Get";
constexpr const char* getAll = "GetAll";
} // namespace properties
namespace redundancy
{
constexpr const char* collection = "Collection";
constexpr const char* status = "Status";
constexpr const char* interface = "xyz.openbmc_project.Control.FanRedundancy";
} // namespace redundancy
DbusPassiveRedundancy::DbusPassiveRedundancy(sdbusplus::bus_t& bus) :
match(bus,
"type='signal',member='PropertiesChanged',arg0namespace='" +
std::string(redundancy::interface) + "'",
std::move([this](sdbusplus::message_t& message) {
std::string objectName;
std::unordered_map<
std::string,
std::variant<std::string, std::vector<std::string>>>
result;
try
{
message.read(objectName, result);
}
catch (const sdbusplus::exception_t&)
{
std::cerr << "Error reading match data";
return;
}
auto findStatus = result.find("Status");
if (findStatus == result.end())
{
return;
}
std::string status = std::get<std::string>(findStatus->second);
auto methodCall = passiveBus.new_method_call(
message.get_sender(), message.get_path(),
properties::interface, properties::get);
methodCall.append(redundancy::interface, redundancy::collection);
std::variant<std::vector<std::string>> collection;
try
{
auto reply = passiveBus.call(methodCall);
reply.read(collection);
}
catch (const sdbusplus::exception_t&)
{
std::cerr << "Error reading match data";
return;
}
auto data = std::get<std::vector<std::string>>(collection);
if (status.rfind("Failed") != std::string::npos)
{
failed.insert(data.begin(), data.end());
}
else
{
for (const auto& d : data)
{
failed.erase(d);
}
}
})),
passiveBus(bus)
{
populateFailures();
}
void DbusPassiveRedundancy::populateFailures(void)
{
auto mapper = passiveBus.new_method_call(
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetSubTree");
mapper.append("/", 0, std::array<const char*, 1>{redundancy::interface});
std::unordered_map<
std::string, std::unordered_map<std::string, std::vector<std::string>>>
respData;
try
{
auto resp = passiveBus.call(mapper);
resp.read(respData);
}
catch (const sdbusplus::exception_t&)
{
std::cerr << "Populate Failures Mapper Error\n";
return;
}
/*
* The subtree response looks like:
* {path :
* {busname:
* {interface, interface, interface, ...}
* }
* }
*
* This loops through this structure to pre-poulate the already failed items
*/
for (const auto& [path, interfaceDict] : respData)
{
for (const auto& [owner, _] : interfaceDict)
{
auto call = passiveBus.new_method_call(owner.c_str(), path.c_str(),
properties::interface,
properties::getAll);
call.append(redundancy::interface);
std::unordered_map<
std::string,
std::variant<std::string, std::vector<std::string>>>
getAll;
try
{
auto data = passiveBus.call(call);
data.read(getAll);
}
catch (const sdbusplus::exception_t&)
{
std::cerr << "Populate Failures Mapper Error\n";
return;
}
std::string status =
std::get<std::string>(getAll[redundancy::status]);
if (status.rfind("Failed") == std::string::npos)
{
continue;
}
std::vector<std::string> collection =
std::get<std::vector<std::string>>(
getAll[redundancy::collection]);
failed.insert(collection.begin(), collection.end());
}
}
}
const std::set<std::string>& DbusPassiveRedundancy::getFailed()
{
return failed;
}
} // namespace pid_control