Vernon Mauery | 9cf0838 | 2023-04-28 14:00:11 -0700 | [diff] [blame] | 1 | #include <ipmid/entity_map_json.hpp> |
Patrick Williams | fbc6c9d | 2023-05-10 07:50:16 -0500 | [diff] [blame] | 2 | #include <ipmid/types.hpp> |
| 3 | #include <nlohmann/json.hpp> |
| 4 | |
Patrick Venture | 02e3237 | 2019-08-16 10:50:18 -0700 | [diff] [blame] | 5 | #include <exception> |
Patrick Venture | c2b7fc1 | 2019-08-19 11:53:22 -0700 | [diff] [blame] | 6 | #include <fstream> |
Patrick Venture | 87fd2cd | 2019-08-19 12:07:18 -0700 | [diff] [blame] | 7 | #include <memory> |
Patrick Venture | 02e3237 | 2019-08-16 10:50:18 -0700 | [diff] [blame] | 8 | #include <string> |
| 9 | #include <utility> |
| 10 | |
| 11 | namespace ipmi |
| 12 | { |
| 13 | namespace sensor |
| 14 | { |
| 15 | |
Patrick Venture | 87fd2cd | 2019-08-19 12:07:18 -0700 | [diff] [blame] | 16 | EntityInfoMapContainer* EntityInfoMapContainer::getContainer() |
Patrick Venture | 99bf1c4 | 2019-08-23 09:02:13 -0700 | [diff] [blame] | 17 | { |
Patrick Venture | 87fd2cd | 2019-08-19 12:07:18 -0700 | [diff] [blame] | 18 | static std::unique_ptr<EntityInfoMapContainer> instance; |
| 19 | |
| 20 | if (!instance) |
| 21 | { |
| 22 | /* TODO: With multi-threading this would all need to be locked so |
| 23 | * the first thread to hit it would set it up. |
| 24 | */ |
| 25 | EntityInfoMap builtEntityMap = buildEntityMapFromFile(); |
Patrick Venture | 1ad9da8 | 2019-08-19 12:25:54 -0700 | [diff] [blame] | 26 | instance = std::unique_ptr<EntityInfoMapContainer>( |
| 27 | new EntityInfoMapContainer(builtEntityMap)); |
Patrick Venture | 87fd2cd | 2019-08-19 12:07:18 -0700 | [diff] [blame] | 28 | } |
| 29 | |
| 30 | return instance.get(); |
| 31 | } |
| 32 | |
| 33 | const EntityInfoMap& EntityInfoMapContainer::getIpmiEntityRecords() |
| 34 | { |
| 35 | return entityRecords; |
Patrick Venture | 99bf1c4 | 2019-08-23 09:02:13 -0700 | [diff] [blame] | 36 | } |
| 37 | |
Patrick Venture | c2b7fc1 | 2019-08-19 11:53:22 -0700 | [diff] [blame] | 38 | EntityInfoMap buildEntityMapFromFile() |
| 39 | { |
| 40 | const char* entityMapJsonFilename = |
| 41 | "/usr/share/ipmi-providers/entity-map.json"; |
| 42 | EntityInfoMap builtMap; |
| 43 | |
| 44 | std::ifstream mapFile(entityMapJsonFilename); |
| 45 | if (!mapFile.is_open()) |
| 46 | { |
| 47 | return builtMap; |
| 48 | } |
| 49 | |
| 50 | auto data = nlohmann::json::parse(mapFile, nullptr, false); |
| 51 | if (data.is_discarded()) |
| 52 | { |
| 53 | return builtMap; |
| 54 | } |
| 55 | |
| 56 | return buildJsonEntityMap(data); |
| 57 | } |
| 58 | |
Patrick Venture | 02e3237 | 2019-08-16 10:50:18 -0700 | [diff] [blame] | 59 | EntityInfoMap buildJsonEntityMap(const nlohmann::json& data) |
| 60 | { |
| 61 | EntityInfoMap builtMap; |
| 62 | |
| 63 | if (data.type() != nlohmann::json::value_t::array) |
| 64 | { |
| 65 | return builtMap; |
| 66 | } |
| 67 | |
| 68 | try |
| 69 | { |
| 70 | for (const auto& entry : data) |
| 71 | { |
| 72 | /* It's an array entry with the following fields: id, |
| 73 | * containerEntityId, containerEntityInstance, isList, isLinked, |
| 74 | * entities[4] |
| 75 | */ |
| 76 | EntityInfo obj; |
| 77 | Id recordId = entry.at("id").get<Id>(); |
| 78 | obj.containerEntityId = |
| 79 | entry.at("containerEntityId").get<uint8_t>(); |
| 80 | obj.containerEntityInstance = |
| 81 | entry.at("containerEntityInstance").get<uint8_t>(); |
| 82 | obj.isList = entry.at("isList").get<bool>(); |
| 83 | obj.isLinked = entry.at("isLinked").get<bool>(); |
| 84 | |
| 85 | auto jsonEntities = entry.at("entities"); |
| 86 | |
| 87 | if (jsonEntities.type() != nlohmann::json::value_t::array) |
| 88 | { |
| 89 | throw std::runtime_error( |
| 90 | "Invalid type for entities entry, must be array"); |
| 91 | } |
| 92 | if (jsonEntities.size() != obj.containedEntities.size()) |
| 93 | { |
| 94 | throw std::runtime_error( |
| 95 | "Entities must be in pairs of " + |
| 96 | std::to_string(obj.containedEntities.size())); |
| 97 | } |
| 98 | |
| 99 | for (std::size_t i = 0; i < obj.containedEntities.size(); i++) |
| 100 | { |
| 101 | obj.containedEntities[i] = std::make_pair( |
| 102 | jsonEntities[i].at("id").get<uint8_t>(), |
| 103 | jsonEntities[i].at("instance").get<uint8_t>()); |
| 104 | } |
| 105 | |
| 106 | builtMap.insert({recordId, obj}); |
| 107 | } |
| 108 | } |
| 109 | catch (const std::exception& e) |
| 110 | { |
| 111 | /* If any entry is invalid, the entire file cannot be trusted. */ |
| 112 | builtMap.clear(); |
| 113 | } |
| 114 | |
| 115 | return builtMap; |
| 116 | } |
| 117 | |
| 118 | } // namespace sensor |
| 119 | } // namespace ipmi |