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, 50b01bf299SEd Tanous const std::initializer_list<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 { 571028f7ebcSEddie James unit = "PowerConsumedWatts"; 572028f7ebcSEddie James } 573028f7ebcSEddie James else if (sensorNameLower.find("input") != std::string::npos) 57449c53ac9SJohnathan Mantey { 57549c53ac9SJohnathan Mantey unit = "PowerInputWatts"; 57649c53ac9SJohnathan Mantey } 57749c53ac9SJohnathan Mantey else 57849c53ac9SJohnathan Mantey { 57949c53ac9SJohnathan Mantey unit = "PowerOutputWatts"; 58049c53ac9SJohnathan Mantey } 5812474adfaSEd Tanous } 5821abe55efSEd Tanous else 5831abe55efSEd Tanous { 58455c7b7a2SEd Tanous BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName; 58508777fb0SLewanczyk, Dawid return; 58608777fb0SLewanczyk, Dawid } 58708777fb0SLewanczyk, Dawid // Map of dbus interface name, dbus property name and redfish property_name 58808777fb0SLewanczyk, Dawid std::vector<std::tuple<const char*, const char*, const char*>> properties; 58908777fb0SLewanczyk, Dawid properties.reserve(7); 59008777fb0SLewanczyk, Dawid 59108777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit); 592de629b6eSShawn McCarney 593de629b6eSShawn McCarney // If sensor type doesn't map to Redfish PowerSupply, add threshold props 594de629b6eSShawn McCarney if ((sensorType != "current") && (sensorType != "power")) 595de629b6eSShawn McCarney { 59608777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning", 59708777fb0SLewanczyk, Dawid "WarningHigh", "UpperThresholdNonCritical"); 59808777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning", 59908777fb0SLewanczyk, Dawid "WarningLow", "LowerThresholdNonCritical"); 60008777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical", 60108777fb0SLewanczyk, Dawid "CriticalHigh", "UpperThresholdCritical"); 60208777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical", 60308777fb0SLewanczyk, Dawid "CriticalLow", "LowerThresholdCritical"); 604de629b6eSShawn McCarney } 60508777fb0SLewanczyk, Dawid 6062474adfaSEd Tanous // TODO Need to get UpperThresholdFatal and LowerThresholdFatal 6072474adfaSEd Tanous 6081abe55efSEd Tanous if (sensorType == "temperature") 6091abe55efSEd Tanous { 61008777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue", 61108777fb0SLewanczyk, Dawid "MinReadingRangeTemp"); 61208777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue", 61308777fb0SLewanczyk, Dawid "MaxReadingRangeTemp"); 6141abe55efSEd Tanous } 615de629b6eSShawn McCarney else if ((sensorType != "current") && (sensorType != "power")) 6161abe55efSEd Tanous { 617de629b6eSShawn McCarney // Sensor type doesn't map to Redfish PowerSupply; add min/max props 61808777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue", 61908777fb0SLewanczyk, Dawid "MinReadingRange"); 62008777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue", 62108777fb0SLewanczyk, Dawid "MaxReadingRange"); 62208777fb0SLewanczyk, Dawid } 62308777fb0SLewanczyk, Dawid 62408777fb0SLewanczyk, Dawid for (const std::tuple<const char*, const char*, const char*>& p : 6251abe55efSEd Tanous properties) 6261abe55efSEd Tanous { 62708777fb0SLewanczyk, Dawid auto interfaceProperties = interfacesDict.find(std::get<0>(p)); 6281abe55efSEd Tanous if (interfaceProperties != interfacesDict.end()) 6291abe55efSEd Tanous { 630b01bf299SEd Tanous auto valueIt = interfaceProperties->second.find(std::get<1>(p)); 631b01bf299SEd Tanous if (valueIt != interfaceProperties->second.end()) 6321abe55efSEd Tanous { 633b01bf299SEd Tanous const SensorVariant& valueVariant = valueIt->second; 634b01bf299SEd Tanous nlohmann::json& valueIt = sensor_json[std::get<2>(p)]; 63508777fb0SLewanczyk, Dawid // Attempt to pull the int64 directly 636abf2add6SEd Tanous const int64_t* int64Value = std::get_if<int64_t>(&valueVariant); 63708777fb0SLewanczyk, Dawid 638abf2add6SEd Tanous const double* doubleValue = std::get_if<double>(&valueVariant); 639028f7ebcSEddie James const uint32_t* uValue = std::get_if<uint32_t>(&valueVariant); 6406f6d0d32SEd Tanous double temp = 0.0; 6416f6d0d32SEd Tanous if (int64Value != nullptr) 6421abe55efSEd Tanous { 6436f6d0d32SEd Tanous temp = *int64Value; 6446f6d0d32SEd Tanous } 6456f6d0d32SEd Tanous else if (doubleValue != nullptr) 6461abe55efSEd Tanous { 6476f6d0d32SEd Tanous temp = *doubleValue; 6481abe55efSEd Tanous } 649028f7ebcSEddie James else if (uValue != nullptr) 650028f7ebcSEddie James { 651028f7ebcSEddie James temp = *uValue; 652028f7ebcSEddie James } 6531abe55efSEd Tanous else 6541abe55efSEd Tanous { 6556f6d0d32SEd Tanous BMCWEB_LOG_ERROR 6566f6d0d32SEd Tanous << "Got value interface that wasn't int or double"; 6576f6d0d32SEd Tanous continue; 65808777fb0SLewanczyk, Dawid } 6596f6d0d32SEd Tanous temp = temp * std::pow(10, scaleMultiplier); 6606f6d0d32SEd Tanous if (forceToInt) 6616f6d0d32SEd Tanous { 662b01bf299SEd Tanous valueIt = static_cast<int64_t>(temp); 6636f6d0d32SEd Tanous } 6646f6d0d32SEd Tanous else 6656f6d0d32SEd Tanous { 666b01bf299SEd Tanous valueIt = temp; 66708777fb0SLewanczyk, Dawid } 66808777fb0SLewanczyk, Dawid } 66908777fb0SLewanczyk, Dawid } 67008777fb0SLewanczyk, Dawid } 67155c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "Added sensor " << sensorName; 67208777fb0SLewanczyk, Dawid } 67308777fb0SLewanczyk, Dawid 6748bd25ccdSJames Feist static void 6758bd25ccdSJames Feist populateFanRedundancy(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp) 6768bd25ccdSJames Feist { 6778bd25ccdSJames Feist crow::connections::systemBus->async_method_call( 6788bd25ccdSJames Feist [sensorsAsyncResp](const boost::system::error_code ec, 6798bd25ccdSJames Feist const GetSubTreeType& resp) { 6808bd25ccdSJames Feist if (ec) 6818bd25ccdSJames Feist { 6828bd25ccdSJames Feist return; // don't have to have this interface 6838bd25ccdSJames Feist } 684e278c18fSEd Tanous for (const std::pair<std::string, 685e278c18fSEd Tanous std::vector<std::pair< 686e278c18fSEd Tanous std::string, std::vector<std::string>>>>& 687e278c18fSEd Tanous pathPair : resp) 6888bd25ccdSJames Feist { 689e278c18fSEd Tanous const std::string& path = pathPair.first; 690e278c18fSEd Tanous const std::vector< 691e278c18fSEd Tanous std::pair<std::string, std::vector<std::string>>>& objDict = 692e278c18fSEd Tanous pathPair.second; 6938bd25ccdSJames Feist if (objDict.empty()) 6948bd25ccdSJames Feist { 6958bd25ccdSJames Feist continue; // this should be impossible 6968bd25ccdSJames Feist } 6978bd25ccdSJames Feist 6988bd25ccdSJames Feist const std::string& owner = objDict.begin()->first; 6998bd25ccdSJames Feist crow::connections::systemBus->async_method_call( 7008bd25ccdSJames Feist [path, owner, 7018bd25ccdSJames Feist sensorsAsyncResp](const boost::system::error_code ec, 7028bd25ccdSJames Feist std::variant<std::vector<std::string>> 7038bd25ccdSJames Feist variantEndpoints) { 7048bd25ccdSJames Feist if (ec) 7058bd25ccdSJames Feist { 7068bd25ccdSJames Feist return; // if they don't have an association we 7078bd25ccdSJames Feist // can't tell what chassis is 7088bd25ccdSJames Feist } 7098bd25ccdSJames Feist // verify part of the right chassis 7108bd25ccdSJames Feist auto endpoints = std::get_if<std::vector<std::string>>( 7118bd25ccdSJames Feist &variantEndpoints); 7128bd25ccdSJames Feist 7138bd25ccdSJames Feist if (endpoints == nullptr) 7148bd25ccdSJames Feist { 7158bd25ccdSJames Feist BMCWEB_LOG_ERROR << "Invalid association interface"; 7168bd25ccdSJames Feist messages::internalError(sensorsAsyncResp->res); 7178bd25ccdSJames Feist return; 7188bd25ccdSJames Feist } 7198bd25ccdSJames Feist 7208bd25ccdSJames Feist auto found = std::find_if( 7218bd25ccdSJames Feist endpoints->begin(), endpoints->end(), 7228bd25ccdSJames Feist [sensorsAsyncResp](const std::string& entry) { 7238bd25ccdSJames Feist return entry.find( 7248bd25ccdSJames Feist sensorsAsyncResp->chassisId) != 7258bd25ccdSJames Feist std::string::npos; 7268bd25ccdSJames Feist }); 7278bd25ccdSJames Feist 7288bd25ccdSJames Feist if (found == endpoints->end()) 7298bd25ccdSJames Feist { 7308bd25ccdSJames Feist return; 7318bd25ccdSJames Feist } 7328bd25ccdSJames Feist crow::connections::systemBus->async_method_call( 7338bd25ccdSJames Feist [path, sensorsAsyncResp]( 7348bd25ccdSJames Feist const boost::system::error_code ec, 7358bd25ccdSJames Feist const boost::container::flat_map< 7368bd25ccdSJames Feist std::string, 7378bd25ccdSJames Feist std::variant<uint8_t, 7388bd25ccdSJames Feist std::vector<std::string>, 7398bd25ccdSJames Feist std::string>>& ret) { 7408bd25ccdSJames Feist if (ec) 7418bd25ccdSJames Feist { 7428bd25ccdSJames Feist return; // don't have to have this 7438bd25ccdSJames Feist // interface 7448bd25ccdSJames Feist } 7458bd25ccdSJames Feist auto findFailures = ret.find("AllowedFailures"); 7468bd25ccdSJames Feist auto findCollection = ret.find("Collection"); 7478bd25ccdSJames Feist auto findStatus = ret.find("Status"); 7488bd25ccdSJames Feist 7498bd25ccdSJames Feist if (findFailures == ret.end() || 7508bd25ccdSJames Feist findCollection == ret.end() || 7518bd25ccdSJames Feist findStatus == ret.end()) 7528bd25ccdSJames Feist { 7538bd25ccdSJames Feist BMCWEB_LOG_ERROR 7548bd25ccdSJames Feist << "Invalid redundancy interface"; 7558bd25ccdSJames Feist messages::internalError( 7568bd25ccdSJames Feist sensorsAsyncResp->res); 7578bd25ccdSJames Feist return; 7588bd25ccdSJames Feist } 7598bd25ccdSJames Feist 7608bd25ccdSJames Feist auto allowedFailures = std::get_if<uint8_t>( 7618bd25ccdSJames Feist &(findFailures->second)); 7628bd25ccdSJames Feist auto collection = 7638bd25ccdSJames Feist std::get_if<std::vector<std::string>>( 7648bd25ccdSJames Feist &(findCollection->second)); 7658bd25ccdSJames Feist auto status = std::get_if<std::string>( 7668bd25ccdSJames Feist &(findStatus->second)); 7678bd25ccdSJames Feist 7688bd25ccdSJames Feist if (allowedFailures == nullptr || 7698bd25ccdSJames Feist collection == nullptr || status == nullptr) 7708bd25ccdSJames Feist { 7718bd25ccdSJames Feist 7728bd25ccdSJames Feist BMCWEB_LOG_ERROR 7738bd25ccdSJames Feist << "Invalid redundancy interface " 7748bd25ccdSJames Feist "types"; 7758bd25ccdSJames Feist messages::internalError( 7768bd25ccdSJames Feist sensorsAsyncResp->res); 7778bd25ccdSJames Feist return; 7788bd25ccdSJames Feist } 7798bd25ccdSJames Feist size_t lastSlash = path.rfind("/"); 7808bd25ccdSJames Feist if (lastSlash == std::string::npos) 7818bd25ccdSJames Feist { 7828bd25ccdSJames Feist // this should be impossible 7838bd25ccdSJames Feist messages::internalError( 7848bd25ccdSJames Feist sensorsAsyncResp->res); 7858bd25ccdSJames Feist return; 7868bd25ccdSJames Feist } 7878bd25ccdSJames Feist std::string name = path.substr(lastSlash + 1); 7888bd25ccdSJames Feist std::replace(name.begin(), name.end(), '_', 7898bd25ccdSJames Feist ' '); 7908bd25ccdSJames Feist 7918bd25ccdSJames Feist std::string health; 7928bd25ccdSJames Feist 7938bd25ccdSJames Feist if (boost::ends_with(*status, "Full")) 7948bd25ccdSJames Feist { 7958bd25ccdSJames Feist health = "OK"; 7968bd25ccdSJames Feist } 7978bd25ccdSJames Feist else if (boost::ends_with(*status, "Degraded")) 7988bd25ccdSJames Feist { 7998bd25ccdSJames Feist health = "Warning"; 8008bd25ccdSJames Feist } 8018bd25ccdSJames Feist else 8028bd25ccdSJames Feist { 8038bd25ccdSJames Feist health = "Critical"; 8048bd25ccdSJames Feist } 8058bd25ccdSJames Feist std::vector<nlohmann::json> redfishCollection; 8068bd25ccdSJames Feist const auto& fanRedfish = 8078bd25ccdSJames Feist sensorsAsyncResp->res.jsonValue["Fans"]; 8088bd25ccdSJames Feist for (const std::string& item : *collection) 8098bd25ccdSJames Feist { 8108bd25ccdSJames Feist lastSlash = item.rfind("/"); 8118bd25ccdSJames Feist // make a copy as collection is const 8128bd25ccdSJames Feist std::string itemName = 8138bd25ccdSJames Feist item.substr(lastSlash + 1); 8148bd25ccdSJames Feist /* 8158bd25ccdSJames Feist todo(ed): merge patch that fixes the names 8168bd25ccdSJames Feist std::replace(itemName.begin(), 8178bd25ccdSJames Feist itemName.end(), '_', ' ');*/ 8188bd25ccdSJames Feist auto schemaItem = std::find_if( 8198bd25ccdSJames Feist fanRedfish.begin(), fanRedfish.end(), 8208bd25ccdSJames Feist [itemName](const nlohmann::json& fan) { 8218bd25ccdSJames Feist return fan["MemberId"] == itemName; 8228bd25ccdSJames Feist }); 8238bd25ccdSJames Feist if (schemaItem != fanRedfish.end()) 8248bd25ccdSJames Feist { 8258bd25ccdSJames Feist redfishCollection.push_back( 8268bd25ccdSJames Feist {{"@odata.id", 8278bd25ccdSJames Feist (*schemaItem)["@odata.id"]}}); 8288bd25ccdSJames Feist } 8298bd25ccdSJames Feist else 8308bd25ccdSJames Feist { 8318bd25ccdSJames Feist BMCWEB_LOG_ERROR 8328bd25ccdSJames Feist << "failed to find fan in schema"; 8338bd25ccdSJames Feist messages::internalError( 8348bd25ccdSJames Feist sensorsAsyncResp->res); 8358bd25ccdSJames Feist return; 8368bd25ccdSJames Feist } 8378bd25ccdSJames Feist } 8388bd25ccdSJames Feist 8398bd25ccdSJames Feist auto& resp = sensorsAsyncResp->res 8408bd25ccdSJames Feist .jsonValue["Redundancy"]; 8418bd25ccdSJames Feist resp.push_back( 8428bd25ccdSJames Feist {{"@odata.id", 8438bd25ccdSJames Feist "/refish/v1/Chassis/" + 8448bd25ccdSJames Feist sensorsAsyncResp->chassisId + "/" + 8458bd25ccdSJames Feist sensorsAsyncResp->chassisSubNode + 8468bd25ccdSJames Feist "#/Redundancy/" + 8478bd25ccdSJames Feist std::to_string(resp.size())}, 8488bd25ccdSJames Feist {"@odata.type", 8498bd25ccdSJames Feist "#Redundancy.v1_3_2.Redundancy"}, 8508bd25ccdSJames Feist {"MinNumNeeded", 8518bd25ccdSJames Feist collection->size() - *allowedFailures}, 8528bd25ccdSJames Feist {"MemberId", name}, 8538bd25ccdSJames Feist {"Mode", "N+m"}, 8548bd25ccdSJames Feist {"Name", name}, 8558bd25ccdSJames Feist {"RedundancySet", redfishCollection}, 8568bd25ccdSJames Feist {"Status", 8578bd25ccdSJames Feist {{"Health", health}, 8588bd25ccdSJames Feist {"State", "Enabled"}}}}); 8598bd25ccdSJames Feist }, 8608bd25ccdSJames Feist owner, path, "org.freedesktop.DBus.Properties", 8618bd25ccdSJames Feist "GetAll", 8628bd25ccdSJames Feist "xyz.openbmc_project.Control.FanRedundancy"); 8638bd25ccdSJames Feist }, 864*02e92e32SJames Feist "xyz.openbmc_project.ObjectMapper", path + "/chassis", 8658bd25ccdSJames Feist "org.freedesktop.DBus.Properties", "Get", 8668bd25ccdSJames Feist "xyz.openbmc_project.Association", "endpoints"); 8678bd25ccdSJames Feist } 8688bd25ccdSJames Feist }, 8698bd25ccdSJames Feist "xyz.openbmc_project.ObjectMapper", 8708bd25ccdSJames Feist "/xyz/openbmc_project/object_mapper", 8718bd25ccdSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", 8728bd25ccdSJames Feist "/xyz/openbmc_project/control", 2, 8738bd25ccdSJames Feist std::array<const char*, 1>{ 8748bd25ccdSJames Feist "xyz.openbmc_project.Control.FanRedundancy"}); 8758bd25ccdSJames Feist } 8768bd25ccdSJames Feist 87749c53ac9SJohnathan Mantey void sortJSONResponse(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp) 87849c53ac9SJohnathan Mantey { 87949c53ac9SJohnathan Mantey nlohmann::json& response = SensorsAsyncResp->res.jsonValue; 88049c53ac9SJohnathan Mantey std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"}; 88149c53ac9SJohnathan Mantey if (SensorsAsyncResp->chassisSubNode == "Power") 88249c53ac9SJohnathan Mantey { 88349c53ac9SJohnathan Mantey sensorHeaders = {"Voltages", "PowerSupplies"}; 88449c53ac9SJohnathan Mantey } 88549c53ac9SJohnathan Mantey for (const std::string& sensorGroup : sensorHeaders) 88649c53ac9SJohnathan Mantey { 88749c53ac9SJohnathan Mantey nlohmann::json::iterator entry = response.find(sensorGroup); 88849c53ac9SJohnathan Mantey if (entry != response.end()) 88949c53ac9SJohnathan Mantey { 89049c53ac9SJohnathan Mantey std::sort(entry->begin(), entry->end(), 89149c53ac9SJohnathan Mantey [](nlohmann::json& c1, nlohmann::json& c2) { 89249c53ac9SJohnathan Mantey return c1["Name"] < c2["Name"]; 89349c53ac9SJohnathan Mantey }); 89449c53ac9SJohnathan Mantey 89549c53ac9SJohnathan Mantey // add the index counts to the end of each entry 89649c53ac9SJohnathan Mantey size_t count = 0; 89749c53ac9SJohnathan Mantey for (nlohmann::json& sensorJson : *entry) 89849c53ac9SJohnathan Mantey { 89949c53ac9SJohnathan Mantey nlohmann::json::iterator odata = sensorJson.find("@odata.id"); 90049c53ac9SJohnathan Mantey if (odata == sensorJson.end()) 90149c53ac9SJohnathan Mantey { 90249c53ac9SJohnathan Mantey continue; 90349c53ac9SJohnathan Mantey } 90449c53ac9SJohnathan Mantey std::string* value = odata->get_ptr<std::string*>(); 90549c53ac9SJohnathan Mantey if (value != nullptr) 90649c53ac9SJohnathan Mantey { 90749c53ac9SJohnathan Mantey *value += std::to_string(count); 90849c53ac9SJohnathan Mantey count++; 90949c53ac9SJohnathan Mantey } 91049c53ac9SJohnathan Mantey } 91149c53ac9SJohnathan Mantey } 91249c53ac9SJohnathan Mantey } 91349c53ac9SJohnathan Mantey } 91449c53ac9SJohnathan Mantey 91508777fb0SLewanczyk, Dawid /** 9168fb49dd6SShawn McCarney * @brief Finds the JSON object for the specified sensor. 9178fb49dd6SShawn McCarney * 9188fb49dd6SShawn McCarney * Searches the JSON response in sensorsAsyncResp for an object corresponding to 9198fb49dd6SShawn McCarney * the specified sensor. 9208fb49dd6SShawn McCarney * 9218fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 9228fb49dd6SShawn McCarney * @param sensorName DBus object path to the sensor. 9238fb49dd6SShawn McCarney * @return Pointer to JSON object, or nullptr if object not found. 9248fb49dd6SShawn McCarney */ 9258fb49dd6SShawn McCarney static nlohmann::json* 9268fb49dd6SShawn McCarney findSensorJson(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 9278fb49dd6SShawn McCarney const std::string& sensorName) 9288fb49dd6SShawn McCarney { 9298fb49dd6SShawn McCarney // Get base name of sensor 9308fb49dd6SShawn McCarney std::size_t lastSlash = sensorName.rfind('/'); 9318fb49dd6SShawn McCarney if (lastSlash != std::string::npos) 9328fb49dd6SShawn McCarney { 9338fb49dd6SShawn McCarney std::string baseSensorName = sensorName.substr(lastSlash + 1); 9348fb49dd6SShawn McCarney 9358fb49dd6SShawn McCarney // Loop through JSON sensor groups that could contain sensor 9368fb49dd6SShawn McCarney nlohmann::json& response = sensorsAsyncResp->res.jsonValue; 9378fb49dd6SShawn McCarney std::array<std::string, 4> sensorGroups{"Temperatures", "Fans", 9388fb49dd6SShawn McCarney "Voltages", "PowerSupplies"}; 9398fb49dd6SShawn McCarney for (const std::string& sensorGroup : sensorGroups) 9408fb49dd6SShawn McCarney { 9418fb49dd6SShawn McCarney nlohmann::json::iterator groupIt = response.find(sensorGroup); 9428fb49dd6SShawn McCarney if (groupIt != response.end()) 9438fb49dd6SShawn McCarney { 9448fb49dd6SShawn McCarney // Loop through sensors in current group 9458fb49dd6SShawn McCarney for (nlohmann::json& sensorJson : *groupIt) 9468fb49dd6SShawn McCarney { 9478fb49dd6SShawn McCarney // Check if this is the sensor we are looking for 9488fb49dd6SShawn McCarney nlohmann::json::iterator memberIdIt = 9498fb49dd6SShawn McCarney sensorJson.find("MemberId"); 9508fb49dd6SShawn McCarney if (memberIdIt != sensorJson.end()) 9518fb49dd6SShawn McCarney { 9528fb49dd6SShawn McCarney std::string* memberId = 9538fb49dd6SShawn McCarney memberIdIt->get_ptr<std::string*>(); 9548fb49dd6SShawn McCarney if ((memberId != nullptr) && 9558fb49dd6SShawn McCarney (*memberId == baseSensorName)) 9568fb49dd6SShawn McCarney { 9578fb49dd6SShawn McCarney return &sensorJson; 9588fb49dd6SShawn McCarney } 9598fb49dd6SShawn McCarney } 9608fb49dd6SShawn McCarney } 9618fb49dd6SShawn McCarney } 9628fb49dd6SShawn McCarney } 9638fb49dd6SShawn McCarney } 9648fb49dd6SShawn McCarney 9658fb49dd6SShawn McCarney // Unable to find JSON object for specified sensor 9668fb49dd6SShawn McCarney return nullptr; 9678fb49dd6SShawn McCarney } 9688fb49dd6SShawn McCarney 9698fb49dd6SShawn McCarney /** 9708fb49dd6SShawn McCarney * @brief Updates sensor status in JSON response based on inventory item status. 9718fb49dd6SShawn McCarney * 9728fb49dd6SShawn McCarney * Updates the status of the specified sensor based on the status of a related 9738fb49dd6SShawn McCarney * inventory item. 9748fb49dd6SShawn McCarney * 9758fb49dd6SShawn McCarney * Modifies the Redfish Status property in the JSON response if the inventory 9768fb49dd6SShawn McCarney * item indicates the hardware is not present or not functional. 9778fb49dd6SShawn McCarney * 9788fb49dd6SShawn McCarney * The D-Bus Present and Functional properties are typically on the inventory 9798fb49dd6SShawn McCarney * item rather than the sensor. 9808fb49dd6SShawn McCarney * 9818fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 9828fb49dd6SShawn McCarney * @param sensorName DBus object path to the sensor. 9838fb49dd6SShawn McCarney * @param interfacesDict Map containing the interfaces and properties of the 9848fb49dd6SShawn McCarney * inventory item associated with this sensor. 9858fb49dd6SShawn McCarney */ 9868fb49dd6SShawn McCarney static void updateSensorStatus( 9878fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 9888fb49dd6SShawn McCarney const std::string& sensorName, 9898fb49dd6SShawn McCarney const boost::container::flat_map< 9908fb49dd6SShawn McCarney std::string, boost::container::flat_map<std::string, SensorVariant>>& 9918fb49dd6SShawn McCarney interfacesDict) 9928fb49dd6SShawn McCarney { 9938fb49dd6SShawn McCarney // Find the JSON object in the response for this sensor 9948fb49dd6SShawn McCarney nlohmann::json* sensorJson = findSensorJson(sensorsAsyncResp, sensorName); 9958fb49dd6SShawn McCarney if (sensorJson != nullptr) 9968fb49dd6SShawn McCarney { 9978fb49dd6SShawn McCarney // Get Inventory.Item.Present property of inventory item 9988fb49dd6SShawn McCarney auto itemIt = interfacesDict.find("xyz.openbmc_project.Inventory.Item"); 9998fb49dd6SShawn McCarney if (itemIt != interfacesDict.end()) 10008fb49dd6SShawn McCarney { 10018fb49dd6SShawn McCarney auto presentIt = itemIt->second.find("Present"); 10028fb49dd6SShawn McCarney if (presentIt != itemIt->second.end()) 10038fb49dd6SShawn McCarney { 10048fb49dd6SShawn McCarney const bool* present = std::get_if<bool>(&presentIt->second); 10058fb49dd6SShawn McCarney if ((present != nullptr) && (*present == false)) 10068fb49dd6SShawn McCarney { 10078fb49dd6SShawn McCarney // Inventory item is not present; update sensor State 10088fb49dd6SShawn McCarney (*sensorJson)["Status"]["State"] = "Absent"; 10098fb49dd6SShawn McCarney } 10108fb49dd6SShawn McCarney } 10118fb49dd6SShawn McCarney } 10128fb49dd6SShawn McCarney 10138fb49dd6SShawn McCarney // Get OperationalStatus.Functional property of inventory item 10148fb49dd6SShawn McCarney auto opStatusIt = interfacesDict.find( 10158fb49dd6SShawn McCarney "xyz.openbmc_project.State.Decorator.OperationalStatus"); 10168fb49dd6SShawn McCarney if (opStatusIt != interfacesDict.end()) 10178fb49dd6SShawn McCarney { 10188fb49dd6SShawn McCarney auto functionalIt = opStatusIt->second.find("Functional"); 10198fb49dd6SShawn McCarney if (functionalIt != opStatusIt->second.end()) 10208fb49dd6SShawn McCarney { 10218fb49dd6SShawn McCarney const bool* functional = 10228fb49dd6SShawn McCarney std::get_if<bool>(&functionalIt->second); 10238fb49dd6SShawn McCarney if ((functional != nullptr) && (*functional == false)) 10248fb49dd6SShawn McCarney { 10258fb49dd6SShawn McCarney // Inventory item is not functional; update sensor Health 10268fb49dd6SShawn McCarney (*sensorJson)["Status"]["Health"] = "Critical"; 10278fb49dd6SShawn McCarney } 10288fb49dd6SShawn McCarney } 10298fb49dd6SShawn McCarney } 10308fb49dd6SShawn McCarney } 10318fb49dd6SShawn McCarney } 10328fb49dd6SShawn McCarney 10338fb49dd6SShawn McCarney /** 10348fb49dd6SShawn McCarney * @brief Gets status of inventory items associated with sensors. 10358fb49dd6SShawn McCarney * 10368fb49dd6SShawn McCarney * Gets the D-Bus status properties for the inventory items associated with 10378fb49dd6SShawn McCarney * sensors. 10388fb49dd6SShawn McCarney * 10398fb49dd6SShawn McCarney * Updates the Redfish sensors status in the JSON response, if needed, based on 10408fb49dd6SShawn McCarney * the inventory items status. 10418fb49dd6SShawn McCarney * 10428fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 10438fb49dd6SShawn McCarney * @param sensorToInvMap Mappings from sensor object path to the associated 10448fb49dd6SShawn McCarney * inventory object path. 10458fb49dd6SShawn McCarney * @param invConnections Connections that provide the status 10468fb49dd6SShawn McCarney * interfaces/properties for the inventory items. 10478fb49dd6SShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 10488fb49dd6SShawn McCarney * implements ObjectManager. 10498fb49dd6SShawn McCarney */ 10508fb49dd6SShawn McCarney static void getInventoryItemsStatus( 10518fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 10528fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 10538fb49dd6SShawn McCarney sensorToInvMap, 10548fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_set<std::string>> invConnections, 10558fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 10568fb49dd6SShawn McCarney objectMgrPaths) 10578fb49dd6SShawn McCarney { 10588fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsStatus enter"; 10598fb49dd6SShawn McCarney 10608fb49dd6SShawn McCarney // Loop through all connections providing inventory item status 10618fb49dd6SShawn McCarney for (const std::string& invConnection : *invConnections) 10628fb49dd6SShawn McCarney { 10638fb49dd6SShawn McCarney // Response handler for GetManagedObjects 10648fb49dd6SShawn McCarney auto respHandler = [sensorsAsyncResp, 10658fb49dd6SShawn McCarney sensorToInvMap](const boost::system::error_code ec, 10668fb49dd6SShawn McCarney ManagedObjectsVectorType& resp) { 10678fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsStatus respHandler enter"; 10688fb49dd6SShawn McCarney if (ec) 10698fb49dd6SShawn McCarney { 10708fb49dd6SShawn McCarney BMCWEB_LOG_ERROR 10718fb49dd6SShawn McCarney << "getInventoryItemsStatus respHandler DBus error " << ec; 10728fb49dd6SShawn McCarney messages::internalError(sensorsAsyncResp->res); 10738fb49dd6SShawn McCarney return; 10748fb49dd6SShawn McCarney } 10758fb49dd6SShawn McCarney 10768fb49dd6SShawn McCarney // Loop through returned object paths 10778fb49dd6SShawn McCarney for (const auto& objDictEntry : resp) 10788fb49dd6SShawn McCarney { 10798fb49dd6SShawn McCarney const std::string& objPath = 10808fb49dd6SShawn McCarney static_cast<const std::string&>(objDictEntry.first); 10818fb49dd6SShawn McCarney 10828fb49dd6SShawn McCarney // Find all sensors associated with this inventory item 10838fb49dd6SShawn McCarney for (const std::pair<std::string, std::string>& pair : 10848fb49dd6SShawn McCarney *sensorToInvMap) 10858fb49dd6SShawn McCarney { 10868fb49dd6SShawn McCarney if (pair.second == objPath) 10878fb49dd6SShawn McCarney { 10888fb49dd6SShawn McCarney // Update sensor status based on inventory item status 10898fb49dd6SShawn McCarney updateSensorStatus(sensorsAsyncResp, pair.first, 10908fb49dd6SShawn McCarney objDictEntry.second); 10918fb49dd6SShawn McCarney } 10928fb49dd6SShawn McCarney } 10938fb49dd6SShawn McCarney } 10948fb49dd6SShawn McCarney 10958fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsStatus respHandler exit"; 10968fb49dd6SShawn McCarney }; 10978fb49dd6SShawn McCarney 10988fb49dd6SShawn McCarney // Find DBus object path that implements ObjectManager for the current 10998fb49dd6SShawn McCarney // connection. If no mapping found, default to "/". 11008fb49dd6SShawn McCarney auto iter = objectMgrPaths->find(invConnection); 11018fb49dd6SShawn McCarney const std::string& objectMgrPath = 11028fb49dd6SShawn McCarney (iter != objectMgrPaths->end()) ? iter->second : "/"; 11038fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "ObjectManager path for " << invConnection << " is " 11048fb49dd6SShawn McCarney << objectMgrPath; 11058fb49dd6SShawn McCarney 11068fb49dd6SShawn McCarney // Get all object paths and their interfaces for current connection 11078fb49dd6SShawn McCarney crow::connections::systemBus->async_method_call( 11088fb49dd6SShawn McCarney std::move(respHandler), invConnection, objectMgrPath, 11098fb49dd6SShawn McCarney "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 11108fb49dd6SShawn McCarney } 11118fb49dd6SShawn McCarney 11128fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsStatus exit"; 11138fb49dd6SShawn McCarney } 11148fb49dd6SShawn McCarney 11158fb49dd6SShawn McCarney /** 11168fb49dd6SShawn McCarney * @brief Gets connections that provide status information on inventory items. 11178fb49dd6SShawn McCarney * 11188fb49dd6SShawn McCarney * Gets the D-Bus connections (services) that provide the interfaces and 11198fb49dd6SShawn McCarney * properties containing status information for the inventory items. 11208fb49dd6SShawn McCarney * 11218fb49dd6SShawn McCarney * Finds the connections asynchronously. Invokes callback when information has 11228fb49dd6SShawn McCarney * been obtained. 11238fb49dd6SShawn McCarney * 11248fb49dd6SShawn McCarney * The callback must have the following signature: 11258fb49dd6SShawn McCarney * @code 11268fb49dd6SShawn McCarney * callback(std::shared_ptr<boost::container::flat_set<std::string>> 11278fb49dd6SShawn McCarney * invConnections) 11288fb49dd6SShawn McCarney * @endcode 11298fb49dd6SShawn McCarney * 11308fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 11318fb49dd6SShawn McCarney * @param sensorToInvMap Mappings from sensor object path to the associated 11328fb49dd6SShawn McCarney * inventory object path. 11338fb49dd6SShawn McCarney * @param callback Callback to invoke when connections have been obtained. 11348fb49dd6SShawn McCarney */ 11358fb49dd6SShawn McCarney template <typename Callback> 11368fb49dd6SShawn McCarney static void getInventoryItemsConnections( 11378fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 11388fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 11398fb49dd6SShawn McCarney sensorToInvMap, 11408fb49dd6SShawn McCarney Callback&& callback) 11418fb49dd6SShawn McCarney { 11428fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections enter"; 11438fb49dd6SShawn McCarney 11448fb49dd6SShawn McCarney const std::string path = "/xyz/openbmc_project/inventory"; 11458fb49dd6SShawn McCarney const std::array<std::string, 2> interfaces = { 11468fb49dd6SShawn McCarney "xyz.openbmc_project.Inventory.Item", 11478fb49dd6SShawn McCarney "xyz.openbmc_project.State.Decorator.OperationalStatus"}; 11488fb49dd6SShawn McCarney 11498fb49dd6SShawn McCarney // Response handler for parsing output from GetSubTree 11508fb49dd6SShawn McCarney auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp, 11518fb49dd6SShawn McCarney sensorToInvMap](const boost::system::error_code ec, 11528fb49dd6SShawn McCarney const GetSubTreeType& subtree) { 11538fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler enter"; 11548fb49dd6SShawn McCarney if (ec) 11558fb49dd6SShawn McCarney { 11568fb49dd6SShawn McCarney messages::internalError(sensorsAsyncResp->res); 11578fb49dd6SShawn McCarney BMCWEB_LOG_ERROR 11588fb49dd6SShawn McCarney << "getInventoryItemsConnections respHandler DBus error " << ec; 11598fb49dd6SShawn McCarney return; 11608fb49dd6SShawn McCarney } 11618fb49dd6SShawn McCarney 11628fb49dd6SShawn McCarney // Make unique list of connections for desired inventory items 11638fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_set<std::string>> 11648fb49dd6SShawn McCarney invConnections = 11658fb49dd6SShawn McCarney std::make_shared<boost::container::flat_set<std::string>>(); 11668fb49dd6SShawn McCarney invConnections->reserve(8); 11678fb49dd6SShawn McCarney 11688fb49dd6SShawn McCarney // Loop through objects from GetSubTree 11698fb49dd6SShawn McCarney for (const std::pair< 11708fb49dd6SShawn McCarney std::string, 11718fb49dd6SShawn McCarney std::vector<std::pair<std::string, std::vector<std::string>>>>& 11728fb49dd6SShawn McCarney object : subtree) 11738fb49dd6SShawn McCarney { 11748fb49dd6SShawn McCarney // Look for inventory item object path in the sensor->inventory map 11758fb49dd6SShawn McCarney const std::string& objPath = object.first; 11768fb49dd6SShawn McCarney for (const std::pair<std::string, std::string>& pair : 11778fb49dd6SShawn McCarney *sensorToInvMap) 11788fb49dd6SShawn McCarney { 11798fb49dd6SShawn McCarney if (pair.second == objPath) 11808fb49dd6SShawn McCarney { 11818fb49dd6SShawn McCarney // Store all connections to inventory item 11828fb49dd6SShawn McCarney for (const std::pair<std::string, std::vector<std::string>>& 11838fb49dd6SShawn McCarney objData : object.second) 11848fb49dd6SShawn McCarney { 11858fb49dd6SShawn McCarney const std::string& invConnection = objData.first; 11868fb49dd6SShawn McCarney invConnections->insert(invConnection); 11878fb49dd6SShawn McCarney } 11888fb49dd6SShawn McCarney break; 11898fb49dd6SShawn McCarney } 11908fb49dd6SShawn McCarney } 11918fb49dd6SShawn McCarney } 11928fb49dd6SShawn McCarney callback(invConnections); 11938fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit"; 11948fb49dd6SShawn McCarney }; 11958fb49dd6SShawn McCarney 11968fb49dd6SShawn McCarney // Make call to ObjectMapper to find all inventory items 11978fb49dd6SShawn McCarney crow::connections::systemBus->async_method_call( 11988fb49dd6SShawn McCarney std::move(respHandler), "xyz.openbmc_project.ObjectMapper", 11998fb49dd6SShawn McCarney "/xyz/openbmc_project/object_mapper", 12008fb49dd6SShawn McCarney "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces); 12018fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections exit"; 12028fb49dd6SShawn McCarney } 12038fb49dd6SShawn McCarney 12048fb49dd6SShawn McCarney /** 12058fb49dd6SShawn McCarney * @brief Gets inventory items associated with the specified sensors. 12068fb49dd6SShawn McCarney * 12078fb49dd6SShawn McCarney * Looks for ObjectMapper associations from the specified sensors to related 12088fb49dd6SShawn McCarney * inventory items. Builds map where key is sensor object path and value is 12098fb49dd6SShawn McCarney * inventory item object path. 12108fb49dd6SShawn McCarney * 12118fb49dd6SShawn McCarney * Finds the inventory items asynchronously. Invokes callback when information 12128fb49dd6SShawn McCarney * has been obtained. 12138fb49dd6SShawn McCarney * 12148fb49dd6SShawn McCarney * The callback must have the following signature: 12158fb49dd6SShawn McCarney * @code 12168fb49dd6SShawn McCarney * callback(std::shared_ptr<boost::container::flat_map< 12178fb49dd6SShawn McCarney std::string, std::string>> sensorToInvMap) 12188fb49dd6SShawn McCarney * @endcode 12198fb49dd6SShawn McCarney * 12208fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 12218fb49dd6SShawn McCarney * @param sensorNames All sensors within the current chassis. 12228fb49dd6SShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 12238fb49dd6SShawn McCarney * implements ObjectManager. 12248fb49dd6SShawn McCarney * @param callback Callback to invoke when inventory items have been obtained. 12258fb49dd6SShawn McCarney */ 12268fb49dd6SShawn McCarney template <typename Callback> 12278fb49dd6SShawn McCarney static void getInventoryItems( 12288fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 12298fb49dd6SShawn McCarney const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 12308fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 12318fb49dd6SShawn McCarney objectMgrPaths, 12328fb49dd6SShawn McCarney Callback&& callback) 12338fb49dd6SShawn McCarney { 12348fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems enter"; 12358fb49dd6SShawn McCarney 12368fb49dd6SShawn McCarney // Response handler for GetManagedObjects 12378fb49dd6SShawn McCarney auto respHandler = [callback{std::move(callback)}, sensorsAsyncResp, 12388fb49dd6SShawn McCarney sensorNames](const boost::system::error_code ec, 12398fb49dd6SShawn McCarney dbus::utility::ManagedObjectType& resp) { 12408fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems respHandler enter"; 12418fb49dd6SShawn McCarney if (ec) 12428fb49dd6SShawn McCarney { 12438fb49dd6SShawn McCarney BMCWEB_LOG_ERROR << "getInventoryItems respHandler DBus error " 12448fb49dd6SShawn McCarney << ec; 12458fb49dd6SShawn McCarney messages::internalError(sensorsAsyncResp->res); 12468fb49dd6SShawn McCarney return; 12478fb49dd6SShawn McCarney } 12488fb49dd6SShawn McCarney 12498fb49dd6SShawn McCarney // Loop through returned object paths 12508fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 12518fb49dd6SShawn McCarney sensorToInvMap = std::make_shared< 12528fb49dd6SShawn McCarney boost::container::flat_map<std::string, std::string>>(); 12538fb49dd6SShawn McCarney std::string sensorAssocPath; 12548fb49dd6SShawn McCarney sensorAssocPath.reserve(128); // avoid memory allocations 12558fb49dd6SShawn McCarney for (const auto& objDictEntry : resp) 12568fb49dd6SShawn McCarney { 12578fb49dd6SShawn McCarney const std::string& objPath = 12588fb49dd6SShawn McCarney static_cast<const std::string&>(objDictEntry.first); 12598fb49dd6SShawn McCarney const boost::container::flat_map< 12608fb49dd6SShawn McCarney std::string, boost::container::flat_map< 12618fb49dd6SShawn McCarney std::string, dbus::utility::DbusVariantType>>& 12628fb49dd6SShawn McCarney interfacesDict = objDictEntry.second; 12638fb49dd6SShawn McCarney 12648fb49dd6SShawn McCarney // If path is inventory association for one of the specified sensors 12658fb49dd6SShawn McCarney for (const std::string& sensorName : *sensorNames) 12668fb49dd6SShawn McCarney { 12678fb49dd6SShawn McCarney sensorAssocPath = sensorName; 12688fb49dd6SShawn McCarney sensorAssocPath += "/inventory"; 12698fb49dd6SShawn McCarney if (objPath == sensorAssocPath) 12708fb49dd6SShawn McCarney { 12718fb49dd6SShawn McCarney // Get Association interface for object path 12728fb49dd6SShawn McCarney auto assocIt = 12738fb49dd6SShawn McCarney interfacesDict.find("xyz.openbmc_project.Association"); 12748fb49dd6SShawn McCarney if (assocIt != interfacesDict.end()) 12758fb49dd6SShawn McCarney { 12768fb49dd6SShawn McCarney // Get inventory item from end point 12778fb49dd6SShawn McCarney auto endpointsIt = assocIt->second.find("endpoints"); 12788fb49dd6SShawn McCarney if (endpointsIt != assocIt->second.end()) 12798fb49dd6SShawn McCarney { 12808fb49dd6SShawn McCarney const std::vector<std::string>* endpoints = 12818fb49dd6SShawn McCarney std::get_if<std::vector<std::string>>( 12828fb49dd6SShawn McCarney &endpointsIt->second); 12838fb49dd6SShawn McCarney if ((endpoints != nullptr) && !endpoints->empty()) 12848fb49dd6SShawn McCarney { 12858fb49dd6SShawn McCarney // Store sensor -> inventory item mapping 12868fb49dd6SShawn McCarney const std::string& invItem = endpoints->front(); 12878fb49dd6SShawn McCarney (*sensorToInvMap)[sensorName] = invItem; 12888fb49dd6SShawn McCarney } 12898fb49dd6SShawn McCarney } 12908fb49dd6SShawn McCarney } 12918fb49dd6SShawn McCarney break; 12928fb49dd6SShawn McCarney } 12938fb49dd6SShawn McCarney } 12948fb49dd6SShawn McCarney } 12958fb49dd6SShawn McCarney 12968fb49dd6SShawn McCarney // Call callback if at least one inventory item was found 12978fb49dd6SShawn McCarney if (!sensorToInvMap->empty()) 12988fb49dd6SShawn McCarney { 12998fb49dd6SShawn McCarney callback(sensorToInvMap); 13008fb49dd6SShawn McCarney } 13018fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems respHandler exit"; 13028fb49dd6SShawn McCarney }; 13038fb49dd6SShawn McCarney 13048fb49dd6SShawn McCarney // Find DBus object path that implements ObjectManager for ObjectMapper 13058fb49dd6SShawn McCarney std::string connection = "xyz.openbmc_project.ObjectMapper"; 13068fb49dd6SShawn McCarney auto iter = objectMgrPaths->find(connection); 13078fb49dd6SShawn McCarney const std::string& objectMgrPath = 13088fb49dd6SShawn McCarney (iter != objectMgrPaths->end()) ? iter->second : "/"; 13098fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is " 13108fb49dd6SShawn McCarney << objectMgrPath; 13118fb49dd6SShawn McCarney 13128fb49dd6SShawn McCarney // Call GetManagedObjects on the ObjectMapper to get all associations 13138fb49dd6SShawn McCarney crow::connections::systemBus->async_method_call( 13148fb49dd6SShawn McCarney std::move(respHandler), connection, objectMgrPath, 13158fb49dd6SShawn McCarney "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 13168fb49dd6SShawn McCarney 13178fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems exit"; 13188fb49dd6SShawn McCarney } 13198fb49dd6SShawn McCarney 13208fb49dd6SShawn McCarney /** 13218fb49dd6SShawn McCarney * @brief Checks the status of inventory items associated with sensors. 13228fb49dd6SShawn McCarney * 13238fb49dd6SShawn McCarney * Finds the inventory items that are associated with the specified sensors. 13248fb49dd6SShawn McCarney * Gets the status of those inventory items. 13258fb49dd6SShawn McCarney * 13268fb49dd6SShawn McCarney * If the inventory items are not present or functional, the sensor status is 13278fb49dd6SShawn McCarney * updated in the JSON response. 13288fb49dd6SShawn McCarney * 13298fb49dd6SShawn McCarney * In D-Bus, the hardware present and functional properties are typically on the 13308fb49dd6SShawn McCarney * inventory item rather than the sensor. 13318fb49dd6SShawn McCarney * 13328fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 13338fb49dd6SShawn McCarney * @param sensorNames All sensors within the current chassis. 13348fb49dd6SShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 13358fb49dd6SShawn McCarney * implements ObjectManager. 13368fb49dd6SShawn McCarney */ 13378fb49dd6SShawn McCarney static void checkInventoryItemsStatus( 13388fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 13398fb49dd6SShawn McCarney const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 13408fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 13418fb49dd6SShawn McCarney objectMgrPaths) 13428fb49dd6SShawn McCarney { 13438fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "checkInventoryItemsStatus enter"; 13448fb49dd6SShawn McCarney auto getInventoryItemsCb = 13458fb49dd6SShawn McCarney [sensorsAsyncResp, 13468fb49dd6SShawn McCarney objectMgrPaths](std::shared_ptr< 13478fb49dd6SShawn McCarney boost::container::flat_map<std::string, std::string>> 13488fb49dd6SShawn McCarney sensorToInvMap) { 13498fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsCb enter"; 13508fb49dd6SShawn McCarney auto getInventoryItemsConnectionsCb = 13518fb49dd6SShawn McCarney [sensorsAsyncResp, sensorToInvMap, objectMgrPaths]( 13528fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_set<std::string>> 13538fb49dd6SShawn McCarney invConnections) { 13548fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter"; 13558fb49dd6SShawn McCarney 13568fb49dd6SShawn McCarney // Get status of inventory items and update sensors 13578fb49dd6SShawn McCarney getInventoryItemsStatus(sensorsAsyncResp, sensorToInvMap, 13588fb49dd6SShawn McCarney invConnections, objectMgrPaths); 13598fb49dd6SShawn McCarney 13608fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit"; 13618fb49dd6SShawn McCarney }; 13628fb49dd6SShawn McCarney 13638fb49dd6SShawn McCarney // Get connections that provide status of inventory items 13648fb49dd6SShawn McCarney getInventoryItemsConnections( 13658fb49dd6SShawn McCarney sensorsAsyncResp, sensorToInvMap, 13668fb49dd6SShawn McCarney std::move(getInventoryItemsConnectionsCb)); 13678fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsCb exit"; 13688fb49dd6SShawn McCarney }; 13698fb49dd6SShawn McCarney 13708fb49dd6SShawn McCarney // Get inventory items that are associated with specified sensors 13718fb49dd6SShawn McCarney getInventoryItems(sensorsAsyncResp, sensorNames, objectMgrPaths, 13728fb49dd6SShawn McCarney std::move(getInventoryItemsCb)); 13738fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "checkInventoryItemsStatus exit"; 13748fb49dd6SShawn McCarney } 13758fb49dd6SShawn McCarney 13768fb49dd6SShawn McCarney /** 1377de629b6eSShawn McCarney * @brief Gets the values of the specified sensors. 1378de629b6eSShawn McCarney * 1379de629b6eSShawn McCarney * Stores the results as JSON in the SensorsAsyncResp. 1380de629b6eSShawn McCarney * 1381de629b6eSShawn McCarney * Gets the sensor values asynchronously. Stores the results later when the 1382de629b6eSShawn McCarney * information has been obtained. 1383de629b6eSShawn McCarney * 1384de629b6eSShawn McCarney * The sensorNames set contains all sensors for the current chassis. 1385de629b6eSShawn McCarney * SensorsAsyncResp contains the requested sensor types. Only sensors of a 1386de629b6eSShawn McCarney * requested type are included in the JSON output. 1387de629b6eSShawn McCarney * 1388de629b6eSShawn McCarney * To minimize the number of DBus calls, the DBus method 1389de629b6eSShawn McCarney * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the 1390de629b6eSShawn McCarney * values of all sensors provided by a connection (service). 1391de629b6eSShawn McCarney * 1392de629b6eSShawn McCarney * The connections set contains all the connections that provide sensor values. 1393de629b6eSShawn McCarney * 1394de629b6eSShawn McCarney * The objectMgrPaths map contains mappings from a connection name to the 1395de629b6eSShawn McCarney * corresponding DBus object path that implements ObjectManager. 1396de629b6eSShawn McCarney * 1397de629b6eSShawn McCarney * @param SensorsAsyncResp Pointer to object holding response data. 1398de629b6eSShawn McCarney * @param sensorNames All sensors within the current chassis. 1399de629b6eSShawn McCarney * @param connections Connections that provide sensor values. 1400de629b6eSShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 1401de629b6eSShawn McCarney * implements ObjectManager. 1402de629b6eSShawn McCarney */ 1403de629b6eSShawn McCarney void getSensorData( 1404de629b6eSShawn McCarney std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp, 140549c53ac9SJohnathan Mantey const std::shared_ptr<boost::container::flat_set<std::string>> sensorNames, 1406de629b6eSShawn McCarney const boost::container::flat_set<std::string>& connections, 14078fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, std::string>> 14088fb49dd6SShawn McCarney objectMgrPaths) 1409de629b6eSShawn McCarney { 1410de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getSensorData enter"; 1411de629b6eSShawn McCarney // Get managed objects from all services exposing sensors 1412de629b6eSShawn McCarney for (const std::string& connection : connections) 1413de629b6eSShawn McCarney { 1414de629b6eSShawn McCarney // Response handler to process managed objects 14158fb49dd6SShawn McCarney auto getManagedObjectsCb = [SensorsAsyncResp, sensorNames, 14168fb49dd6SShawn McCarney objectMgrPaths]( 1417de629b6eSShawn McCarney const boost::system::error_code ec, 1418de629b6eSShawn McCarney ManagedObjectsVectorType& resp) { 1419de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter"; 1420de629b6eSShawn McCarney if (ec) 1421de629b6eSShawn McCarney { 1422de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec; 1423de629b6eSShawn McCarney messages::internalError(SensorsAsyncResp->res); 1424de629b6eSShawn McCarney return; 1425de629b6eSShawn McCarney } 1426de629b6eSShawn McCarney // Go through all objects and update response with sensor data 1427de629b6eSShawn McCarney for (const auto& objDictEntry : resp) 1428de629b6eSShawn McCarney { 1429de629b6eSShawn McCarney const std::string& objPath = 1430de629b6eSShawn McCarney static_cast<const std::string&>(objDictEntry.first); 1431de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object " 1432de629b6eSShawn McCarney << objPath; 1433de629b6eSShawn McCarney 1434de629b6eSShawn McCarney std::vector<std::string> split; 1435de629b6eSShawn McCarney // Reserve space for 1436de629b6eSShawn McCarney // /xyz/openbmc_project/sensors/<name>/<subname> 1437de629b6eSShawn McCarney split.reserve(6); 1438de629b6eSShawn McCarney boost::algorithm::split(split, objPath, boost::is_any_of("/")); 1439de629b6eSShawn McCarney if (split.size() < 6) 1440de629b6eSShawn McCarney { 1441de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "Got path that isn't long enough " 1442de629b6eSShawn McCarney << objPath; 1443de629b6eSShawn McCarney continue; 1444de629b6eSShawn McCarney } 1445de629b6eSShawn McCarney // These indexes aren't intuitive, as boost::split puts an empty 1446de629b6eSShawn McCarney // string at the beginning 1447de629b6eSShawn McCarney const std::string& sensorType = split[4]; 1448de629b6eSShawn McCarney const std::string& sensorName = split[5]; 1449de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "sensorName " << sensorName 1450de629b6eSShawn McCarney << " sensorType " << sensorType; 145149c53ac9SJohnathan Mantey if (sensorNames->find(objPath) == sensorNames->end()) 1452de629b6eSShawn McCarney { 1453de629b6eSShawn McCarney BMCWEB_LOG_ERROR << sensorName << " not in sensor list "; 1454de629b6eSShawn McCarney continue; 1455de629b6eSShawn McCarney } 1456de629b6eSShawn McCarney 1457de629b6eSShawn McCarney const char* fieldName = nullptr; 1458de629b6eSShawn McCarney if (sensorType == "temperature") 1459de629b6eSShawn McCarney { 1460de629b6eSShawn McCarney fieldName = "Temperatures"; 1461de629b6eSShawn McCarney } 1462de629b6eSShawn McCarney else if (sensorType == "fan" || sensorType == "fan_tach" || 1463de629b6eSShawn McCarney sensorType == "fan_pwm") 1464de629b6eSShawn McCarney { 1465de629b6eSShawn McCarney fieldName = "Fans"; 1466de629b6eSShawn McCarney } 1467de629b6eSShawn McCarney else if (sensorType == "voltage") 1468de629b6eSShawn McCarney { 1469de629b6eSShawn McCarney fieldName = "Voltages"; 1470de629b6eSShawn McCarney } 1471de629b6eSShawn McCarney else if (sensorType == "current") 1472de629b6eSShawn McCarney { 1473de629b6eSShawn McCarney fieldName = "PowerSupplies"; 1474de629b6eSShawn McCarney } 1475de629b6eSShawn McCarney else if (sensorType == "power") 1476de629b6eSShawn McCarney { 1477028f7ebcSEddie James if (!sensorName.compare("total_power")) 1478028f7ebcSEddie James { 1479028f7ebcSEddie James fieldName = "PowerControl"; 1480028f7ebcSEddie James } 1481028f7ebcSEddie James else 1482028f7ebcSEddie James { 1483de629b6eSShawn McCarney fieldName = "PowerSupplies"; 1484de629b6eSShawn McCarney } 1485028f7ebcSEddie James } 1486de629b6eSShawn McCarney else 1487de629b6eSShawn McCarney { 1488de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "Unsure how to handle sensorType " 1489de629b6eSShawn McCarney << sensorType; 1490de629b6eSShawn McCarney continue; 1491de629b6eSShawn McCarney } 1492de629b6eSShawn McCarney 1493de629b6eSShawn McCarney nlohmann::json& tempArray = 1494de629b6eSShawn McCarney SensorsAsyncResp->res.jsonValue[fieldName]; 1495de629b6eSShawn McCarney 149649c53ac9SJohnathan Mantey if (fieldName == "PowerSupplies" && !tempArray.empty()) 149749c53ac9SJohnathan Mantey { 149849c53ac9SJohnathan Mantey // Power supplies put multiple "sensors" into a single power 149949c53ac9SJohnathan Mantey // supply entry, so only create the first one 150049c53ac9SJohnathan Mantey } 150149c53ac9SJohnathan Mantey else 150249c53ac9SJohnathan Mantey { 1503de629b6eSShawn McCarney tempArray.push_back( 150449c53ac9SJohnathan Mantey {{"@odata.id", "/redfish/v1/Chassis/" + 150549c53ac9SJohnathan Mantey SensorsAsyncResp->chassisId + "/" + 150649c53ac9SJohnathan Mantey SensorsAsyncResp->chassisSubNode + 150749c53ac9SJohnathan Mantey "#/" + fieldName + "/"}}); 150849c53ac9SJohnathan Mantey } 1509de629b6eSShawn McCarney nlohmann::json& sensorJson = tempArray.back(); 1510de629b6eSShawn McCarney 1511de629b6eSShawn McCarney objectInterfacesToJson(sensorName, sensorType, 1512de629b6eSShawn McCarney objDictEntry.second, sensorJson); 1513de629b6eSShawn McCarney } 151449c53ac9SJohnathan Mantey if (SensorsAsyncResp.use_count() == 1) 151549c53ac9SJohnathan Mantey { 151649c53ac9SJohnathan Mantey sortJSONResponse(SensorsAsyncResp); 15178fb49dd6SShawn McCarney checkInventoryItemsStatus(SensorsAsyncResp, sensorNames, 15188fb49dd6SShawn McCarney objectMgrPaths); 151949c53ac9SJohnathan Mantey if (SensorsAsyncResp->chassisSubNode == "Thermal") 15208bd25ccdSJames Feist { 15218bd25ccdSJames Feist populateFanRedundancy(SensorsAsyncResp); 15228bd25ccdSJames Feist } 152349c53ac9SJohnathan Mantey } 1524de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit"; 1525de629b6eSShawn McCarney }; 1526de629b6eSShawn McCarney 1527de629b6eSShawn McCarney // Find DBus object path that implements ObjectManager for the current 1528de629b6eSShawn McCarney // connection. If no mapping found, default to "/". 15298fb49dd6SShawn McCarney auto iter = objectMgrPaths->find(connection); 1530de629b6eSShawn McCarney const std::string& objectMgrPath = 15318fb49dd6SShawn McCarney (iter != objectMgrPaths->end()) ? iter->second : "/"; 1532de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is " 1533de629b6eSShawn McCarney << objectMgrPath; 1534de629b6eSShawn McCarney 1535de629b6eSShawn McCarney crow::connections::systemBus->async_method_call( 1536de629b6eSShawn McCarney getManagedObjectsCb, connection, objectMgrPath, 1537de629b6eSShawn McCarney "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1538de629b6eSShawn McCarney }; 1539de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getSensorData exit"; 1540de629b6eSShawn McCarney } 1541de629b6eSShawn McCarney 1542de629b6eSShawn McCarney /** 154308777fb0SLewanczyk, Dawid * @brief Entry point for retrieving sensors data related to requested 154408777fb0SLewanczyk, Dawid * chassis. 1545588c3f0dSKowalski, Kamil * @param SensorsAsyncResp Pointer to object holding response data 154608777fb0SLewanczyk, Dawid */ 15471abe55efSEd Tanous void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp) 15481abe55efSEd Tanous { 154955c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisData enter"; 155049c53ac9SJohnathan Mantey auto getChassisCb = 155149c53ac9SJohnathan Mantey [SensorsAsyncResp]( 155249c53ac9SJohnathan Mantey std::shared_ptr<boost::container::flat_set<std::string>> 155308777fb0SLewanczyk, Dawid sensorNames) { 155455c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisCb enter"; 15558fb49dd6SShawn McCarney auto getConnectionCb = [SensorsAsyncResp, sensorNames]( 15568fb49dd6SShawn McCarney const boost::container::flat_set< 15578fb49dd6SShawn McCarney std::string>& connections) { 155855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getConnectionCb enter"; 1559de629b6eSShawn McCarney auto getObjectManagerPathsCb = 156049c53ac9SJohnathan Mantey [SensorsAsyncResp, sensorNames, connections]( 15618fb49dd6SShawn McCarney std::shared_ptr<boost::container::flat_map<std::string, 15628fb49dd6SShawn McCarney std::string>> 15638fb49dd6SShawn McCarney objectMgrPaths) { 1564de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter"; 156549c53ac9SJohnathan Mantey // Get sensor data and store results in JSON 156649c53ac9SJohnathan Mantey // response 1567de629b6eSShawn McCarney getSensorData(SensorsAsyncResp, sensorNames, 1568de629b6eSShawn McCarney connections, objectMgrPaths); 1569de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit"; 157008777fb0SLewanczyk, Dawid }; 1571de629b6eSShawn McCarney 157249c53ac9SJohnathan Mantey // Get mapping from connection names to the DBus object 157349c53ac9SJohnathan Mantey // paths that implement the ObjectManager interface 1574de629b6eSShawn McCarney getObjectManagerPaths(SensorsAsyncResp, 1575de629b6eSShawn McCarney std::move(getObjectManagerPathsCb)); 157655c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getConnectionCb exit"; 157708777fb0SLewanczyk, Dawid }; 1578de629b6eSShawn McCarney 1579de629b6eSShawn McCarney // Get set of connections that provide sensor values 15801abe55efSEd Tanous getConnections(SensorsAsyncResp, sensorNames, 15811abe55efSEd Tanous std::move(getConnectionCb)); 158255c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisCb exit"; 158308777fb0SLewanczyk, Dawid }; 15844f9a2130SJennifer Lee SensorsAsyncResp->res.jsonValue["Redundancy"] = nlohmann::json::array(); 158508777fb0SLewanczyk, Dawid 158626f03899SShawn McCarney // Get set of sensors in chassis 1587588c3f0dSKowalski, Kamil getChassis(SensorsAsyncResp, std::move(getChassisCb)); 158855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisData exit"; 158908777fb0SLewanczyk, Dawid }; 159008777fb0SLewanczyk, Dawid 1591413961deSRichard Marian Thomaiyar /** 159249c53ac9SJohnathan Mantey * @brief Find the requested sensorName in the list of all sensors supplied by 159349c53ac9SJohnathan Mantey * the chassis node 159449c53ac9SJohnathan Mantey * 159549c53ac9SJohnathan Mantey * @param sensorName The sensor name supplied in the PATCH request 159649c53ac9SJohnathan Mantey * @param sensorsList The list of sensors managed by the chassis node 159749c53ac9SJohnathan Mantey * @param sensorsModified The list of sensors that were found as a result of 159849c53ac9SJohnathan Mantey * repeated calls to this function 159949c53ac9SJohnathan Mantey */ 160049c53ac9SJohnathan Mantey bool findSensorNameUsingSensorPath( 16010a86febdSRichard Marian Thomaiyar std::string_view sensorName, 160249c53ac9SJohnathan Mantey boost::container::flat_set<std::string>& sensorsList, 160349c53ac9SJohnathan Mantey boost::container::flat_set<std::string>& sensorsModified) 160449c53ac9SJohnathan Mantey { 16050a86febdSRichard Marian Thomaiyar for (std::string_view chassisSensor : sensorsList) 160649c53ac9SJohnathan Mantey { 16070a86febdSRichard Marian Thomaiyar std::size_t pos = chassisSensor.rfind("/"); 16080a86febdSRichard Marian Thomaiyar if (pos >= (chassisSensor.size() - 1)) 160949c53ac9SJohnathan Mantey { 161049c53ac9SJohnathan Mantey continue; 161149c53ac9SJohnathan Mantey } 16120a86febdSRichard Marian Thomaiyar std::string_view thisSensorName = chassisSensor.substr(pos + 1); 161349c53ac9SJohnathan Mantey if (thisSensorName == sensorName) 161449c53ac9SJohnathan Mantey { 161549c53ac9SJohnathan Mantey sensorsModified.emplace(chassisSensor); 161649c53ac9SJohnathan Mantey return true; 161749c53ac9SJohnathan Mantey } 161849c53ac9SJohnathan Mantey } 161949c53ac9SJohnathan Mantey return false; 162049c53ac9SJohnathan Mantey } 162149c53ac9SJohnathan Mantey 162249c53ac9SJohnathan Mantey /** 1623413961deSRichard Marian Thomaiyar * @brief Entry point for overriding sensor values of given sensor 1624413961deSRichard Marian Thomaiyar * 1625413961deSRichard Marian Thomaiyar * @param res response object 1626413961deSRichard Marian Thomaiyar * @param req request object 1627413961deSRichard Marian Thomaiyar * @param params parameter passed for CRUD 1628413961deSRichard Marian Thomaiyar * @param typeList TypeList of sensors for the resource queried 1629413961deSRichard Marian Thomaiyar * @param chassisSubNode Chassis Node for which the query has to happen 1630413961deSRichard Marian Thomaiyar */ 1631413961deSRichard Marian Thomaiyar void setSensorOverride(crow::Response& res, const crow::Request& req, 1632413961deSRichard Marian Thomaiyar const std::vector<std::string>& params, 1633b01bf299SEd Tanous const std::initializer_list<const char*> typeList, 1634413961deSRichard Marian Thomaiyar const std::string& chassisSubNode) 1635413961deSRichard Marian Thomaiyar { 1636413961deSRichard Marian Thomaiyar 1637413961deSRichard Marian Thomaiyar // TODO: Need to figure out dynamic way to restrict patch (Set Sensor 1638413961deSRichard Marian Thomaiyar // override) based on another d-bus announcement to be more generic. 1639413961deSRichard Marian Thomaiyar if (params.size() != 1) 1640413961deSRichard Marian Thomaiyar { 1641413961deSRichard Marian Thomaiyar messages::internalError(res); 1642413961deSRichard Marian Thomaiyar res.end(); 1643413961deSRichard Marian Thomaiyar return; 1644413961deSRichard Marian Thomaiyar } 1645f65af9e8SRichard Marian Thomaiyar 1646f65af9e8SRichard Marian Thomaiyar std::unordered_map<std::string, std::vector<nlohmann::json>> allCollections; 1647f65af9e8SRichard Marian Thomaiyar std::optional<std::vector<nlohmann::json>> temperatureCollections; 1648f65af9e8SRichard Marian Thomaiyar std::optional<std::vector<nlohmann::json>> fanCollections; 1649f65af9e8SRichard Marian Thomaiyar std::vector<nlohmann::json> voltageCollections; 1650f65af9e8SRichard Marian Thomaiyar BMCWEB_LOG_INFO << "setSensorOverride for subNode" << chassisSubNode 1651f65af9e8SRichard Marian Thomaiyar << "\n"; 1652f65af9e8SRichard Marian Thomaiyar 1653413961deSRichard Marian Thomaiyar if (chassisSubNode == "Thermal") 1654413961deSRichard Marian Thomaiyar { 1655f65af9e8SRichard Marian Thomaiyar if (!json_util::readJson(req, res, "Temperatures", 1656f65af9e8SRichard Marian Thomaiyar temperatureCollections, "Fans", 1657f65af9e8SRichard Marian Thomaiyar fanCollections)) 1658f65af9e8SRichard Marian Thomaiyar { 1659f65af9e8SRichard Marian Thomaiyar return; 1660f65af9e8SRichard Marian Thomaiyar } 1661f65af9e8SRichard Marian Thomaiyar if (!temperatureCollections && !fanCollections) 1662f65af9e8SRichard Marian Thomaiyar { 1663f65af9e8SRichard Marian Thomaiyar messages::resourceNotFound(res, "Thermal", 1664f65af9e8SRichard Marian Thomaiyar "Temperatures / Voltages"); 1665f65af9e8SRichard Marian Thomaiyar res.end(); 1666f65af9e8SRichard Marian Thomaiyar return; 1667f65af9e8SRichard Marian Thomaiyar } 1668f65af9e8SRichard Marian Thomaiyar if (temperatureCollections) 1669f65af9e8SRichard Marian Thomaiyar { 1670f65af9e8SRichard Marian Thomaiyar allCollections.emplace("Temperatures", 1671f65af9e8SRichard Marian Thomaiyar *std::move(temperatureCollections)); 1672f65af9e8SRichard Marian Thomaiyar } 1673f65af9e8SRichard Marian Thomaiyar if (fanCollections) 1674f65af9e8SRichard Marian Thomaiyar { 1675f65af9e8SRichard Marian Thomaiyar allCollections.emplace("Fans", *std::move(fanCollections)); 1676f65af9e8SRichard Marian Thomaiyar } 1677413961deSRichard Marian Thomaiyar } 1678413961deSRichard Marian Thomaiyar else if (chassisSubNode == "Power") 1679413961deSRichard Marian Thomaiyar { 1680f65af9e8SRichard Marian Thomaiyar if (!json_util::readJson(req, res, "Voltages", voltageCollections)) 1681f65af9e8SRichard Marian Thomaiyar { 1682f65af9e8SRichard Marian Thomaiyar return; 1683f65af9e8SRichard Marian Thomaiyar } 1684f65af9e8SRichard Marian Thomaiyar allCollections.emplace("Voltages", std::move(voltageCollections)); 1685413961deSRichard Marian Thomaiyar } 1686413961deSRichard Marian Thomaiyar else 1687413961deSRichard Marian Thomaiyar { 1688413961deSRichard Marian Thomaiyar res.result(boost::beast::http::status::not_found); 1689413961deSRichard Marian Thomaiyar res.end(); 1690413961deSRichard Marian Thomaiyar return; 1691413961deSRichard Marian Thomaiyar } 1692413961deSRichard Marian Thomaiyar 1693f65af9e8SRichard Marian Thomaiyar const char* propertyValueName; 1694f65af9e8SRichard Marian Thomaiyar std::unordered_map<std::string, std::pair<double, std::string>> overrideMap; 1695413961deSRichard Marian Thomaiyar std::string memberId; 1696413961deSRichard Marian Thomaiyar double value; 1697f65af9e8SRichard Marian Thomaiyar for (auto& collectionItems : allCollections) 1698f65af9e8SRichard Marian Thomaiyar { 1699f65af9e8SRichard Marian Thomaiyar if (collectionItems.first == "Temperatures") 1700f65af9e8SRichard Marian Thomaiyar { 1701f65af9e8SRichard Marian Thomaiyar propertyValueName = "ReadingCelsius"; 1702f65af9e8SRichard Marian Thomaiyar } 1703f65af9e8SRichard Marian Thomaiyar else if (collectionItems.first == "Fans") 1704f65af9e8SRichard Marian Thomaiyar { 1705f65af9e8SRichard Marian Thomaiyar propertyValueName = "Reading"; 1706f65af9e8SRichard Marian Thomaiyar } 1707f65af9e8SRichard Marian Thomaiyar else 1708f65af9e8SRichard Marian Thomaiyar { 1709f65af9e8SRichard Marian Thomaiyar propertyValueName = "ReadingVolts"; 1710f65af9e8SRichard Marian Thomaiyar } 1711f65af9e8SRichard Marian Thomaiyar for (auto& item : collectionItems.second) 1712f65af9e8SRichard Marian Thomaiyar { 1713f65af9e8SRichard Marian Thomaiyar if (!json_util::readJson(item, res, "MemberId", memberId, 1714413961deSRichard Marian Thomaiyar propertyValueName, value)) 1715413961deSRichard Marian Thomaiyar { 1716413961deSRichard Marian Thomaiyar return; 1717413961deSRichard Marian Thomaiyar } 1718f65af9e8SRichard Marian Thomaiyar overrideMap.emplace(memberId, 1719f65af9e8SRichard Marian Thomaiyar std::make_pair(value, collectionItems.first)); 1720f65af9e8SRichard Marian Thomaiyar } 1721f65af9e8SRichard Marian Thomaiyar } 1722413961deSRichard Marian Thomaiyar const std::string& chassisName = params[0]; 1723413961deSRichard Marian Thomaiyar auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>( 1724413961deSRichard Marian Thomaiyar res, chassisName, typeList, chassisSubNode); 172549c53ac9SJohnathan Mantey auto getChassisSensorListCb = [sensorAsyncResp, 172649c53ac9SJohnathan Mantey overrideMap](const std::shared_ptr< 172749c53ac9SJohnathan Mantey boost::container::flat_set< 172849c53ac9SJohnathan Mantey std::string>> 172949c53ac9SJohnathan Mantey sensorsList) { 173049c53ac9SJohnathan Mantey // Match sensor names in the PATCH request to those managed by the 173149c53ac9SJohnathan Mantey // chassis node 173249c53ac9SJohnathan Mantey const std::shared_ptr<boost::container::flat_set<std::string>> 173349c53ac9SJohnathan Mantey sensorNames = 173449c53ac9SJohnathan Mantey std::make_shared<boost::container::flat_set<std::string>>(); 1735f65af9e8SRichard Marian Thomaiyar for (const auto& item : overrideMap) 1736413961deSRichard Marian Thomaiyar { 1737f65af9e8SRichard Marian Thomaiyar const auto& sensor = item.first; 173849c53ac9SJohnathan Mantey if (!findSensorNameUsingSensorPath(sensor, *sensorsList, 173949c53ac9SJohnathan Mantey *sensorNames)) 1740f65af9e8SRichard Marian Thomaiyar { 1741f65af9e8SRichard Marian Thomaiyar BMCWEB_LOG_INFO << "Unable to find memberId " << item.first; 1742413961deSRichard Marian Thomaiyar messages::resourceNotFound(sensorAsyncResp->res, 1743f65af9e8SRichard Marian Thomaiyar item.second.second, item.first); 1744413961deSRichard Marian Thomaiyar return; 1745413961deSRichard Marian Thomaiyar } 1746f65af9e8SRichard Marian Thomaiyar } 1747413961deSRichard Marian Thomaiyar // Get the connection to which the memberId belongs 1748413961deSRichard Marian Thomaiyar auto getObjectsWithConnectionCb = 1749f65af9e8SRichard Marian Thomaiyar [sensorAsyncResp, overrideMap]( 1750413961deSRichard Marian Thomaiyar const boost::container::flat_set<std::string>& connections, 1751413961deSRichard Marian Thomaiyar const std::set<std::pair<std::string, std::string>>& 1752413961deSRichard Marian Thomaiyar objectsWithConnection) { 1753f65af9e8SRichard Marian Thomaiyar if (objectsWithConnection.size() != overrideMap.size()) 1754413961deSRichard Marian Thomaiyar { 1755413961deSRichard Marian Thomaiyar BMCWEB_LOG_INFO 1756f65af9e8SRichard Marian Thomaiyar << "Unable to find all objects with proper connection " 1757f65af9e8SRichard Marian Thomaiyar << objectsWithConnection.size() << " requested " 1758f65af9e8SRichard Marian Thomaiyar << overrideMap.size() << "\n"; 1759413961deSRichard Marian Thomaiyar messages::resourceNotFound( 1760413961deSRichard Marian Thomaiyar sensorAsyncResp->res, 1761413961deSRichard Marian Thomaiyar sensorAsyncResp->chassisSubNode == "Thermal" 1762413961deSRichard Marian Thomaiyar ? "Temperatures" 1763413961deSRichard Marian Thomaiyar : "Voltages", 1764f65af9e8SRichard Marian Thomaiyar "Count"); 1765f65af9e8SRichard Marian Thomaiyar return; 1766f65af9e8SRichard Marian Thomaiyar } 1767f65af9e8SRichard Marian Thomaiyar for (const auto& item : objectsWithConnection) 1768f65af9e8SRichard Marian Thomaiyar { 1769f65af9e8SRichard Marian Thomaiyar 1770f65af9e8SRichard Marian Thomaiyar auto lastPos = item.first.rfind('/'); 1771f65af9e8SRichard Marian Thomaiyar if (lastPos == std::string::npos) 1772f65af9e8SRichard Marian Thomaiyar { 1773f65af9e8SRichard Marian Thomaiyar messages::internalError(sensorAsyncResp->res); 1774f65af9e8SRichard Marian Thomaiyar return; 1775f65af9e8SRichard Marian Thomaiyar } 1776f65af9e8SRichard Marian Thomaiyar std::string sensorName = item.first.substr(lastPos + 1); 1777f65af9e8SRichard Marian Thomaiyar 1778f65af9e8SRichard Marian Thomaiyar const auto& iterator = overrideMap.find(sensorName); 1779f65af9e8SRichard Marian Thomaiyar if (iterator == overrideMap.end()) 1780f65af9e8SRichard Marian Thomaiyar { 1781f65af9e8SRichard Marian Thomaiyar BMCWEB_LOG_INFO << "Unable to find sensor object" 1782f65af9e8SRichard Marian Thomaiyar << item.first << "\n"; 1783f65af9e8SRichard Marian Thomaiyar messages::internalError(sensorAsyncResp->res); 1784413961deSRichard Marian Thomaiyar return; 1785413961deSRichard Marian Thomaiyar } 1786413961deSRichard Marian Thomaiyar crow::connections::systemBus->async_method_call( 1787f65af9e8SRichard Marian Thomaiyar [sensorAsyncResp](const boost::system::error_code ec) { 1788413961deSRichard Marian Thomaiyar if (ec) 1789413961deSRichard Marian Thomaiyar { 1790413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG 1791f65af9e8SRichard Marian Thomaiyar << "setOverrideValueStatus DBUS error: " 1792413961deSRichard Marian Thomaiyar << ec; 1793413961deSRichard Marian Thomaiyar messages::internalError(sensorAsyncResp->res); 1794413961deSRichard Marian Thomaiyar return; 1795413961deSRichard Marian Thomaiyar } 1796413961deSRichard Marian Thomaiyar }, 1797f65af9e8SRichard Marian Thomaiyar item.second, item.first, 1798413961deSRichard Marian Thomaiyar "org.freedesktop.DBus.Properties", "Set", 1799413961deSRichard Marian Thomaiyar "xyz.openbmc_project.Sensor.Value", "Value", 1800f65af9e8SRichard Marian Thomaiyar sdbusplus::message::variant<double>( 1801f65af9e8SRichard Marian Thomaiyar iterator->second.first)); 1802f65af9e8SRichard Marian Thomaiyar } 1803413961deSRichard Marian Thomaiyar }; 1804413961deSRichard Marian Thomaiyar // Get object with connection for the given sensor name 1805413961deSRichard Marian Thomaiyar getObjectsWithConnection(sensorAsyncResp, sensorNames, 1806413961deSRichard Marian Thomaiyar std::move(getObjectsWithConnectionCb)); 1807413961deSRichard Marian Thomaiyar }; 1808413961deSRichard Marian Thomaiyar // get full sensor list for the given chassisId and cross verify the sensor. 1809413961deSRichard Marian Thomaiyar getChassis(sensorAsyncResp, std::move(getChassisSensorListCb)); 1810413961deSRichard Marian Thomaiyar } 1811413961deSRichard Marian Thomaiyar 181208777fb0SLewanczyk, Dawid } // namespace redfish 1813