108777fb0SLewanczyk, Dawid /* 208777fb0SLewanczyk, Dawid // Copyright (c) 2018 Intel Corporation 308777fb0SLewanczyk, Dawid // 408777fb0SLewanczyk, Dawid // Licensed under the Apache License, Version 2.0 (the "License"); 508777fb0SLewanczyk, Dawid // you may not use this file except in compliance with the License. 608777fb0SLewanczyk, Dawid // You may obtain a copy of the License at 708777fb0SLewanczyk, Dawid // 808777fb0SLewanczyk, Dawid // http://www.apache.org/licenses/LICENSE-2.0 908777fb0SLewanczyk, Dawid // 1008777fb0SLewanczyk, Dawid // Unless required by applicable law or agreed to in writing, software 1108777fb0SLewanczyk, Dawid // distributed under the License is distributed on an "AS IS" BASIS, 1208777fb0SLewanczyk, Dawid // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1308777fb0SLewanczyk, Dawid // See the License for the specific language governing permissions and 1408777fb0SLewanczyk, Dawid // limitations under the License. 1508777fb0SLewanczyk, Dawid */ 1608777fb0SLewanczyk, Dawid #pragma once 1708777fb0SLewanczyk, Dawid 1808777fb0SLewanczyk, Dawid #include <math.h> 191abe55efSEd Tanous 2008777fb0SLewanczyk, Dawid #include <boost/algorithm/string/predicate.hpp> 2108777fb0SLewanczyk, Dawid #include <boost/algorithm/string/split.hpp> 2208777fb0SLewanczyk, Dawid #include <boost/container/flat_map.hpp> 2308777fb0SLewanczyk, Dawid #include <boost/range/algorithm/replace_copy_if.hpp> 241abe55efSEd Tanous #include <dbus_singleton.hpp> 25413961deSRichard Marian Thomaiyar #include <utils/json_utils.hpp> 26abf2add6SEd Tanous #include <variant> 2708777fb0SLewanczyk, Dawid 281abe55efSEd Tanous namespace redfish 291abe55efSEd Tanous { 3008777fb0SLewanczyk, Dawid 3108777fb0SLewanczyk, Dawid using GetSubTreeType = std::vector< 3208777fb0SLewanczyk, Dawid std::pair<std::string, 3308777fb0SLewanczyk, Dawid std::vector<std::pair<std::string, std::vector<std::string>>>>>; 3408777fb0SLewanczyk, Dawid 35028f7ebcSEddie James using SensorVariant = std::variant<int64_t, double, uint32_t, bool>; 36aa2e59c1SEd Tanous 3708777fb0SLewanczyk, Dawid using ManagedObjectsVectorType = std::vector<std::pair< 38aa2e59c1SEd Tanous sdbusplus::message::object_path, 3908777fb0SLewanczyk, Dawid boost::container::flat_map< 40aa2e59c1SEd Tanous std::string, boost::container::flat_map<std::string, SensorVariant>>>>; 4108777fb0SLewanczyk, Dawid 4208777fb0SLewanczyk, Dawid /** 43588c3f0dSKowalski, Kamil * SensorsAsyncResp 4408777fb0SLewanczyk, Dawid * Gathers data needed for response processing after async calls are done 4508777fb0SLewanczyk, Dawid */ 461abe55efSEd Tanous class SensorsAsyncResp 471abe55efSEd Tanous { 4808777fb0SLewanczyk, Dawid public: 4955c7b7a2SEd Tanous SensorsAsyncResp(crow::Response& response, const std::string& chassisId, 5085e1424fSEd Tanous const std::vector<const char*> types, 512474adfaSEd Tanous const std::string& subNode) : 5243b761d0SEd Tanous res(response), 5343b761d0SEd Tanous chassisId(chassisId), types(types), chassisSubNode(subNode) 541abe55efSEd Tanous { 5508777fb0SLewanczyk, Dawid } 5608777fb0SLewanczyk, Dawid 571abe55efSEd Tanous ~SensorsAsyncResp() 581abe55efSEd Tanous { 591abe55efSEd Tanous if (res.result() == boost::beast::http::status::internal_server_error) 601abe55efSEd Tanous { 611abe55efSEd Tanous // Reset the json object to clear out any data that made it in 621abe55efSEd Tanous // before the error happened todo(ed) handle error condition with 631abe55efSEd Tanous // proper code 6455c7b7a2SEd Tanous res.jsonValue = nlohmann::json::object(); 6508777fb0SLewanczyk, Dawid } 6608777fb0SLewanczyk, Dawid res.end(); 6708777fb0SLewanczyk, Dawid } 68588c3f0dSKowalski, Kamil 6955c7b7a2SEd Tanous crow::Response& res; 70588c3f0dSKowalski, Kamil std::string chassisId{}; 7108777fb0SLewanczyk, Dawid const std::vector<const char*> types; 722474adfaSEd Tanous std::string chassisSubNode{}; 7308777fb0SLewanczyk, Dawid }; 7408777fb0SLewanczyk, Dawid 7508777fb0SLewanczyk, Dawid /** 76413961deSRichard Marian Thomaiyar * @brief Get objects with connection necessary for sensors 77588c3f0dSKowalski, Kamil * @param SensorsAsyncResp Pointer to object holding response data 7808777fb0SLewanczyk, Dawid * @param sensorNames Sensors retrieved from chassis 7908777fb0SLewanczyk, Dawid * @param callback Callback for processing gathered connections 8008777fb0SLewanczyk, Dawid */ 8108777fb0SLewanczyk, Dawid template <typename Callback> 82413961deSRichard Marian Thomaiyar void getObjectsWithConnection( 83413961deSRichard Marian Thomaiyar std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp, 8449c53ac9SJohnathan Mantey const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 851abe55efSEd Tanous Callback&& callback) 861abe55efSEd Tanous { 87413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG << "getObjectsWithConnection enter"; 8803b5bae3SJames Feist const std::string path = "/xyz/openbmc_project/sensors"; 8908777fb0SLewanczyk, Dawid const std::array<std::string, 1> interfaces = { 9008777fb0SLewanczyk, Dawid "xyz.openbmc_project.Sensor.Value"}; 9108777fb0SLewanczyk, Dawid 9208777fb0SLewanczyk, Dawid // Response handler for parsing objects subtree 931abe55efSEd Tanous auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp, 941abe55efSEd Tanous sensorNames](const boost::system::error_code ec, 951abe55efSEd Tanous const GetSubTreeType& subtree) { 96413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler enter"; 971abe55efSEd Tanous if (ec) 981abe55efSEd Tanous { 995f7d88c4SEd Tanous messages::internalError(SensorsAsyncResp->res); 100413961deSRichard Marian Thomaiyar BMCWEB_LOG_ERROR 101413961deSRichard Marian Thomaiyar << "getObjectsWithConnection resp_handler: Dbus error " << ec; 10208777fb0SLewanczyk, Dawid return; 10308777fb0SLewanczyk, Dawid } 10408777fb0SLewanczyk, Dawid 10555c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees"; 10608777fb0SLewanczyk, Dawid 10708777fb0SLewanczyk, Dawid // Make unique list of connections only for requested sensor types and 10808777fb0SLewanczyk, Dawid // found in the chassis 10908777fb0SLewanczyk, Dawid boost::container::flat_set<std::string> connections; 110413961deSRichard Marian Thomaiyar std::set<std::pair<std::string, std::string>> objectsWithConnection; 1111abe55efSEd Tanous // Intrinsic to avoid malloc. Most systems will have < 8 sensor 1121abe55efSEd Tanous // producers 11308777fb0SLewanczyk, Dawid connections.reserve(8); 11408777fb0SLewanczyk, Dawid 11549c53ac9SJohnathan Mantey BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames->size(); 11649c53ac9SJohnathan Mantey for (const std::string& tsensor : *sensorNames) 1171abe55efSEd Tanous { 11855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor; 11908777fb0SLewanczyk, Dawid } 12008777fb0SLewanczyk, Dawid 12108777fb0SLewanczyk, Dawid for (const std::pair< 12208777fb0SLewanczyk, Dawid std::string, 12308777fb0SLewanczyk, Dawid std::vector<std::pair<std::string, std::vector<std::string>>>>& 1241abe55efSEd Tanous object : subtree) 1251abe55efSEd Tanous { 12649c53ac9SJohnathan Mantey if (sensorNames->find(object.first) != sensorNames->end()) 1271abe55efSEd Tanous { 12849c53ac9SJohnathan Mantey for (const std::pair<std::string, std::vector<std::string>>& 1291abe55efSEd Tanous objData : object.second) 1301abe55efSEd Tanous { 13149c53ac9SJohnathan Mantey BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first; 13208777fb0SLewanczyk, Dawid connections.insert(objData.first); 133de629b6eSShawn McCarney objectsWithConnection.insert( 134de629b6eSShawn McCarney std::make_pair(object.first, objData.first)); 13508777fb0SLewanczyk, Dawid } 13608777fb0SLewanczyk, Dawid } 13708777fb0SLewanczyk, Dawid } 13855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections"; 139413961deSRichard Marian Thomaiyar callback(std::move(connections), std::move(objectsWithConnection)); 140413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler exit"; 14108777fb0SLewanczyk, Dawid }; 14208777fb0SLewanczyk, Dawid // Make call to ObjectMapper to find all sensors objects 14355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 14455c7b7a2SEd Tanous std::move(respHandler), "xyz.openbmc_project.ObjectMapper", 1451abe55efSEd Tanous "/xyz/openbmc_project/object_mapper", 1461abe55efSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces); 147413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG << "getObjectsWithConnection exit"; 148413961deSRichard Marian Thomaiyar } 149413961deSRichard Marian Thomaiyar 150413961deSRichard Marian Thomaiyar /** 151413961deSRichard Marian Thomaiyar * @brief Create connections necessary for sensors 152413961deSRichard Marian Thomaiyar * @param SensorsAsyncResp Pointer to object holding response data 153413961deSRichard Marian Thomaiyar * @param sensorNames Sensors retrieved from chassis 154413961deSRichard Marian Thomaiyar * @param callback Callback for processing gathered connections 155413961deSRichard Marian Thomaiyar */ 156413961deSRichard Marian Thomaiyar template <typename Callback> 15749c53ac9SJohnathan Mantey void getConnections( 15849c53ac9SJohnathan Mantey std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp, 15949c53ac9SJohnathan Mantey const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 160413961deSRichard Marian Thomaiyar Callback&& callback) 161413961deSRichard Marian Thomaiyar { 162413961deSRichard Marian Thomaiyar auto objectsWithConnectionCb = 163413961deSRichard Marian Thomaiyar [callback](const boost::container::flat_set<std::string>& connections, 164413961deSRichard Marian Thomaiyar const std::set<std::pair<std::string, std::string>>& 165413961deSRichard Marian Thomaiyar objectsWithConnection) { 166413961deSRichard Marian Thomaiyar callback(std::move(connections)); 167413961deSRichard Marian Thomaiyar }; 168413961deSRichard Marian Thomaiyar getObjectsWithConnection(SensorsAsyncResp, sensorNames, 169413961deSRichard Marian Thomaiyar std::move(objectsWithConnectionCb)); 17008777fb0SLewanczyk, Dawid } 17108777fb0SLewanczyk, Dawid 17208777fb0SLewanczyk, Dawid /** 17349c53ac9SJohnathan Mantey * @brief Shrinks the list of sensors for processing 17449c53ac9SJohnathan Mantey * @param SensorsAysncResp The class holding the Redfish response 17549c53ac9SJohnathan Mantey * @param allSensors A list of all the sensors associated to the 17649c53ac9SJohnathan Mantey * chassis element (i.e. baseboard, front panel, etc...) 17749c53ac9SJohnathan Mantey * @param activeSensors A list that is a reduction of the incoming 17849c53ac9SJohnathan Mantey * allSensors list. Eliminate Thermal sensors when a Power request is 17949c53ac9SJohnathan Mantey * made, and eliminate Power sensors when a Thermal request is made. 18049c53ac9SJohnathan Mantey */ 18149c53ac9SJohnathan Mantey void reduceSensorList( 18249c53ac9SJohnathan Mantey std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp, 18349c53ac9SJohnathan Mantey const std::vector<std::string>* allSensors, 18449c53ac9SJohnathan Mantey std::shared_ptr<boost::container::flat_set<std::string>> activeSensors) 18549c53ac9SJohnathan Mantey { 18649c53ac9SJohnathan Mantey if (SensorsAsyncResp == nullptr) 18749c53ac9SJohnathan Mantey { 18849c53ac9SJohnathan Mantey return; 18949c53ac9SJohnathan Mantey } 19049c53ac9SJohnathan Mantey if ((allSensors == nullptr) || (activeSensors == nullptr)) 19149c53ac9SJohnathan Mantey { 19249c53ac9SJohnathan Mantey messages::resourceNotFound( 19349c53ac9SJohnathan Mantey SensorsAsyncResp->res, SensorsAsyncResp->chassisSubNode, 19449c53ac9SJohnathan Mantey SensorsAsyncResp->chassisSubNode == "Thermal" ? "Temperatures" 19549c53ac9SJohnathan Mantey : "Voltages"); 19649c53ac9SJohnathan Mantey 19749c53ac9SJohnathan Mantey return; 19849c53ac9SJohnathan Mantey } 19949c53ac9SJohnathan Mantey if (allSensors->empty()) 20049c53ac9SJohnathan Mantey { 20149c53ac9SJohnathan Mantey // Nothing to do, the activeSensors object is also empty 20249c53ac9SJohnathan Mantey return; 20349c53ac9SJohnathan Mantey } 20449c53ac9SJohnathan Mantey 20549c53ac9SJohnathan Mantey for (const char* type : SensorsAsyncResp->types) 20649c53ac9SJohnathan Mantey { 20749c53ac9SJohnathan Mantey for (const std::string& sensor : *allSensors) 20849c53ac9SJohnathan Mantey { 20949c53ac9SJohnathan Mantey if (boost::starts_with(sensor, type)) 21049c53ac9SJohnathan Mantey { 21149c53ac9SJohnathan Mantey activeSensors->emplace(sensor); 21249c53ac9SJohnathan Mantey } 21349c53ac9SJohnathan Mantey } 21449c53ac9SJohnathan Mantey } 21549c53ac9SJohnathan Mantey } 21649c53ac9SJohnathan Mantey 21749c53ac9SJohnathan Mantey /** 21808777fb0SLewanczyk, Dawid * @brief Retrieves requested chassis sensors and redundancy data from DBus . 219588c3f0dSKowalski, Kamil * @param SensorsAsyncResp Pointer to object holding response data 22008777fb0SLewanczyk, Dawid * @param callback Callback for next step in gathered sensor processing 22108777fb0SLewanczyk, Dawid */ 22208777fb0SLewanczyk, Dawid template <typename Callback> 22349c53ac9SJohnathan Mantey void getChassis(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 2241abe55efSEd Tanous Callback&& callback) 2251abe55efSEd Tanous { 22655c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassis enter"; 22749c53ac9SJohnathan Mantey const std::array<const char*, 3> interfaces = { 22849c53ac9SJohnathan Mantey "xyz.openbmc_project.Inventory.Item.Board", 22949c53ac9SJohnathan Mantey "xyz.openbmc_project.Inventory.Item.Chassis", 23049c53ac9SJohnathan Mantey "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 23149c53ac9SJohnathan Mantey auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp]( 23249c53ac9SJohnathan Mantey const boost::system::error_code ec, 23349c53ac9SJohnathan Mantey const std::vector<std::string>& chassisPaths) { 23455c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassis respHandler enter"; 2351abe55efSEd Tanous if (ec) 2361abe55efSEd Tanous { 23755c7b7a2SEd Tanous BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec; 23849c53ac9SJohnathan Mantey messages::internalError(sensorsAsyncResp->res); 23908777fb0SLewanczyk, Dawid return; 24008777fb0SLewanczyk, Dawid } 24108777fb0SLewanczyk, Dawid 24249c53ac9SJohnathan Mantey const std::string* chassisPath = nullptr; 24349c53ac9SJohnathan Mantey std::string chassisName; 24449c53ac9SJohnathan Mantey for (const std::string& chassis : chassisPaths) 2451abe55efSEd Tanous { 24649c53ac9SJohnathan Mantey std::size_t lastPos = chassis.rfind("/"); 24749c53ac9SJohnathan Mantey if (lastPos == std::string::npos) 2481abe55efSEd Tanous { 24949c53ac9SJohnathan Mantey BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis; 250daf36e2eSEd Tanous continue; 251daf36e2eSEd Tanous } 25249c53ac9SJohnathan Mantey chassisName = chassis.substr(lastPos + 1); 25349c53ac9SJohnathan Mantey if (chassisName == sensorsAsyncResp->chassisId) 2541abe55efSEd Tanous { 25549c53ac9SJohnathan Mantey chassisPath = &chassis; 25649c53ac9SJohnathan Mantey break; 257daf36e2eSEd Tanous } 25849c53ac9SJohnathan Mantey } 25949c53ac9SJohnathan Mantey if (chassisPath == nullptr) 2601abe55efSEd Tanous { 26149c53ac9SJohnathan Mantey messages::resourceNotFound(sensorsAsyncResp->res, "Chassis", 26249c53ac9SJohnathan Mantey sensorsAsyncResp->chassisId); 26349c53ac9SJohnathan Mantey return; 2641abe55efSEd Tanous } 26508777fb0SLewanczyk, Dawid 26649c53ac9SJohnathan Mantey const std::string& chassisSubNode = sensorsAsyncResp->chassisSubNode; 26749c53ac9SJohnathan Mantey if (chassisSubNode == "Power") 26849c53ac9SJohnathan Mantey { 26949c53ac9SJohnathan Mantey sensorsAsyncResp->res.jsonValue["@odata.type"] = 27049c53ac9SJohnathan Mantey "#Power.v1_5_2.Power"; 27149c53ac9SJohnathan Mantey } 27249c53ac9SJohnathan Mantey else if (chassisSubNode == "Thermal") 27349c53ac9SJohnathan Mantey { 27449c53ac9SJohnathan Mantey sensorsAsyncResp->res.jsonValue["@odata.type"] = 27549c53ac9SJohnathan Mantey "#Thermal.v1_4_0.Thermal"; 2764f9a2130SJennifer Lee sensorsAsyncResp->res.jsonValue["Fans"] = nlohmann::json::array(); 2774f9a2130SJennifer Lee sensorsAsyncResp->res.jsonValue["Temperatures"] = 2784f9a2130SJennifer Lee nlohmann::json::array(); 27949c53ac9SJohnathan Mantey } 28049c53ac9SJohnathan Mantey sensorsAsyncResp->res.jsonValue["@odata.id"] = 28149c53ac9SJohnathan Mantey "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId + "/" + 28249c53ac9SJohnathan Mantey chassisSubNode; 28349c53ac9SJohnathan Mantey 28449c53ac9SJohnathan Mantey sensorsAsyncResp->res.jsonValue["@odata.context"] = 28549c53ac9SJohnathan Mantey "/redfish/v1/$metadata#" + chassisSubNode + "." + chassisSubNode; 28649c53ac9SJohnathan Mantey sensorsAsyncResp->res.jsonValue["Id"] = chassisSubNode; 28749c53ac9SJohnathan Mantey sensorsAsyncResp->res.jsonValue["Name"] = chassisSubNode; 28849c53ac9SJohnathan Mantey 2898fb49dd6SShawn McCarney // Get the list of all sensors for this Chassis element 2908fb49dd6SShawn McCarney std::string sensorPath = *chassisPath + "/all_sensors"; 29155c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 29249c53ac9SJohnathan Mantey [sensorsAsyncResp, callback{std::move(callback)}]( 29349c53ac9SJohnathan Mantey const boost::system::error_code ec, 29449c53ac9SJohnathan Mantey const std::variant<std::vector<std::string>>& 29549c53ac9SJohnathan Mantey variantEndpoints) { 29649c53ac9SJohnathan Mantey if (ec) 29749c53ac9SJohnathan Mantey { 29849c53ac9SJohnathan Mantey if (ec.value() != EBADR) 29949c53ac9SJohnathan Mantey { 30049c53ac9SJohnathan Mantey messages::internalError(sensorsAsyncResp->res); 30149c53ac9SJohnathan Mantey return; 30249c53ac9SJohnathan Mantey } 30349c53ac9SJohnathan Mantey } 30449c53ac9SJohnathan Mantey const std::vector<std::string>* nodeSensorList = 30549c53ac9SJohnathan Mantey std::get_if<std::vector<std::string>>(&(variantEndpoints)); 30649c53ac9SJohnathan Mantey if (nodeSensorList == nullptr) 30749c53ac9SJohnathan Mantey { 30849c53ac9SJohnathan Mantey messages::resourceNotFound( 30949c53ac9SJohnathan Mantey sensorsAsyncResp->res, sensorsAsyncResp->chassisSubNode, 31049c53ac9SJohnathan Mantey sensorsAsyncResp->chassisSubNode == "Thermal" 31149c53ac9SJohnathan Mantey ? "Temperatures" 31249c53ac9SJohnathan Mantey : "Voltages"); 31349c53ac9SJohnathan Mantey return; 31449c53ac9SJohnathan Mantey } 31549c53ac9SJohnathan Mantey const std::shared_ptr<boost::container::flat_set<std::string>> 31649c53ac9SJohnathan Mantey culledSensorList = std::make_shared< 31749c53ac9SJohnathan Mantey boost::container::flat_set<std::string>>(); 31849c53ac9SJohnathan Mantey reduceSensorList(sensorsAsyncResp, nodeSensorList, 31949c53ac9SJohnathan Mantey culledSensorList); 32049c53ac9SJohnathan Mantey callback(culledSensorList); 32149c53ac9SJohnathan Mantey }, 32249c53ac9SJohnathan Mantey "xyz.openbmc_project.ObjectMapper", sensorPath, 32349c53ac9SJohnathan Mantey "org.freedesktop.DBus.Properties", "Get", 32449c53ac9SJohnathan Mantey "xyz.openbmc_project.Association", "endpoints"); 32549c53ac9SJohnathan Mantey }; 32649c53ac9SJohnathan Mantey 32749c53ac9SJohnathan Mantey // Get the Chassis Collection 32849c53ac9SJohnathan Mantey crow::connections::systemBus->async_method_call( 32949c53ac9SJohnathan Mantey respHandler, "xyz.openbmc_project.ObjectMapper", 33049c53ac9SJohnathan Mantey "/xyz/openbmc_project/object_mapper", 33149c53ac9SJohnathan Mantey "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 33249c53ac9SJohnathan Mantey "/xyz/openbmc_project/inventory", int32_t(0), interfaces); 33355c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassis exit"; 33408777fb0SLewanczyk, Dawid } 33508777fb0SLewanczyk, Dawid 33608777fb0SLewanczyk, Dawid /** 337de629b6eSShawn McCarney * @brief Finds all DBus object paths that implement ObjectManager. 338de629b6eSShawn McCarney * 339de629b6eSShawn McCarney * Creates a mapping from the associated connection name to the object path. 340de629b6eSShawn McCarney * 341de629b6eSShawn McCarney * Finds the object paths asynchronously. Invokes callback when information has 342de629b6eSShawn McCarney * been obtained. 343de629b6eSShawn McCarney * 344de629b6eSShawn McCarney * The callback must have the following signature: 345de629b6eSShawn McCarney * @code 3468fb49dd6SShawn McCarney * callback(std::shared_ptr<boost::container::flat_map<std::string, 3478fb49dd6SShawn McCarney * std::string>> objectMgrPaths) 348de629b6eSShawn McCarney * @endcode 349de629b6eSShawn McCarney * 35049c53ac9SJohnathan Mantey * @param sensorsAsyncResp Pointer to object holding response data. 351de629b6eSShawn McCarney * @param callback Callback to invoke when object paths obtained. 352de629b6eSShawn McCarney */ 353de629b6eSShawn McCarney template <typename Callback> 354de629b6eSShawn McCarney void getObjectManagerPaths(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp, 355de629b6eSShawn McCarney Callback&& callback) 356de629b6eSShawn McCarney { 357de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPaths enter"; 358de629b6eSShawn McCarney const std::array<std::string, 1> interfaces = { 359de629b6eSShawn McCarney "org.freedesktop.DBus.ObjectManager"}; 360de629b6eSShawn McCarney 361de629b6eSShawn McCarney // Response handler for GetSubTree DBus method 362de629b6eSShawn McCarney auto respHandler = [callback{std::move(callback)}, 363de629b6eSShawn McCarney SensorsAsyncResp](const boost::system::error_code ec, 364de629b6eSShawn McCarney const GetSubTreeType& subtree) { 365de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler enter"; 366de629b6eSShawn McCarney if (ec) 367de629b6eSShawn McCarney { 368de629b6eSShawn McCarney messages::internalError(SensorsAsyncResp->res); 369de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "getObjectManagerPaths respHandler: DBus error " 370de629b6eSShawn McCarney << ec; 371de629b6eSShawn McCarney return; 372de629b6eSShawn McCarney } 373de629b6eSShawn McCarney 374de629b6eSShawn McCarney // Loop over returned object paths 3758fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 3768fb49dd6SShawn McCarney objectMgrPaths = std::make_shared< 3778fb49dd6SShawn McCarney boost::container::flat_map<std::string, std::string>>(); 378de629b6eSShawn McCarney for (const std::pair< 379de629b6eSShawn McCarney std::string, 380de629b6eSShawn McCarney std::vector<std::pair<std::string, std::vector<std::string>>>>& 381de629b6eSShawn McCarney object : subtree) 382de629b6eSShawn McCarney { 383de629b6eSShawn McCarney // Loop over connections for current object path 384de629b6eSShawn McCarney const std::string& objectPath = object.first; 385de629b6eSShawn McCarney for (const std::pair<std::string, std::vector<std::string>>& 386de629b6eSShawn McCarney objData : object.second) 387de629b6eSShawn McCarney { 388de629b6eSShawn McCarney // Add mapping from connection to object path 389de629b6eSShawn McCarney const std::string& connection = objData.first; 3908fb49dd6SShawn McCarney (*objectMgrPaths)[connection] = objectPath; 391de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "Added mapping " << connection << " -> " 392de629b6eSShawn McCarney << objectPath; 393de629b6eSShawn McCarney } 394de629b6eSShawn McCarney } 3958fb49dd6SShawn McCarney callback(objectMgrPaths); 396de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler exit"; 397de629b6eSShawn McCarney }; 398de629b6eSShawn McCarney 399de629b6eSShawn McCarney // Query mapper for all DBus object paths that implement ObjectManager 400de629b6eSShawn McCarney crow::connections::systemBus->async_method_call( 401de629b6eSShawn McCarney std::move(respHandler), "xyz.openbmc_project.ObjectMapper", 402de629b6eSShawn McCarney "/xyz/openbmc_project/object_mapper", 403de629b6eSShawn McCarney "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 404de629b6eSShawn McCarney interfaces); 405de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit"; 406de629b6eSShawn McCarney } 407de629b6eSShawn McCarney 408de629b6eSShawn McCarney /** 40934dd179eSJames Feist * @brief Retrieves the health from a sensor . 41034dd179eSJames Feist * @param interfacesDict Map of all sensor interfaces 41134dd179eSJames Feist */ 41234dd179eSJames Feist 41334dd179eSJames Feist static std::string getHealth( 41434dd179eSJames Feist const boost::container::flat_map< 41534dd179eSJames Feist std::string, boost::container::flat_map<std::string, SensorVariant>>& 41634dd179eSJames Feist interfacesDict) 41734dd179eSJames Feist { 41834dd179eSJames Feist auto criticalThresholdIt = 41934dd179eSJames Feist interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Critical"); 42034dd179eSJames Feist if (criticalThresholdIt != interfacesDict.end()) 42134dd179eSJames Feist { 42234dd179eSJames Feist auto thresholdHighIt = 42334dd179eSJames Feist criticalThresholdIt->second.find("CriticalAlarmHigh"); 42434dd179eSJames Feist auto thresholdLowIt = 42534dd179eSJames Feist criticalThresholdIt->second.find("CriticalAlarmLow"); 42634dd179eSJames Feist if (thresholdHighIt != criticalThresholdIt->second.end()) 42734dd179eSJames Feist { 42834dd179eSJames Feist const bool* asserted = std::get_if<bool>(&thresholdHighIt->second); 42934dd179eSJames Feist if (asserted == nullptr) 43034dd179eSJames Feist { 43134dd179eSJames Feist BMCWEB_LOG_ERROR << "Illegal sensor threshold"; 43234dd179eSJames Feist } 43334dd179eSJames Feist else if (*asserted) 43434dd179eSJames Feist { 43534dd179eSJames Feist return "Critical"; 43634dd179eSJames Feist } 43734dd179eSJames Feist } 43834dd179eSJames Feist if (thresholdLowIt != criticalThresholdIt->second.end()) 43934dd179eSJames Feist { 44034dd179eSJames Feist const bool* asserted = std::get_if<bool>(&thresholdLowIt->second); 44134dd179eSJames Feist if (asserted == nullptr) 44234dd179eSJames Feist { 44334dd179eSJames Feist BMCWEB_LOG_ERROR << "Illegal sensor threshold"; 44434dd179eSJames Feist } 44534dd179eSJames Feist else if (*asserted) 44634dd179eSJames Feist { 44734dd179eSJames Feist return "Critical"; 44834dd179eSJames Feist } 44934dd179eSJames Feist } 45034dd179eSJames Feist } 45134dd179eSJames Feist 45234dd179eSJames Feist auto warningThresholdIt = 45334dd179eSJames Feist interfacesDict.find("xyz.openbmc_project.Sensor.Threshold.Warning"); 45434dd179eSJames Feist if (warningThresholdIt != interfacesDict.end()) 45534dd179eSJames Feist { 45634dd179eSJames Feist auto thresholdHighIt = 45734dd179eSJames Feist warningThresholdIt->second.find("WarningAlarmHigh"); 45834dd179eSJames Feist auto thresholdLowIt = 45934dd179eSJames Feist warningThresholdIt->second.find("WarningAlarmLow"); 46034dd179eSJames Feist if (thresholdHighIt != warningThresholdIt->second.end()) 46134dd179eSJames Feist { 46234dd179eSJames Feist const bool* asserted = std::get_if<bool>(&thresholdHighIt->second); 46334dd179eSJames Feist if (asserted == nullptr) 46434dd179eSJames Feist { 46534dd179eSJames Feist BMCWEB_LOG_ERROR << "Illegal sensor threshold"; 46634dd179eSJames Feist } 46734dd179eSJames Feist else if (*asserted) 46834dd179eSJames Feist { 46934dd179eSJames Feist return "Warning"; 47034dd179eSJames Feist } 47134dd179eSJames Feist } 47234dd179eSJames Feist if (thresholdLowIt != warningThresholdIt->second.end()) 47334dd179eSJames Feist { 47434dd179eSJames Feist const bool* asserted = std::get_if<bool>(&thresholdLowIt->second); 47534dd179eSJames Feist if (asserted == nullptr) 47634dd179eSJames Feist { 47734dd179eSJames Feist BMCWEB_LOG_ERROR << "Illegal sensor threshold"; 47834dd179eSJames Feist } 47934dd179eSJames Feist else if (*asserted) 48034dd179eSJames Feist { 48134dd179eSJames Feist return "Warning"; 48234dd179eSJames Feist } 48334dd179eSJames Feist } 48434dd179eSJames Feist } 48534dd179eSJames Feist return "OK"; 48634dd179eSJames Feist } 48734dd179eSJames Feist 48834dd179eSJames Feist /** 48908777fb0SLewanczyk, Dawid * @brief Builds a json sensor representation of a sensor. 49008777fb0SLewanczyk, Dawid * @param sensorName The name of the sensor to be built 491274fad5aSGunnar Mills * @param sensorType The type (temperature, fan_tach, etc) of the sensor to 49208777fb0SLewanczyk, Dawid * build 49308777fb0SLewanczyk, Dawid * @param interfacesDict A dictionary of the interfaces and properties of said 49408777fb0SLewanczyk, Dawid * interfaces to be built from 49508777fb0SLewanczyk, Dawid * @param sensor_json The json object to fill 49608777fb0SLewanczyk, Dawid */ 49708777fb0SLewanczyk, Dawid void objectInterfacesToJson( 49808777fb0SLewanczyk, Dawid const std::string& sensorName, const std::string& sensorType, 49908777fb0SLewanczyk, Dawid const boost::container::flat_map< 500aa2e59c1SEd Tanous std::string, boost::container::flat_map<std::string, SensorVariant>>& 50108777fb0SLewanczyk, Dawid interfacesDict, 5021abe55efSEd Tanous nlohmann::json& sensor_json) 5031abe55efSEd Tanous { 50408777fb0SLewanczyk, Dawid // We need a value interface before we can do anything with it 50555c7b7a2SEd Tanous auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value"); 5061abe55efSEd Tanous if (valueIt == interfacesDict.end()) 5071abe55efSEd Tanous { 50855c7b7a2SEd Tanous BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface"; 50908777fb0SLewanczyk, Dawid return; 51008777fb0SLewanczyk, Dawid } 51108777fb0SLewanczyk, Dawid 51208777fb0SLewanczyk, Dawid // Assume values exist as is (10^0 == 1) if no scale exists 51308777fb0SLewanczyk, Dawid int64_t scaleMultiplier = 0; 51408777fb0SLewanczyk, Dawid 51555c7b7a2SEd Tanous auto scaleIt = valueIt->second.find("Scale"); 51608777fb0SLewanczyk, Dawid // If a scale exists, pull value as int64, and use the scaling. 5171abe55efSEd Tanous if (scaleIt != valueIt->second.end()) 5181abe55efSEd Tanous { 519abf2add6SEd Tanous const int64_t* int64Value = std::get_if<int64_t>(&scaleIt->second); 5201abe55efSEd Tanous if (int64Value != nullptr) 5211abe55efSEd Tanous { 52208777fb0SLewanczyk, Dawid scaleMultiplier = *int64Value; 52308777fb0SLewanczyk, Dawid } 52408777fb0SLewanczyk, Dawid } 52508777fb0SLewanczyk, Dawid 52608777fb0SLewanczyk, Dawid sensor_json["MemberId"] = sensorName; 527e742b6ccSEd Tanous sensor_json["Name"] = boost::replace_all_copy(sensorName, "_", " "); 528e742b6ccSEd Tanous 52908777fb0SLewanczyk, Dawid sensor_json["Status"]["State"] = "Enabled"; 53034dd179eSJames Feist sensor_json["Status"]["Health"] = getHealth(interfacesDict); 53108777fb0SLewanczyk, Dawid 53208777fb0SLewanczyk, Dawid // Parameter to set to override the type we get from dbus, and force it to 53308777fb0SLewanczyk, Dawid // int, regardless of what is available. This is used for schemas like fan, 53408777fb0SLewanczyk, Dawid // that require integers, not floats. 53508777fb0SLewanczyk, Dawid bool forceToInt = false; 53608777fb0SLewanczyk, Dawid 53708777fb0SLewanczyk, Dawid const char* unit = "Reading"; 5381abe55efSEd Tanous if (sensorType == "temperature") 5391abe55efSEd Tanous { 54008777fb0SLewanczyk, Dawid unit = "ReadingCelsius"; 5417885954aSLewanczyk, Dawid sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature"; 54208777fb0SLewanczyk, Dawid // TODO(ed) Documentation says that path should be type fan_tach, 54308777fb0SLewanczyk, Dawid // implementation seems to implement fan 5441abe55efSEd Tanous } 5451abe55efSEd Tanous else if (sensorType == "fan" || sensorType == "fan_tach") 5461abe55efSEd Tanous { 54708777fb0SLewanczyk, Dawid unit = "Reading"; 54808777fb0SLewanczyk, Dawid sensor_json["ReadingUnits"] = "RPM"; 5497885954aSLewanczyk, Dawid sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan"; 55008777fb0SLewanczyk, Dawid forceToInt = true; 5511abe55efSEd Tanous } 5526f6d0d32SEd Tanous else if (sensorType == "fan_pwm") 5536f6d0d32SEd Tanous { 5546f6d0d32SEd Tanous unit = "Reading"; 5556f6d0d32SEd Tanous sensor_json["ReadingUnits"] = "Percent"; 5566f6d0d32SEd Tanous sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan"; 5576f6d0d32SEd Tanous forceToInt = true; 5586f6d0d32SEd Tanous } 5591abe55efSEd Tanous else if (sensorType == "voltage") 5601abe55efSEd Tanous { 56108777fb0SLewanczyk, Dawid unit = "ReadingVolts"; 5627885954aSLewanczyk, Dawid sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage"; 5631abe55efSEd Tanous } 5642474adfaSEd Tanous else if (sensorType == "power") 5652474adfaSEd Tanous { 56649c53ac9SJohnathan Mantey std::string sensorNameLower = 56749c53ac9SJohnathan Mantey boost::algorithm::to_lower_copy(sensorName); 56849c53ac9SJohnathan Mantey 569028f7ebcSEddie James if (!sensorName.compare("total_power")) 570028f7ebcSEddie James { 571*7ab06f49SGunnar Mills sensor_json["@odata.type"] = "#Power.v1_0_0.PowerControl"; 572*7ab06f49SGunnar Mills // Put multiple "sensors" into a single PowerControl, so have 573*7ab06f49SGunnar Mills // generic names for MemberId and Name. Follows Redfish mockup. 574*7ab06f49SGunnar Mills sensor_json["MemberId"] = "0"; 575*7ab06f49SGunnar Mills sensor_json["Name"] = "Chassis Power Control"; 576028f7ebcSEddie James unit = "PowerConsumedWatts"; 577028f7ebcSEddie James } 578028f7ebcSEddie James else if (sensorNameLower.find("input") != std::string::npos) 57949c53ac9SJohnathan Mantey { 58049c53ac9SJohnathan Mantey unit = "PowerInputWatts"; 58149c53ac9SJohnathan Mantey } 58249c53ac9SJohnathan Mantey else 58349c53ac9SJohnathan Mantey { 58449c53ac9SJohnathan Mantey unit = "PowerOutputWatts"; 58549c53ac9SJohnathan Mantey } 5862474adfaSEd Tanous } 5871abe55efSEd Tanous else 5881abe55efSEd Tanous { 58955c7b7a2SEd Tanous BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName; 59008777fb0SLewanczyk, Dawid return; 59108777fb0SLewanczyk, Dawid } 59208777fb0SLewanczyk, Dawid // Map of dbus interface name, dbus property name and redfish property_name 59308777fb0SLewanczyk, Dawid std::vector<std::tuple<const char*, const char*, const char*>> properties; 59408777fb0SLewanczyk, Dawid properties.reserve(7); 59508777fb0SLewanczyk, Dawid 59608777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit); 597de629b6eSShawn McCarney 598de629b6eSShawn McCarney // If sensor type doesn't map to Redfish PowerSupply, add threshold props 599de629b6eSShawn McCarney if ((sensorType != "current") && (sensorType != "power")) 600de629b6eSShawn McCarney { 60108777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning", 60208777fb0SLewanczyk, Dawid "WarningHigh", "UpperThresholdNonCritical"); 60308777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning", 60408777fb0SLewanczyk, Dawid "WarningLow", "LowerThresholdNonCritical"); 60508777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical", 60608777fb0SLewanczyk, Dawid "CriticalHigh", "UpperThresholdCritical"); 60708777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical", 60808777fb0SLewanczyk, Dawid "CriticalLow", "LowerThresholdCritical"); 609de629b6eSShawn McCarney } 61008777fb0SLewanczyk, Dawid 6112474adfaSEd Tanous // TODO Need to get UpperThresholdFatal and LowerThresholdFatal 6122474adfaSEd Tanous 6131abe55efSEd Tanous if (sensorType == "temperature") 6141abe55efSEd Tanous { 61508777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue", 61608777fb0SLewanczyk, Dawid "MinReadingRangeTemp"); 61708777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue", 61808777fb0SLewanczyk, Dawid "MaxReadingRangeTemp"); 6191abe55efSEd Tanous } 620de629b6eSShawn McCarney else if ((sensorType != "current") && (sensorType != "power")) 6211abe55efSEd Tanous { 622de629b6eSShawn McCarney // Sensor type doesn't map to Redfish PowerSupply; add min/max props 62308777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue", 62408777fb0SLewanczyk, Dawid "MinReadingRange"); 62508777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue", 62608777fb0SLewanczyk, Dawid "MaxReadingRange"); 62708777fb0SLewanczyk, Dawid } 62808777fb0SLewanczyk, Dawid 62908777fb0SLewanczyk, Dawid for (const std::tuple<const char*, const char*, const char*>& p : 6301abe55efSEd Tanous properties) 6311abe55efSEd Tanous { 63208777fb0SLewanczyk, Dawid auto interfaceProperties = interfacesDict.find(std::get<0>(p)); 6331abe55efSEd Tanous if (interfaceProperties != interfacesDict.end()) 6341abe55efSEd Tanous { 635b01bf299SEd Tanous auto valueIt = interfaceProperties->second.find(std::get<1>(p)); 636b01bf299SEd Tanous if (valueIt != interfaceProperties->second.end()) 6371abe55efSEd Tanous { 638b01bf299SEd Tanous const SensorVariant& valueVariant = valueIt->second; 639b01bf299SEd Tanous nlohmann::json& valueIt = sensor_json[std::get<2>(p)]; 64008777fb0SLewanczyk, Dawid // Attempt to pull the int64 directly 641abf2add6SEd Tanous const int64_t* int64Value = std::get_if<int64_t>(&valueVariant); 64208777fb0SLewanczyk, Dawid 643abf2add6SEd Tanous const double* doubleValue = std::get_if<double>(&valueVariant); 644028f7ebcSEddie James const uint32_t* uValue = std::get_if<uint32_t>(&valueVariant); 6456f6d0d32SEd Tanous double temp = 0.0; 6466f6d0d32SEd Tanous if (int64Value != nullptr) 6471abe55efSEd Tanous { 6486f6d0d32SEd Tanous temp = *int64Value; 6496f6d0d32SEd Tanous } 6506f6d0d32SEd Tanous else if (doubleValue != nullptr) 6511abe55efSEd Tanous { 6526f6d0d32SEd Tanous temp = *doubleValue; 6531abe55efSEd Tanous } 654028f7ebcSEddie James else if (uValue != nullptr) 655028f7ebcSEddie James { 656028f7ebcSEddie James temp = *uValue; 657028f7ebcSEddie James } 6581abe55efSEd Tanous else 6591abe55efSEd Tanous { 6606f6d0d32SEd Tanous BMCWEB_LOG_ERROR 6616f6d0d32SEd Tanous << "Got value interface that wasn't int or double"; 6626f6d0d32SEd Tanous continue; 66308777fb0SLewanczyk, Dawid } 6646f6d0d32SEd Tanous temp = temp * std::pow(10, scaleMultiplier); 6656f6d0d32SEd Tanous if (forceToInt) 6666f6d0d32SEd Tanous { 667b01bf299SEd Tanous valueIt = static_cast<int64_t>(temp); 6686f6d0d32SEd Tanous } 6696f6d0d32SEd Tanous else 6706f6d0d32SEd Tanous { 671b01bf299SEd Tanous valueIt = temp; 67208777fb0SLewanczyk, Dawid } 67308777fb0SLewanczyk, Dawid } 67408777fb0SLewanczyk, Dawid } 67508777fb0SLewanczyk, Dawid } 67655c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "Added sensor " << sensorName; 67708777fb0SLewanczyk, Dawid } 67808777fb0SLewanczyk, Dawid 6798bd25ccdSJames Feist static void 6808bd25ccdSJames Feist populateFanRedundancy(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp) 6818bd25ccdSJames Feist { 6828bd25ccdSJames Feist crow::connections::systemBus->async_method_call( 6838bd25ccdSJames Feist [sensorsAsyncResp](const boost::system::error_code ec, 6848bd25ccdSJames Feist const GetSubTreeType& resp) { 6858bd25ccdSJames Feist if (ec) 6868bd25ccdSJames Feist { 6878bd25ccdSJames Feist return; // don't have to have this interface 6888bd25ccdSJames Feist } 689e278c18fSEd Tanous for (const std::pair<std::string, 690e278c18fSEd Tanous std::vector<std::pair< 691e278c18fSEd Tanous std::string, std::vector<std::string>>>>& 692e278c18fSEd Tanous pathPair : resp) 6938bd25ccdSJames Feist { 694e278c18fSEd Tanous const std::string& path = pathPair.first; 695e278c18fSEd Tanous const std::vector< 696e278c18fSEd Tanous std::pair<std::string, std::vector<std::string>>>& objDict = 697e278c18fSEd Tanous pathPair.second; 6988bd25ccdSJames Feist if (objDict.empty()) 6998bd25ccdSJames Feist { 7008bd25ccdSJames Feist continue; // this should be impossible 7018bd25ccdSJames Feist } 7028bd25ccdSJames Feist 7038bd25ccdSJames Feist const std::string& owner = objDict.begin()->first; 7048bd25ccdSJames Feist crow::connections::systemBus->async_method_call( 7058bd25ccdSJames Feist [path, owner, 7068bd25ccdSJames Feist sensorsAsyncResp](const boost::system::error_code ec, 7078bd25ccdSJames Feist std::variant<std::vector<std::string>> 7088bd25ccdSJames Feist variantEndpoints) { 7098bd25ccdSJames Feist if (ec) 7108bd25ccdSJames Feist { 7118bd25ccdSJames Feist return; // if they don't have an association we 7128bd25ccdSJames Feist // can't tell what chassis is 7138bd25ccdSJames Feist } 7148bd25ccdSJames Feist // verify part of the right chassis 7158bd25ccdSJames Feist auto endpoints = std::get_if<std::vector<std::string>>( 7168bd25ccdSJames Feist &variantEndpoints); 7178bd25ccdSJames Feist 7188bd25ccdSJames Feist if (endpoints == nullptr) 7198bd25ccdSJames Feist { 7208bd25ccdSJames Feist BMCWEB_LOG_ERROR << "Invalid association interface"; 7218bd25ccdSJames Feist messages::internalError(sensorsAsyncResp->res); 7228bd25ccdSJames Feist return; 7238bd25ccdSJames Feist } 7248bd25ccdSJames Feist 7258bd25ccdSJames Feist auto found = std::find_if( 7268bd25ccdSJames Feist endpoints->begin(), endpoints->end(), 7278bd25ccdSJames Feist [sensorsAsyncResp](const std::string& entry) { 7288bd25ccdSJames Feist return entry.find( 7298bd25ccdSJames Feist sensorsAsyncResp->chassisId) != 7308bd25ccdSJames Feist std::string::npos; 7318bd25ccdSJames Feist }); 7328bd25ccdSJames Feist 7338bd25ccdSJames Feist if (found == endpoints->end()) 7348bd25ccdSJames Feist { 7358bd25ccdSJames Feist return; 7368bd25ccdSJames Feist } 7378bd25ccdSJames Feist crow::connections::systemBus->async_method_call( 7388bd25ccdSJames Feist [path, sensorsAsyncResp]( 7398bd25ccdSJames Feist const boost::system::error_code ec, 7408bd25ccdSJames Feist const boost::container::flat_map< 7418bd25ccdSJames Feist std::string, 7428bd25ccdSJames Feist std::variant<uint8_t, 7438bd25ccdSJames Feist std::vector<std::string>, 7448bd25ccdSJames Feist std::string>>& ret) { 7458bd25ccdSJames Feist if (ec) 7468bd25ccdSJames Feist { 7478bd25ccdSJames Feist return; // don't have to have this 7488bd25ccdSJames Feist // interface 7498bd25ccdSJames Feist } 7508bd25ccdSJames Feist auto findFailures = ret.find("AllowedFailures"); 7518bd25ccdSJames Feist auto findCollection = ret.find("Collection"); 7528bd25ccdSJames Feist auto findStatus = ret.find("Status"); 7538bd25ccdSJames Feist 7548bd25ccdSJames Feist if (findFailures == ret.end() || 7558bd25ccdSJames Feist findCollection == ret.end() || 7568bd25ccdSJames Feist findStatus == ret.end()) 7578bd25ccdSJames Feist { 7588bd25ccdSJames Feist BMCWEB_LOG_ERROR 7598bd25ccdSJames Feist << "Invalid redundancy interface"; 7608bd25ccdSJames Feist messages::internalError( 7618bd25ccdSJames Feist sensorsAsyncResp->res); 7628bd25ccdSJames Feist return; 7638bd25ccdSJames Feist } 7648bd25ccdSJames Feist 7658bd25ccdSJames Feist auto allowedFailures = std::get_if<uint8_t>( 7668bd25ccdSJames Feist &(findFailures->second)); 7678bd25ccdSJames Feist auto collection = 7688bd25ccdSJames Feist std::get_if<std::vector<std::string>>( 7698bd25ccdSJames Feist &(findCollection->second)); 7708bd25ccdSJames Feist auto status = std::get_if<std::string>( 7718bd25ccdSJames Feist &(findStatus->second)); 7728bd25ccdSJames Feist 7738bd25ccdSJames Feist if (allowedFailures == nullptr || 7748bd25ccdSJames Feist collection == nullptr || status == nullptr) 7758bd25ccdSJames Feist { 7768bd25ccdSJames Feist 7778bd25ccdSJames Feist BMCWEB_LOG_ERROR 7788bd25ccdSJames Feist << "Invalid redundancy interface " 7798bd25ccdSJames Feist "types"; 7808bd25ccdSJames Feist messages::internalError( 7818bd25ccdSJames Feist sensorsAsyncResp->res); 7828bd25ccdSJames Feist return; 7838bd25ccdSJames Feist } 7848bd25ccdSJames Feist size_t lastSlash = path.rfind("/"); 7858bd25ccdSJames Feist if (lastSlash == std::string::npos) 7868bd25ccdSJames Feist { 7878bd25ccdSJames Feist // this should be impossible 7888bd25ccdSJames Feist messages::internalError( 7898bd25ccdSJames Feist sensorsAsyncResp->res); 7908bd25ccdSJames Feist return; 7918bd25ccdSJames Feist } 7928bd25ccdSJames Feist std::string name = path.substr(lastSlash + 1); 7938bd25ccdSJames Feist std::replace(name.begin(), name.end(), '_', 7948bd25ccdSJames Feist ' '); 7958bd25ccdSJames Feist 7968bd25ccdSJames Feist std::string health; 7978bd25ccdSJames Feist 7988bd25ccdSJames Feist if (boost::ends_with(*status, "Full")) 7998bd25ccdSJames Feist { 8008bd25ccdSJames Feist health = "OK"; 8018bd25ccdSJames Feist } 8028bd25ccdSJames Feist else if (boost::ends_with(*status, "Degraded")) 8038bd25ccdSJames Feist { 8048bd25ccdSJames Feist health = "Warning"; 8058bd25ccdSJames Feist } 8068bd25ccdSJames Feist else 8078bd25ccdSJames Feist { 8088bd25ccdSJames Feist health = "Critical"; 8098bd25ccdSJames Feist } 8108bd25ccdSJames Feist std::vector<nlohmann::json> redfishCollection; 8118bd25ccdSJames Feist const auto& fanRedfish = 8128bd25ccdSJames Feist sensorsAsyncResp->res.jsonValue["Fans"]; 8138bd25ccdSJames Feist for (const std::string& item : *collection) 8148bd25ccdSJames Feist { 8158bd25ccdSJames Feist lastSlash = item.rfind("/"); 8168bd25ccdSJames Feist // make a copy as collection is const 8178bd25ccdSJames Feist std::string itemName = 8188bd25ccdSJames Feist item.substr(lastSlash + 1); 8198bd25ccdSJames Feist /* 8208bd25ccdSJames Feist todo(ed): merge patch that fixes the names 8218bd25ccdSJames Feist std::replace(itemName.begin(), 8228bd25ccdSJames Feist itemName.end(), '_', ' ');*/ 8238bd25ccdSJames Feist auto schemaItem = std::find_if( 8248bd25ccdSJames Feist fanRedfish.begin(), fanRedfish.end(), 8258bd25ccdSJames Feist [itemName](const nlohmann::json& fan) { 8268bd25ccdSJames Feist return fan["MemberId"] == itemName; 8278bd25ccdSJames Feist }); 8288bd25ccdSJames Feist if (schemaItem != fanRedfish.end()) 8298bd25ccdSJames Feist { 8308bd25ccdSJames Feist redfishCollection.push_back( 8318bd25ccdSJames Feist {{"@odata.id", 8328bd25ccdSJames Feist (*schemaItem)["@odata.id"]}}); 8338bd25ccdSJames Feist } 8348bd25ccdSJames Feist else 8358bd25ccdSJames Feist { 8368bd25ccdSJames Feist BMCWEB_LOG_ERROR 8378bd25ccdSJames Feist << "failed to find fan in schema"; 8388bd25ccdSJames Feist messages::internalError( 8398bd25ccdSJames Feist sensorsAsyncResp->res); 8408bd25ccdSJames Feist return; 8418bd25ccdSJames Feist } 8428bd25ccdSJames Feist } 8438bd25ccdSJames Feist 8448bd25ccdSJames Feist auto& resp = sensorsAsyncResp->res 8458bd25ccdSJames Feist .jsonValue["Redundancy"]; 8468bd25ccdSJames Feist resp.push_back( 8478bd25ccdSJames Feist {{"@odata.id", 8488bd25ccdSJames Feist "/refish/v1/Chassis/" + 8498bd25ccdSJames Feist sensorsAsyncResp->chassisId + "/" + 8508bd25ccdSJames Feist sensorsAsyncResp->chassisSubNode + 8518bd25ccdSJames Feist "#/Redundancy/" + 8528bd25ccdSJames Feist std::to_string(resp.size())}, 8538bd25ccdSJames Feist {"@odata.type", 8548bd25ccdSJames Feist "#Redundancy.v1_3_2.Redundancy"}, 8558bd25ccdSJames Feist {"MinNumNeeded", 8568bd25ccdSJames Feist collection->size() - *allowedFailures}, 8578bd25ccdSJames Feist {"MemberId", name}, 8588bd25ccdSJames Feist {"Mode", "N+m"}, 8598bd25ccdSJames Feist {"Name", name}, 8608bd25ccdSJames Feist {"RedundancySet", redfishCollection}, 8618bd25ccdSJames Feist {"Status", 8628bd25ccdSJames Feist {{"Health", health}, 8638bd25ccdSJames Feist {"State", "Enabled"}}}}); 8648bd25ccdSJames Feist }, 8658bd25ccdSJames Feist owner, path, "org.freedesktop.DBus.Properties", 8668bd25ccdSJames Feist "GetAll", 8678bd25ccdSJames Feist "xyz.openbmc_project.Control.FanRedundancy"); 8688bd25ccdSJames Feist }, 86902e92e32SJames Feist "xyz.openbmc_project.ObjectMapper", path + "/chassis", 8708bd25ccdSJames Feist "org.freedesktop.DBus.Properties", "Get", 8718bd25ccdSJames Feist "xyz.openbmc_project.Association", "endpoints"); 8728bd25ccdSJames Feist } 8738bd25ccdSJames Feist }, 8748bd25ccdSJames Feist "xyz.openbmc_project.ObjectMapper", 8758bd25ccdSJames Feist "/xyz/openbmc_project/object_mapper", 8768bd25ccdSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", 8778bd25ccdSJames Feist "/xyz/openbmc_project/control", 2, 8788bd25ccdSJames Feist std::array<const char*, 1>{ 8798bd25ccdSJames Feist "xyz.openbmc_project.Control.FanRedundancy"}); 8808bd25ccdSJames Feist } 8818bd25ccdSJames Feist 88249c53ac9SJohnathan Mantey void sortJSONResponse(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp) 88349c53ac9SJohnathan Mantey { 88449c53ac9SJohnathan Mantey nlohmann::json& response = SensorsAsyncResp->res.jsonValue; 88549c53ac9SJohnathan Mantey std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"}; 88649c53ac9SJohnathan Mantey if (SensorsAsyncResp->chassisSubNode == "Power") 88749c53ac9SJohnathan Mantey { 88849c53ac9SJohnathan Mantey sensorHeaders = {"Voltages", "PowerSupplies"}; 88949c53ac9SJohnathan Mantey } 89049c53ac9SJohnathan Mantey for (const std::string& sensorGroup : sensorHeaders) 89149c53ac9SJohnathan Mantey { 89249c53ac9SJohnathan Mantey nlohmann::json::iterator entry = response.find(sensorGroup); 89349c53ac9SJohnathan Mantey if (entry != response.end()) 89449c53ac9SJohnathan Mantey { 89549c53ac9SJohnathan Mantey std::sort(entry->begin(), entry->end(), 89649c53ac9SJohnathan Mantey [](nlohmann::json& c1, nlohmann::json& c2) { 89749c53ac9SJohnathan Mantey return c1["Name"] < c2["Name"]; 89849c53ac9SJohnathan Mantey }); 89949c53ac9SJohnathan Mantey 90049c53ac9SJohnathan Mantey // add the index counts to the end of each entry 90149c53ac9SJohnathan Mantey size_t count = 0; 90249c53ac9SJohnathan Mantey for (nlohmann::json& sensorJson : *entry) 90349c53ac9SJohnathan Mantey { 90449c53ac9SJohnathan Mantey nlohmann::json::iterator odata = sensorJson.find("@odata.id"); 90549c53ac9SJohnathan Mantey if (odata == sensorJson.end()) 90649c53ac9SJohnathan Mantey { 90749c53ac9SJohnathan Mantey continue; 90849c53ac9SJohnathan Mantey } 90949c53ac9SJohnathan Mantey std::string* value = odata->get_ptr<std::string*>(); 91049c53ac9SJohnathan Mantey if (value != nullptr) 91149c53ac9SJohnathan Mantey { 91249c53ac9SJohnathan Mantey *value += std::to_string(count); 91349c53ac9SJohnathan Mantey count++; 91449c53ac9SJohnathan Mantey } 91549c53ac9SJohnathan Mantey } 91649c53ac9SJohnathan Mantey } 91749c53ac9SJohnathan Mantey } 91849c53ac9SJohnathan Mantey } 91949c53ac9SJohnathan Mantey 92008777fb0SLewanczyk, Dawid /** 9218fb49dd6SShawn McCarney * @brief Finds the JSON object for the specified sensor. 9228fb49dd6SShawn McCarney * 9238fb49dd6SShawn McCarney * Searches the JSON response in sensorsAsyncResp for an object corresponding to 9248fb49dd6SShawn McCarney * the specified sensor. 9258fb49dd6SShawn McCarney * 9268fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 9278fb49dd6SShawn McCarney * @param sensorName DBus object path to the sensor. 9288fb49dd6SShawn McCarney * @return Pointer to JSON object, or nullptr if object not found. 9298fb49dd6SShawn McCarney */ 9308fb49dd6SShawn McCarney static nlohmann::json* 9318fb49dd6SShawn McCarney findSensorJson(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 9328fb49dd6SShawn McCarney const std::string& sensorName) 9338fb49dd6SShawn McCarney { 9348fb49dd6SShawn McCarney // Get base name of sensor 9358fb49dd6SShawn McCarney std::size_t lastSlash = sensorName.rfind('/'); 9368fb49dd6SShawn McCarney if (lastSlash != std::string::npos) 9378fb49dd6SShawn McCarney { 9388fb49dd6SShawn McCarney std::string baseSensorName = sensorName.substr(lastSlash + 1); 9398fb49dd6SShawn McCarney 9408fb49dd6SShawn McCarney // Loop through JSON sensor groups that could contain sensor 9418fb49dd6SShawn McCarney nlohmann::json& response = sensorsAsyncResp->res.jsonValue; 9428fb49dd6SShawn McCarney std::array<std::string, 4> sensorGroups{"Temperatures", "Fans", 9438fb49dd6SShawn McCarney "Voltages", "PowerSupplies"}; 9448fb49dd6SShawn McCarney for (const std::string& sensorGroup : sensorGroups) 9458fb49dd6SShawn McCarney { 9468fb49dd6SShawn McCarney nlohmann::json::iterator groupIt = response.find(sensorGroup); 9478fb49dd6SShawn McCarney if (groupIt != response.end()) 9488fb49dd6SShawn McCarney { 9498fb49dd6SShawn McCarney // Loop through sensors in current group 9508fb49dd6SShawn McCarney for (nlohmann::json& sensorJson : *groupIt) 9518fb49dd6SShawn McCarney { 9528fb49dd6SShawn McCarney // Check if this is the sensor we are looking for 9538fb49dd6SShawn McCarney nlohmann::json::iterator memberIdIt = 9548fb49dd6SShawn McCarney sensorJson.find("MemberId"); 9558fb49dd6SShawn McCarney if (memberIdIt != sensorJson.end()) 9568fb49dd6SShawn McCarney { 9578fb49dd6SShawn McCarney std::string* memberId = 9588fb49dd6SShawn McCarney memberIdIt->get_ptr<std::string*>(); 9598fb49dd6SShawn McCarney if ((memberId != nullptr) && 9608fb49dd6SShawn McCarney (*memberId == baseSensorName)) 9618fb49dd6SShawn McCarney { 9628fb49dd6SShawn McCarney return &sensorJson; 9638fb49dd6SShawn McCarney } 9648fb49dd6SShawn McCarney } 9658fb49dd6SShawn McCarney } 9668fb49dd6SShawn McCarney } 9678fb49dd6SShawn McCarney } 9688fb49dd6SShawn McCarney } 9698fb49dd6SShawn McCarney 9708fb49dd6SShawn McCarney // Unable to find JSON object for specified sensor 9718fb49dd6SShawn McCarney return nullptr; 9728fb49dd6SShawn McCarney } 9738fb49dd6SShawn McCarney 9748fb49dd6SShawn McCarney /** 9758fb49dd6SShawn McCarney * @brief Updates sensor status in JSON response based on inventory item status. 9768fb49dd6SShawn McCarney * 9778fb49dd6SShawn McCarney * Updates the status of the specified sensor based on the status of a related 9788fb49dd6SShawn McCarney * inventory item. 9798fb49dd6SShawn McCarney * 9808fb49dd6SShawn McCarney * Modifies the Redfish Status property in the JSON response if the inventory 9818fb49dd6SShawn McCarney * item indicates the hardware is not present or not functional. 9828fb49dd6SShawn McCarney * 9838fb49dd6SShawn McCarney * The D-Bus Present and Functional properties are typically on the inventory 9848fb49dd6SShawn McCarney * item rather than the sensor. 9858fb49dd6SShawn McCarney * 9868fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 9878fb49dd6SShawn McCarney * @param sensorName DBus object path to the sensor. 9888fb49dd6SShawn McCarney * @param interfacesDict Map containing the interfaces and properties of the 9898fb49dd6SShawn McCarney * inventory item associated with this sensor. 9908fb49dd6SShawn McCarney */ 9918fb49dd6SShawn McCarney static void updateSensorStatus( 9928fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 9938fb49dd6SShawn McCarney const std::string& sensorName, 9948fb49dd6SShawn McCarney const boost::container::flat_map< 9958fb49dd6SShawn McCarney std::string, boost::container::flat_map<std::string, SensorVariant>>& 9968fb49dd6SShawn McCarney interfacesDict) 9978fb49dd6SShawn McCarney { 9988fb49dd6SShawn McCarney // Find the JSON object in the response for this sensor 9998fb49dd6SShawn McCarney nlohmann::json* sensorJson = findSensorJson(sensorsAsyncResp, sensorName); 10008fb49dd6SShawn McCarney if (sensorJson != nullptr) 10018fb49dd6SShawn McCarney { 10028fb49dd6SShawn McCarney // Get Inventory.Item.Present property of inventory item 10038fb49dd6SShawn McCarney auto itemIt = interfacesDict.find("xyz.openbmc_project.Inventory.Item"); 10048fb49dd6SShawn McCarney if (itemIt != interfacesDict.end()) 10058fb49dd6SShawn McCarney { 10068fb49dd6SShawn McCarney auto presentIt = itemIt->second.find("Present"); 10078fb49dd6SShawn McCarney if (presentIt != itemIt->second.end()) 10088fb49dd6SShawn McCarney { 10098fb49dd6SShawn McCarney const bool* present = std::get_if<bool>(&presentIt->second); 10108fb49dd6SShawn McCarney if ((present != nullptr) && (*present == false)) 10118fb49dd6SShawn McCarney { 10128fb49dd6SShawn McCarney // Inventory item is not present; update sensor State 10138fb49dd6SShawn McCarney (*sensorJson)["Status"]["State"] = "Absent"; 10148fb49dd6SShawn McCarney } 10158fb49dd6SShawn McCarney } 10168fb49dd6SShawn McCarney } 10178fb49dd6SShawn McCarney 10188fb49dd6SShawn McCarney // Get OperationalStatus.Functional property of inventory item 10198fb49dd6SShawn McCarney auto opStatusIt = interfacesDict.find( 10208fb49dd6SShawn McCarney "xyz.openbmc_project.State.Decorator.OperationalStatus"); 10218fb49dd6SShawn McCarney if (opStatusIt != interfacesDict.end()) 10228fb49dd6SShawn McCarney { 10238fb49dd6SShawn McCarney auto functionalIt = opStatusIt->second.find("Functional"); 10248fb49dd6SShawn McCarney if (functionalIt != opStatusIt->second.end()) 10258fb49dd6SShawn McCarney { 10268fb49dd6SShawn McCarney const bool* functional = 10278fb49dd6SShawn McCarney std::get_if<bool>(&functionalIt->second); 10288fb49dd6SShawn McCarney if ((functional != nullptr) && (*functional == false)) 10298fb49dd6SShawn McCarney { 10308fb49dd6SShawn McCarney // Inventory item is not functional; update sensor Health 10318fb49dd6SShawn McCarney (*sensorJson)["Status"]["Health"] = "Critical"; 10328fb49dd6SShawn McCarney } 10338fb49dd6SShawn McCarney } 10348fb49dd6SShawn McCarney } 10358fb49dd6SShawn McCarney } 10368fb49dd6SShawn McCarney } 10378fb49dd6SShawn McCarney 10388fb49dd6SShawn McCarney /** 10398fb49dd6SShawn McCarney * @brief Gets status of inventory items associated with sensors. 10408fb49dd6SShawn McCarney * 10418fb49dd6SShawn McCarney * Gets the D-Bus status properties for the inventory items associated with 10428fb49dd6SShawn McCarney * sensors. 10438fb49dd6SShawn McCarney * 10448fb49dd6SShawn McCarney * Updates the Redfish sensors status in the JSON response, if needed, based on 10458fb49dd6SShawn McCarney * the inventory items status. 10468fb49dd6SShawn McCarney * 10478fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 10488fb49dd6SShawn McCarney * @param sensorToInvMap Mappings from sensor object path to the associated 10498fb49dd6SShawn McCarney * inventory object path. 10508fb49dd6SShawn McCarney * @param invConnections Connections that provide the status 10518fb49dd6SShawn McCarney * interfaces/properties for the inventory items. 10528fb49dd6SShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 10538fb49dd6SShawn McCarney * implements ObjectManager. 10548fb49dd6SShawn McCarney */ 10558fb49dd6SShawn McCarney static void getInventoryItemsStatus( 10568fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 10578fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 10588fb49dd6SShawn McCarney sensorToInvMap, 10598fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_set<std::string>> invConnections, 10608fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 10618fb49dd6SShawn McCarney objectMgrPaths) 10628fb49dd6SShawn McCarney { 10638fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsStatus enter"; 10648fb49dd6SShawn McCarney 10658fb49dd6SShawn McCarney // Loop through all connections providing inventory item status 10668fb49dd6SShawn McCarney for (const std::string& invConnection : *invConnections) 10678fb49dd6SShawn McCarney { 10688fb49dd6SShawn McCarney // Response handler for GetManagedObjects 10698fb49dd6SShawn McCarney auto respHandler = [sensorsAsyncResp, 10708fb49dd6SShawn McCarney sensorToInvMap](const boost::system::error_code ec, 10718fb49dd6SShawn McCarney ManagedObjectsVectorType& resp) { 10728fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsStatus respHandler enter"; 10738fb49dd6SShawn McCarney if (ec) 10748fb49dd6SShawn McCarney { 10758fb49dd6SShawn McCarney BMCWEB_LOG_ERROR 10768fb49dd6SShawn McCarney << "getInventoryItemsStatus respHandler DBus error " << ec; 10778fb49dd6SShawn McCarney messages::internalError(sensorsAsyncResp->res); 10788fb49dd6SShawn McCarney return; 10798fb49dd6SShawn McCarney } 10808fb49dd6SShawn McCarney 10818fb49dd6SShawn McCarney // Loop through returned object paths 10828fb49dd6SShawn McCarney for (const auto& objDictEntry : resp) 10838fb49dd6SShawn McCarney { 10848fb49dd6SShawn McCarney const std::string& objPath = 10858fb49dd6SShawn McCarney static_cast<const std::string&>(objDictEntry.first); 10868fb49dd6SShawn McCarney 10878fb49dd6SShawn McCarney // Find all sensors associated with this inventory item 10888fb49dd6SShawn McCarney for (const std::pair<std::string, std::string>& pair : 10898fb49dd6SShawn McCarney *sensorToInvMap) 10908fb49dd6SShawn McCarney { 10918fb49dd6SShawn McCarney if (pair.second == objPath) 10928fb49dd6SShawn McCarney { 10938fb49dd6SShawn McCarney // Update sensor status based on inventory item status 10948fb49dd6SShawn McCarney updateSensorStatus(sensorsAsyncResp, pair.first, 10958fb49dd6SShawn McCarney objDictEntry.second); 10968fb49dd6SShawn McCarney } 10978fb49dd6SShawn McCarney } 10988fb49dd6SShawn McCarney } 10998fb49dd6SShawn McCarney 11008fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsStatus respHandler exit"; 11018fb49dd6SShawn McCarney }; 11028fb49dd6SShawn McCarney 11038fb49dd6SShawn McCarney // Find DBus object path that implements ObjectManager for the current 11048fb49dd6SShawn McCarney // connection. If no mapping found, default to "/". 11058fb49dd6SShawn McCarney auto iter = objectMgrPaths->find(invConnection); 11068fb49dd6SShawn McCarney const std::string& objectMgrPath = 11078fb49dd6SShawn McCarney (iter != objectMgrPaths->end()) ? iter->second : "/"; 11088fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "ObjectManager path for " << invConnection << " is " 11098fb49dd6SShawn McCarney << objectMgrPath; 11108fb49dd6SShawn McCarney 11118fb49dd6SShawn McCarney // Get all object paths and their interfaces for current connection 11128fb49dd6SShawn McCarney crow::connections::systemBus->async_method_call( 11138fb49dd6SShawn McCarney std::move(respHandler), invConnection, objectMgrPath, 11148fb49dd6SShawn McCarney "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 11158fb49dd6SShawn McCarney } 11168fb49dd6SShawn McCarney 11178fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsStatus exit"; 11188fb49dd6SShawn McCarney } 11198fb49dd6SShawn McCarney 11208fb49dd6SShawn McCarney /** 11218fb49dd6SShawn McCarney * @brief Gets connections that provide status information on inventory items. 11228fb49dd6SShawn McCarney * 11238fb49dd6SShawn McCarney * Gets the D-Bus connections (services) that provide the interfaces and 11248fb49dd6SShawn McCarney * properties containing status information for the inventory items. 11258fb49dd6SShawn McCarney * 11268fb49dd6SShawn McCarney * Finds the connections asynchronously. Invokes callback when information has 11278fb49dd6SShawn McCarney * been obtained. 11288fb49dd6SShawn McCarney * 11298fb49dd6SShawn McCarney * The callback must have the following signature: 11308fb49dd6SShawn McCarney * @code 11318fb49dd6SShawn McCarney * callback(std::shared_ptr<boost::container::flat_set<std::string>> 11328fb49dd6SShawn McCarney * invConnections) 11338fb49dd6SShawn McCarney * @endcode 11348fb49dd6SShawn McCarney * 11358fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 11368fb49dd6SShawn McCarney * @param sensorToInvMap Mappings from sensor object path to the associated 11378fb49dd6SShawn McCarney * inventory object path. 11388fb49dd6SShawn McCarney * @param callback Callback to invoke when connections have been obtained. 11398fb49dd6SShawn McCarney */ 11408fb49dd6SShawn McCarney template <typename Callback> 11418fb49dd6SShawn McCarney static void getInventoryItemsConnections( 11428fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 11438fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 11448fb49dd6SShawn McCarney sensorToInvMap, 11458fb49dd6SShawn McCarney Callback&& callback) 11468fb49dd6SShawn McCarney { 11478fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections enter"; 11488fb49dd6SShawn McCarney 11498fb49dd6SShawn McCarney const std::string path = "/xyz/openbmc_project/inventory"; 11508fb49dd6SShawn McCarney const std::array<std::string, 2> interfaces = { 11518fb49dd6SShawn McCarney "xyz.openbmc_project.Inventory.Item", 11528fb49dd6SShawn McCarney "xyz.openbmc_project.State.Decorator.OperationalStatus"}; 11538fb49dd6SShawn McCarney 11548fb49dd6SShawn McCarney // Response handler for parsing output from GetSubTree 11558fb49dd6SShawn McCarney auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp, 11568fb49dd6SShawn McCarney sensorToInvMap](const boost::system::error_code ec, 11578fb49dd6SShawn McCarney const GetSubTreeType& subtree) { 11588fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler enter"; 11598fb49dd6SShawn McCarney if (ec) 11608fb49dd6SShawn McCarney { 11618fb49dd6SShawn McCarney messages::internalError(sensorsAsyncResp->res); 11628fb49dd6SShawn McCarney BMCWEB_LOG_ERROR 11638fb49dd6SShawn McCarney << "getInventoryItemsConnections respHandler DBus error " << ec; 11648fb49dd6SShawn McCarney return; 11658fb49dd6SShawn McCarney } 11668fb49dd6SShawn McCarney 11678fb49dd6SShawn McCarney // Make unique list of connections for desired inventory items 11688fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_set<std::string>> 11698fb49dd6SShawn McCarney invConnections = 11708fb49dd6SShawn McCarney std::make_shared<boost::container::flat_set<std::string>>(); 11718fb49dd6SShawn McCarney invConnections->reserve(8); 11728fb49dd6SShawn McCarney 11738fb49dd6SShawn McCarney // Loop through objects from GetSubTree 11748fb49dd6SShawn McCarney for (const std::pair< 11758fb49dd6SShawn McCarney std::string, 11768fb49dd6SShawn McCarney std::vector<std::pair<std::string, std::vector<std::string>>>>& 11778fb49dd6SShawn McCarney object : subtree) 11788fb49dd6SShawn McCarney { 11798fb49dd6SShawn McCarney // Look for inventory item object path in the sensor->inventory map 11808fb49dd6SShawn McCarney const std::string& objPath = object.first; 11818fb49dd6SShawn McCarney for (const std::pair<std::string, std::string>& pair : 11828fb49dd6SShawn McCarney *sensorToInvMap) 11838fb49dd6SShawn McCarney { 11848fb49dd6SShawn McCarney if (pair.second == objPath) 11858fb49dd6SShawn McCarney { 11868fb49dd6SShawn McCarney // Store all connections to inventory item 11878fb49dd6SShawn McCarney for (const std::pair<std::string, std::vector<std::string>>& 11888fb49dd6SShawn McCarney objData : object.second) 11898fb49dd6SShawn McCarney { 11908fb49dd6SShawn McCarney const std::string& invConnection = objData.first; 11918fb49dd6SShawn McCarney invConnections->insert(invConnection); 11928fb49dd6SShawn McCarney } 11938fb49dd6SShawn McCarney break; 11948fb49dd6SShawn McCarney } 11958fb49dd6SShawn McCarney } 11968fb49dd6SShawn McCarney } 11978fb49dd6SShawn McCarney callback(invConnections); 11988fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit"; 11998fb49dd6SShawn McCarney }; 12008fb49dd6SShawn McCarney 12018fb49dd6SShawn McCarney // Make call to ObjectMapper to find all inventory items 12028fb49dd6SShawn McCarney crow::connections::systemBus->async_method_call( 12038fb49dd6SShawn McCarney std::move(respHandler), "xyz.openbmc_project.ObjectMapper", 12048fb49dd6SShawn McCarney "/xyz/openbmc_project/object_mapper", 12058fb49dd6SShawn McCarney "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces); 12068fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections exit"; 12078fb49dd6SShawn McCarney } 12088fb49dd6SShawn McCarney 12098fb49dd6SShawn McCarney /** 12108fb49dd6SShawn McCarney * @brief Gets inventory items associated with the specified sensors. 12118fb49dd6SShawn McCarney * 12128fb49dd6SShawn McCarney * Looks for ObjectMapper associations from the specified sensors to related 12138fb49dd6SShawn McCarney * inventory items. Builds map where key is sensor object path and value is 12148fb49dd6SShawn McCarney * inventory item object path. 12158fb49dd6SShawn McCarney * 12168fb49dd6SShawn McCarney * Finds the inventory items asynchronously. Invokes callback when information 12178fb49dd6SShawn McCarney * has been obtained. 12188fb49dd6SShawn McCarney * 12198fb49dd6SShawn McCarney * The callback must have the following signature: 12208fb49dd6SShawn McCarney * @code 12218fb49dd6SShawn McCarney * callback(std::shared_ptr<boost::container::flat_map< 12228fb49dd6SShawn McCarney std::string, std::string>> sensorToInvMap) 12238fb49dd6SShawn McCarney * @endcode 12248fb49dd6SShawn McCarney * 12258fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 12268fb49dd6SShawn McCarney * @param sensorNames All sensors within the current chassis. 12278fb49dd6SShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 12288fb49dd6SShawn McCarney * implements ObjectManager. 12298fb49dd6SShawn McCarney * @param callback Callback to invoke when inventory items have been obtained. 12308fb49dd6SShawn McCarney */ 12318fb49dd6SShawn McCarney template <typename Callback> 12328fb49dd6SShawn McCarney static void getInventoryItems( 12338fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 12348fb49dd6SShawn McCarney const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 12358fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 12368fb49dd6SShawn McCarney objectMgrPaths, 12378fb49dd6SShawn McCarney Callback&& callback) 12388fb49dd6SShawn McCarney { 12398fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems enter"; 12408fb49dd6SShawn McCarney 12418fb49dd6SShawn McCarney // Response handler for GetManagedObjects 12428fb49dd6SShawn McCarney auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp, 12438fb49dd6SShawn McCarney sensorNames](const boost::system::error_code ec, 12448fb49dd6SShawn McCarney dbus::utility::ManagedObjectType& resp) { 12458fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems respHandler enter"; 12468fb49dd6SShawn McCarney if (ec) 12478fb49dd6SShawn McCarney { 12488fb49dd6SShawn McCarney BMCWEB_LOG_ERROR << "getInventoryItems respHandler DBus error " 12498fb49dd6SShawn McCarney << ec; 12508fb49dd6SShawn McCarney messages::internalError(sensorsAsyncResp->res); 12518fb49dd6SShawn McCarney return; 12528fb49dd6SShawn McCarney } 12538fb49dd6SShawn McCarney 12548fb49dd6SShawn McCarney // Loop through returned object paths 12558fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 12568fb49dd6SShawn McCarney sensorToInvMap = std::make_shared< 12578fb49dd6SShawn McCarney boost::container::flat_map<std::string, std::string>>(); 12588fb49dd6SShawn McCarney std::string sensorAssocPath; 12598fb49dd6SShawn McCarney sensorAssocPath.reserve(128); // avoid memory allocations 12608fb49dd6SShawn McCarney for (const auto& objDictEntry : resp) 12618fb49dd6SShawn McCarney { 12628fb49dd6SShawn McCarney const std::string& objPath = 12638fb49dd6SShawn McCarney static_cast<const std::string&>(objDictEntry.first); 12648fb49dd6SShawn McCarney const boost::container::flat_map< 12658fb49dd6SShawn McCarney std::string, boost::container::flat_map< 12668fb49dd6SShawn McCarney std::string, dbus::utility::DbusVariantType>>& 12678fb49dd6SShawn McCarney interfacesDict = objDictEntry.second; 12688fb49dd6SShawn McCarney 12698fb49dd6SShawn McCarney // If path is inventory association for one of the specified sensors 12708fb49dd6SShawn McCarney for (const std::string& sensorName : *sensorNames) 12718fb49dd6SShawn McCarney { 12728fb49dd6SShawn McCarney sensorAssocPath = sensorName; 12738fb49dd6SShawn McCarney sensorAssocPath += "/inventory"; 12748fb49dd6SShawn McCarney if (objPath == sensorAssocPath) 12758fb49dd6SShawn McCarney { 12768fb49dd6SShawn McCarney // Get Association interface for object path 12778fb49dd6SShawn McCarney auto assocIt = 12788fb49dd6SShawn McCarney interfacesDict.find("xyz.openbmc_project.Association"); 12798fb49dd6SShawn McCarney if (assocIt != interfacesDict.end()) 12808fb49dd6SShawn McCarney { 12818fb49dd6SShawn McCarney // Get inventory item from end point 12828fb49dd6SShawn McCarney auto endpointsIt = assocIt->second.find("endpoints"); 12838fb49dd6SShawn McCarney if (endpointsIt != assocIt->second.end()) 12848fb49dd6SShawn McCarney { 12858fb49dd6SShawn McCarney const std::vector<std::string>* endpoints = 12868fb49dd6SShawn McCarney std::get_if<std::vector<std::string>>( 12878fb49dd6SShawn McCarney &endpointsIt->second); 12888fb49dd6SShawn McCarney if ((endpoints != nullptr) && !endpoints->empty()) 12898fb49dd6SShawn McCarney { 12908fb49dd6SShawn McCarney // Store sensor -> inventory item mapping 12918fb49dd6SShawn McCarney const std::string& invItem = endpoints->front(); 12928fb49dd6SShawn McCarney (*sensorToInvMap)[sensorName] = invItem; 12938fb49dd6SShawn McCarney } 12948fb49dd6SShawn McCarney } 12958fb49dd6SShawn McCarney } 12968fb49dd6SShawn McCarney break; 12978fb49dd6SShawn McCarney } 12988fb49dd6SShawn McCarney } 12998fb49dd6SShawn McCarney } 13008fb49dd6SShawn McCarney 13018fb49dd6SShawn McCarney // Call callback if at least one inventory item was found 13028fb49dd6SShawn McCarney if (!sensorToInvMap->empty()) 13038fb49dd6SShawn McCarney { 13048fb49dd6SShawn McCarney callback(sensorToInvMap); 13058fb49dd6SShawn McCarney } 13068fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems respHandler exit"; 13078fb49dd6SShawn McCarney }; 13088fb49dd6SShawn McCarney 13098fb49dd6SShawn McCarney // Find DBus object path that implements ObjectManager for ObjectMapper 13108fb49dd6SShawn McCarney std::string connection = "xyz.openbmc_project.ObjectMapper"; 13118fb49dd6SShawn McCarney auto iter = objectMgrPaths->find(connection); 13128fb49dd6SShawn McCarney const std::string& objectMgrPath = 13138fb49dd6SShawn McCarney (iter != objectMgrPaths->end()) ? iter->second : "/"; 13148fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is " 13158fb49dd6SShawn McCarney << objectMgrPath; 13168fb49dd6SShawn McCarney 13178fb49dd6SShawn McCarney // Call GetManagedObjects on the ObjectMapper to get all associations 13188fb49dd6SShawn McCarney crow::connections::systemBus->async_method_call( 13198fb49dd6SShawn McCarney std::move(respHandler), connection, objectMgrPath, 13208fb49dd6SShawn McCarney "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 13218fb49dd6SShawn McCarney 13228fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems exit"; 13238fb49dd6SShawn McCarney } 13248fb49dd6SShawn McCarney 13258fb49dd6SShawn McCarney /** 13268fb49dd6SShawn McCarney * @brief Checks the status of inventory items associated with sensors. 13278fb49dd6SShawn McCarney * 13288fb49dd6SShawn McCarney * Finds the inventory items that are associated with the specified sensors. 13298fb49dd6SShawn McCarney * Gets the status of those inventory items. 13308fb49dd6SShawn McCarney * 13318fb49dd6SShawn McCarney * If the inventory items are not present or functional, the sensor status is 13328fb49dd6SShawn McCarney * updated in the JSON response. 13338fb49dd6SShawn McCarney * 13348fb49dd6SShawn McCarney * In D-Bus, the hardware present and functional properties are typically on the 13358fb49dd6SShawn McCarney * inventory item rather than the sensor. 13368fb49dd6SShawn McCarney * 13378fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 13388fb49dd6SShawn McCarney * @param sensorNames All sensors within the current chassis. 13398fb49dd6SShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 13408fb49dd6SShawn McCarney * implements ObjectManager. 13418fb49dd6SShawn McCarney */ 13428fb49dd6SShawn McCarney static void checkInventoryItemsStatus( 13438fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 13448fb49dd6SShawn McCarney const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 13458fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 13468fb49dd6SShawn McCarney objectMgrPaths) 13478fb49dd6SShawn McCarney { 13488fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "checkInventoryItemsStatus enter"; 13498fb49dd6SShawn McCarney auto getInventoryItemsCb = 13508fb49dd6SShawn McCarney [sensorsAsyncResp, 13518fb49dd6SShawn McCarney objectMgrPaths](std::shared_ptr< 13528fb49dd6SShawn McCarney boost::container::flat_map<std::string, std::string>> 13538fb49dd6SShawn McCarney sensorToInvMap) { 13548fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsCb enter"; 13558fb49dd6SShawn McCarney auto getInventoryItemsConnectionsCb = 13568fb49dd6SShawn McCarney [sensorsAsyncResp, sensorToInvMap, objectMgrPaths]( 13578fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_set<std::string>> 13588fb49dd6SShawn McCarney invConnections) { 13598fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter"; 13608fb49dd6SShawn McCarney 13618fb49dd6SShawn McCarney // Get status of inventory items and update sensors 13628fb49dd6SShawn McCarney getInventoryItemsStatus(sensorsAsyncResp, sensorToInvMap, 13638fb49dd6SShawn McCarney invConnections, objectMgrPaths); 13648fb49dd6SShawn McCarney 13658fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit"; 13668fb49dd6SShawn McCarney }; 13678fb49dd6SShawn McCarney 13688fb49dd6SShawn McCarney // Get connections that provide status of inventory items 13698fb49dd6SShawn McCarney getInventoryItemsConnections( 13708fb49dd6SShawn McCarney sensorsAsyncResp, sensorToInvMap, 13718fb49dd6SShawn McCarney std::move(getInventoryItemsConnectionsCb)); 13728fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsCb exit"; 13738fb49dd6SShawn McCarney }; 13748fb49dd6SShawn McCarney 13758fb49dd6SShawn McCarney // Get inventory items that are associated with specified sensors 13768fb49dd6SShawn McCarney getInventoryItems(sensorsAsyncResp, sensorNames, objectMgrPaths, 13778fb49dd6SShawn McCarney std::move(getInventoryItemsCb)); 13788fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "checkInventoryItemsStatus exit"; 13798fb49dd6SShawn McCarney } 13808fb49dd6SShawn McCarney 13818fb49dd6SShawn McCarney /** 1382de629b6eSShawn McCarney * @brief Gets the values of the specified sensors. 1383de629b6eSShawn McCarney * 1384de629b6eSShawn McCarney * Stores the results as JSON in the SensorsAsyncResp. 1385de629b6eSShawn McCarney * 1386de629b6eSShawn McCarney * Gets the sensor values asynchronously. Stores the results later when the 1387de629b6eSShawn McCarney * information has been obtained. 1388de629b6eSShawn McCarney * 1389de629b6eSShawn McCarney * The sensorNames set contains all sensors for the current chassis. 1390de629b6eSShawn McCarney * SensorsAsyncResp contains the requested sensor types. Only sensors of a 1391de629b6eSShawn McCarney * requested type are included in the JSON output. 1392de629b6eSShawn McCarney * 1393de629b6eSShawn McCarney * To minimize the number of DBus calls, the DBus method 1394de629b6eSShawn McCarney * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the 1395de629b6eSShawn McCarney * values of all sensors provided by a connection (service). 1396de629b6eSShawn McCarney * 1397de629b6eSShawn McCarney * The connections set contains all the connections that provide sensor values. 1398de629b6eSShawn McCarney * 1399de629b6eSShawn McCarney * The objectMgrPaths map contains mappings from a connection name to the 1400de629b6eSShawn McCarney * corresponding DBus object path that implements ObjectManager. 1401de629b6eSShawn McCarney * 1402de629b6eSShawn McCarney * @param SensorsAsyncResp Pointer to object holding response data. 1403de629b6eSShawn McCarney * @param sensorNames All sensors within the current chassis. 1404de629b6eSShawn McCarney * @param connections Connections that provide sensor values. 1405de629b6eSShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 1406de629b6eSShawn McCarney * implements ObjectManager. 1407de629b6eSShawn McCarney */ 1408de629b6eSShawn McCarney void getSensorData( 1409de629b6eSShawn McCarney std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp, 141049c53ac9SJohnathan Mantey const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 1411de629b6eSShawn McCarney const boost::container::flat_set<std::string>& connections, 14128fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 14138fb49dd6SShawn McCarney objectMgrPaths) 1414de629b6eSShawn McCarney { 1415de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getSensorData enter"; 1416de629b6eSShawn McCarney // Get managed objects from all services exposing sensors 1417de629b6eSShawn McCarney for (const std::string& connection : connections) 1418de629b6eSShawn McCarney { 1419de629b6eSShawn McCarney // Response handler to process managed objects 14208fb49dd6SShawn McCarney auto getManagedObjectsCb = [SensorsAsyncResp, sensorNames, 14218fb49dd6SShawn McCarney objectMgrPaths]( 1422de629b6eSShawn McCarney const boost::system::error_code ec, 1423de629b6eSShawn McCarney ManagedObjectsVectorType& resp) { 1424de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter"; 1425de629b6eSShawn McCarney if (ec) 1426de629b6eSShawn McCarney { 1427de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec; 1428de629b6eSShawn McCarney messages::internalError(SensorsAsyncResp->res); 1429de629b6eSShawn McCarney return; 1430de629b6eSShawn McCarney } 1431de629b6eSShawn McCarney // Go through all objects and update response with sensor data 1432de629b6eSShawn McCarney for (const auto& objDictEntry : resp) 1433de629b6eSShawn McCarney { 1434de629b6eSShawn McCarney const std::string& objPath = 1435de629b6eSShawn McCarney static_cast<const std::string&>(objDictEntry.first); 1436de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object " 1437de629b6eSShawn McCarney << objPath; 1438de629b6eSShawn McCarney 1439de629b6eSShawn McCarney std::vector<std::string> split; 1440de629b6eSShawn McCarney // Reserve space for 1441de629b6eSShawn McCarney // /xyz/openbmc_project/sensors/<name>/<subname> 1442de629b6eSShawn McCarney split.reserve(6); 1443de629b6eSShawn McCarney boost::algorithm::split(split, objPath, boost::is_any_of("/")); 1444de629b6eSShawn McCarney if (split.size() < 6) 1445de629b6eSShawn McCarney { 1446de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "Got path that isn't long enough " 1447de629b6eSShawn McCarney << objPath; 1448de629b6eSShawn McCarney continue; 1449de629b6eSShawn McCarney } 1450de629b6eSShawn McCarney // These indexes aren't intuitive, as boost::split puts an empty 1451de629b6eSShawn McCarney // string at the beginning 1452de629b6eSShawn McCarney const std::string& sensorType = split[4]; 1453de629b6eSShawn McCarney const std::string& sensorName = split[5]; 1454de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "sensorName " << sensorName 1455de629b6eSShawn McCarney << " sensorType " << sensorType; 145649c53ac9SJohnathan Mantey if (sensorNames->find(objPath) == sensorNames->end()) 1457de629b6eSShawn McCarney { 1458de629b6eSShawn McCarney BMCWEB_LOG_ERROR << sensorName << " not in sensor list "; 1459de629b6eSShawn McCarney continue; 1460de629b6eSShawn McCarney } 1461de629b6eSShawn McCarney 1462de629b6eSShawn McCarney const char* fieldName = nullptr; 1463de629b6eSShawn McCarney if (sensorType == "temperature") 1464de629b6eSShawn McCarney { 1465de629b6eSShawn McCarney fieldName = "Temperatures"; 1466de629b6eSShawn McCarney } 1467de629b6eSShawn McCarney else if (sensorType == "fan" || sensorType == "fan_tach" || 1468de629b6eSShawn McCarney sensorType == "fan_pwm") 1469de629b6eSShawn McCarney { 1470de629b6eSShawn McCarney fieldName = "Fans"; 1471de629b6eSShawn McCarney } 1472de629b6eSShawn McCarney else if (sensorType == "voltage") 1473de629b6eSShawn McCarney { 1474de629b6eSShawn McCarney fieldName = "Voltages"; 1475de629b6eSShawn McCarney } 1476de629b6eSShawn McCarney else if (sensorType == "current") 1477de629b6eSShawn McCarney { 1478de629b6eSShawn McCarney fieldName = "PowerSupplies"; 1479de629b6eSShawn McCarney } 1480de629b6eSShawn McCarney else if (sensorType == "power") 1481de629b6eSShawn McCarney { 1482028f7ebcSEddie James if (!sensorName.compare("total_power")) 1483028f7ebcSEddie James { 1484028f7ebcSEddie James fieldName = "PowerControl"; 1485028f7ebcSEddie James } 1486028f7ebcSEddie James else 1487028f7ebcSEddie James { 1488de629b6eSShawn McCarney fieldName = "PowerSupplies"; 1489de629b6eSShawn McCarney } 1490028f7ebcSEddie James } 1491de629b6eSShawn McCarney else 1492de629b6eSShawn McCarney { 1493de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "Unsure how to handle sensorType " 1494de629b6eSShawn McCarney << sensorType; 1495de629b6eSShawn McCarney continue; 1496de629b6eSShawn McCarney } 1497de629b6eSShawn McCarney 1498de629b6eSShawn McCarney nlohmann::json& tempArray = 1499de629b6eSShawn McCarney SensorsAsyncResp->res.jsonValue[fieldName]; 1500de629b6eSShawn McCarney 1501*7ab06f49SGunnar Mills if ((fieldName == "PowerSupplies" || 1502*7ab06f49SGunnar Mills fieldName == "PowerControl") && 1503*7ab06f49SGunnar Mills !tempArray.empty()) 150449c53ac9SJohnathan Mantey { 1505*7ab06f49SGunnar Mills // For power supplies and power control put multiple 1506*7ab06f49SGunnar Mills // "sensors" into a single power supply or power control 1507*7ab06f49SGunnar Mills // entry, so only create the first one 1508*7ab06f49SGunnar Mills } 1509*7ab06f49SGunnar Mills else if (fieldName == "PowerControl") 1510*7ab06f49SGunnar Mills { 1511*7ab06f49SGunnar Mills // Put multiple "sensors" into a single PowerControl. 1512*7ab06f49SGunnar Mills // Follows MemberId naming and naming in power.hpp. 1513*7ab06f49SGunnar Mills tempArray.push_back( 1514*7ab06f49SGunnar Mills {{"@odata.id", "/redfish/v1/Chassis/" + 1515*7ab06f49SGunnar Mills SensorsAsyncResp->chassisId + "/" + 1516*7ab06f49SGunnar Mills SensorsAsyncResp->chassisSubNode + 1517*7ab06f49SGunnar Mills "#/" + fieldName + "/0"}}); 151849c53ac9SJohnathan Mantey } 151949c53ac9SJohnathan Mantey else 152049c53ac9SJohnathan Mantey { 1521de629b6eSShawn McCarney tempArray.push_back( 152249c53ac9SJohnathan Mantey {{"@odata.id", "/redfish/v1/Chassis/" + 152349c53ac9SJohnathan Mantey SensorsAsyncResp->chassisId + "/" + 152449c53ac9SJohnathan Mantey SensorsAsyncResp->chassisSubNode + 152549c53ac9SJohnathan Mantey "#/" + fieldName + "/"}}); 152649c53ac9SJohnathan Mantey } 1527de629b6eSShawn McCarney nlohmann::json& sensorJson = tempArray.back(); 1528de629b6eSShawn McCarney 1529de629b6eSShawn McCarney objectInterfacesToJson(sensorName, sensorType, 1530de629b6eSShawn McCarney objDictEntry.second, sensorJson); 1531de629b6eSShawn McCarney } 153249c53ac9SJohnathan Mantey if (SensorsAsyncResp.use_count() == 1) 153349c53ac9SJohnathan Mantey { 153449c53ac9SJohnathan Mantey sortJSONResponse(SensorsAsyncResp); 15358fb49dd6SShawn McCarney checkInventoryItemsStatus(SensorsAsyncResp, sensorNames, 15368fb49dd6SShawn McCarney objectMgrPaths); 153749c53ac9SJohnathan Mantey if (SensorsAsyncResp->chassisSubNode == "Thermal") 15388bd25ccdSJames Feist { 15398bd25ccdSJames Feist populateFanRedundancy(SensorsAsyncResp); 15408bd25ccdSJames Feist } 154149c53ac9SJohnathan Mantey } 1542de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit"; 1543de629b6eSShawn McCarney }; 1544de629b6eSShawn McCarney 1545de629b6eSShawn McCarney // Find DBus object path that implements ObjectManager for the current 1546de629b6eSShawn McCarney // connection. If no mapping found, default to "/". 15478fb49dd6SShawn McCarney auto iter = objectMgrPaths->find(connection); 1548de629b6eSShawn McCarney const std::string& objectMgrPath = 15498fb49dd6SShawn McCarney (iter != objectMgrPaths->end()) ? iter->second : "/"; 1550de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is " 1551de629b6eSShawn McCarney << objectMgrPath; 1552de629b6eSShawn McCarney 1553de629b6eSShawn McCarney crow::connections::systemBus->async_method_call( 1554de629b6eSShawn McCarney getManagedObjectsCb, connection, objectMgrPath, 1555de629b6eSShawn McCarney "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1556de629b6eSShawn McCarney }; 1557de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getSensorData exit"; 1558de629b6eSShawn McCarney } 1559de629b6eSShawn McCarney 1560de629b6eSShawn McCarney /** 156108777fb0SLewanczyk, Dawid * @brief Entry point for retrieving sensors data related to requested 156208777fb0SLewanczyk, Dawid * chassis. 1563588c3f0dSKowalski, Kamil * @param SensorsAsyncResp Pointer to object holding response data 156408777fb0SLewanczyk, Dawid */ 15651abe55efSEd Tanous void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp) 15661abe55efSEd Tanous { 156755c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisData enter"; 156849c53ac9SJohnathan Mantey auto getChassisCb = 156949c53ac9SJohnathan Mantey [SensorsAsyncResp]( 157049c53ac9SJohnathan Mantey std::shared_ptr<boost::container::flat_set<std::string>> 157108777fb0SLewanczyk, Dawid sensorNames) { 157255c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisCb enter"; 15738fb49dd6SShawn McCarney auto getConnectionCb = [SensorsAsyncResp, sensorNames]( 15748fb49dd6SShawn McCarney const boost::container::flat_set< 15758fb49dd6SShawn McCarney std::string>& connections) { 157655c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getConnectionCb enter"; 1577de629b6eSShawn McCarney auto getObjectManagerPathsCb = 157849c53ac9SJohnathan Mantey [SensorsAsyncResp, sensorNames, connections]( 15798fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, 15808fb49dd6SShawn McCarney std::string>> 15818fb49dd6SShawn McCarney objectMgrPaths) { 1582de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter"; 158349c53ac9SJohnathan Mantey // Get sensor data and store results in JSON 158449c53ac9SJohnathan Mantey // response 1585de629b6eSShawn McCarney getSensorData(SensorsAsyncResp, sensorNames, 1586de629b6eSShawn McCarney connections, objectMgrPaths); 1587de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit"; 158808777fb0SLewanczyk, Dawid }; 1589de629b6eSShawn McCarney 159049c53ac9SJohnathan Mantey // Get mapping from connection names to the DBus object 159149c53ac9SJohnathan Mantey // paths that implement the ObjectManager interface 1592de629b6eSShawn McCarney getObjectManagerPaths(SensorsAsyncResp, 1593de629b6eSShawn McCarney std::move(getObjectManagerPathsCb)); 159455c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getConnectionCb exit"; 159508777fb0SLewanczyk, Dawid }; 1596de629b6eSShawn McCarney 1597de629b6eSShawn McCarney // Get set of connections that provide sensor values 15981abe55efSEd Tanous getConnections(SensorsAsyncResp, sensorNames, 15991abe55efSEd Tanous std::move(getConnectionCb)); 160055c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisCb exit"; 160108777fb0SLewanczyk, Dawid }; 16024f9a2130SJennifer Lee SensorsAsyncResp->res.jsonValue["Redundancy"] = nlohmann::json::array(); 160308777fb0SLewanczyk, Dawid 160426f03899SShawn McCarney // Get set of sensors in chassis 1605588c3f0dSKowalski, Kamil getChassis(SensorsAsyncResp, std::move(getChassisCb)); 160655c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisData exit"; 160708777fb0SLewanczyk, Dawid }; 160808777fb0SLewanczyk, Dawid 1609413961deSRichard Marian Thomaiyar /** 161049c53ac9SJohnathan Mantey * @brief Find the requested sensorName in the list of all sensors supplied by 161149c53ac9SJohnathan Mantey * the chassis node 161249c53ac9SJohnathan Mantey * 161349c53ac9SJohnathan Mantey * @param sensorName The sensor name supplied in the PATCH request 161449c53ac9SJohnathan Mantey * @param sensorsList The list of sensors managed by the chassis node 161549c53ac9SJohnathan Mantey * @param sensorsModified The list of sensors that were found as a result of 161649c53ac9SJohnathan Mantey * repeated calls to this function 161749c53ac9SJohnathan Mantey */ 161849c53ac9SJohnathan Mantey bool findSensorNameUsingSensorPath( 16190a86febdSRichard Marian Thomaiyar std::string_view sensorName, 162049c53ac9SJohnathan Mantey boost::container::flat_set<std::string>& sensorsList, 162149c53ac9SJohnathan Mantey boost::container::flat_set<std::string>& sensorsModified) 162249c53ac9SJohnathan Mantey { 16230a86febdSRichard Marian Thomaiyar for (std::string_view chassisSensor : sensorsList) 162449c53ac9SJohnathan Mantey { 16250a86febdSRichard Marian Thomaiyar std::size_t pos = chassisSensor.rfind("/"); 16260a86febdSRichard Marian Thomaiyar if (pos >= (chassisSensor.size() - 1)) 162749c53ac9SJohnathan Mantey { 162849c53ac9SJohnathan Mantey continue; 162949c53ac9SJohnathan Mantey } 16300a86febdSRichard Marian Thomaiyar std::string_view thisSensorName = chassisSensor.substr(pos + 1); 163149c53ac9SJohnathan Mantey if (thisSensorName == sensorName) 163249c53ac9SJohnathan Mantey { 163349c53ac9SJohnathan Mantey sensorsModified.emplace(chassisSensor); 163449c53ac9SJohnathan Mantey return true; 163549c53ac9SJohnathan Mantey } 163649c53ac9SJohnathan Mantey } 163749c53ac9SJohnathan Mantey return false; 163849c53ac9SJohnathan Mantey } 163949c53ac9SJohnathan Mantey 164049c53ac9SJohnathan Mantey /** 1641413961deSRichard Marian Thomaiyar * @brief Entry point for overriding sensor values of given sensor 1642413961deSRichard Marian Thomaiyar * 1643413961deSRichard Marian Thomaiyar * @param res response object 1644413961deSRichard Marian Thomaiyar * @param req request object 1645413961deSRichard Marian Thomaiyar * @param params parameter passed for CRUD 1646413961deSRichard Marian Thomaiyar * @param typeList TypeList of sensors for the resource queried 1647413961deSRichard Marian Thomaiyar * @param chassisSubNode Chassis Node for which the query has to happen 1648413961deSRichard Marian Thomaiyar */ 1649413961deSRichard Marian Thomaiyar void setSensorOverride(crow::Response& res, const crow::Request& req, 1650413961deSRichard Marian Thomaiyar const std::vector<std::string>& params, 165185e1424fSEd Tanous const std::vector<const char*> typeList, 1652413961deSRichard Marian Thomaiyar const std::string& chassisSubNode) 1653413961deSRichard Marian Thomaiyar { 1654413961deSRichard Marian Thomaiyar 1655413961deSRichard Marian Thomaiyar // TODO: Need to figure out dynamic way to restrict patch (Set Sensor 1656413961deSRichard Marian Thomaiyar // override) based on another d-bus announcement to be more generic. 1657413961deSRichard Marian Thomaiyar if (params.size() != 1) 1658413961deSRichard Marian Thomaiyar { 1659413961deSRichard Marian Thomaiyar messages::internalError(res); 1660413961deSRichard Marian Thomaiyar res.end(); 1661413961deSRichard Marian Thomaiyar return; 1662413961deSRichard Marian Thomaiyar } 1663f65af9e8SRichard Marian Thomaiyar 1664f65af9e8SRichard Marian Thomaiyar std::unordered_map<std::string, std::vector<nlohmann::json>> allCollections; 1665f65af9e8SRichard Marian Thomaiyar std::optional<std::vector<nlohmann::json>> temperatureCollections; 1666f65af9e8SRichard Marian Thomaiyar std::optional<std::vector<nlohmann::json>> fanCollections; 1667f65af9e8SRichard Marian Thomaiyar std::vector<nlohmann::json> voltageCollections; 1668f65af9e8SRichard Marian Thomaiyar BMCWEB_LOG_INFO << "setSensorOverride for subNode" << chassisSubNode 1669f65af9e8SRichard Marian Thomaiyar << "\n"; 1670f65af9e8SRichard Marian Thomaiyar 1671413961deSRichard Marian Thomaiyar if (chassisSubNode == "Thermal") 1672413961deSRichard Marian Thomaiyar { 1673f65af9e8SRichard Marian Thomaiyar if (!json_util::readJson(req, res, "Temperatures", 1674f65af9e8SRichard Marian Thomaiyar temperatureCollections, "Fans", 1675f65af9e8SRichard Marian Thomaiyar fanCollections)) 1676f65af9e8SRichard Marian Thomaiyar { 1677f65af9e8SRichard Marian Thomaiyar return; 1678f65af9e8SRichard Marian Thomaiyar } 1679f65af9e8SRichard Marian Thomaiyar if (!temperatureCollections && !fanCollections) 1680f65af9e8SRichard Marian Thomaiyar { 1681f65af9e8SRichard Marian Thomaiyar messages::resourceNotFound(res, "Thermal", 1682f65af9e8SRichard Marian Thomaiyar "Temperatures / Voltages"); 1683f65af9e8SRichard Marian Thomaiyar res.end(); 1684f65af9e8SRichard Marian Thomaiyar return; 1685f65af9e8SRichard Marian Thomaiyar } 1686f65af9e8SRichard Marian Thomaiyar if (temperatureCollections) 1687f65af9e8SRichard Marian Thomaiyar { 1688f65af9e8SRichard Marian Thomaiyar allCollections.emplace("Temperatures", 1689f65af9e8SRichard Marian Thomaiyar *std::move(temperatureCollections)); 1690f65af9e8SRichard Marian Thomaiyar } 1691f65af9e8SRichard Marian Thomaiyar if (fanCollections) 1692f65af9e8SRichard Marian Thomaiyar { 1693f65af9e8SRichard Marian Thomaiyar allCollections.emplace("Fans", *std::move(fanCollections)); 1694f65af9e8SRichard Marian Thomaiyar } 1695413961deSRichard Marian Thomaiyar } 1696413961deSRichard Marian Thomaiyar else if (chassisSubNode == "Power") 1697413961deSRichard Marian Thomaiyar { 1698f65af9e8SRichard Marian Thomaiyar if (!json_util::readJson(req, res, "Voltages", voltageCollections)) 1699f65af9e8SRichard Marian Thomaiyar { 1700f65af9e8SRichard Marian Thomaiyar return; 1701f65af9e8SRichard Marian Thomaiyar } 1702f65af9e8SRichard Marian Thomaiyar allCollections.emplace("Voltages", std::move(voltageCollections)); 1703413961deSRichard Marian Thomaiyar } 1704413961deSRichard Marian Thomaiyar else 1705413961deSRichard Marian Thomaiyar { 1706413961deSRichard Marian Thomaiyar res.result(boost::beast::http::status::not_found); 1707413961deSRichard Marian Thomaiyar res.end(); 1708413961deSRichard Marian Thomaiyar return; 1709413961deSRichard Marian Thomaiyar } 1710413961deSRichard Marian Thomaiyar 1711f65af9e8SRichard Marian Thomaiyar const char* propertyValueName; 1712f65af9e8SRichard Marian Thomaiyar std::unordered_map<std::string, std::pair<double, std::string>> overrideMap; 1713413961deSRichard Marian Thomaiyar std::string memberId; 1714413961deSRichard Marian Thomaiyar double value; 1715f65af9e8SRichard Marian Thomaiyar for (auto& collectionItems : allCollections) 1716f65af9e8SRichard Marian Thomaiyar { 1717f65af9e8SRichard Marian Thomaiyar if (collectionItems.first == "Temperatures") 1718f65af9e8SRichard Marian Thomaiyar { 1719f65af9e8SRichard Marian Thomaiyar propertyValueName = "ReadingCelsius"; 1720f65af9e8SRichard Marian Thomaiyar } 1721f65af9e8SRichard Marian Thomaiyar else if (collectionItems.first == "Fans") 1722f65af9e8SRichard Marian Thomaiyar { 1723f65af9e8SRichard Marian Thomaiyar propertyValueName = "Reading"; 1724f65af9e8SRichard Marian Thomaiyar } 1725f65af9e8SRichard Marian Thomaiyar else 1726f65af9e8SRichard Marian Thomaiyar { 1727f65af9e8SRichard Marian Thomaiyar propertyValueName = "ReadingVolts"; 1728f65af9e8SRichard Marian Thomaiyar } 1729f65af9e8SRichard Marian Thomaiyar for (auto& item : collectionItems.second) 1730f65af9e8SRichard Marian Thomaiyar { 1731f65af9e8SRichard Marian Thomaiyar if (!json_util::readJson(item, res, "MemberId", memberId, 1732413961deSRichard Marian Thomaiyar propertyValueName, value)) 1733413961deSRichard Marian Thomaiyar { 1734413961deSRichard Marian Thomaiyar return; 1735413961deSRichard Marian Thomaiyar } 1736f65af9e8SRichard Marian Thomaiyar overrideMap.emplace(memberId, 1737f65af9e8SRichard Marian Thomaiyar std::make_pair(value, collectionItems.first)); 1738f65af9e8SRichard Marian Thomaiyar } 1739f65af9e8SRichard Marian Thomaiyar } 1740413961deSRichard Marian Thomaiyar const std::string& chassisName = params[0]; 1741413961deSRichard Marian Thomaiyar auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>( 1742413961deSRichard Marian Thomaiyar res, chassisName, typeList, chassisSubNode); 174349c53ac9SJohnathan Mantey auto getChassisSensorListCb = [sensorAsyncResp, 174449c53ac9SJohnathan Mantey overrideMap](const std::shared_ptr< 174549c53ac9SJohnathan Mantey boost::container::flat_set< 174649c53ac9SJohnathan Mantey std::string>> 174749c53ac9SJohnathan Mantey sensorsList) { 174849c53ac9SJohnathan Mantey // Match sensor names in the PATCH request to those managed by the 174949c53ac9SJohnathan Mantey // chassis node 175049c53ac9SJohnathan Mantey const std::shared_ptr<boost::container::flat_set<std::string>> 175149c53ac9SJohnathan Mantey sensorNames = 175249c53ac9SJohnathan Mantey std::make_shared<boost::container::flat_set<std::string>>(); 1753f65af9e8SRichard Marian Thomaiyar for (const auto& item : overrideMap) 1754413961deSRichard Marian Thomaiyar { 1755f65af9e8SRichard Marian Thomaiyar const auto& sensor = item.first; 175649c53ac9SJohnathan Mantey if (!findSensorNameUsingSensorPath(sensor, *sensorsList, 175749c53ac9SJohnathan Mantey *sensorNames)) 1758f65af9e8SRichard Marian Thomaiyar { 1759f65af9e8SRichard Marian Thomaiyar BMCWEB_LOG_INFO << "Unable to find memberId " << item.first; 1760413961deSRichard Marian Thomaiyar messages::resourceNotFound(sensorAsyncResp->res, 1761f65af9e8SRichard Marian Thomaiyar item.second.second, item.first); 1762413961deSRichard Marian Thomaiyar return; 1763413961deSRichard Marian Thomaiyar } 1764f65af9e8SRichard Marian Thomaiyar } 1765413961deSRichard Marian Thomaiyar // Get the connection to which the memberId belongs 1766413961deSRichard Marian Thomaiyar auto getObjectsWithConnectionCb = 1767f65af9e8SRichard Marian Thomaiyar [sensorAsyncResp, overrideMap]( 1768413961deSRichard Marian Thomaiyar const boost::container::flat_set<std::string>& connections, 1769413961deSRichard Marian Thomaiyar const std::set<std::pair<std::string, std::string>>& 1770413961deSRichard Marian Thomaiyar objectsWithConnection) { 1771f65af9e8SRichard Marian Thomaiyar if (objectsWithConnection.size() != overrideMap.size()) 1772413961deSRichard Marian Thomaiyar { 1773413961deSRichard Marian Thomaiyar BMCWEB_LOG_INFO 1774f65af9e8SRichard Marian Thomaiyar << "Unable to find all objects with proper connection " 1775f65af9e8SRichard Marian Thomaiyar << objectsWithConnection.size() << " requested " 1776f65af9e8SRichard Marian Thomaiyar << overrideMap.size() << "\n"; 1777413961deSRichard Marian Thomaiyar messages::resourceNotFound( 1778413961deSRichard Marian Thomaiyar sensorAsyncResp->res, 1779413961deSRichard Marian Thomaiyar sensorAsyncResp->chassisSubNode == "Thermal" 1780413961deSRichard Marian Thomaiyar ? "Temperatures" 1781413961deSRichard Marian Thomaiyar : "Voltages", 1782f65af9e8SRichard Marian Thomaiyar "Count"); 1783f65af9e8SRichard Marian Thomaiyar return; 1784f65af9e8SRichard Marian Thomaiyar } 1785f65af9e8SRichard Marian Thomaiyar for (const auto& item : objectsWithConnection) 1786f65af9e8SRichard Marian Thomaiyar { 1787f65af9e8SRichard Marian Thomaiyar 1788f65af9e8SRichard Marian Thomaiyar auto lastPos = item.first.rfind('/'); 1789f65af9e8SRichard Marian Thomaiyar if (lastPos == std::string::npos) 1790f65af9e8SRichard Marian Thomaiyar { 1791f65af9e8SRichard Marian Thomaiyar messages::internalError(sensorAsyncResp->res); 1792f65af9e8SRichard Marian Thomaiyar return; 1793f65af9e8SRichard Marian Thomaiyar } 1794f65af9e8SRichard Marian Thomaiyar std::string sensorName = item.first.substr(lastPos + 1); 1795f65af9e8SRichard Marian Thomaiyar 1796f65af9e8SRichard Marian Thomaiyar const auto& iterator = overrideMap.find(sensorName); 1797f65af9e8SRichard Marian Thomaiyar if (iterator == overrideMap.end()) 1798f65af9e8SRichard Marian Thomaiyar { 1799f65af9e8SRichard Marian Thomaiyar BMCWEB_LOG_INFO << "Unable to find sensor object" 1800f65af9e8SRichard Marian Thomaiyar << item.first << "\n"; 1801f65af9e8SRichard Marian Thomaiyar messages::internalError(sensorAsyncResp->res); 1802413961deSRichard Marian Thomaiyar return; 1803413961deSRichard Marian Thomaiyar } 1804413961deSRichard Marian Thomaiyar crow::connections::systemBus->async_method_call( 1805f65af9e8SRichard Marian Thomaiyar [sensorAsyncResp](const boost::system::error_code ec) { 1806413961deSRichard Marian Thomaiyar if (ec) 1807413961deSRichard Marian Thomaiyar { 1808413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG 1809f65af9e8SRichard Marian Thomaiyar << "setOverrideValueStatus DBUS error: " 1810413961deSRichard Marian Thomaiyar << ec; 1811413961deSRichard Marian Thomaiyar messages::internalError(sensorAsyncResp->res); 1812413961deSRichard Marian Thomaiyar return; 1813413961deSRichard Marian Thomaiyar } 1814413961deSRichard Marian Thomaiyar }, 1815f65af9e8SRichard Marian Thomaiyar item.second, item.first, 1816413961deSRichard Marian Thomaiyar "org.freedesktop.DBus.Properties", "Set", 1817413961deSRichard Marian Thomaiyar "xyz.openbmc_project.Sensor.Value", "Value", 1818f65af9e8SRichard Marian Thomaiyar sdbusplus::message::variant<double>( 1819f65af9e8SRichard Marian Thomaiyar iterator->second.first)); 1820f65af9e8SRichard Marian Thomaiyar } 1821413961deSRichard Marian Thomaiyar }; 1822413961deSRichard Marian Thomaiyar // Get object with connection for the given sensor name 1823413961deSRichard Marian Thomaiyar getObjectsWithConnection(sensorAsyncResp, sensorNames, 1824413961deSRichard Marian Thomaiyar std::move(getObjectsWithConnectionCb)); 1825413961deSRichard Marian Thomaiyar }; 1826413961deSRichard Marian Thomaiyar // get full sensor list for the given chassisId and cross verify the sensor. 1827413961deSRichard Marian Thomaiyar getChassis(sensorAsyncResp, std::move(getChassisSensorListCb)); 1828413961deSRichard Marian Thomaiyar } 1829413961deSRichard Marian Thomaiyar 183008777fb0SLewanczyk, Dawid } // namespace redfish 1831