| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1 | /* | 
|  | 2 | // Copyright (c) 2018 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 | */ | 
| Brad Bishop | e45d8c7 | 2022-05-25 15:12:53 -0400 | [diff] [blame] | 16 | /// \file entity_manager.cpp | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 17 |  | 
| Brad Bishop | e45d8c7 | 2022-05-25 15:12:53 -0400 | [diff] [blame] | 18 | #include "entity_manager.hpp" | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 19 |  | 
| Brad Bishop | e45d8c7 | 2022-05-25 15:12:53 -0400 | [diff] [blame] | 20 | #include "overlay.hpp" | 
| Benjamin Fair | ca2eb04 | 2022-09-13 06:40:42 +0000 | [diff] [blame] | 21 | #include "topology.hpp" | 
| Brad Bishop | e45d8c7 | 2022-05-25 15:12:53 -0400 | [diff] [blame] | 22 | #include "utils.hpp" | 
|  | 23 | #include "variant_visitors.hpp" | 
| James Feist | 481c5d5 | 2019-08-13 14:40:40 -0700 | [diff] [blame] | 24 |  | 
| James Feist | 11be667 | 2018-04-06 14:05:32 -0700 | [diff] [blame] | 25 | #include <boost/algorithm/string/case_conv.hpp> | 
| James Feist | f5125b0 | 2019-06-06 11:27:43 -0700 | [diff] [blame] | 26 | #include <boost/algorithm/string/classification.hpp> | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 27 | #include <boost/algorithm/string/predicate.hpp> | 
|  | 28 | #include <boost/algorithm/string/replace.hpp> | 
| James Feist | f5125b0 | 2019-06-06 11:27:43 -0700 | [diff] [blame] | 29 | #include <boost/algorithm/string/split.hpp> | 
| James Feist | 02d2b93 | 2020-02-06 16:28:48 -0800 | [diff] [blame] | 30 | #include <boost/asio/io_context.hpp> | 
| Ed Tanous | 49a888c | 2023-03-06 13:44:51 -0800 | [diff] [blame] | 31 | #include <boost/asio/post.hpp> | 
| James Feist | b1728ca | 2020-04-30 15:40:55 -0700 | [diff] [blame] | 32 | #include <boost/asio/steady_timer.hpp> | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 33 | #include <boost/container/flat_map.hpp> | 
|  | 34 | #include <boost/container/flat_set.hpp> | 
| James Feist | f5125b0 | 2019-06-06 11:27:43 -0700 | [diff] [blame] | 35 | #include <boost/range/iterator_range.hpp> | 
| James Feist | 8c505da | 2020-05-28 10:06:33 -0700 | [diff] [blame] | 36 | #include <nlohmann/json.hpp> | 
|  | 37 | #include <sdbusplus/asio/connection.hpp> | 
|  | 38 | #include <sdbusplus/asio/object_server.hpp> | 
|  | 39 |  | 
| Igor Kononenko | 9fd87e5 | 2020-10-06 01:18:17 +0300 | [diff] [blame] | 40 | #include <charconv> | 
| James Feist | 637b3ef | 2019-04-15 16:35:30 -0700 | [diff] [blame] | 41 | #include <filesystem> | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 42 | #include <fstream> | 
| Andrew Jeffery | e35d0ac | 2022-03-24 15:53:13 +1030 | [diff] [blame] | 43 | #include <functional> | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 44 | #include <iostream> | 
| Andrew Jeffery | 666583b | 2021-12-01 15:50:12 +1030 | [diff] [blame] | 45 | #include <map> | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 46 | #include <regex> | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 47 | #include <variant> | 
| Andrew Jeffery | a9c5892 | 2021-06-01 09:28:59 +0930 | [diff] [blame] | 48 | constexpr const char* hostConfigurationDirectory = SYSCONF_DIR "configurations"; | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 49 | constexpr const char* configurationDirectory = PACKAGE_DIR "configurations"; | 
|  | 50 | constexpr const char* schemaDirectory = PACKAGE_DIR "configurations/schemas"; | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 51 | constexpr const char* tempConfigDir = "/tmp/configuration/"; | 
|  | 52 | constexpr const char* lastConfiguration = "/tmp/configuration/last.json"; | 
|  | 53 | constexpr const char* currentConfiguration = "/var/configuration/system.json"; | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 54 | constexpr const char* globalSchema = "global.json"; | 
| James Feist | f1b1414 | 2019-04-10 15:22:09 -0700 | [diff] [blame] | 55 |  | 
| Andrew Jeffery | 666583b | 2021-12-01 15:50:12 +1030 | [diff] [blame] | 56 | const boost::container::flat_map<const char*, probe_type_codes, CmpStr> | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 57 | probeTypes{{{"FALSE", probe_type_codes::FALSE_T}, | 
|  | 58 | {"TRUE", probe_type_codes::TRUE_T}, | 
|  | 59 | {"AND", probe_type_codes::AND}, | 
|  | 60 | {"OR", probe_type_codes::OR}, | 
|  | 61 | {"FOUND", probe_type_codes::FOUND}, | 
|  | 62 | {"MATCH_ONE", probe_type_codes::MATCH_ONE}}}; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 63 |  | 
| Adrian Ambrożewicz | c789fca | 2020-05-14 15:50:05 +0200 | [diff] [blame] | 64 | static constexpr std::array<const char*, 6> settableInterfaces = { | 
|  | 65 | "FanProfile", "Pid", "Pid.Zone", "Stepwise", "Thresholds", "Polling"}; | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 66 | using JsonVariantType = | 
| James Feist | 338b8a7 | 2019-03-01 10:16:45 -0800 | [diff] [blame] | 67 | std::variant<std::vector<std::string>, std::vector<double>, std::string, | 
|  | 68 | int64_t, uint64_t, double, int32_t, uint32_t, int16_t, | 
|  | 69 | uint16_t, uint8_t, bool>; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 70 |  | 
| Ed Tanous | fc17142 | 2024-04-04 17:18:16 -0700 | [diff] [blame] | 71 | // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 72 | // store reference to all interfaces so we can destroy them later | 
|  | 73 | boost::container::flat_map< | 
| James Feist | 02d2b93 | 2020-02-06 16:28:48 -0800 | [diff] [blame] | 74 | std::string, std::vector<std::weak_ptr<sdbusplus::asio::dbus_interface>>> | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 75 | inventory; | 
|  | 76 |  | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 77 | // todo: pass this through nicer | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 78 | std::shared_ptr<sdbusplus::asio::connection> systemBus; | 
| Andrew Jeffery | 47af65a | 2021-12-01 14:16:31 +1030 | [diff] [blame] | 79 | nlohmann::json lastJson; | 
| Matt Spinler | 6eb6097 | 2023-08-14 16:36:20 -0500 | [diff] [blame] | 80 | Topology topology; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 81 |  | 
| James Feist | 02d2b93 | 2020-02-06 16:28:48 -0800 | [diff] [blame] | 82 | boost::asio::io_context io; | 
| Ed Tanous | fc17142 | 2024-04-04 17:18:16 -0700 | [diff] [blame] | 83 | // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) | 
| James Feist | 02d2b93 | 2020-02-06 16:28:48 -0800 | [diff] [blame] | 84 |  | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 85 | const std::regex illegalDbusPathRegex("[^A-Za-z0-9_.]"); | 
|  | 86 | const std::regex illegalDbusMemberRegex("[^A-Za-z0-9_]"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 87 |  | 
| John Edward Broadbent | d97c631 | 2023-10-26 20:32:07 +0000 | [diff] [blame] | 88 | void tryIfaceInitialize(std::shared_ptr<sdbusplus::asio::dbus_interface>& iface) | 
|  | 89 | { | 
|  | 90 | try | 
|  | 91 | { | 
|  | 92 | iface->initialize(); | 
|  | 93 | } | 
|  | 94 | catch (std::exception& e) | 
|  | 95 | { | 
|  | 96 | std::cerr << "Unable to initialize dbus interface : " << e.what() | 
|  | 97 | << "\n" | 
|  | 98 | << "object Path : " << iface->get_object_path() << "\n" | 
|  | 99 | << "interface name : " << iface->get_interface_name() << "\n"; | 
|  | 100 | } | 
|  | 101 | } | 
|  | 102 |  | 
| Andrew Jeffery | 666583b | 2021-12-01 15:50:12 +1030 | [diff] [blame] | 103 | FoundProbeTypeT findProbeType(const std::string& probe) | 
|  | 104 | { | 
|  | 105 | boost::container::flat_map<const char*, probe_type_codes, | 
|  | 106 | CmpStr>::const_iterator probeType; | 
|  | 107 | for (probeType = probeTypes.begin(); probeType != probeTypes.end(); | 
|  | 108 | ++probeType) | 
|  | 109 | { | 
|  | 110 | if (probe.find(probeType->first) != std::string::npos) | 
|  | 111 | { | 
|  | 112 | return probeType; | 
|  | 113 | } | 
|  | 114 | } | 
|  | 115 |  | 
|  | 116 | return std::nullopt; | 
|  | 117 | } | 
|  | 118 |  | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 119 | static std::shared_ptr<sdbusplus::asio::dbus_interface> | 
|  | 120 | createInterface(sdbusplus::asio::object_server& objServer, | 
|  | 121 | const std::string& path, const std::string& interface, | 
| James Feist | 02d2b93 | 2020-02-06 16:28:48 -0800 | [diff] [blame] | 122 | const std::string& parent, bool checkNull = false) | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 123 | { | 
| James Feist | 02d2b93 | 2020-02-06 16:28:48 -0800 | [diff] [blame] | 124 | // on first add we have no reason to check for null before add, as there | 
|  | 125 | // won't be any. For dynamically added interfaces, we check for null so that | 
|  | 126 | // a constant delete/add will not create a memory leak | 
|  | 127 |  | 
|  | 128 | auto ptr = objServer.add_interface(path, interface); | 
|  | 129 | auto& dataVector = inventory[parent]; | 
|  | 130 | if (checkNull) | 
|  | 131 | { | 
|  | 132 | auto it = std::find_if(dataVector.begin(), dataVector.end(), | 
|  | 133 | [](const auto& p) { return p.expired(); }); | 
|  | 134 | if (it != dataVector.end()) | 
|  | 135 | { | 
|  | 136 | *it = ptr; | 
|  | 137 | return ptr; | 
|  | 138 | } | 
|  | 139 | } | 
|  | 140 | dataVector.emplace_back(ptr); | 
|  | 141 | return ptr; | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 142 | } | 
|  | 143 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 144 | // writes output files to persist data | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 145 | bool writeJsonFiles(const nlohmann::json& systemConfiguration) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 146 | { | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 147 | std::filesystem::create_directory(configurationOutDir); | 
|  | 148 | std::ofstream output(currentConfiguration); | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 149 | if (!output.good()) | 
|  | 150 | { | 
|  | 151 | return false; | 
|  | 152 | } | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 153 | output << systemConfiguration.dump(4); | 
|  | 154 | output.close(); | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 155 | return true; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 156 | } | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 157 |  | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 158 | template <typename JsonType> | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 159 | bool setJsonFromPointer(const std::string& ptrStr, const JsonType& value, | 
|  | 160 | nlohmann::json& systemConfiguration) | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 161 | { | 
|  | 162 | try | 
|  | 163 | { | 
|  | 164 | nlohmann::json::json_pointer ptr(ptrStr); | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 165 | nlohmann::json& ref = systemConfiguration[ptr]; | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 166 | ref = value; | 
|  | 167 | return true; | 
|  | 168 | } | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 169 | catch (const std::out_of_range&) | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 170 | { | 
|  | 171 | return false; | 
|  | 172 | } | 
|  | 173 | } | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 174 |  | 
| James Feist | ebcc26b | 2019-03-22 12:30:43 -0700 | [diff] [blame] | 175 | // template function to add array as dbus property | 
|  | 176 | template <typename PropertyType> | 
|  | 177 | void addArrayToDbus(const std::string& name, const nlohmann::json& array, | 
|  | 178 | sdbusplus::asio::dbus_interface* iface, | 
|  | 179 | sdbusplus::asio::PropertyPermission permission, | 
|  | 180 | nlohmann::json& systemConfiguration, | 
|  | 181 | const std::string& jsonPointerString) | 
|  | 182 | { | 
|  | 183 | std::vector<PropertyType> values; | 
|  | 184 | for (const auto& property : array) | 
|  | 185 | { | 
|  | 186 | auto ptr = property.get_ptr<const PropertyType*>(); | 
|  | 187 | if (ptr != nullptr) | 
|  | 188 | { | 
|  | 189 | values.emplace_back(*ptr); | 
|  | 190 | } | 
|  | 191 | } | 
|  | 192 |  | 
|  | 193 | if (permission == sdbusplus::asio::PropertyPermission::readOnly) | 
|  | 194 | { | 
|  | 195 | iface->register_property(name, values); | 
|  | 196 | } | 
|  | 197 | else | 
|  | 198 | { | 
|  | 199 | iface->register_property( | 
|  | 200 | name, values, | 
|  | 201 | [&systemConfiguration, | 
|  | 202 | jsonPointerString{std::string(jsonPointerString)}]( | 
|  | 203 | const std::vector<PropertyType>& newVal, | 
|  | 204 | std::vector<PropertyType>& val) { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 205 | val = newVal; | 
|  | 206 | if (!setJsonFromPointer(jsonPointerString, val, | 
|  | 207 | systemConfiguration)) | 
|  | 208 | { | 
|  | 209 | std::cerr << "error setting json field\n"; | 
|  | 210 | return -1; | 
|  | 211 | } | 
|  | 212 | if (!writeJsonFiles(systemConfiguration)) | 
|  | 213 | { | 
|  | 214 | std::cerr << "error setting json file\n"; | 
|  | 215 | return -1; | 
|  | 216 | } | 
|  | 217 | return 1; | 
|  | 218 | }); | 
| James Feist | ebcc26b | 2019-03-22 12:30:43 -0700 | [diff] [blame] | 219 | } | 
|  | 220 | } | 
|  | 221 |  | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 222 | template <typename PropertyType> | 
| Ed Tanous | 3013fb4 | 2022-07-09 08:27:06 -0700 | [diff] [blame] | 223 | void addProperty(const std::string& name, const PropertyType& value, | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 224 | sdbusplus::asio::dbus_interface* iface, | 
|  | 225 | nlohmann::json& systemConfiguration, | 
|  | 226 | const std::string& jsonPointerString, | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 227 | sdbusplus::asio::PropertyPermission permission) | 
|  | 228 | { | 
|  | 229 | if (permission == sdbusplus::asio::PropertyPermission::readOnly) | 
|  | 230 | { | 
| Ed Tanous | 3013fb4 | 2022-07-09 08:27:06 -0700 | [diff] [blame] | 231 | iface->register_property(name, value); | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 232 | return; | 
|  | 233 | } | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 234 | iface->register_property( | 
| Ed Tanous | 3013fb4 | 2022-07-09 08:27:06 -0700 | [diff] [blame] | 235 | name, value, | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 236 | [&systemConfiguration, | 
|  | 237 | jsonPointerString{std::string(jsonPointerString)}]( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 238 | const PropertyType& newVal, PropertyType& val) { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 239 | val = newVal; | 
|  | 240 | if (!setJsonFromPointer(jsonPointerString, val, | 
|  | 241 | systemConfiguration)) | 
|  | 242 | { | 
|  | 243 | std::cerr << "error setting json field\n"; | 
|  | 244 | return -1; | 
|  | 245 | } | 
|  | 246 | if (!writeJsonFiles(systemConfiguration)) | 
|  | 247 | { | 
|  | 248 | std::cerr << "error setting json file\n"; | 
|  | 249 | return -1; | 
|  | 250 | } | 
|  | 251 | return 1; | 
|  | 252 | }); | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 253 | } | 
|  | 254 |  | 
|  | 255 | void createDeleteObjectMethod( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 256 | const std::string& jsonPointerPath, | 
|  | 257 | const std::shared_ptr<sdbusplus::asio::dbus_interface>& iface, | 
|  | 258 | sdbusplus::asio::object_server& objServer, | 
|  | 259 | nlohmann::json& systemConfiguration) | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 260 | { | 
|  | 261 | std::weak_ptr<sdbusplus::asio::dbus_interface> interface = iface; | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 262 | iface->register_method( | 
|  | 263 | "Delete", [&objServer, &systemConfiguration, interface, | 
|  | 264 | jsonPointerPath{std::string(jsonPointerPath)}]() { | 
|  | 265 | std::shared_ptr<sdbusplus::asio::dbus_interface> dbusInterface = | 
|  | 266 | interface.lock(); | 
|  | 267 | if (!dbusInterface) | 
|  | 268 | { | 
|  | 269 | // this technically can't happen as the pointer is pointing to | 
|  | 270 | // us | 
|  | 271 | throw DBusInternalError(); | 
|  | 272 | } | 
|  | 273 | nlohmann::json::json_pointer ptr(jsonPointerPath); | 
|  | 274 | systemConfiguration[ptr] = nullptr; | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 275 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 276 | // todo(james): dig through sdbusplus to find out why we can't | 
|  | 277 | // delete it in a method call | 
|  | 278 | boost::asio::post(io, [&objServer, dbusInterface]() mutable { | 
|  | 279 | objServer.remove_interface(dbusInterface); | 
|  | 280 | }); | 
|  | 281 |  | 
|  | 282 | if (!writeJsonFiles(systemConfiguration)) | 
|  | 283 | { | 
|  | 284 | std::cerr << "error setting json file\n"; | 
|  | 285 | throw DBusInternalError(); | 
|  | 286 | } | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 287 | }); | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 288 | } | 
|  | 289 |  | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 290 | // adds simple json types to interface's properties | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 291 | void populateInterfaceFromJson( | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 292 | nlohmann::json& systemConfiguration, const std::string& jsonPointerPath, | 
|  | 293 | std::shared_ptr<sdbusplus::asio::dbus_interface>& iface, | 
|  | 294 | nlohmann::json& dict, sdbusplus::asio::object_server& objServer, | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 295 | sdbusplus::asio::PropertyPermission permission = | 
|  | 296 | sdbusplus::asio::PropertyPermission::readOnly) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 297 | { | 
| Patrick Williams | 2594d36 | 2022-09-28 06:46:24 -0500 | [diff] [blame] | 298 | for (const auto& [key, value] : dict.items()) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 299 | { | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 300 | auto type = value.type(); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 301 | bool array = false; | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 302 | if (value.type() == nlohmann::json::value_t::array) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 303 | { | 
|  | 304 | array = true; | 
| Ed Tanous | 3013fb4 | 2022-07-09 08:27:06 -0700 | [diff] [blame] | 305 | if (value.empty()) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 306 | { | 
|  | 307 | continue; | 
|  | 308 | } | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 309 | type = value[0].type(); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 310 | bool isLegal = true; | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 311 | for (const auto& arrayItem : value) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 312 | { | 
|  | 313 | if (arrayItem.type() != type) | 
|  | 314 | { | 
|  | 315 | isLegal = false; | 
|  | 316 | break; | 
|  | 317 | } | 
|  | 318 | } | 
|  | 319 | if (!isLegal) | 
|  | 320 | { | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 321 | std::cerr << "dbus format error" << value << "\n"; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 322 | continue; | 
|  | 323 | } | 
| James Feist | a218ddb | 2019-04-11 14:01:31 -0700 | [diff] [blame] | 324 | } | 
|  | 325 | if (type == nlohmann::json::value_t::object) | 
|  | 326 | { | 
|  | 327 | continue; // handled elsewhere | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 328 | } | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 329 |  | 
|  | 330 | std::string path = jsonPointerPath; | 
|  | 331 | path.append("/").append(key); | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 332 | if (permission == sdbusplus::asio::PropertyPermission::readWrite) | 
|  | 333 | { | 
|  | 334 | // all setable numbers are doubles as it is difficult to always | 
|  | 335 | // create a configuration file with all whole numbers as decimals | 
|  | 336 | // i.e. 1.0 | 
| James Feist | ebcc26b | 2019-03-22 12:30:43 -0700 | [diff] [blame] | 337 | if (array) | 
|  | 338 | { | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 339 | if (value[0].is_number()) | 
| James Feist | ebcc26b | 2019-03-22 12:30:43 -0700 | [diff] [blame] | 340 | { | 
|  | 341 | type = nlohmann::json::value_t::number_float; | 
|  | 342 | } | 
|  | 343 | } | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 344 | else if (value.is_number()) | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 345 | { | 
|  | 346 | type = nlohmann::json::value_t::number_float; | 
|  | 347 | } | 
|  | 348 | } | 
|  | 349 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 350 | switch (type) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 351 | { | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 352 | case (nlohmann::json::value_t::boolean): | 
|  | 353 | { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 354 | if (array) | 
|  | 355 | { | 
|  | 356 | // todo: array of bool isn't detected correctly by | 
|  | 357 | // sdbusplus, change it to numbers | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 358 | addArrayToDbus<uint64_t>(key, value, iface.get(), | 
|  | 359 | permission, systemConfiguration, | 
|  | 360 | path); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 361 | } | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 362 |  | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 363 | else | 
|  | 364 | { | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 365 | addProperty(key, value.get<bool>(), iface.get(), | 
|  | 366 | systemConfiguration, path, permission); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 367 | } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 368 | break; | 
|  | 369 | } | 
|  | 370 | case (nlohmann::json::value_t::number_integer): | 
|  | 371 | { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 372 | if (array) | 
|  | 373 | { | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 374 | addArrayToDbus<int64_t>(key, value, iface.get(), permission, | 
| Andrew Jeffery | 029ee28 | 2022-03-25 13:11:36 +1030 | [diff] [blame] | 375 | systemConfiguration, path); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 376 | } | 
|  | 377 | else | 
|  | 378 | { | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 379 | addProperty(key, value.get<int64_t>(), iface.get(), | 
|  | 380 | systemConfiguration, path, | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 381 | sdbusplus::asio::PropertyPermission::readOnly); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 382 | } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 383 | break; | 
|  | 384 | } | 
|  | 385 | case (nlohmann::json::value_t::number_unsigned): | 
|  | 386 | { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 387 | if (array) | 
|  | 388 | { | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 389 | addArrayToDbus<uint64_t>(key, value, iface.get(), | 
|  | 390 | permission, systemConfiguration, | 
|  | 391 | path); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 392 | } | 
|  | 393 | else | 
|  | 394 | { | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 395 | addProperty(key, value.get<uint64_t>(), iface.get(), | 
| Andrew Jeffery | 029ee28 | 2022-03-25 13:11:36 +1030 | [diff] [blame] | 396 | systemConfiguration, path, | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 397 | sdbusplus::asio::PropertyPermission::readOnly); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 398 | } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 399 | break; | 
|  | 400 | } | 
|  | 401 | case (nlohmann::json::value_t::number_float): | 
|  | 402 | { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 403 | if (array) | 
|  | 404 | { | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 405 | addArrayToDbus<double>(key, value, iface.get(), permission, | 
| Andrew Jeffery | 029ee28 | 2022-03-25 13:11:36 +1030 | [diff] [blame] | 406 | systemConfiguration, path); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 407 | } | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 408 |  | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 409 | else | 
|  | 410 | { | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 411 | addProperty(key, value.get<double>(), iface.get(), | 
|  | 412 | systemConfiguration, path, permission); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 413 | } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 414 | break; | 
|  | 415 | } | 
|  | 416 | case (nlohmann::json::value_t::string): | 
|  | 417 | { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 418 | if (array) | 
|  | 419 | { | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 420 | addArrayToDbus<std::string>(key, value, iface.get(), | 
|  | 421 | permission, systemConfiguration, | 
|  | 422 | path); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 423 | } | 
|  | 424 | else | 
|  | 425 | { | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 426 | addProperty(key, value.get<std::string>(), iface.get(), | 
|  | 427 | systemConfiguration, path, permission); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 428 | } | 
| James Feist | 9eb0b58 | 2018-04-27 12:15:46 -0700 | [diff] [blame] | 429 | break; | 
|  | 430 | } | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 431 | default: | 
|  | 432 | { | 
| James Feist | a218ddb | 2019-04-11 14:01:31 -0700 | [diff] [blame] | 433 | std::cerr << "Unexpected json type in system configuration " | 
| Andrew Jeffery | 65ea450 | 2022-03-25 13:15:34 +1030 | [diff] [blame] | 434 | << key << ": " << value.type_name() << "\n"; | 
| James Feist | 0eb4035 | 2019-04-09 14:44:04 -0700 | [diff] [blame] | 435 | break; | 
|  | 436 | } | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 437 | } | 
|  | 438 | } | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 439 | if (permission == sdbusplus::asio::PropertyPermission::readWrite) | 
|  | 440 | { | 
|  | 441 | createDeleteObjectMethod(jsonPointerPath, iface, objServer, | 
|  | 442 | systemConfiguration); | 
|  | 443 | } | 
| John Edward Broadbent | d97c631 | 2023-10-26 20:32:07 +0000 | [diff] [blame] | 444 | tryIfaceInitialize(iface); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 445 | } | 
|  | 446 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 447 | sdbusplus::asio::PropertyPermission getPermission(const std::string& interface) | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 448 | { | 
|  | 449 | return std::find(settableInterfaces.begin(), settableInterfaces.end(), | 
|  | 450 | interface) != settableInterfaces.end() | 
|  | 451 | ? sdbusplus::asio::PropertyPermission::readWrite | 
|  | 452 | : sdbusplus::asio::PropertyPermission::readOnly; | 
|  | 453 | } | 
|  | 454 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 455 | void createAddObjectMethod( | 
|  | 456 | const std::string& jsonPointerPath, const std::string& path, | 
|  | 457 | nlohmann::json& systemConfiguration, | 
|  | 458 | sdbusplus::asio::object_server& objServer, const std::string& board) | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 459 | { | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 460 | std::shared_ptr<sdbusplus::asio::dbus_interface> iface = createInterface( | 
|  | 461 | objServer, path, "xyz.openbmc_project.AddObject", board); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 462 |  | 
|  | 463 | iface->register_method( | 
|  | 464 | "AddObject", | 
|  | 465 | [&systemConfiguration, &objServer, | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 466 | jsonPointerPath{std::string(jsonPointerPath)}, path{std::string(path)}, | 
|  | 467 | board](const boost::container::flat_map<std::string, JsonVariantType>& | 
|  | 468 | data) { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 469 | nlohmann::json::json_pointer ptr(jsonPointerPath); | 
|  | 470 | nlohmann::json& base = systemConfiguration[ptr]; | 
|  | 471 | auto findExposes = base.find("Exposes"); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 472 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 473 | if (findExposes == base.end()) | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 474 | { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 475 | throw std::invalid_argument("Entity must have children."); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 476 | } | 
|  | 477 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 478 | // this will throw invalid-argument to sdbusplus if invalid json | 
|  | 479 | nlohmann::json newData{}; | 
|  | 480 | for (const auto& item : data) | 
|  | 481 | { | 
|  | 482 | nlohmann::json& newJson = newData[item.first]; | 
|  | 483 | std::visit( | 
|  | 484 | [&newJson](auto&& val) { | 
|  | 485 | newJson = std::forward<decltype(val)>(val); | 
|  | 486 | }, | 
|  | 487 | item.second); | 
|  | 488 | } | 
|  | 489 |  | 
|  | 490 | auto findName = newData.find("Name"); | 
|  | 491 | auto findType = newData.find("Type"); | 
|  | 492 | if (findName == newData.end() || findType == newData.end()) | 
|  | 493 | { | 
|  | 494 | throw std::invalid_argument("AddObject missing Name or Type"); | 
|  | 495 | } | 
|  | 496 | const std::string* type = findType->get_ptr<const std::string*>(); | 
|  | 497 | const std::string* name = findName->get_ptr<const std::string*>(); | 
|  | 498 | if (type == nullptr || name == nullptr) | 
|  | 499 | { | 
|  | 500 | throw std::invalid_argument("Type and Name must be a string."); | 
|  | 501 | } | 
|  | 502 |  | 
|  | 503 | bool foundNull = false; | 
|  | 504 | size_t lastIndex = 0; | 
|  | 505 | // we add in the "exposes" | 
|  | 506 | for (const auto& expose : *findExposes) | 
|  | 507 | { | 
|  | 508 | if (expose.is_null()) | 
|  | 509 | { | 
|  | 510 | foundNull = true; | 
|  | 511 | continue; | 
|  | 512 | } | 
|  | 513 |  | 
|  | 514 | if (expose["Name"] == *name && expose["Type"] == *type) | 
|  | 515 | { | 
|  | 516 | throw std::invalid_argument( | 
|  | 517 | "Field already in JSON, not adding"); | 
|  | 518 | } | 
|  | 519 |  | 
|  | 520 | if (foundNull) | 
|  | 521 | { | 
|  | 522 | continue; | 
|  | 523 | } | 
|  | 524 |  | 
|  | 525 | lastIndex++; | 
|  | 526 | } | 
|  | 527 |  | 
|  | 528 | std::ifstream schemaFile(std::string(schemaDirectory) + "/" + | 
|  | 529 | boost::to_lower_copy(*type) + ".json"); | 
|  | 530 | // todo(james) we might want to also make a list of 'can add' | 
|  | 531 | // interfaces but for now I think the assumption if there is a | 
|  | 532 | // schema avaliable that it is allowed to update is fine | 
|  | 533 | if (!schemaFile.good()) | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 534 | { | 
|  | 535 | throw std::invalid_argument( | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 536 | "No schema avaliable, cannot validate."); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 537 | } | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 538 | nlohmann::json schema = | 
|  | 539 | nlohmann::json::parse(schemaFile, nullptr, false, true); | 
|  | 540 | if (schema.is_discarded()) | 
|  | 541 | { | 
|  | 542 | std::cerr << "Schema not legal" << *type << ".json\n"; | 
|  | 543 | throw DBusInternalError(); | 
|  | 544 | } | 
|  | 545 | if (!validateJson(schema, newData)) | 
|  | 546 | { | 
|  | 547 | throw std::invalid_argument("Data does not match schema"); | 
|  | 548 | } | 
| James Feist | 02d2b93 | 2020-02-06 16:28:48 -0800 | [diff] [blame] | 549 | if (foundNull) | 
|  | 550 | { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 551 | findExposes->at(lastIndex) = newData; | 
| James Feist | 02d2b93 | 2020-02-06 16:28:48 -0800 | [diff] [blame] | 552 | } | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 553 | else | 
|  | 554 | { | 
|  | 555 | findExposes->push_back(newData); | 
|  | 556 | } | 
|  | 557 | if (!writeJsonFiles(systemConfiguration)) | 
|  | 558 | { | 
|  | 559 | std::cerr << "Error writing json files\n"; | 
|  | 560 | throw DBusInternalError(); | 
|  | 561 | } | 
|  | 562 | std::string dbusName = *name; | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 563 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 564 | std::regex_replace(dbusName.begin(), dbusName.begin(), | 
|  | 565 | dbusName.end(), illegalDbusMemberRegex, "_"); | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 566 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 567 | std::shared_ptr<sdbusplus::asio::dbus_interface> interface = | 
|  | 568 | createInterface(objServer, path + "/" + dbusName, | 
|  | 569 | "xyz.openbmc_project.Configuration." + *type, | 
|  | 570 | board, true); | 
|  | 571 | // permission is read-write, as since we just created it, must be | 
|  | 572 | // runtime modifiable | 
|  | 573 | populateInterfaceFromJson( | 
|  | 574 | systemConfiguration, | 
|  | 575 | jsonPointerPath + "/Exposes/" + std::to_string(lastIndex), | 
|  | 576 | interface, newData, objServer, | 
|  | 577 | sdbusplus::asio::PropertyPermission::readWrite); | 
|  | 578 | }); | 
| John Edward Broadbent | d97c631 | 2023-10-26 20:32:07 +0000 | [diff] [blame] | 579 | tryIfaceInitialize(iface); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 580 | } | 
|  | 581 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 582 | void postToDbus(const nlohmann::json& newConfiguration, | 
|  | 583 | nlohmann::json& systemConfiguration, | 
|  | 584 | sdbusplus::asio::object_server& objServer) | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 585 |  | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 586 | { | 
| Matt Spinler | 6eb6097 | 2023-08-14 16:36:20 -0500 | [diff] [blame] | 587 | std::map<std::string, std::string> newBoards; // path -> name | 
| Benjamin Fair | ca2eb04 | 2022-09-13 06:40:42 +0000 | [diff] [blame] | 588 |  | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 589 | // iterate through boards | 
| Patrick Williams | 2594d36 | 2022-09-28 06:46:24 -0500 | [diff] [blame] | 590 | for (const auto& [boardId, boardConfig] : newConfiguration.items()) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 591 | { | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 592 | std::string boardName = boardConfig["Name"]; | 
|  | 593 | std::string boardNameOrig = boardConfig["Name"]; | 
| Andrew Jeffery | 13132df | 2022-03-25 13:29:41 +1030 | [diff] [blame] | 594 | std::string jsonPointerPath = "/" + boardId; | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 595 | // loop through newConfiguration, but use values from system | 
|  | 596 | // configuration to be able to modify via dbus later | 
| Andrew Jeffery | 13132df | 2022-03-25 13:29:41 +1030 | [diff] [blame] | 597 | auto boardValues = systemConfiguration[boardId]; | 
| James Feist | d63d18a | 2018-07-19 15:23:45 -0700 | [diff] [blame] | 598 | auto findBoardType = boardValues.find("Type"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 599 | std::string boardType; | 
|  | 600 | if (findBoardType != boardValues.end() && | 
|  | 601 | findBoardType->type() == nlohmann::json::value_t::string) | 
|  | 602 | { | 
|  | 603 | boardType = findBoardType->get<std::string>(); | 
|  | 604 | std::regex_replace(boardType.begin(), boardType.begin(), | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 605 | boardType.end(), illegalDbusMemberRegex, "_"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 606 | } | 
|  | 607 | else | 
|  | 608 | { | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 609 | std::cerr << "Unable to find type for " << boardName | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 610 | << " reverting to Chassis.\n"; | 
|  | 611 | boardType = "Chassis"; | 
|  | 612 | } | 
| James Feist | 11be667 | 2018-04-06 14:05:32 -0700 | [diff] [blame] | 613 | std::string boardtypeLower = boost::algorithm::to_lower_copy(boardType); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 614 |  | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 615 | std::regex_replace(boardName.begin(), boardName.begin(), | 
|  | 616 | boardName.end(), illegalDbusMemberRegex, "_"); | 
|  | 617 | std::string boardPath = "/xyz/openbmc_project/inventory/system/"; | 
|  | 618 | boardPath += boardtypeLower; | 
|  | 619 | boardPath += "/"; | 
|  | 620 | boardPath += boardName; | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 621 |  | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 622 | std::shared_ptr<sdbusplus::asio::dbus_interface> inventoryIface = | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 623 | createInterface(objServer, boardPath, | 
|  | 624 | "xyz.openbmc_project.Inventory.Item", boardName); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 625 |  | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 626 | std::shared_ptr<sdbusplus::asio::dbus_interface> boardIface = | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 627 | createInterface(objServer, boardPath, | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 628 | "xyz.openbmc_project.Inventory.Item." + boardType, | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 629 | boardNameOrig); | 
| James Feist | 11be667 | 2018-04-06 14:05:32 -0700 | [diff] [blame] | 630 |  | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 631 | createAddObjectMethod(jsonPointerPath, boardPath, systemConfiguration, | 
|  | 632 | objServer, boardNameOrig); | 
| James Feist | 68500ff | 2018-08-08 15:40:42 -0700 | [diff] [blame] | 633 |  | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 634 | populateInterfaceFromJson(systemConfiguration, jsonPointerPath, | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 635 | boardIface, boardValues, objServer); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 636 | jsonPointerPath += "/"; | 
|  | 637 | // iterate through board properties | 
| Patrick Williams | 2594d36 | 2022-09-28 06:46:24 -0500 | [diff] [blame] | 638 | for (const auto& [propName, propValue] : boardValues.items()) | 
| James Feist | 11be667 | 2018-04-06 14:05:32 -0700 | [diff] [blame] | 639 | { | 
| Andrew Jeffery | a96950d | 2022-03-25 13:32:46 +1030 | [diff] [blame] | 640 | if (propValue.type() == nlohmann::json::value_t::object) | 
| James Feist | 11be667 | 2018-04-06 14:05:32 -0700 | [diff] [blame] | 641 | { | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 642 | std::shared_ptr<sdbusplus::asio::dbus_interface> iface = | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 643 | createInterface(objServer, boardPath, propName, | 
|  | 644 | boardNameOrig); | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 645 |  | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 646 | populateInterfaceFromJson(systemConfiguration, | 
| Andrew Jeffery | a96950d | 2022-03-25 13:32:46 +1030 | [diff] [blame] | 647 | jsonPointerPath + propName, iface, | 
|  | 648 | propValue, objServer); | 
| James Feist | 11be667 | 2018-04-06 14:05:32 -0700 | [diff] [blame] | 649 | } | 
|  | 650 | } | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 651 |  | 
| James Feist | 1e3e698 | 2018-08-03 16:09:28 -0700 | [diff] [blame] | 652 | auto exposes = boardValues.find("Exposes"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 653 | if (exposes == boardValues.end()) | 
|  | 654 | { | 
|  | 655 | continue; | 
|  | 656 | } | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 657 | // iterate through exposes | 
| James Feist | 1e3e698 | 2018-08-03 16:09:28 -0700 | [diff] [blame] | 658 | jsonPointerPath += "Exposes/"; | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 659 |  | 
|  | 660 | // store the board level pointer so we can modify it on the way down | 
|  | 661 | std::string jsonPointerPathBoard = jsonPointerPath; | 
|  | 662 | size_t exposesIndex = -1; | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 663 | for (auto& item : *exposes) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 664 | { | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 665 | exposesIndex++; | 
|  | 666 | jsonPointerPath = jsonPointerPathBoard; | 
|  | 667 | jsonPointerPath += std::to_string(exposesIndex); | 
|  | 668 |  | 
| James Feist | d63d18a | 2018-07-19 15:23:45 -0700 | [diff] [blame] | 669 | auto findName = item.find("Name"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 670 | if (findName == item.end()) | 
|  | 671 | { | 
|  | 672 | std::cerr << "cannot find name in field " << item << "\n"; | 
|  | 673 | continue; | 
|  | 674 | } | 
| James Feist | 1e3e698 | 2018-08-03 16:09:28 -0700 | [diff] [blame] | 675 | auto findStatus = item.find("Status"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 676 | // if status is not found it is assumed to be status = 'okay' | 
|  | 677 | if (findStatus != item.end()) | 
|  | 678 | { | 
|  | 679 | if (*findStatus == "disabled") | 
|  | 680 | { | 
|  | 681 | continue; | 
|  | 682 | } | 
|  | 683 | } | 
| James Feist | d63d18a | 2018-07-19 15:23:45 -0700 | [diff] [blame] | 684 | auto findType = item.find("Type"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 685 | std::string itemType; | 
|  | 686 | if (findType != item.end()) | 
|  | 687 | { | 
|  | 688 | itemType = findType->get<std::string>(); | 
|  | 689 | std::regex_replace(itemType.begin(), itemType.begin(), | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 690 | itemType.end(), illegalDbusPathRegex, "_"); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 691 | } | 
|  | 692 | else | 
|  | 693 | { | 
|  | 694 | itemType = "unknown"; | 
|  | 695 | } | 
|  | 696 | std::string itemName = findName->get<std::string>(); | 
|  | 697 | std::regex_replace(itemName.begin(), itemName.begin(), | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 698 | itemName.end(), illegalDbusMemberRegex, "_"); | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 699 | std::string ifacePath = boardPath; | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 700 | ifacePath += "/"; | 
|  | 701 | ifacePath += itemName; | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 702 |  | 
| Sui Chen | 74ebe59 | 2022-09-13 10:22:03 -0700 | [diff] [blame] | 703 | if (itemType == "BMC") | 
|  | 704 | { | 
|  | 705 | std::shared_ptr<sdbusplus::asio::dbus_interface> bmcIface = | 
|  | 706 | createInterface(objServer, ifacePath, | 
|  | 707 | "xyz.openbmc_project.Inventory.Item.Bmc", | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 708 | boardNameOrig); | 
| Sui Chen | 74ebe59 | 2022-09-13 10:22:03 -0700 | [diff] [blame] | 709 | populateInterfaceFromJson(systemConfiguration, jsonPointerPath, | 
|  | 710 | bmcIface, item, objServer, | 
|  | 711 | getPermission(itemType)); | 
|  | 712 | } | 
| Edward Lee | eb587b4 | 2023-03-08 18:59:04 +0000 | [diff] [blame] | 713 | else if (itemType == "System") | 
|  | 714 | { | 
|  | 715 | std::shared_ptr<sdbusplus::asio::dbus_interface> systemIface = | 
|  | 716 | createInterface(objServer, ifacePath, | 
|  | 717 | "xyz.openbmc_project.Inventory.Item.System", | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 718 | boardNameOrig); | 
| Edward Lee | eb587b4 | 2023-03-08 18:59:04 +0000 | [diff] [blame] | 719 | populateInterfaceFromJson(systemConfiguration, jsonPointerPath, | 
|  | 720 | systemIface, item, objServer, | 
|  | 721 | getPermission(itemType)); | 
|  | 722 | } | 
| Sui Chen | 74ebe59 | 2022-09-13 10:22:03 -0700 | [diff] [blame] | 723 |  | 
| Patrick Williams | 2594d36 | 2022-09-28 06:46:24 -0500 | [diff] [blame] | 724 | for (const auto& [name, config] : item.items()) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 725 | { | 
| Andrew Jeffery | 5a6379c | 2022-03-25 13:25:31 +1030 | [diff] [blame] | 726 | jsonPointerPath = jsonPointerPathBoard; | 
|  | 727 | jsonPointerPath.append(std::to_string(exposesIndex)) | 
|  | 728 | .append("/") | 
|  | 729 | .append(name); | 
|  | 730 | if (config.type() == nlohmann::json::value_t::object) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 731 | { | 
| Andrew Jeffery | 5a6379c | 2022-03-25 13:25:31 +1030 | [diff] [blame] | 732 | std::string ifaceName = | 
|  | 733 | "xyz.openbmc_project.Configuration."; | 
|  | 734 | ifaceName.append(itemType).append(".").append(name); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 735 |  | 
| Andrew Jeffery | 5a6379c | 2022-03-25 13:25:31 +1030 | [diff] [blame] | 736 | std::shared_ptr<sdbusplus::asio::dbus_interface> | 
|  | 737 | objectIface = createInterface(objServer, ifacePath, | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 738 | ifaceName, boardNameOrig); | 
| Andrew Jeffery | 5a6379c | 2022-03-25 13:25:31 +1030 | [diff] [blame] | 739 |  | 
|  | 740 | populateInterfaceFromJson( | 
|  | 741 | systemConfiguration, jsonPointerPath, objectIface, | 
|  | 742 | config, objServer, getPermission(name)); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 743 | } | 
| Andrew Jeffery | 5a6379c | 2022-03-25 13:25:31 +1030 | [diff] [blame] | 744 | else if (config.type() == nlohmann::json::value_t::array) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 745 | { | 
|  | 746 | size_t index = 0; | 
| Ed Tanous | 3013fb4 | 2022-07-09 08:27:06 -0700 | [diff] [blame] | 747 | if (config.empty()) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 748 | { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 749 | continue; | 
|  | 750 | } | 
|  | 751 | bool isLegal = true; | 
| Andrew Jeffery | 5a6379c | 2022-03-25 13:25:31 +1030 | [diff] [blame] | 752 | auto type = config[0].type(); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 753 | if (type != nlohmann::json::value_t::object) | 
|  | 754 | { | 
|  | 755 | continue; | 
|  | 756 | } | 
|  | 757 |  | 
|  | 758 | // verify legal json | 
| Andrew Jeffery | 5a6379c | 2022-03-25 13:25:31 +1030 | [diff] [blame] | 759 | for (const auto& arrayItem : config) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 760 | { | 
|  | 761 | if (arrayItem.type() != type) | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 762 | { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 763 | isLegal = false; | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 764 | break; | 
|  | 765 | } | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 766 | } | 
|  | 767 | if (!isLegal) | 
|  | 768 | { | 
| Andrew Jeffery | 5a6379c | 2022-03-25 13:25:31 +1030 | [diff] [blame] | 769 | std::cerr << "dbus format error" << config << "\n"; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 770 | break; | 
|  | 771 | } | 
|  | 772 |  | 
| Andrew Jeffery | 5a6379c | 2022-03-25 13:25:31 +1030 | [diff] [blame] | 773 | for (auto& arrayItem : config) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 774 | { | 
| Andrew Jeffery | 5a6379c | 2022-03-25 13:25:31 +1030 | [diff] [blame] | 775 | std::string ifaceName = | 
|  | 776 | "xyz.openbmc_project.Configuration."; | 
|  | 777 | ifaceName.append(itemType).append(".").append(name); | 
|  | 778 | ifaceName.append(std::to_string(index)); | 
| James Feist | 97a63f1 | 2018-05-17 13:50:57 -0700 | [diff] [blame] | 779 |  | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 780 | std::shared_ptr<sdbusplus::asio::dbus_interface> | 
|  | 781 | objectIface = createInterface( | 
| Matt Spinler | 3d1909a | 2023-08-10 16:39:44 -0500 | [diff] [blame] | 782 | objServer, ifacePath, ifaceName, boardNameOrig); | 
| James Feist | d58879a8 | 2019-09-11 11:26:07 -0700 | [diff] [blame] | 783 |  | 
| James Feist | c6248a5 | 2018-08-14 10:09:45 -0700 | [diff] [blame] | 784 | populateInterfaceFromJson( | 
|  | 785 | systemConfiguration, | 
|  | 786 | jsonPointerPath + "/" + std::to_string(index), | 
|  | 787 | objectIface, arrayItem, objServer, | 
| Andrew Jeffery | 5a6379c | 2022-03-25 13:25:31 +1030 | [diff] [blame] | 788 | getPermission(name)); | 
| James Feist | bb43d02 | 2018-06-12 15:44:33 -0700 | [diff] [blame] | 789 | index++; | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 790 | } | 
|  | 791 | } | 
|  | 792 | } | 
| Benjamin Fair | ca2eb04 | 2022-09-13 06:40:42 +0000 | [diff] [blame] | 793 |  | 
| George Liu | 5c1a61a | 2024-10-24 18:02:29 +0800 | [diff] [blame] | 794 | std::shared_ptr<sdbusplus::asio::dbus_interface> itemIface = | 
|  | 795 | createInterface(objServer, ifacePath, | 
|  | 796 | "xyz.openbmc_project.Configuration." + itemType, | 
|  | 797 | boardNameOrig); | 
|  | 798 |  | 
|  | 799 | populateInterfaceFromJson(systemConfiguration, jsonPointerPath, | 
|  | 800 | itemIface, item, objServer, | 
|  | 801 | getPermission(itemType)); | 
|  | 802 |  | 
| Matt Spinler | 6eb6097 | 2023-08-14 16:36:20 -0500 | [diff] [blame] | 803 | topology.addBoard(boardPath, boardType, boardNameOrig, item); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 804 | } | 
| Matt Spinler | 6eb6097 | 2023-08-14 16:36:20 -0500 | [diff] [blame] | 805 |  | 
|  | 806 | newBoards.emplace(boardPath, boardNameOrig); | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 807 | } | 
| Benjamin Fair | ca2eb04 | 2022-09-13 06:40:42 +0000 | [diff] [blame] | 808 |  | 
| Matt Spinler | 6eb6097 | 2023-08-14 16:36:20 -0500 | [diff] [blame] | 809 | for (const auto& [assocPath, assocPropValue] : | 
|  | 810 | topology.getAssocs(newBoards)) | 
| Benjamin Fair | ca2eb04 | 2022-09-13 06:40:42 +0000 | [diff] [blame] | 811 | { | 
| Matt Spinler | 6eb6097 | 2023-08-14 16:36:20 -0500 | [diff] [blame] | 812 | auto findBoard = newBoards.find(assocPath); | 
|  | 813 | if (findBoard == newBoards.end()) | 
|  | 814 | { | 
|  | 815 | continue; | 
|  | 816 | } | 
| Benjamin Fair | ca2eb04 | 2022-09-13 06:40:42 +0000 | [diff] [blame] | 817 |  | 
| Matt Spinler | 6eb6097 | 2023-08-14 16:36:20 -0500 | [diff] [blame] | 818 | auto ifacePtr = createInterface( | 
|  | 819 | objServer, assocPath, "xyz.openbmc_project.Association.Definitions", | 
|  | 820 | findBoard->second); | 
|  | 821 |  | 
|  | 822 | ifacePtr->register_property("Associations", assocPropValue); | 
| John Edward Broadbent | d97c631 | 2023-10-26 20:32:07 +0000 | [diff] [blame] | 823 | tryIfaceInitialize(ifacePtr); | 
| Benjamin Fair | ca2eb04 | 2022-09-13 06:40:42 +0000 | [diff] [blame] | 824 | } | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 825 | } | 
|  | 826 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 827 | // reads json files out of the filesystem | 
| Andrew Jeffery | f331179 | 2022-03-29 22:09:00 +1030 | [diff] [blame] | 828 | bool loadConfigurations(std::list<nlohmann::json>& configurations) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 829 | { | 
|  | 830 | // find configuration files | 
| Ed Tanous | 072e25d | 2018-12-16 21:45:20 -0800 | [diff] [blame] | 831 | std::vector<std::filesystem::path> jsonPaths; | 
| Andrew Jeffery | a9c5892 | 2021-06-01 09:28:59 +0930 | [diff] [blame] | 832 | if (!findFiles( | 
|  | 833 | std::vector<std::filesystem::path>{configurationDirectory, | 
|  | 834 | hostConfigurationDirectory}, | 
|  | 835 | R"(.*\.json)", jsonPaths)) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 836 | { | 
|  | 837 | std::cerr << "Unable to find any configuration files in " | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 838 | << configurationDirectory << "\n"; | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 839 | return false; | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 840 | } | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 841 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 842 | std::ifstream schemaStream( | 
|  | 843 | std::string(schemaDirectory) + "/" + globalSchema); | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 844 | if (!schemaStream.good()) | 
|  | 845 | { | 
|  | 846 | std::cerr | 
|  | 847 | << "Cannot open schema file,  cannot validate JSON, exiting\n\n"; | 
|  | 848 | std::exit(EXIT_FAILURE); | 
| Ed Tanous | 072e25d | 2018-12-16 21:45:20 -0800 | [diff] [blame] | 849 | return false; | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 850 | } | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 851 | nlohmann::json schema = | 
|  | 852 | nlohmann::json::parse(schemaStream, nullptr, false, true); | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 853 | if (schema.is_discarded()) | 
|  | 854 | { | 
|  | 855 | std::cerr | 
|  | 856 | << "Illegal schema file detected, cannot validate JSON, exiting\n"; | 
|  | 857 | std::exit(EXIT_FAILURE); | 
| Ed Tanous | 072e25d | 2018-12-16 21:45:20 -0800 | [diff] [blame] | 858 | return false; | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 859 | } | 
|  | 860 |  | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 861 | for (auto& jsonPath : jsonPaths) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 862 | { | 
|  | 863 | std::ifstream jsonStream(jsonPath.c_str()); | 
|  | 864 | if (!jsonStream.good()) | 
|  | 865 | { | 
|  | 866 | std::cerr << "unable to open " << jsonPath.string() << "\n"; | 
|  | 867 | continue; | 
|  | 868 | } | 
| Potin Lai | 0f3a4d9 | 2023-12-05 00:13:55 +0800 | [diff] [blame] | 869 | auto data = nlohmann::json::parse(jsonStream, nullptr, false, true); | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 870 | if (data.is_discarded()) | 
|  | 871 | { | 
|  | 872 | std::cerr << "syntax error in " << jsonPath.string() << "\n"; | 
|  | 873 | continue; | 
|  | 874 | } | 
| James Feist | 8da9919 | 2019-01-24 08:20:16 -0800 | [diff] [blame] | 875 | /* | 
|  | 876 | * todo(james): reenable this once less things are in flight | 
|  | 877 | * | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 878 | if (!validateJson(schema, data)) | 
|  | 879 | { | 
|  | 880 | std::cerr << "Error validating " << jsonPath.string() << "\n"; | 
|  | 881 | continue; | 
|  | 882 | } | 
| James Feist | 8da9919 | 2019-01-24 08:20:16 -0800 | [diff] [blame] | 883 | */ | 
| James Feist | b4383f4 | 2018-08-06 16:54:10 -0700 | [diff] [blame] | 884 |  | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 885 | if (data.type() == nlohmann::json::value_t::array) | 
|  | 886 | { | 
| James Feist | a465ccc | 2019-02-08 12:51:01 -0800 | [diff] [blame] | 887 | for (auto& d : data) | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 888 | { | 
|  | 889 | configurations.emplace_back(d); | 
|  | 890 | } | 
|  | 891 | } | 
|  | 892 | else | 
|  | 893 | { | 
|  | 894 | configurations.emplace_back(data); | 
|  | 895 | } | 
|  | 896 | } | 
| Ed Tanous | 072e25d | 2018-12-16 21:45:20 -0800 | [diff] [blame] | 897 | return true; | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 898 | } | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 899 |  | 
| Andrew Jeffery | 5519293 | 2022-03-24 12:29:27 +1030 | [diff] [blame] | 900 | static bool deviceRequiresPowerOn(const nlohmann::json& entity) | 
|  | 901 | { | 
|  | 902 | auto powerState = entity.find("PowerState"); | 
| Andrew Jeffery | b620944 | 2022-03-24 12:36:20 +1030 | [diff] [blame] | 903 | if (powerState == entity.end()) | 
| Andrew Jeffery | 5519293 | 2022-03-24 12:29:27 +1030 | [diff] [blame] | 904 | { | 
| Andrew Jeffery | b620944 | 2022-03-24 12:36:20 +1030 | [diff] [blame] | 905 | return false; | 
| Andrew Jeffery | 5519293 | 2022-03-24 12:29:27 +1030 | [diff] [blame] | 906 | } | 
|  | 907 |  | 
| Ed Tanous | 3013fb4 | 2022-07-09 08:27:06 -0700 | [diff] [blame] | 908 | const auto* ptr = powerState->get_ptr<const std::string*>(); | 
|  | 909 | if (ptr == nullptr) | 
| Andrew Jeffery | b620944 | 2022-03-24 12:36:20 +1030 | [diff] [blame] | 910 | { | 
|  | 911 | return false; | 
|  | 912 | } | 
|  | 913 |  | 
|  | 914 | return *ptr == "On" || *ptr == "BiosPost"; | 
| Andrew Jeffery | 5519293 | 2022-03-24 12:29:27 +1030 | [diff] [blame] | 915 | } | 
|  | 916 |  | 
| Andrew Jeffery | 89ec352 | 2022-03-24 13:30:41 +1030 | [diff] [blame] | 917 | static void pruneDevice(const nlohmann::json& systemConfiguration, | 
|  | 918 | const bool powerOff, const bool scannedPowerOff, | 
|  | 919 | const std::string& name, const nlohmann::json& device) | 
|  | 920 | { | 
|  | 921 | if (systemConfiguration.contains(name)) | 
|  | 922 | { | 
|  | 923 | return; | 
|  | 924 | } | 
|  | 925 |  | 
| Andrew Jeffery | 4db38bc | 2022-03-24 13:42:41 +1030 | [diff] [blame] | 926 | if (deviceRequiresPowerOn(device) && (powerOff || scannedPowerOff)) | 
| Andrew Jeffery | 89ec352 | 2022-03-24 13:30:41 +1030 | [diff] [blame] | 927 | { | 
| Andrew Jeffery | 89ec352 | 2022-03-24 13:30:41 +1030 | [diff] [blame] | 928 | return; | 
|  | 929 | } | 
|  | 930 |  | 
|  | 931 | logDeviceRemoved(device); | 
|  | 932 | } | 
|  | 933 |  | 
| James Feist | b1728ca | 2020-04-30 15:40:55 -0700 | [diff] [blame] | 934 | void startRemovedTimer(boost::asio::steady_timer& timer, | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 935 | nlohmann::json& systemConfiguration) | 
|  | 936 | { | 
|  | 937 | static bool scannedPowerOff = false; | 
|  | 938 | static bool scannedPowerOn = false; | 
|  | 939 |  | 
| James Feist | fb00f39 | 2019-06-25 14:16:48 -0700 | [diff] [blame] | 940 | if (systemConfiguration.empty() || lastJson.empty()) | 
|  | 941 | { | 
|  | 942 | return; // not ready yet | 
|  | 943 | } | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 944 | if (scannedPowerOn) | 
|  | 945 | { | 
|  | 946 | return; | 
|  | 947 | } | 
|  | 948 |  | 
|  | 949 | if (!isPowerOn() && scannedPowerOff) | 
|  | 950 | { | 
|  | 951 | return; | 
|  | 952 | } | 
|  | 953 |  | 
| James Feist | b1728ca | 2020-04-30 15:40:55 -0700 | [diff] [blame] | 954 | timer.expires_after(std::chrono::seconds(10)); | 
| Andrew Jeffery | 27a1cfb | 2022-03-24 12:31:53 +1030 | [diff] [blame] | 955 | timer.async_wait( | 
|  | 956 | [&systemConfiguration](const boost::system::error_code& ec) { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 957 | if (ec == boost::asio::error::operation_aborted) | 
|  | 958 | { | 
|  | 959 | return; | 
|  | 960 | } | 
| Andrew Jeffery | 27a1cfb | 2022-03-24 12:31:53 +1030 | [diff] [blame] | 961 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 962 | bool powerOff = !isPowerOn(); | 
|  | 963 | for (const auto& [name, device] : lastJson.items()) | 
|  | 964 | { | 
|  | 965 | pruneDevice(systemConfiguration, powerOff, scannedPowerOff, | 
|  | 966 | name, device); | 
|  | 967 | } | 
| Andrew Jeffery | 89ec352 | 2022-03-24 13:30:41 +1030 | [diff] [blame] | 968 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 969 | scannedPowerOff = true; | 
|  | 970 | if (!powerOff) | 
|  | 971 | { | 
|  | 972 | scannedPowerOn = true; | 
|  | 973 | } | 
|  | 974 | }); | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 975 | } | 
|  | 976 |  | 
| Andrew Jeffery | 2f750d2 | 2022-03-24 14:32:57 +1030 | [diff] [blame] | 977 | static std::vector<std::weak_ptr<sdbusplus::asio::dbus_interface>>& | 
|  | 978 | getDeviceInterfaces(const nlohmann::json& device) | 
|  | 979 | { | 
|  | 980 | return inventory[device["Name"].get<std::string>()]; | 
|  | 981 | } | 
|  | 982 |  | 
| Andrew Jeffery | 0d0c146 | 2022-03-24 15:26:39 +1030 | [diff] [blame] | 983 | static void pruneConfiguration(nlohmann::json& systemConfiguration, | 
|  | 984 | sdbusplus::asio::object_server& objServer, | 
|  | 985 | bool powerOff, const std::string& name, | 
|  | 986 | const nlohmann::json& device) | 
|  | 987 | { | 
|  | 988 | if (powerOff && deviceRequiresPowerOn(device)) | 
|  | 989 | { | 
|  | 990 | // power not on yet, don't know if it's there or not | 
|  | 991 | return; | 
|  | 992 | } | 
|  | 993 |  | 
|  | 994 | auto& ifaces = getDeviceInterfaces(device); | 
|  | 995 | for (auto& iface : ifaces) | 
|  | 996 | { | 
|  | 997 | auto sharedPtr = iface.lock(); | 
|  | 998 | if (!!sharedPtr) | 
|  | 999 | { | 
|  | 1000 | objServer.remove_interface(sharedPtr); | 
|  | 1001 | } | 
|  | 1002 | } | 
|  | 1003 |  | 
|  | 1004 | ifaces.clear(); | 
|  | 1005 | systemConfiguration.erase(name); | 
| Matt Spinler | 6eb6097 | 2023-08-14 16:36:20 -0500 | [diff] [blame] | 1006 | topology.remove(device["Name"].get<std::string>()); | 
| Andrew Jeffery | 0d0c146 | 2022-03-24 15:26:39 +1030 | [diff] [blame] | 1007 | logDeviceRemoved(device); | 
|  | 1008 | } | 
|  | 1009 |  | 
| Andrew Jeffery | 7c4cbbe | 2022-03-24 15:27:10 +1030 | [diff] [blame] | 1010 | static void deriveNewConfiguration(const nlohmann::json& oldConfiguration, | 
|  | 1011 | nlohmann::json& newConfiguration) | 
|  | 1012 | { | 
|  | 1013 | for (auto it = newConfiguration.begin(); it != newConfiguration.end();) | 
|  | 1014 | { | 
|  | 1015 | auto findKey = oldConfiguration.find(it.key()); | 
|  | 1016 | if (findKey != oldConfiguration.end()) | 
|  | 1017 | { | 
|  | 1018 | it = newConfiguration.erase(it); | 
|  | 1019 | } | 
|  | 1020 | else | 
|  | 1021 | { | 
|  | 1022 | it++; | 
|  | 1023 | } | 
|  | 1024 | } | 
|  | 1025 | } | 
|  | 1026 |  | 
| Andrew Jeffery | e35d0ac | 2022-03-24 15:53:13 +1030 | [diff] [blame] | 1027 | static void publishNewConfiguration( | 
|  | 1028 | const size_t& instance, const size_t count, | 
|  | 1029 | boost::asio::steady_timer& timer, nlohmann::json& systemConfiguration, | 
|  | 1030 | // Gerrit discussion: | 
|  | 1031 | // https://gerrit.openbmc-project.xyz/c/openbmc/entity-manager/+/52316/6 | 
|  | 1032 | // | 
|  | 1033 | // Discord discussion: | 
|  | 1034 | // https://discord.com/channels/775381525260664832/867820390406422538/958048437729910854 | 
|  | 1035 | // | 
|  | 1036 | // NOLINTNEXTLINE(performance-unnecessary-value-param) | 
|  | 1037 | const nlohmann::json newConfiguration, | 
|  | 1038 | sdbusplus::asio::object_server& objServer) | 
|  | 1039 | { | 
|  | 1040 | loadOverlays(newConfiguration); | 
|  | 1041 |  | 
| Ed Tanous | 49a888c | 2023-03-06 13:44:51 -0800 | [diff] [blame] | 1042 | boost::asio::post(io, [systemConfiguration]() { | 
| Andrew Jeffery | e35d0ac | 2022-03-24 15:53:13 +1030 | [diff] [blame] | 1043 | if (!writeJsonFiles(systemConfiguration)) | 
|  | 1044 | { | 
|  | 1045 | std::cerr << "Error writing json files\n"; | 
|  | 1046 | } | 
|  | 1047 | }); | 
|  | 1048 |  | 
| Ed Tanous | 49a888c | 2023-03-06 13:44:51 -0800 | [diff] [blame] | 1049 | boost::asio::post(io, [&instance, count, &timer, newConfiguration, | 
|  | 1050 | &systemConfiguration, &objServer]() { | 
| Andrew Jeffery | e35d0ac | 2022-03-24 15:53:13 +1030 | [diff] [blame] | 1051 | postToDbus(newConfiguration, systemConfiguration, objServer); | 
|  | 1052 | if (count == instance) | 
|  | 1053 | { | 
|  | 1054 | startRemovedTimer(timer, systemConfiguration); | 
|  | 1055 | } | 
|  | 1056 | }); | 
|  | 1057 | } | 
|  | 1058 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1059 | // main properties changed entry | 
| James Feist | 4dc617b | 2020-05-01 09:54:47 -0700 | [diff] [blame] | 1060 | void propertiesChangedCallback(nlohmann::json& systemConfiguration, | 
|  | 1061 | sdbusplus::asio::object_server& objServer) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1062 | { | 
| James Feist | 2539ccd | 2020-05-01 16:15:08 -0700 | [diff] [blame] | 1063 | static bool inProgress = false; | 
| James Feist | b1728ca | 2020-04-30 15:40:55 -0700 | [diff] [blame] | 1064 | static boost::asio::steady_timer timer(io); | 
| James Feist | 899e17f | 2019-09-13 11:46:29 -0700 | [diff] [blame] | 1065 | static size_t instance = 0; | 
|  | 1066 | instance++; | 
|  | 1067 | size_t count = instance; | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1068 |  | 
| Anupama B R | bf26398 | 2024-01-25 04:42:39 -0600 | [diff] [blame] | 1069 | timer.expires_after(std::chrono::milliseconds(500)); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1070 |  | 
|  | 1071 | // setup an async wait as we normally get flooded with new requests | 
| James Feist | 4dc617b | 2020-05-01 09:54:47 -0700 | [diff] [blame] | 1072 | timer.async_wait([&systemConfiguration, &objServer, | 
| James Feist | 899e17f | 2019-09-13 11:46:29 -0700 | [diff] [blame] | 1073 | count](const boost::system::error_code& ec) { | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1074 | if (ec == boost::asio::error::operation_aborted) | 
|  | 1075 | { | 
|  | 1076 | // we were cancelled | 
|  | 1077 | return; | 
|  | 1078 | } | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 1079 | if (ec) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1080 | { | 
|  | 1081 | std::cerr << "async wait error " << ec << "\n"; | 
|  | 1082 | return; | 
|  | 1083 | } | 
|  | 1084 |  | 
| James Feist | 2539ccd | 2020-05-01 16:15:08 -0700 | [diff] [blame] | 1085 | if (inProgress) | 
|  | 1086 | { | 
|  | 1087 | propertiesChangedCallback(systemConfiguration, objServer); | 
|  | 1088 | return; | 
|  | 1089 | } | 
|  | 1090 | inProgress = true; | 
|  | 1091 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1092 | nlohmann::json oldConfiguration = systemConfiguration; | 
| James Feist | 899e17f | 2019-09-13 11:46:29 -0700 | [diff] [blame] | 1093 | auto missingConfigurations = std::make_shared<nlohmann::json>(); | 
|  | 1094 | *missingConfigurations = systemConfiguration; | 
|  | 1095 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1096 | std::list<nlohmann::json> configurations; | 
| Andrew Jeffery | f331179 | 2022-03-29 22:09:00 +1030 | [diff] [blame] | 1097 | if (!loadConfigurations(configurations)) | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1098 | { | 
| Andrew Jeffery | f331179 | 2022-03-29 22:09:00 +1030 | [diff] [blame] | 1099 | std::cerr << "Could not load configurations\n"; | 
| James Feist | 2539ccd | 2020-05-01 16:15:08 -0700 | [diff] [blame] | 1100 | inProgress = false; | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1101 | return; | 
|  | 1102 | } | 
|  | 1103 |  | 
|  | 1104 | auto perfScan = std::make_shared<PerformScan>( | 
| James Feist | 899e17f | 2019-09-13 11:46:29 -0700 | [diff] [blame] | 1105 | systemConfiguration, *missingConfigurations, configurations, | 
| James Feist | 4dc617b | 2020-05-01 09:54:47 -0700 | [diff] [blame] | 1106 | objServer, | 
|  | 1107 | [&systemConfiguration, &objServer, count, oldConfiguration, | 
|  | 1108 | missingConfigurations]() { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1109 | // this is something that since ac has been applied to the bmc | 
|  | 1110 | // we saw, and we no longer see it | 
|  | 1111 | bool powerOff = !isPowerOn(); | 
|  | 1112 | for (const auto& [name, device] : | 
|  | 1113 | missingConfigurations->items()) | 
|  | 1114 | { | 
|  | 1115 | pruneConfiguration(systemConfiguration, objServer, powerOff, | 
|  | 1116 | name, device); | 
|  | 1117 | } | 
| James Feist | 899e17f | 2019-09-13 11:46:29 -0700 | [diff] [blame] | 1118 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1119 | nlohmann::json newConfiguration = systemConfiguration; | 
| Andrew Jeffery | 7c4cbbe | 2022-03-24 15:27:10 +1030 | [diff] [blame] | 1120 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1121 | deriveNewConfiguration(oldConfiguration, newConfiguration); | 
| Andrew Jeffery | 7c4cbbe | 2022-03-24 15:27:10 +1030 | [diff] [blame] | 1122 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1123 | for (const auto& [_, device] : newConfiguration.items()) | 
|  | 1124 | { | 
|  | 1125 | logDeviceAdded(device); | 
|  | 1126 | } | 
| James Feist | 899e17f | 2019-09-13 11:46:29 -0700 | [diff] [blame] | 1127 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1128 | inProgress = false; | 
| James Feist | 2539ccd | 2020-05-01 16:15:08 -0700 | [diff] [blame] | 1129 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1130 | boost::asio::post( | 
|  | 1131 | io, std::bind_front( | 
|  | 1132 | publishNewConfiguration, std::ref(instance), count, | 
|  | 1133 | std::ref(timer), std::ref(systemConfiguration), | 
|  | 1134 | newConfiguration, std::ref(objServer))); | 
|  | 1135 | }); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1136 | perfScan->run(); | 
|  | 1137 | }); | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1138 | } | 
|  | 1139 |  | 
| Matt Spinler | 8d1ac3a | 2023-02-02 09:48:04 -0600 | [diff] [blame] | 1140 | // Extract the D-Bus interfaces to probe from the JSON config files. | 
|  | 1141 | static std::set<std::string> getProbeInterfaces() | 
|  | 1142 | { | 
|  | 1143 | std::set<std::string> interfaces; | 
|  | 1144 | std::list<nlohmann::json> configurations; | 
|  | 1145 | if (!loadConfigurations(configurations)) | 
|  | 1146 | { | 
|  | 1147 | return interfaces; | 
|  | 1148 | } | 
|  | 1149 |  | 
|  | 1150 | for (auto it = configurations.begin(); it != configurations.end();) | 
|  | 1151 | { | 
|  | 1152 | auto findProbe = it->find("Probe"); | 
|  | 1153 | if (findProbe == it->end()) | 
|  | 1154 | { | 
|  | 1155 | std::cerr << "configuration file missing probe:\n " << *it << "\n"; | 
|  | 1156 | it++; | 
|  | 1157 | continue; | 
|  | 1158 | } | 
|  | 1159 |  | 
|  | 1160 | nlohmann::json probeCommand; | 
|  | 1161 | if ((*findProbe).type() != nlohmann::json::value_t::array) | 
|  | 1162 | { | 
|  | 1163 | probeCommand = nlohmann::json::array(); | 
|  | 1164 | probeCommand.push_back(*findProbe); | 
|  | 1165 | } | 
|  | 1166 | else | 
|  | 1167 | { | 
|  | 1168 | probeCommand = *findProbe; | 
|  | 1169 | } | 
|  | 1170 |  | 
|  | 1171 | for (const nlohmann::json& probeJson : probeCommand) | 
|  | 1172 | { | 
|  | 1173 | const std::string* probe = probeJson.get_ptr<const std::string*>(); | 
|  | 1174 | if (probe == nullptr) | 
|  | 1175 | { | 
|  | 1176 | std::cerr << "Probe statement wasn't a string, can't parse"; | 
|  | 1177 | continue; | 
|  | 1178 | } | 
|  | 1179 | // Skip it if the probe cmd doesn't contain an interface. | 
|  | 1180 | if (findProbeType(*probe)) | 
|  | 1181 | { | 
|  | 1182 | continue; | 
|  | 1183 | } | 
|  | 1184 |  | 
|  | 1185 | // syntax requires probe before first open brace | 
|  | 1186 | auto findStart = probe->find('('); | 
|  | 1187 | if (findStart != std::string::npos) | 
|  | 1188 | { | 
|  | 1189 | std::string interface = probe->substr(0, findStart); | 
|  | 1190 | interfaces.emplace(interface); | 
|  | 1191 | } | 
|  | 1192 | } | 
|  | 1193 | it++; | 
|  | 1194 | } | 
|  | 1195 |  | 
|  | 1196 | return interfaces; | 
|  | 1197 | } | 
|  | 1198 |  | 
|  | 1199 | // Check if InterfacesAdded payload contains an iface that needs probing. | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1200 | static bool iaContainsProbeInterface( | 
|  | 1201 | sdbusplus::message_t& msg, const std::set<std::string>& probeInterfaces) | 
| Matt Spinler | 8d1ac3a | 2023-02-02 09:48:04 -0600 | [diff] [blame] | 1202 | { | 
|  | 1203 | sdbusplus::message::object_path path; | 
|  | 1204 | DBusObject interfaces; | 
|  | 1205 | std::set<std::string> interfaceSet; | 
|  | 1206 | std::set<std::string> intersect; | 
|  | 1207 |  | 
|  | 1208 | msg.read(path, interfaces); | 
|  | 1209 |  | 
|  | 1210 | std::for_each(interfaces.begin(), interfaces.end(), | 
|  | 1211 | [&interfaceSet](const auto& iface) { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1212 | interfaceSet.insert(iface.first); | 
|  | 1213 | }); | 
| Matt Spinler | 8d1ac3a | 2023-02-02 09:48:04 -0600 | [diff] [blame] | 1214 |  | 
|  | 1215 | std::set_intersection(interfaceSet.begin(), interfaceSet.end(), | 
|  | 1216 | probeInterfaces.begin(), probeInterfaces.end(), | 
|  | 1217 | std::inserter(intersect, intersect.end())); | 
|  | 1218 | return !intersect.empty(); | 
|  | 1219 | } | 
|  | 1220 |  | 
|  | 1221 | // Check if InterfacesRemoved payload contains an iface that needs probing. | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1222 | static bool irContainsProbeInterface( | 
|  | 1223 | sdbusplus::message_t& msg, const std::set<std::string>& probeInterfaces) | 
| Matt Spinler | 8d1ac3a | 2023-02-02 09:48:04 -0600 | [diff] [blame] | 1224 | { | 
|  | 1225 | sdbusplus::message::object_path path; | 
|  | 1226 | std::set<std::string> interfaces; | 
|  | 1227 | std::set<std::string> intersect; | 
|  | 1228 |  | 
|  | 1229 | msg.read(path, interfaces); | 
|  | 1230 |  | 
|  | 1231 | std::set_intersection(interfaces.begin(), interfaces.end(), | 
|  | 1232 | probeInterfaces.begin(), probeInterfaces.end(), | 
|  | 1233 | std::inserter(intersect, intersect.end())); | 
|  | 1234 | return !intersect.empty(); | 
|  | 1235 | } | 
|  | 1236 |  | 
| James Feist | 9813279 | 2019-07-09 13:29:09 -0700 | [diff] [blame] | 1237 | int main() | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1238 | { | 
|  | 1239 | // setup connection to dbus | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 1240 | systemBus = std::make_shared<sdbusplus::asio::connection>(io); | 
|  | 1241 | systemBus->request_name("xyz.openbmc_project.EntityManager"); | 
| James Feist | 4131aea | 2018-03-09 09:47:30 -0800 | [diff] [blame] | 1242 |  | 
| Nan Zhou | a331567 | 2022-09-20 19:48:14 +0000 | [diff] [blame] | 1243 | // The EntityManager object itself doesn't expose any properties. | 
|  | 1244 | // No need to set up ObjectManager for the |EntityManager| object. | 
|  | 1245 | sdbusplus::asio::object_server objServer(systemBus, /*skipManager=*/true); | 
|  | 1246 |  | 
|  | 1247 | // All other objects that EntityManager currently support are under the | 
|  | 1248 | // inventory subtree. | 
|  | 1249 | // See the discussion at | 
|  | 1250 | // https://discord.com/channels/775381525260664832/1018929092009144380 | 
|  | 1251 | objServer.add_manager("/xyz/openbmc_project/inventory"); | 
| James Feist | fd1264a | 2018-05-03 12:10:00 -0700 | [diff] [blame] | 1252 |  | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1253 | std::shared_ptr<sdbusplus::asio::dbus_interface> entityIface = | 
|  | 1254 | objServer.add_interface("/xyz/openbmc_project/EntityManager", | 
|  | 1255 | "xyz.openbmc_project.EntityManager"); | 
| James Feist | fd1264a | 2018-05-03 12:10:00 -0700 | [diff] [blame] | 1256 |  | 
| James Feist | 4131aea | 2018-03-09 09:47:30 -0800 | [diff] [blame] | 1257 | // to keep reference to the match / filter objects so they don't get | 
|  | 1258 | // destroyed | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1259 |  | 
|  | 1260 | nlohmann::json systemConfiguration = nlohmann::json::object(); | 
|  | 1261 |  | 
| Matt Spinler | 8d1ac3a | 2023-02-02 09:48:04 -0600 | [diff] [blame] | 1262 | std::set<std::string> probeInterfaces = getProbeInterfaces(); | 
|  | 1263 |  | 
| Brad Bishop | c76af0f | 2020-12-04 13:50:23 -0500 | [diff] [blame] | 1264 | // We need a poke from DBus for static providers that create all their | 
|  | 1265 | // objects prior to claiming a well-known name, and thus don't emit any | 
|  | 1266 | // org.freedesktop.DBus.Properties signals.  Similarly if a process exits | 
|  | 1267 | // for any reason, expected or otherwise, we'll need a poke to remove | 
|  | 1268 | // entities from DBus. | 
| Patrick Williams | 2af3922 | 2022-07-22 19:26:56 -0500 | [diff] [blame] | 1269 | sdbusplus::bus::match_t nameOwnerChangedMatch( | 
|  | 1270 | static_cast<sdbusplus::bus_t&>(*systemBus), | 
| Brad Bishop | c76af0f | 2020-12-04 13:50:23 -0500 | [diff] [blame] | 1271 | sdbusplus::bus::match::rules::nameOwnerChanged(), | 
| Patrick Williams | 7b8786f | 2022-10-10 10:23:37 -0500 | [diff] [blame] | 1272 | [&](sdbusplus::message_t& m) { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1273 | auto [name, oldOwner, | 
|  | 1274 | newOwner] = m.unpack<std::string, std::string, std::string>(); | 
| Patrick Williams | 7b8786f | 2022-10-10 10:23:37 -0500 | [diff] [blame] | 1275 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1276 | if (name.starts_with(':')) | 
|  | 1277 | { | 
|  | 1278 | // We should do nothing with unique-name connections. | 
|  | 1279 | return; | 
|  | 1280 | } | 
| Patrick Williams | 7b8786f | 2022-10-10 10:23:37 -0500 | [diff] [blame] | 1281 |  | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1282 | propertiesChangedCallback(systemConfiguration, objServer); | 
|  | 1283 | }); | 
| Brad Bishop | 10a8c5f | 2020-12-07 21:40:07 -0500 | [diff] [blame] | 1284 | // We also need a poke from DBus when new interfaces are created or | 
|  | 1285 | // destroyed. | 
| Patrick Williams | 2af3922 | 2022-07-22 19:26:56 -0500 | [diff] [blame] | 1286 | sdbusplus::bus::match_t interfacesAddedMatch( | 
|  | 1287 | static_cast<sdbusplus::bus_t&>(*systemBus), | 
| Brad Bishop | 10a8c5f | 2020-12-07 21:40:07 -0500 | [diff] [blame] | 1288 | sdbusplus::bus::match::rules::interfacesAdded(), | 
| Matt Spinler | 8d1ac3a | 2023-02-02 09:48:04 -0600 | [diff] [blame] | 1289 | [&](sdbusplus::message_t& msg) { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1290 | if (iaContainsProbeInterface(msg, probeInterfaces)) | 
|  | 1291 | { | 
|  | 1292 | propertiesChangedCallback(systemConfiguration, objServer); | 
|  | 1293 | } | 
|  | 1294 | }); | 
| Patrick Williams | 2af3922 | 2022-07-22 19:26:56 -0500 | [diff] [blame] | 1295 | sdbusplus::bus::match_t interfacesRemovedMatch( | 
|  | 1296 | static_cast<sdbusplus::bus_t&>(*systemBus), | 
| Brad Bishop | 10a8c5f | 2020-12-07 21:40:07 -0500 | [diff] [blame] | 1297 | sdbusplus::bus::match::rules::interfacesRemoved(), | 
| Matt Spinler | 8d1ac3a | 2023-02-02 09:48:04 -0600 | [diff] [blame] | 1298 | [&](sdbusplus::message_t& msg) { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1299 | if (irContainsProbeInterface(msg, probeInterfaces)) | 
|  | 1300 | { | 
|  | 1301 | propertiesChangedCallback(systemConfiguration, objServer); | 
|  | 1302 | } | 
|  | 1303 | }); | 
| Brad Bishop | c76af0f | 2020-12-04 13:50:23 -0500 | [diff] [blame] | 1304 |  | 
| Ed Tanous | 49a888c | 2023-03-06 13:44:51 -0800 | [diff] [blame] | 1305 | boost::asio::post(io, [&]() { | 
|  | 1306 | propertiesChangedCallback(systemConfiguration, objServer); | 
|  | 1307 | }); | 
| James Feist | 4131aea | 2018-03-09 09:47:30 -0800 | [diff] [blame] | 1308 |  | 
| James Feist | fd1264a | 2018-05-03 12:10:00 -0700 | [diff] [blame] | 1309 | entityIface->register_method("ReScan", [&]() { | 
| James Feist | 4dc617b | 2020-05-01 09:54:47 -0700 | [diff] [blame] | 1310 | propertiesChangedCallback(systemConfiguration, objServer); | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1311 | }); | 
| John Edward Broadbent | d97c631 | 2023-10-26 20:32:07 +0000 | [diff] [blame] | 1312 | tryIfaceInitialize(entityIface); | 
| James Feist | 8f2710a | 2018-05-09 17:18:55 -0700 | [diff] [blame] | 1313 |  | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1314 | if (fwVersionIsSame()) | 
|  | 1315 | { | 
|  | 1316 | if (std::filesystem::is_regular_file(currentConfiguration)) | 
|  | 1317 | { | 
|  | 1318 | // this file could just be deleted, but it's nice for debug | 
|  | 1319 | std::filesystem::create_directory(tempConfigDir); | 
|  | 1320 | std::filesystem::remove(lastConfiguration); | 
|  | 1321 | std::filesystem::copy(currentConfiguration, lastConfiguration); | 
|  | 1322 | std::filesystem::remove(currentConfiguration); | 
|  | 1323 |  | 
|  | 1324 | std::ifstream jsonStream(lastConfiguration); | 
|  | 1325 | if (jsonStream.good()) | 
|  | 1326 | { | 
|  | 1327 | auto data = nlohmann::json::parse(jsonStream, nullptr, false); | 
|  | 1328 | if (data.is_discarded()) | 
|  | 1329 | { | 
| Patrick Williams | b707743 | 2024-08-16 15:22:21 -0400 | [diff] [blame] | 1330 | std::cerr | 
|  | 1331 | << "syntax error in " << lastConfiguration << "\n"; | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1332 | } | 
|  | 1333 | else | 
|  | 1334 | { | 
|  | 1335 | lastJson = std::move(data); | 
|  | 1336 | } | 
|  | 1337 | } | 
|  | 1338 | else | 
|  | 1339 | { | 
|  | 1340 | std::cerr << "unable to open " << lastConfiguration << "\n"; | 
|  | 1341 | } | 
|  | 1342 | } | 
|  | 1343 | } | 
|  | 1344 | else | 
|  | 1345 | { | 
|  | 1346 | // not an error, just logging at this level to make it in the journal | 
|  | 1347 | std::cerr << "Clearing previous configuration\n"; | 
|  | 1348 | std::filesystem::remove(currentConfiguration); | 
|  | 1349 | } | 
|  | 1350 |  | 
|  | 1351 | // some boards only show up after power is on, we want to not say they are | 
|  | 1352 | // removed until the same state happens | 
| Ed Tanous | 07d467b | 2021-02-23 14:48:37 -0800 | [diff] [blame] | 1353 | setupPowerMatch(systemBus); | 
| James Feist | 1df06a4 | 2019-04-11 14:23:04 -0700 | [diff] [blame] | 1354 |  | 
| James Feist | 1b2e224 | 2018-01-30 13:45:19 -0800 | [diff] [blame] | 1355 | io.run(); | 
| James Feist | 3cb5fec | 2018-01-23 14:41:51 -0800 | [diff] [blame] | 1356 |  | 
|  | 1357 | return 0; | 
| James Feist | 75fdeeb | 2018-02-20 14:26:16 -0800 | [diff] [blame] | 1358 | } |