Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions redfish-core/include/utils/resource_utils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright OpenBMC Authors
#pragma once

#include "async_resp.hpp"
#include "dbus_utility.hpp"
#include "error_messages.hpp"
#include "generated/enums/resource.hpp"
#include "logging.hpp"

#include <asm-generic/errno.h>

#include <boost/system/error_code.hpp>
#include <boost/url/format.hpp>
#include <nlohmann/json.hpp>
#include <sdbusplus/message/native_types.hpp>

#include <functional>
#include <memory>
#include <string>

namespace redfish
{
namespace resource_utils
{

struct ResourceStatus
{
bool present = true;
bool available = true;
bool functional = true;
uint8_t pending = 0;
};

/**
* @brief Fetches resource status from DBus interfaces
*
*/
inline void determineResourceState(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::shared_ptr<ResourceStatus>& status,
const nlohmann::json::json_pointer& jsonPtr)
{
BMCWEB_LOG_DEBUG("determineResourceState");
if (--status->pending != 0)
{
return;
}

nlohmann::json& statusJson = asyncResp->res.jsonValue[jsonPtr]["Status"];

// Absent takes priority over unavailable
if (!status->present)
{
statusJson["State"] = resource::State::Absent;
}
else if (!status->available)
{
statusJson["State"] = resource::State::UnavailableOffline;
}
else
{
statusJson["State"] = resource::State::Enabled;
}

if (!status->functional)
{
statusJson["Health"] = resource::Health::Critical;
}
else
{
statusJson["Health"] = resource::Health::OK;
}
}

/**
* @brief Helper to fetch boolean property and update status
*
*/
inline void getStatusProperty(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::shared_ptr<ResourceStatus>& status, const std::string& service,
const std::string& path, const std::string& interface,
const std::string& property, const nlohmann::json::json_pointer& jsonPtr,
std::function<void(ResourceStatus&, bool)>&& callback)
{
sdbusplus::asio::getProperty<bool>(
*crow::connections::systemBus, service, path, interface, property,
[status, asyncResp, property, jsonPtr, callback{std::move(callback)}](
const boost::system::error_code& ec, bool value) {
if (ec)
{
if (ec.value() != EBADR)
{
BMCWEB_LOG_ERROR("DBUS response error for {}, ec {}",
property, ec.value());
messages::internalError(asyncResp->res);
return;
}
}
else
{
callback(*status, value);
}
determineResourceState(asyncResp, status, jsonPtr);
});
}

/*
* @brief Retrieves the status of the resource's state and health
*
* Queries three interfaces:
* - xyz.openbmc_project.Inventory.Item::Present
* - xyz.openbmc_project.State.Decorator.Availability::Available
* - xyz.openbmc_project.State.Decorator.OperationalStatus::Functional
*/
inline void getResourceStatus(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& service, const std::string& path,
const nlohmann::json::json_pointer& jsonPtr)
{
// Default values
asyncResp->res.jsonValue[jsonPtr]["Status"]["State"] =
resource::State::Enabled;
asyncResp->res.jsonValue[jsonPtr]["Status"]["Health"] =
resource::Health::OK;

BMCWEB_LOG_DEBUG("getResourceStatus");
auto status = std::make_shared<ResourceStatus>();
status->pending = 3;

getStatusProperty(asyncResp, status, service, path,
"xyz.openbmc_project.Inventory.Item", "Present", jsonPtr,
[](ResourceStatus& s, bool val) { s.present = val; });
getStatusProperty(asyncResp, status, service, path,
"xyz.openbmc_project.State.Decorator.Availability",
"Available", jsonPtr,
[](ResourceStatus& s, bool val) { s.available = val; });
getStatusProperty(asyncResp, status, service, path,
"xyz.openbmc_project.State.Decorator.OperationalStatus",
"Functional", jsonPtr,
[](ResourceStatus& s, bool val) { s.functional = val; });
}

inline void getResourceStatus(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& service, const std::string& path)
{
getResourceStatus(asyncResp, service, path, ""_json_pointer);
}

} // namespace resource_utils
} // namespace redfish
55 changes: 7 additions & 48 deletions redfish-core/lib/assembly.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "utils/asset_utils.hpp"
#include "utils/json_utils.hpp"
#include "utils/name_utils.hpp"
#include "utils/resource_utils.hpp"

#include <asm-generic/errno.h>

Expand Down Expand Up @@ -77,14 +78,11 @@ inline void getAssemblyLocationCode(
});
}

inline void getAssemblyState(
inline void getAssemblyReadyToRemove(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const auto& serviceName, const auto& assembly,
const nlohmann::json::json_pointer& assemblyJsonPtr)
{
asyncResp->res.jsonValue[assemblyJsonPtr]["Status"]["State"] =
resource::State::Enabled;

dbus::utility::getProperty<bool>(
serviceName, assembly, "xyz.openbmc_project.Inventory.Item", "Present",
[asyncResp, assemblyJsonPtr,
Expand All @@ -99,12 +97,6 @@ inline void getAssemblyState(
return;
}

if (!value)
{
asyncResp->res.jsonValue[assemblyJsonPtr]["Status"]["State"] =
resource::State::Absent;
}

std::string fru =
sdbusplus::message::object_path(assembly).filename();
// Special handling for LCD and base panel CM.
Expand All @@ -122,36 +114,6 @@ inline void getAssemblyState(
});
}

void getAssemblyHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const auto& serviceName, const auto& assembly,
const nlohmann::json::json_pointer& assemblyJsonPtr)
{
asyncResp->res.jsonValue[assemblyJsonPtr]["Status"]["Health"] =
resource::Health::OK;

dbus::utility::getProperty<bool>(
serviceName, assembly,
"xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
[asyncResp, assemblyJsonPtr](const boost::system::error_code& ec,
bool functional) {
if (ec)
{
if (ec.value() != EBADR)
{
BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
messages::internalError(asyncResp->res);
}
return;
}

if (!functional)
{
asyncResp->res.jsonValue[assemblyJsonPtr]["Status"]["Health"] =
resource::Health::Critical;
}
});
}

inline void afterGetDbusObject(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& assembly,
Expand Down Expand Up @@ -188,14 +150,11 @@ inline void afterGetDbusObject(
}
else if (interface == "xyz.openbmc_project.Inventory.Item")
{
getAssemblyState(asyncResp, serviceName, assembly,
assemblyJsonPtr);
}
else if (interface ==
"xyz.openbmc_project.State.Decorator.OperationalStatus")
{
getAssemblyHealth(asyncResp, serviceName, assembly,
assemblyJsonPtr);
resource_utils::getResourceStatus(asyncResp, serviceName,
assembly, assemblyJsonPtr);

getAssemblyReadyToRemove(asyncResp, serviceName, assembly,
assemblyJsonPtr);
}
}
}
Expand Down
33 changes: 3 additions & 30 deletions redfish-core/lib/cable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "utils/chassis_utils.hpp"
#include "utils/collection.hpp"
#include "utils/dbus_utils.hpp"
#include "utils/resource_utils.hpp"

#include <asm-generic/errno.h>
#include <sys/types.h>
Expand Down Expand Up @@ -159,35 +160,6 @@ inline void fillCablePartNumber(
});
}

inline void fillCableHealthState(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& cableObjectPath, const std::string& service)
{
dbus::utility::getProperty<bool>(
*crow::connections::systemBus, service, cableObjectPath,
"xyz.openbmc_project.Inventory.Item", "Present",
[asyncResp,
cableObjectPath](const boost::system::error_code& ec, bool present) {
if (ec)
{
if (ec.value() != EBADR)
{
BMCWEB_LOG_ERROR(
"get presence failed for Cable {} with error {}",
cableObjectPath, ec.value());
messages::internalError(asyncResp->res);
}
return;
}

if (!present)
{
asyncResp->res.jsonValue["Status"]["State"] =
resource::State::Absent;
}
});
}

inline void afterGetCableUpstreamResources(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const boost::system::error_code& ec,
Expand Down Expand Up @@ -490,7 +462,8 @@ inline void getCableProperties(
}
else if (interface == "xyz.openbmc_project.Inventory.Item")
{
fillCableHealthState(asyncResp, cableObjectPath, service);
resource_utils::getResourceStatus(asyncResp, service,
cableObjectPath);
}
else if (interface ==
"xyz.openbmc_project.Inventory.Decorator.Asset")
Expand Down
61 changes: 3 additions & 58 deletions redfish-core/lib/fabric_adapters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "utils/collection.hpp"
#include "utils/json_utils.hpp"
#include "utils/name_utils.hpp"
#include "utils/resource_utils.hpp"

#include <asm-generic/errno.h>

Expand Down Expand Up @@ -65,59 +66,6 @@ inline void getFabricAdapterLocation(
});
}

inline void getFabricAdapterState(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& serviceName, const std::string& fabricAdapterPath)
{
dbus::utility::getProperty<bool>(
serviceName, fabricAdapterPath, "xyz.openbmc_project.Inventory.Item",
"Present",
[asyncResp](const boost::system::error_code& ec, const bool present) {
if (ec)
{
if (ec.value() != EBADR)
{
BMCWEB_LOG_ERROR("DBUS response error for State");
messages::internalError(asyncResp->res);
}
return;
}

if (!present)
{
asyncResp->res.jsonValue["Status"]["State"] =
resource::State::Absent;
}
});
}

inline void getFabricAdapterHealth(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& serviceName, const std::string& fabricAdapterPath)
{
dbus::utility::getProperty<bool>(
serviceName, fabricAdapterPath,
"xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
[asyncResp](const boost::system::error_code& ec,
const bool functional) {
if (ec)
{
if (ec.value() != EBADR)
{
BMCWEB_LOG_ERROR("DBUS response error for Health");
messages::internalError(asyncResp->res);
}
return;
}

if (!functional)
{
asyncResp->res.jsonValue["Status"]["Health"] =
resource::Health::Critical;
}
});
}

inline void afterDoCheckFabricAdapterChassis(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const dbus::utility::MapperEndPoints& pcieSlotPaths,
Expand Down Expand Up @@ -259,9 +207,6 @@ inline void doAdapterGet(
asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
"/redfish/v1/Systems/{}/FabricAdapters/{}", systemName, adapterId);

asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;

asyncResp->res.jsonValue["Ports"]["@odata.id"] =
boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters/{}/Ports",
systemName, adapterId);
Expand All @@ -281,8 +226,8 @@ inline void doAdapterGet(
getFabricAdapterLocation(asyncResp, serviceName, fabricAdapterPath);
asset_utils::getAssetInfo(asyncResp, serviceName, fabricAdapterPath,
""_json_pointer, true);
getFabricAdapterState(asyncResp, serviceName, fabricAdapterPath);
getFabricAdapterHealth(asyncResp, serviceName, fabricAdapterPath);
resource_utils::getResourceStatus(asyncResp, serviceName,
fabricAdapterPath);
getLocationIndicatorActive(asyncResp, fabricAdapterPath);

// if the adapter also implements this interface, link the adapter schema to
Expand Down
Loading