blob: d00fcf07d30ba3c0befeb0f62b5f9bf031c05f8f [file] [log] [blame]
#include "entity_map_json.hpp"
#include <ipmid/types.hpp>
#include <nlohmann/json.hpp>
#include <exception>
#include <fstream>
#include <memory>
#include <string>
#include <utility>
namespace ipmi
{
namespace sensor
{
EntityInfoMapContainer* EntityInfoMapContainer::getContainer()
{
static std::unique_ptr<EntityInfoMapContainer> instance;
if (!instance)
{
/* TODO: With multi-threading this would all need to be locked so
* the first thread to hit it would set it up.
*/
EntityInfoMap builtEntityMap = buildEntityMapFromFile();
instance = std::unique_ptr<EntityInfoMapContainer>(
new EntityInfoMapContainer(builtEntityMap));
}
return instance.get();
}
const EntityInfoMap& EntityInfoMapContainer::getIpmiEntityRecords()
{
return entityRecords;
}
EntityInfoMap buildEntityMapFromFile()
{
const char* entityMapJsonFilename =
"/usr/share/ipmi-providers/entity-map.json";
EntityInfoMap builtMap;
std::ifstream mapFile(entityMapJsonFilename);
if (!mapFile.is_open())
{
return builtMap;
}
auto data = nlohmann::json::parse(mapFile, nullptr, false);
if (data.is_discarded())
{
return builtMap;
}
return buildJsonEntityMap(data);
}
EntityInfoMap buildJsonEntityMap(const nlohmann::json& data)
{
EntityInfoMap builtMap;
if (data.type() != nlohmann::json::value_t::array)
{
return builtMap;
}
try
{
for (const auto& entry : data)
{
/* It's an array entry with the following fields: id,
* containerEntityId, containerEntityInstance, isList, isLinked,
* entities[4]
*/
EntityInfo obj;
Id recordId = entry.at("id").get<Id>();
obj.containerEntityId =
entry.at("containerEntityId").get<uint8_t>();
obj.containerEntityInstance =
entry.at("containerEntityInstance").get<uint8_t>();
obj.isList = entry.at("isList").get<bool>();
obj.isLinked = entry.at("isLinked").get<bool>();
auto jsonEntities = entry.at("entities");
if (jsonEntities.type() != nlohmann::json::value_t::array)
{
throw std::runtime_error(
"Invalid type for entities entry, must be array");
}
if (jsonEntities.size() != obj.containedEntities.size())
{
throw std::runtime_error(
"Entities must be in pairs of " +
std::to_string(obj.containedEntities.size()));
}
for (std::size_t i = 0; i < obj.containedEntities.size(); i++)
{
obj.containedEntities[i] = std::make_pair(
jsonEntities[i].at("id").get<uint8_t>(),
jsonEntities[i].at("instance").get<uint8_t>());
}
builtMap.insert({recordId, obj});
}
}
catch (const std::exception& e)
{
/* If any entry is invalid, the entire file cannot be trusted. */
builtMap.clear();
}
return builtMap;
}
} // namespace sensor
} // namespace ipmi