From 82dbc15a05125a812c140a3c8cff81c366482229 Mon Sep 17 00:00:00 2001 From: "Jason M. Bills" Date: Mon, 7 Dec 2020 13:45:20 -0800 Subject: Update to internal 0.26 Signed-off-by: Jason M. Bills --- ...001-Firmware-update-configuration-changes.patch | 676 +++++++++++++++++++++ ...-Firmware-update-support-for-StandBySpare.patch | 467 -------------- ...2-Use-chip-id-based-UUID-for-Service-Root.patch | 26 +- ...changes-for-setting-ApplyOptions-ClearCfg.patch | 245 -------- .../bmcweb/0004-Remove-QueryString.patch | 621 ------------------- ...-handle-device-or-resource-busy-exception.patch | 16 +- .../0005-EventService-https-client-support.patch | 480 +++++++++------ ...Media-fixes-for-Redfish-Service-Validator.patch | 122 ---- ...-Fix-Image-and-ImageName-values-in-schema.patch | 38 -- ...sh-TelemetryService-schema-implementation.patch | 79 +-- ...pport-for-POST-in-MetricReportDefinitions.patch | 18 +- ...-for-DELETE-in-MetricReportDefinitions-st.patch | 16 +- ...t-for-OnRequest-in-MetricReportDefinition.patch | 16 +- ...5-Add-support-for-MetricDefinition-scheme.patch | 38 +- ...x-MetricReport-timestamp-for-EventService.patch | 78 --- 15 files changed, 1098 insertions(+), 1838 deletions(-) create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-support-for-StandBySpare.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0003-bmcweb-changes-for-setting-ApplyOptions-ClearCfg.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-Remove-QueryString.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-VirtualMedia-fixes-for-Redfish-Service-Validator.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Fix-Image-and-ImageName-values-in-schema.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb') diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch new file mode 100644 index 000000000..022ffdc76 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-configuration-changes.patch @@ -0,0 +1,676 @@ +From 98a84ed284fe71e276d425dbe67a447b6fca1eff Mon Sep 17 00:00:00 2001 +From: Vikram Bodireddy +Date: Wed, 18 Nov 2020 17:14:41 +0530 +Subject: [PATCH 01/10] Firmware update configuration changes + +This commit will provide user to PATCH the below firmware update +attributes before uploding the firmware image. + +1. This will have PATCH support for 'HttpPushUriTargets' and +'HttpPushUriTargetsBusy' attributes. These attributes enables +'HttpPushUri' to distinguish between the firmware update targets. + +2. ApplyOptions are used to specify firmware update specific options +such as ClearConfig which is used while activating the updated +firmware. This setting is maintained in a local static variable +when set using PATCH method. Its used in activate image as input +parameter. This attribute is added as Oem as the default +UpdateService interface doesn't specify any relevant or appropriate +attribute for this. + +Tested: + - GET on "/redfish/v1/UpdateService", got below response +......... + "HttpPushUriTargets": [], + "HttpPushUriTargetsBusy": false +........ + + - PATCH on "/redfish/v1/UpdateService" and works fine. +{ + "HttpPushUriTargets": ["bmc_recovery"], + "HttpPushUriTargetsBusy": true +} + + - Did Firmware update and verified end to end functionality + for both bmc active and backup images. + + - Tested setting ClearConfig to true or false using PATCH + method. + + - Successfully ran redfish validater with no new errors. + +Signed-off-by: Vikram Bodireddy + +%% original patch: 0001-Firmware-update-configuration-changes.patch +--- + redfish-core/lib/update_service.hpp | 337 +++++++++++++++++++-- + .../v1/JsonSchemas/OemUpdateService/index.json | 69 +++++ + static/redfish/v1/schema/OemUpdateService_v1.xml | 40 +++ + 3 files changed, 416 insertions(+), 30 deletions(-) + create mode 100644 static/redfish/v1/JsonSchemas/OemUpdateService/index.json + create mode 100644 static/redfish/v1/schema/OemUpdateService_v1.xml + +diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp +index ddb8b30..399321b 100644 +--- a/redfish-core/lib/update_service.hpp ++++ b/redfish-core/lib/update_service.hpp +@@ -32,6 +32,17 @@ static std::unique_ptr fwUpdateErrorMatcher; + static bool fwUpdateInProgress = false; + // Timer for software available + static std::unique_ptr fwAvailableTimer; ++static constexpr const char* versionIntf = ++ "xyz.openbmc_project.Software.Version"; ++static constexpr const char* activationIntf = ++ "xyz.openbmc_project.Software.Activation"; ++static constexpr const char* reqActivationPropName = "RequestedActivation"; ++static constexpr const char* reqActivationsActive = ++ "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"; ++static constexpr const char* reqActivationsStandBySpare = ++ "xyz.openbmc_project.Software.Activation.RequestedActivations.StandbySpare"; ++static constexpr const char* activationsStandBySpare = ++ "xyz.openbmc_project.Software.Activation.Activations.StandbySpare"; + + static void cleanUp() + { +@@ -40,27 +51,119 @@ static void cleanUp() + fwUpdateErrorMatcher = nullptr; + } + static void activateImage(const std::string& objPath, +- const std::string& service) ++ const std::string& service, ++ const std::vector& imgUriTargets) + { + BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service; ++ // If targets is empty, it will apply to the active. ++ if (imgUriTargets.size() == 0) ++ { ++ crow::connections::systemBus->async_method_call( ++ [](const boost::system::error_code error_code) { ++ if (error_code) ++ { ++ BMCWEB_LOG_DEBUG ++ << "RequestedActivation failed: error_code = " ++ << error_code; ++ BMCWEB_LOG_DEBUG << "error msg = " << error_code.message(); ++ } ++ }, ++ service, objPath, "org.freedesktop.DBus.Properties", "Set", ++ activationIntf, reqActivationPropName, ++ std::variant(reqActivationsActive)); ++ return; ++ } ++ ++ // TODO: Now we support only one target becuase software-manager ++ // code support one activation per object. It will be enhanced ++ // to multiple targets for single image in future. For now, ++ // consider first target alone. + crow::connections::systemBus->async_method_call( +- [](const boost::system::error_code error_code) { +- if (error_code) ++ [objPath, service, imgTarget{imgUriTargets[0]}]( ++ const boost::system::error_code ec, ++ const crow::openbmc_mapper::GetSubTreeType& subtree) { ++ if (ec || !subtree.size()) + { +- BMCWEB_LOG_DEBUG << "error_code = " << error_code; +- BMCWEB_LOG_DEBUG << "error msg = " << error_code.message(); ++ return; ++ } ++ ++ for (const auto& [invObjPath, invDict] : subtree) ++ { ++ std::size_t idPos = invObjPath.rfind("/"); ++ if ((idPos == std::string::npos) || ++ ((idPos + 1) >= invObjPath.size())) ++ { ++ BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; ++ return; ++ } ++ std::string swId = invObjPath.substr(idPos + 1); ++ ++ if (swId != imgTarget) ++ { ++ continue; ++ } ++ ++ if (invDict.size() < 1) ++ { ++ continue; ++ } ++ BMCWEB_LOG_DEBUG << "Image target matched with object " ++ << invObjPath; ++ crow::connections::systemBus->async_method_call( ++ [objPath, ++ service](const boost::system::error_code error_code, ++ const std::variant value) { ++ if (error_code) ++ { ++ BMCWEB_LOG_DEBUG ++ << "Error in querying activation value"; ++ // not all fwtypes are updateable, ++ // this is ok ++ return; ++ } ++ std::string activationValue = ++ std::get(value); ++ BMCWEB_LOG_DEBUG << "Activation Value: " ++ << activationValue; ++ std::string reqActivation = reqActivationsActive; ++ if (activationValue == activationsStandBySpare) ++ { ++ reqActivation = reqActivationsStandBySpare; ++ } ++ BMCWEB_LOG_DEBUG ++ << "Setting RequestedActivation value as " ++ << reqActivation << " for " << service << " " ++ << objPath; ++ crow::connections::systemBus->async_method_call( ++ [](const boost::system::error_code error_code) { ++ if (error_code) ++ { ++ BMCWEB_LOG_DEBUG ++ << "RequestedActivation failed: ec = " ++ << error_code; ++ } ++ return; ++ }, ++ service, objPath, "org.freedesktop.DBus.Properties", ++ "Set", activationIntf, reqActivationPropName, ++ std::variant(reqActivation)); ++ }, ++ invDict[0].first, ++ "/xyz/openbmc_project/software/" + imgTarget, ++ "org.freedesktop.DBus.Properties", "Get", activationIntf, ++ "Activation"); + } + }, +- service, objPath, "org.freedesktop.DBus.Properties", "Set", +- "xyz.openbmc_project.Software.Activation", "RequestedActivation", +- std::variant( +- "xyz.openbmc_project.Software.Activation.RequestedActivations." +- "Active")); ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", ++ static_cast(0), std::array{versionIntf}); + } + + // Note that asyncResp can be either a valid pointer or nullptr. If nullptr + // then no asyncResp updates will occur + static void softwareInterfaceAdded(const std::shared_ptr& asyncResp, ++ const std::vector imgUriTargets, + sdbusplus::message::message& m, + const crow::Request& req) + { +@@ -73,22 +176,24 @@ static void softwareInterfaceAdded(const std::shared_ptr& asyncResp, + + m.read(objPath, interfacesProperties); + +- BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; ++ BMCWEB_LOG_DEBUG << "Software Interface Added. obj path = " << objPath.str; + for (auto& interface : interfacesProperties) + { + BMCWEB_LOG_DEBUG << "interface = " << interface.first; + +- if (interface.first == "xyz.openbmc_project.Software.Activation") ++ if (interface.first == activationIntf) + { + // Retrieve service and activate + crow::connections::systemBus->async_method_call( +- [objPath, asyncResp, ++ [objPath, asyncResp, imgTargets{imgUriTargets}, + req](const boost::system::error_code error_code, + const std::vector>>& objInfo) { + if (error_code) + { +- BMCWEB_LOG_DEBUG << "error_code = " << error_code; ++ BMCWEB_LOG_DEBUG ++ << "GetSoftwareObject path failed: error_code = " ++ << error_code; + BMCWEB_LOG_DEBUG << "error msg = " + << error_code.message(); + if (asyncResp) +@@ -115,7 +220,7 @@ static void softwareInterfaceAdded(const std::shared_ptr& asyncResp, + // is added + fwAvailableTimer = nullptr; + +- activateImage(objPath.str, objInfo[0].first); ++ activateImage(objPath.str, objInfo[0].first, imgTargets); + if (asyncResp) + { + std::shared_ptr task = +@@ -245,8 +350,7 @@ static void softwareInterfaceAdded(const std::shared_ptr& asyncResp, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, +- std::array{ +- "xyz.openbmc_project.Software.Activation"}); ++ std::array{activationIntf}); + } + } + } +@@ -255,7 +359,8 @@ static void softwareInterfaceAdded(const std::shared_ptr& asyncResp, + // then no asyncResp updates will occur + static void monitorForSoftwareAvailable( + const std::shared_ptr& asyncResp, const crow::Request& req, +- const std::string& url, int timeoutTimeSeconds = 10) ++ const std::string& url, const std::vector& imgUriTargets, ++ int timeoutTimeSeconds = 10) + { + // Only allow one FW update at a time + if (fwUpdateInProgress != false) +@@ -295,9 +400,10 @@ static void monitorForSoftwareAvailable( + } + }); + +- auto callback = [asyncResp, req](sdbusplus::message::message& m) { ++ auto callback = [asyncResp, imgTargets{imgUriTargets}, ++ req](sdbusplus::message::message& m) { + BMCWEB_LOG_DEBUG << "Match fired"; +- softwareInterfaceAdded(asyncResp, m, req); ++ softwareInterfaceAdded(asyncResp, imgTargets, m, req); + }; + + fwUpdateInProgress = true; +@@ -463,12 +569,15 @@ class UpdateServiceActionsSimpleUpdate : public Node + std::string fwFile = imageURI.substr(separator + 1); + BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile; + ++ // We will pass empty targets and its handled in activation. ++ std::vector httpUriTargets; ++ + // Setup callback for when new software detected + // Give TFTP 10 minutes to complete + monitorForSoftwareAvailable( + nullptr, req, + "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate", +- 600); ++ httpUriTargets, 600); + + // TFTP can take up to 10 minutes depending on image size and + // connection speed. Return to caller as soon as the TFTP operation +@@ -502,7 +611,8 @@ class UpdateServiceActionsSimpleUpdate : public Node + class UpdateService : public Node + { + public: +- UpdateService(App& app) : Node(app, "/redfish/v1/UpdateService/") ++ UpdateService(App& app) : ++ Node(app, "/redfish/v1/UpdateService/"), httpPushUriTargetBusy(false) + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, +@@ -514,6 +624,8 @@ class UpdateService : public Node + } + + private: ++ std::vector httpPushUriTargets; ++ bool httpPushUriTargetBusy; + void doGet(crow::Response& res, const crow::Request&, + const std::vector&) override + { +@@ -524,6 +636,8 @@ class UpdateService : public Node + res.jsonValue["Description"] = "Service for Software Update"; + res.jsonValue["Name"] = "Update Service"; + res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; ++ res.jsonValue["HttpPushUriTargets"] = httpPushUriTargets; ++ res.jsonValue["HttpPushUriTargetsBusy"] = httpPushUriTargetBusy; + // UpdateService cannot be disabled + res.jsonValue["ServiceEnabled"] = true; + res.jsonValue["FirmwareInventory"] = { +@@ -573,6 +687,29 @@ class UpdateService : public Node + "/xyz/openbmc_project/software/apply_time", + "org.freedesktop.DBus.Properties", "Get", + "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime"); ++ ++ // Get the ApplyOptions value ++ crow::connections::systemBus->async_method_call( ++ [aResp](const boost::system::error_code ec, ++ const std::variant applyOption) { ++ if (ec) ++ { ++ BMCWEB_LOG_DEBUG << "DBUS response error " << ec; ++ messages::internalError(aResp->res); ++ return; ++ } ++ ++ const bool* b = std::get_if(&applyOption); ++ ++ if (b) ++ { ++ aResp->res.jsonValue["Oem"]["ApplyOptions"]["ClearConfig"] = ++ *b; ++ } ++ }, ++ "xyz.openbmc_project.Software.BMC.Updater", ++ "/xyz/openbmc_project/software", "org.freedesktop.DBus.Properties", ++ "Get", "xyz.openbmc_project.Software.ApplyOptions", "ClearConfig"); + } + + void doPatch(crow::Response& res, const crow::Request& req, +@@ -583,12 +720,61 @@ class UpdateService : public Node + std::shared_ptr asyncResp = std::make_shared(res); + + std::optional pushUriOptions; +- if (!json_util::readJson(req, res, "HttpPushUriOptions", +- pushUriOptions)) ++ std::optional> imgTargets; ++ std::optional imgTargetBusy; ++ std::optional oemProps; ++ ++ if (!json_util::readJson(req, res, "HttpPushUriOptions", pushUriOptions, ++ "HttpPushUriTargets", imgTargets, ++ "HttpPushUriTargetsBusy", imgTargetBusy, "Oem", ++ oemProps)) + { ++ BMCWEB_LOG_DEBUG << "UpdateService doPatch: Invalid request body"; + return; + } + ++ if (oemProps) ++ { ++ std::optional applyOptions; ++ ++ if (!json_util::readJson(*oemProps, res, "ApplyOptions", ++ applyOptions)) ++ { ++ return; ++ } ++ ++ if (applyOptions) ++ { ++ std::optional clearConfig; ++ if (!json_util::readJson(*applyOptions, res, "ClearConfig", ++ clearConfig)) ++ { ++ return; ++ } ++ ++ if (clearConfig) ++ { ++ // Set the requested image apply time value ++ crow::connections::systemBus->async_method_call( ++ [asyncResp](const boost::system::error_code ec) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "D-Bus responses error: " ++ << ec; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ messages::success(asyncResp->res); ++ }, ++ "xyz.openbmc_project.Software.BMC.Updater", ++ "/xyz/openbmc_project/software", ++ "org.freedesktop.DBus.Properties", "Set", ++ "xyz.openbmc_project.Software.ApplyOptions", ++ "ClearConfig", std::variant{*clearConfig}); ++ } ++ } ++ } ++ + if (pushUriOptions) + { + std::optional pushUriApplyTime; +@@ -653,6 +839,98 @@ class UpdateService : public Node + } + } + } ++ ++ if (imgTargetBusy) ++ { ++ if ((httpPushUriTargetBusy) && (*imgTargetBusy)) ++ { ++ BMCWEB_LOG_DEBUG ++ << "Other client has reserved the HttpPushUriTargets " ++ "property for firmware updates."; ++ messages::resourceInUse(asyncResp->res); ++ return; ++ } ++ ++ if (imgTargets) ++ { ++ if (!(*imgTargetBusy)) ++ { ++ BMCWEB_LOG_DEBUG ++ << "UpdateService doPatch: httpPushUriTargetBusy " ++ "should be " ++ "true before setting httpPushUriTargets"; ++ messages::invalidObject(asyncResp->res, ++ "HttpPushUriTargetsBusy"); ++ return; ++ } ++ if ((*imgTargets).size() != 0) ++ { ++ // TODO: Now we support max one target becuase ++ // software-manager code support one activation per object. ++ // It will be enhanced to multiple targets for single image ++ // in future. For now, consider first target alone. ++ if ((*imgTargets).size() != 1) ++ { ++ messages::invalidObject(asyncResp->res, ++ "HttpPushUriTargets"); ++ return; ++ } ++ crow::connections::systemBus->async_method_call( ++ [this, asyncResp, uriTargets{*imgTargets}, ++ targetBusy{*imgTargetBusy}]( ++ const boost::system::error_code ec, ++ const std::vector swInvPaths) { ++ if (ec) ++ { ++ return; ++ } ++ ++ bool swInvObjFound = false; ++ for (const std::string& path : swInvPaths) ++ { ++ std::size_t idPos = path.rfind("/"); ++ if ((idPos == std::string::npos) || ++ ((idPos + 1) >= path.size())) ++ { ++ messages::internalError(asyncResp->res); ++ BMCWEB_LOG_DEBUG ++ << "Can't parse firmware ID!!"; ++ return; ++ } ++ std::string swId = path.substr(idPos + 1); ++ ++ if (swId == uriTargets[0]) ++ { ++ swInvObjFound = true; ++ break; ++ } ++ } ++ if (!swInvObjFound) ++ { ++ messages::invalidObject(asyncResp->res, ++ "HttpPushUriTargets"); ++ return; ++ } ++ this->httpPushUriTargetBusy = targetBusy; ++ this->httpPushUriTargets = uriTargets; ++ }, ++ "xyz.openbmc_project.ObjectMapper", ++ "/xyz/openbmc_project/object_mapper", ++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", ++ "/", static_cast(0), ++ std::array{versionIntf}); ++ } ++ else ++ { ++ httpPushUriTargetBusy = *imgTargetBusy; ++ httpPushUriTargets = *imgTargets; ++ } ++ } ++ else ++ { ++ httpPushUriTargetBusy = *imgTargetBusy; ++ } ++ } + } + + void doPost(crow::Response& res, const crow::Request& req, +@@ -663,8 +941,8 @@ class UpdateService : public Node + std::shared_ptr asyncResp = std::make_shared(res); + + // Setup callback for when new software detected +- monitorForSoftwareAvailable(asyncResp, req, +- "/redfish/v1/UpdateService"); ++ monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService", ++ httpPushUriTargets); + + std::string filepath( + "/tmp/images/" + +@@ -749,7 +1027,7 @@ class SoftwareInventoryCollection : public Node + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", + "/xyz/openbmc_project/software", static_cast(0), +- std::array{"xyz.openbmc_project.Software.Version"}); ++ std::array{versionIntf}); + } + }; + +@@ -931,7 +1209,7 @@ class SoftwareInventory : public Node + }, + obj.second[0].first, obj.first, + "org.freedesktop.DBus.Properties", "GetAll", +- "xyz.openbmc_project.Software.Version"); ++ versionIntf); + } + if (!found) + { +@@ -952,8 +1230,7 @@ class SoftwareInventory : public Node + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", +- static_cast(0), +- std::array{"xyz.openbmc_project.Software.Version"}); ++ static_cast(0), std::array{versionIntf}); + } + }; + +diff --git a/static/redfish/v1/JsonSchemas/OemUpdateService/index.json b/static/redfish/v1/JsonSchemas/OemUpdateService/index.json +new file mode 100644 +index 0000000..74e39cd +--- /dev/null ++++ b/static/redfish/v1/JsonSchemas/OemUpdateService/index.json +@@ -0,0 +1,69 @@ ++{ ++ "$id": "http://redfish.dmtf.org/schemas/v1/OemUpdateService.json", ++ "$schema": "http://redfish.dmtf.org/schemas/v1/redfish-schema-v1.json", ++ "copyright": "Copyright 2014-2019 DMTF. For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright", ++ "definitions": { ++ "ApplyOptions": { ++ "additionalProperties": false, ++ "description": "An indication by boolean value whether to update firmware configuration along with firmware image update.", ++ "patternProperties": { ++ "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": { ++ "description": "This property shall specify a valid odata or Redfish property.", ++ "type": [ ++ "array", ++ "boolean", ++ "integer", ++ "number", ++ "null", ++ "object", ++ "string" ++ ] ++ } ++ }, ++ "properties": { ++ "ClearConfig": { ++ "description": "This indicates whether to update firmware configuration or not.", ++ "longDescription": "The value of this property is used to indicate the firmware configuration update.", ++ "readonly": false, ++ "type": [ ++ "boolean", ++ "null" ++ ] ++ } ++ }, ++ "type": "object" ++ }, ++ "Oem": { ++ "additionalProperties": true, ++ "description": "OemUpdateService Oem properties.", ++ "patternProperties": { ++ "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": { ++ "description": "This property shall specify a valid odata or Redfish property.", ++ "type": [ ++ "array", ++ "boolean", ++ "integer", ++ "number", ++ "null", ++ "object", ++ "string" ++ ] ++ } ++ }, ++ "properties": { ++ "ApplyOptions": { ++ "anyOf": [ ++ { ++ "$ref": "#/definitions/ApplyOptions" ++ }, ++ { ++ "type": "null" ++ } ++ ] ++ } ++ }, ++ "type": "object" ++ } ++ }, ++ "title": "#OemUpdateService" ++} +diff --git a/static/redfish/v1/schema/OemUpdateService_v1.xml b/static/redfish/v1/schema/OemUpdateService_v1.xml +new file mode 100644 +index 0000000..cbb7aa4 +--- /dev/null ++++ b/static/redfish/v1/schema/OemUpdateService_v1.xml +@@ -0,0 +1,40 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +-- +2.16.6 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-support-for-StandBySpare.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-support-for-StandBySpare.patch deleted file mode 100644 index 3895424ac..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-support-for-StandBySpare.patch +++ /dev/null @@ -1,467 +0,0 @@ -From 98c57392535227f1906fdc2d6f65980267b5d97c Mon Sep 17 00:00:00 2001 -From: Vikram Bodireddy -Date: Tue, 30 Jun 2020 21:47:55 +0530 -Subject: [PATCH] Firmware update support for StandBySpare - -Firmware update support for StandBySpare. This will -have support for adding 'HttpPushUriTargets' and -'HttpPushUriTargetsBusy' attributes. These attributes enables -'HttpPushUri' to distinguish between the firmware update targets. - -Tested: - - GET on "/redfish/v1/UpdateService", got below response -......... - "HttpPushUriTargets": [], - "HttpPushUriTargetsBusy": false -........ - - - PATCH on "/redfish/v1/UpdateService" and works fine. -{ - "HttpPushUriTargets": ["bmc_recovery"], - "HttpPushUriTargetsBusy": true -} - - - Did Firmware update and verified end to end functionality - for both bmc active and backup images. - - - Successfully ran redfish validater with no new errors. - -Signed-off-by: Vikram Bodireddy ---- - redfish-core/lib/update_service.hpp | 276 ++++++++++++++++++++++++---- - 1 file changed, 243 insertions(+), 33 deletions(-) - -diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp -index 8dae2fb..86ddd8a 100644 ---- a/redfish-core/lib/update_service.hpp -+++ b/redfish-core/lib/update_service.hpp -@@ -32,6 +32,17 @@ static std::unique_ptr fwUpdateErrorMatcher; - static bool fwUpdateInProgress = false; - // Timer for software available - static std::unique_ptr fwAvailableTimer; -+static constexpr const char* versionIntf = -+ "xyz.openbmc_project.Software.Version"; -+static constexpr const char* activationIntf = -+ "xyz.openbmc_project.Software.Activation"; -+static constexpr const char* reqActivationPropName = "RequestedActivation"; -+static constexpr const char* reqActivationsActive = -+ "xyz.openbmc_project.Software.Activation.RequestedActivations.Active"; -+static constexpr const char* reqActivationsStandBySpare = -+ "xyz.openbmc_project.Software.Activation.RequestedActivations.StandbySpare"; -+static constexpr const char* activationsStandBySpare = -+ "xyz.openbmc_project.Software.Activation.Activations.StandbySpare"; - - static void cleanUp() - { -@@ -40,27 +51,119 @@ static void cleanUp() - fwUpdateErrorMatcher = nullptr; - } - static void activateImage(const std::string& objPath, -- const std::string& service) -+ const std::string& service, -+ const std::vector& imgUriTargets) - { - BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service; -+ // If targets is empty, it will apply to the active. -+ if (imgUriTargets.size() == 0) -+ { -+ crow::connections::systemBus->async_method_call( -+ [](const boost::system::error_code error_code) { -+ if (error_code) -+ { -+ BMCWEB_LOG_DEBUG -+ << "RequestedActivation failed: error_code = " -+ << error_code; -+ BMCWEB_LOG_DEBUG << "error msg = " << error_code.message(); -+ } -+ }, -+ service, objPath, "org.freedesktop.DBus.Properties", "Set", -+ activationIntf, reqActivationPropName, -+ std::variant(reqActivationsActive)); -+ return; -+ } -+ -+ // TODO: Now we support only one target becuase software-manager -+ // code support one activation per object. It will be enhanced -+ // to multiple targets for single image in future. For now, -+ // consider first target alone. - crow::connections::systemBus->async_method_call( -- [](const boost::system::error_code error_code) { -- if (error_code) -+ [objPath, service, imgTarget{imgUriTargets[0]}]( -+ const boost::system::error_code ec, -+ const crow::openbmc_mapper::GetSubTreeType& subtree) { -+ if (ec || !subtree.size()) - { -- BMCWEB_LOG_DEBUG << "error_code = " << error_code; -- BMCWEB_LOG_DEBUG << "error msg = " << error_code.message(); -+ return; -+ } -+ -+ for (const auto& [invObjPath, invDict] : subtree) -+ { -+ std::size_t idPos = invObjPath.rfind("/"); -+ if ((idPos == std::string::npos) || -+ ((idPos + 1) >= invObjPath.size())) -+ { -+ BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; -+ return; -+ } -+ std::string swId = invObjPath.substr(idPos + 1); -+ -+ if (swId != imgTarget) -+ { -+ continue; -+ } -+ -+ if (invDict.size() < 1) -+ { -+ continue; -+ } -+ BMCWEB_LOG_DEBUG << "Image target matched with object " -+ << invObjPath; -+ crow::connections::systemBus->async_method_call( -+ [objPath, -+ service](const boost::system::error_code error_code, -+ const std::variant value) { -+ if (error_code) -+ { -+ BMCWEB_LOG_DEBUG -+ << "Error in querying activation value"; -+ // not all fwtypes are updateable, -+ // this is ok -+ return; -+ } -+ std::string activationValue = -+ std::get(value); -+ BMCWEB_LOG_DEBUG << "Activation Value: " -+ << activationValue; -+ std::string reqActivation = reqActivationsActive; -+ if (activationValue == activationsStandBySpare) -+ { -+ reqActivation = reqActivationsStandBySpare; -+ } -+ BMCWEB_LOG_DEBUG -+ << "Setting RequestedActivation value as " -+ << reqActivation << " for " << service << " " -+ << objPath; -+ crow::connections::systemBus->async_method_call( -+ [](const boost::system::error_code error_code) { -+ if (error_code) -+ { -+ BMCWEB_LOG_DEBUG -+ << "RequestedActivation failed: ec = " -+ << error_code; -+ } -+ return; -+ }, -+ service, objPath, "org.freedesktop.DBus.Properties", -+ "Set", activationIntf, reqActivationPropName, -+ std::variant(reqActivation)); -+ }, -+ invDict[0].first, -+ "/xyz/openbmc_project/software/" + imgTarget, -+ "org.freedesktop.DBus.Properties", "Get", activationIntf, -+ "Activation"); - } - }, -- service, objPath, "org.freedesktop.DBus.Properties", "Set", -- "xyz.openbmc_project.Software.Activation", "RequestedActivation", -- std::variant( -- "xyz.openbmc_project.Software.Activation.RequestedActivations." -- "Active")); -+ "xyz.openbmc_project.ObjectMapper", -+ "/xyz/openbmc_project/object_mapper", -+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", -+ static_cast(0), std::array{versionIntf}); - } - - // Note that asyncResp can be either a valid pointer or nullptr. If nullptr - // then no asyncResp updates will occur - static void softwareInterfaceAdded(std::shared_ptr asyncResp, -+ const std::vector imgUriTargets, - sdbusplus::message::message& m, - const crow::Request& req) - { -@@ -73,25 +176,27 @@ static void softwareInterfaceAdded(std::shared_ptr asyncResp, - - m.read(objPath, interfacesProperties); - -- BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; -+ BMCWEB_LOG_DEBUG << "Software Interface Added. obj path = " << objPath.str; - for (auto& interface : interfacesProperties) - { - BMCWEB_LOG_DEBUG << "interface = " << interface.first; - -- if (interface.first == "xyz.openbmc_project.Software.Activation") -+ if (interface.first == activationIntf) - { - // Found our interface, disable callbacks - fwUpdateMatcher = nullptr; - - // Retrieve service and activate - crow::connections::systemBus->async_method_call( -- [objPath, asyncResp, -+ [objPath, asyncResp, imgTargets{imgUriTargets}, - req](const boost::system::error_code error_code, - const std::vector>>& objInfo) { - if (error_code) - { -- BMCWEB_LOG_DEBUG << "error_code = " << error_code; -+ BMCWEB_LOG_DEBUG -+ << "GetSoftwareObject path failed: error_code = " -+ << error_code; - BMCWEB_LOG_DEBUG << "error msg = " - << error_code.message(); - if (asyncResp) -@@ -118,7 +223,7 @@ static void softwareInterfaceAdded(std::shared_ptr asyncResp, - // is added - fwAvailableTimer = nullptr; - -- activateImage(objPath.str, objInfo[0].first); -+ activateImage(objPath.str, objInfo[0].first, imgTargets); - if (asyncResp) - { - std::shared_ptr task = -@@ -248,18 +353,17 @@ static void softwareInterfaceAdded(std::shared_ptr asyncResp, - "xyz.openbmc_project.ObjectMapper", - "/xyz/openbmc_project/object_mapper", - "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, -- std::array{ -- "xyz.openbmc_project.Software.Activation"}); -+ std::array{activationIntf}); - } - } - } - - // Note that asyncResp can be either a valid pointer or nullptr. If nullptr - // then no asyncResp updates will occur --static void monitorForSoftwareAvailable(std::shared_ptr asyncResp, -- const crow::Request& req, -- const std::string& url, -- int timeoutTimeSeconds = 5) -+static void monitorForSoftwareAvailable( -+ std::shared_ptr asyncResp, const crow::Request& req, -+ const std::string& url, const std::vector& imgUriTargets, -+ int timeoutTimeSeconds = 5) - { - // Only allow one FW update at a time - if (fwUpdateInProgress != false) -@@ -299,9 +403,10 @@ static void monitorForSoftwareAvailable(std::shared_ptr asyncResp, - } - }); - -- auto callback = [asyncResp, req](sdbusplus::message::message& m) { -+ auto callback = [asyncResp, imgTargets{imgUriTargets}, -+ req](sdbusplus::message::message& m) { - BMCWEB_LOG_DEBUG << "Match fired"; -- softwareInterfaceAdded(asyncResp, m, req); -+ softwareInterfaceAdded(asyncResp, imgTargets, m, req); - }; - - fwUpdateInProgress = true; -@@ -467,12 +572,15 @@ class UpdateServiceActionsSimpleUpdate : public Node - std::string fwFile = imageURI.substr(separator + 1); - BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile; - -+ // We will pass empty targets and its handled in activation. -+ std::vector httpUriTargets; -+ - // Setup callback for when new software detected - // Give TFTP 2 minutes to complete - monitorForSoftwareAvailable( - nullptr, req, - "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate", -- 120); -+ httpUriTargets, 120); - - // TFTP can take up to 2 minutes depending on image size and - // connection speed. Return to caller as soon as the TFTP operation -@@ -506,7 +614,8 @@ class UpdateServiceActionsSimpleUpdate : public Node - class UpdateService : public Node - { - public: -- UpdateService(CrowApp& app) : Node(app, "/redfish/v1/UpdateService/") -+ UpdateService(CrowApp& app) : -+ Node(app, "/redfish/v1/UpdateService/"), httpPushUriTargetBusy(false) - { - entityPrivileges = { - {boost::beast::http::verb::get, {{"Login"}}}, -@@ -518,6 +627,9 @@ class UpdateService : public Node - } - - private: -+ std::vector httpPushUriTargets; -+ bool httpPushUriTargetBusy; -+ - void doGet(crow::Response& res, const crow::Request& req, - const std::vector& params) override - { -@@ -528,6 +640,8 @@ class UpdateService : public Node - res.jsonValue["Description"] = "Service for Software Update"; - res.jsonValue["Name"] = "Update Service"; - res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; -+ res.jsonValue["HttpPushUriTargets"] = httpPushUriTargets; -+ res.jsonValue["HttpPushUriTargetsBusy"] = httpPushUriTargetBusy; - // UpdateService cannot be disabled - res.jsonValue["ServiceEnabled"] = true; - res.jsonValue["FirmwareInventory"] = { -@@ -587,9 +701,14 @@ class UpdateService : public Node - std::shared_ptr asyncResp = std::make_shared(res); - - std::optional pushUriOptions; -- if (!json_util::readJson(req, res, "HttpPushUriOptions", -- pushUriOptions)) -+ std::optional> imgTargets; -+ std::optional imgTargetBusy; -+ -+ if (!json_util::readJson(req, res, "HttpPushUriOptions", pushUriOptions, -+ "HttpPushUriTargets", imgTargets, -+ "HttpPushUriTargetsBusy", imgTargetBusy)) - { -+ BMCWEB_LOG_DEBUG << "UpdateService doPatch: Invalid request body"; - return; - } - -@@ -657,6 +776,98 @@ class UpdateService : public Node - } - } - } -+ -+ if (imgTargetBusy) -+ { -+ if ((httpPushUriTargetBusy) && (*imgTargetBusy)) -+ { -+ BMCWEB_LOG_DEBUG -+ << "Other client has reserved the HttpPushUriTargets " -+ "property for firmware updates."; -+ messages::resourceInUse(asyncResp->res); -+ return; -+ } -+ -+ if (imgTargets) -+ { -+ if (!(*imgTargetBusy)) -+ { -+ BMCWEB_LOG_DEBUG -+ << "UpdateService doPatch: httpPushUriTargetBusy " -+ "should be " -+ "true before setting httpPushUriTargets"; -+ messages::invalidObject(asyncResp->res, -+ "HttpPushUriTargetsBusy"); -+ return; -+ } -+ if ((*imgTargets).size() != 0) -+ { -+ // TODO: Now we support max one target becuase -+ // software-manager code support one activation per object. -+ // It will be enhanced to multiple targets for single image -+ // in future. For now, consider first target alone. -+ if ((*imgTargets).size() != 1) -+ { -+ messages::invalidObject(asyncResp->res, -+ "HttpPushUriTargets"); -+ return; -+ } -+ crow::connections::systemBus->async_method_call( -+ [this, asyncResp, uriTargets{*imgTargets}, -+ targetBusy{*imgTargetBusy}]( -+ const boost::system::error_code ec, -+ const std::vector swInvPaths) { -+ if (ec) -+ { -+ return; -+ } -+ -+ bool swInvObjFound = false; -+ for (const std::string& path : swInvPaths) -+ { -+ std::size_t idPos = path.rfind("/"); -+ if ((idPos == std::string::npos) || -+ ((idPos + 1) >= path.size())) -+ { -+ messages::internalError(asyncResp->res); -+ BMCWEB_LOG_DEBUG -+ << "Can't parse firmware ID!!"; -+ return; -+ } -+ std::string swId = path.substr(idPos + 1); -+ -+ if (swId == uriTargets[0]) -+ { -+ swInvObjFound = true; -+ break; -+ } -+ } -+ if (!swInvObjFound) -+ { -+ messages::invalidObject(asyncResp->res, -+ "HttpPushUriTargets"); -+ return; -+ } -+ this->httpPushUriTargetBusy = targetBusy; -+ this->httpPushUriTargets = uriTargets; -+ }, -+ "xyz.openbmc_project.ObjectMapper", -+ "/xyz/openbmc_project/object_mapper", -+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", -+ "/", static_cast(0), -+ std::array{versionIntf}); -+ } -+ else -+ { -+ httpPushUriTargetBusy = *imgTargetBusy; -+ httpPushUriTargets = *imgTargets; -+ } -+ } -+ else -+ { -+ httpPushUriTargetBusy = *imgTargetBusy; -+ } -+ } - } - - void doPost(crow::Response& res, const crow::Request& req, -@@ -667,8 +878,8 @@ class UpdateService : public Node - std::shared_ptr asyncResp = std::make_shared(res); - - // Setup callback for when new software detected -- monitorForSoftwareAvailable(asyncResp, req, -- "/redfish/v1/UpdateService"); -+ monitorForSoftwareAvailable(asyncResp, req, "/redfish/v1/UpdateService", -+ httpPushUriTargets); - - std::string filepath( - "/tmp/images/" + -@@ -754,7 +965,7 @@ class SoftwareInventoryCollection : public Node - "/xyz/openbmc_project/object_mapper", - "xyz.openbmc_project.ObjectMapper", "GetSubTree", - "/xyz/openbmc_project/software", static_cast(0), -- std::array{"xyz.openbmc_project.Software.Version"}); -+ std::array{versionIntf}); - } - }; - -@@ -937,7 +1148,7 @@ class SoftwareInventory : public Node - }, - obj.second[0].first, obj.first, - "org.freedesktop.DBus.Properties", "GetAll", -- "xyz.openbmc_project.Software.Version"); -+ versionIntf); - } - if (!found) - { -@@ -958,8 +1169,7 @@ class SoftwareInventory : public Node - "xyz.openbmc_project.ObjectMapper", - "/xyz/openbmc_project/object_mapper", - "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", -- static_cast(0), -- std::array{"xyz.openbmc_project.Software.Version"}); -+ static_cast(0), std::array{versionIntf}); - } - }; - --- -2.17.1 - diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch index e963b1423..31f9abcd5 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0002-Use-chip-id-based-UUID-for-Service-Root.patch @@ -1,7 +1,7 @@ -From b68d62ddf0a9d77a287a7e9a99762915e31d02b9 Mon Sep 17 00:00:00 2001 +From c61ac0a5cf825193f46c734f1db2f92a72d1f3c9 Mon Sep 17 00:00:00 2001 From: Wiktor Golgowski Date: Thu, 30 Apr 2020 11:09:35 +0200 -Subject: [PATCH] Use chip id-based UUID for Service Root. +Subject: [PATCH 02/10] Use chip id-based UUID for Service Root. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -15,16 +15,15 @@ If the sysfs node is not available, code falls back to randomly generated UUID. Signed-off-by: Wiktor Gołgowski - --- - include/persistent_data_middleware.hpp | 32 +++++++++++++++++++++++++++++--- + include/persistent_data.hpp | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) -diff --git a/include/persistent_data_middleware.hpp b/include/persistent_data_middleware.hpp -index de3a6ba..a20b213 100644 ---- a/include/persistent_data_middleware.hpp -+++ b/include/persistent_data_middleware.hpp -@@ -31,6 +31,10 @@ class Middleware +diff --git a/include/persistent_data.hpp b/include/persistent_data.hpp +index 24f7afd..8826b06 100644 +--- a/include/persistent_data.hpp ++++ b/include/persistent_data.hpp +@@ -25,6 +25,10 @@ class ConfigFile public: // todo(ed) should read this from a fixed location somewhere, not CWD static constexpr const char* filename = "bmcweb_persistent_data.json"; @@ -33,9 +32,9 @@ index de3a6ba..a20b213 100644 + static constexpr const char* UuidNs = "{b7b0553a-54cc-4162-982d-" + "944847ed76f5}"; - struct Context - {}; -@@ -141,9 +145,31 @@ class Middleware + ConfigFile() + { +@@ -144,9 +148,31 @@ class ConfigFile if (systemUuid.empty()) { @@ -70,3 +69,6 @@ index de3a6ba..a20b213 100644 } if (fileRevision < jsonRevision) { +-- +2.16.6 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0003-bmcweb-changes-for-setting-ApplyOptions-ClearCfg.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0003-bmcweb-changes-for-setting-ApplyOptions-ClearCfg.patch deleted file mode 100644 index 704031fe1..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0003-bmcweb-changes-for-setting-ApplyOptions-ClearCfg.patch +++ /dev/null @@ -1,245 +0,0 @@ -From e883ea9d43a84998641428448d7220c0f5be72c0 Mon Sep 17 00:00:00 2001 -From: Vikram Bodireddy -Date: Tue, 30 Jun 2020 22:09:10 +0530 -Subject: [PATCH] bmcweb changes for setting ApplyOptions-ClearCfg - -ApplyOptions are used to specify firmware update specific options -such as ClearConfig which is used while activating the updated -firmware. This setting is maintained in a local static variable -when set using PATCH method. Its used in activate image as input -parameter. This attribute is added as Oem as the default -UpdateService interface doesn't specify any relevant or appropriate -attribute for this. - -Tested: Tested setting ClearConfig to true or false using PATCH - method. - Ran Redfish-Service-Validator and no new issues found. - -Signed-off-by: Vikram Bodireddy ---- - redfish-core/lib/update_service.hpp | 69 ++++++++++++++++++- - .../JsonSchemas/OemUpdateService/index.json | 69 +++++++++++++++++++ - .../redfish/v1/schema/OemUpdateService_v1.xml | 40 +++++++++++ - 3 files changed, 177 insertions(+), 1 deletion(-) - create mode 100644 static/redfish/v1/JsonSchemas/OemUpdateService/index.json - create mode 100644 static/redfish/v1/schema/OemUpdateService_v1.xml - -diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp -index 86ddd8a..291acec 100644 ---- a/redfish-core/lib/update_service.hpp -+++ b/redfish-core/lib/update_service.hpp -@@ -691,6 +691,29 @@ class UpdateService : public Node - "/xyz/openbmc_project/software/apply_time", - "org.freedesktop.DBus.Properties", "Get", - "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime"); -+ -+ // Get the ApplyOptions value -+ crow::connections::systemBus->async_method_call( -+ [aResp](const boost::system::error_code ec, -+ const std::variant applyOption) { -+ if (ec) -+ { -+ BMCWEB_LOG_DEBUG << "DBUS response error " << ec; -+ messages::internalError(aResp->res); -+ return; -+ } -+ -+ const bool* b = std::get_if(&applyOption); -+ -+ if (b) -+ { -+ aResp->res.jsonValue["Oem"]["ApplyOptions"]["ClearConfig"] = -+ *b; -+ } -+ }, -+ "xyz.openbmc_project.Software.BMC.Updater", -+ "/xyz/openbmc_project/software", "org.freedesktop.DBus.Properties", -+ "Get", "xyz.openbmc_project.Software.ApplyOptions", "ClearConfig"); - } - - void doPatch(crow::Response& res, const crow::Request& req, -@@ -703,15 +726,59 @@ class UpdateService : public Node - std::optional pushUriOptions; - std::optional> imgTargets; - std::optional imgTargetBusy; -+ std::optional oemProps; - - if (!json_util::readJson(req, res, "HttpPushUriOptions", pushUriOptions, - "HttpPushUriTargets", imgTargets, -- "HttpPushUriTargetsBusy", imgTargetBusy)) -+ "HttpPushUriTargetsBusy", imgTargetBusy, "Oem", -+ oemProps)) - { - BMCWEB_LOG_DEBUG << "UpdateService doPatch: Invalid request body"; - return; - } - -+ if (oemProps) -+ { -+ std::optional applyOptions; -+ -+ if (!json_util::readJson(*oemProps, res, "ApplyOptions", -+ applyOptions)) -+ { -+ return; -+ } -+ -+ if (applyOptions) -+ { -+ std::optional clearConfig; -+ if (!json_util::readJson(*applyOptions, res, "ClearConfig", -+ clearConfig)) -+ { -+ return; -+ } -+ -+ if (clearConfig) -+ { -+ // Set the requested image apply time value -+ crow::connections::systemBus->async_method_call( -+ [asyncResp](const boost::system::error_code ec) { -+ if (ec) -+ { -+ BMCWEB_LOG_ERROR << "D-Bus responses error: " -+ << ec; -+ messages::internalError(asyncResp->res); -+ return; -+ } -+ messages::success(asyncResp->res); -+ }, -+ "xyz.openbmc_project.Software.BMC.Updater", -+ "/xyz/openbmc_project/software", -+ "org.freedesktop.DBus.Properties", "Set", -+ "xyz.openbmc_project.Software.ApplyOptions", -+ "ClearConfig", std::variant{*clearConfig}); -+ } -+ } -+ } -+ - if (pushUriOptions) - { - std::optional pushUriApplyTime; -diff --git a/static/redfish/v1/JsonSchemas/OemUpdateService/index.json b/static/redfish/v1/JsonSchemas/OemUpdateService/index.json -new file mode 100644 -index 0000000..74e39cd ---- /dev/null -+++ b/static/redfish/v1/JsonSchemas/OemUpdateService/index.json -@@ -0,0 +1,69 @@ -+{ -+ "$id": "http://redfish.dmtf.org/schemas/v1/OemUpdateService.json", -+ "$schema": "http://redfish.dmtf.org/schemas/v1/redfish-schema-v1.json", -+ "copyright": "Copyright 2014-2019 DMTF. For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright", -+ "definitions": { -+ "ApplyOptions": { -+ "additionalProperties": false, -+ "description": "An indication by boolean value whether to update firmware configuration along with firmware image update.", -+ "patternProperties": { -+ "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": { -+ "description": "This property shall specify a valid odata or Redfish property.", -+ "type": [ -+ "array", -+ "boolean", -+ "integer", -+ "number", -+ "null", -+ "object", -+ "string" -+ ] -+ } -+ }, -+ "properties": { -+ "ClearConfig": { -+ "description": "This indicates whether to update firmware configuration or not.", -+ "longDescription": "The value of this property is used to indicate the firmware configuration update.", -+ "readonly": false, -+ "type": [ -+ "boolean", -+ "null" -+ ] -+ } -+ }, -+ "type": "object" -+ }, -+ "Oem": { -+ "additionalProperties": true, -+ "description": "OemUpdateService Oem properties.", -+ "patternProperties": { -+ "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": { -+ "description": "This property shall specify a valid odata or Redfish property.", -+ "type": [ -+ "array", -+ "boolean", -+ "integer", -+ "number", -+ "null", -+ "object", -+ "string" -+ ] -+ } -+ }, -+ "properties": { -+ "ApplyOptions": { -+ "anyOf": [ -+ { -+ "$ref": "#/definitions/ApplyOptions" -+ }, -+ { -+ "type": "null" -+ } -+ ] -+ } -+ }, -+ "type": "object" -+ } -+ }, -+ "title": "#OemUpdateService" -+} -diff --git a/static/redfish/v1/schema/OemUpdateService_v1.xml b/static/redfish/v1/schema/OemUpdateService_v1.xml -new file mode 100644 -index 0000000..cbb7aa4 ---- /dev/null -+++ b/static/redfish/v1/schema/OemUpdateService_v1.xml -@@ -0,0 +1,40 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ --- -2.17.1 - diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-Remove-QueryString.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-Remove-QueryString.patch deleted file mode 100644 index 238fb83c7..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-Remove-QueryString.patch +++ /dev/null @@ -1,621 +0,0 @@ -From f8749b5898403ee04a623a5bc534bd939865e221 Mon Sep 17 00:00:00 2001 -From: James Feist -Date: Wed, 22 Jul 2020 09:08:38 -0700 -Subject: [PATCH 1/1] Remove QueryString - -QueryString is an error-prone library that was -leftover from crow. Replace it with boost::url, -a header only library based and written by the -one of the authors of boost beast. - -Tested: Verified logging paging still worked -as expected - -Change-Id: I47c225089aa7d0f7d2299142f91806294f879381 -Signed-off-by: James Feist ---- - CMakeLists.txt | 2 + - CMakeLists.txt.in | 10 + - http/http_connection.h | 21 +- - http/http_request.h | 5 +- - http/query_string.h | 421 ----------------------------- - redfish-core/lib/event_service.hpp | 7 +- - redfish-core/lib/log_services.hpp | 20 +- - 7 files changed, 45 insertions(+), 441 deletions(-) - delete mode 100644 http/query_string.h - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 2886438..50483ad 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -280,6 +280,8 @@ add_definitions (-DBOOST_ALL_NO_LIB) - add_definitions (-DBOOST_NO_RTTI) - add_definitions (-DBOOST_NO_TYPEID) - add_definitions (-DBOOST_COROUTINES_NO_DEPRECATION_WARNING) -+add_definitions (-DBOOST_URL_STANDALONE) -+add_definitions (-DBOOST_URL_HEADER_ONLY) - - # sdbusplus - if (NOT ${YOCTO_DEPENDENCIES}) -diff --git a/CMakeLists.txt.in b/CMakeLists.txt.in -index d14910f..5cd73f6 100644 ---- a/CMakeLists.txt.in -+++ b/CMakeLists.txt.in -@@ -53,3 +53,13 @@ externalproject_add ( - cp -r "${CMAKE_BINARY_DIR}/nlohmann-json-src/include/nlohmann" - "${CMAKE_BINARY_DIR}/prefix/include" - ) -+ -+externalproject_add ( -+ Boost-URL GIT_REPOSITORY "https://github.com/CPPAlliance/url.git" GIT_TAG -+ a56ae0df6d3078319755fbaa67822b4fa7fd352b SOURCE_DIR -+ "${CMAKE_BINARY_DIR}/boost-url-src" BINARY_DIR -+ "${CMAKE_BINARY_DIR}/boost-url-build" CONFIGURE_COMMAND "" BUILD_COMMAND -+ "" INSTALL_COMMAND mkdir -p "${CMAKE_BINARY_DIR}/prefix/include" && -+ cp -r "${CMAKE_BINARY_DIR}/boost-url-src/include/boost" -+ "${CMAKE_BINARY_DIR}/prefix/include" -+) -diff --git a/http/http_connection.h b/http/http_connection.h -index 35bf99c..8dba3d6 100644 ---- a/http/http_connection.h -+++ b/http/http_connection.h -@@ -728,13 +728,9 @@ class Connection : - return; - } - -- // Compute the url parameters for the request -- req->url = req->target(); -- std::size_t index = req->url.find("?"); -- if (index != std::string_view::npos) -- { -- req->url = req->url.substr(0, index); -- } -+ req->urlView = boost::urls::url_view(req->target()); -+ req->url = req->urlView.encoded_path(); -+ - crow::authorization::authenticate(*req, res, session); - - bool loggedIn = req && req->session; -@@ -743,7 +739,16 @@ class Connection : - startDeadline(loggedInAttempts); - BMCWEB_LOG_DEBUG << "Starting slow deadline"; - -- req->urlParams = QueryString(std::string(req->target())); -+ req->urlParams = req->urlView.params(); -+ -+#ifdef BMCWEB_ENABLE_DEBUG -+ std::string paramList = ""; -+ for (const auto param : req->urlParams) -+ { -+ paramList += param->key() + " " + param->value() + " "; -+ } -+ BMCWEB_LOG_DEBUG << "QueryParams: " << paramList; -+#endif - } - else - { -diff --git a/http/http_request.h b/http/http_request.h -index 0691465..95f88c7 100644 ---- a/http/http_request.h -+++ b/http/http_request.h -@@ -1,7 +1,6 @@ - #pragma once - - #include "common.h" --#include "query_string.h" - - #include "sessions.hpp" - -@@ -9,6 +8,7 @@ - #include - #include - #include -+#include - - namespace crow - { -@@ -24,7 +24,8 @@ struct Request - boost::beast::http::request& req; - boost::beast::http::fields& fields; - std::string_view url{}; -- QueryString urlParams{}; -+ boost::urls::url_view urlView{}; -+ boost::urls::url_view::params_type urlParams{}; - bool isSecure{false}; - - const std::string& body; -diff --git a/http/query_string.h b/http/query_string.h -deleted file mode 100644 -index e980280..0000000 ---- a/http/query_string.h -+++ /dev/null -@@ -1,421 +0,0 @@ --#pragma once -- --#include --#include --#include --#include --#include -- --namespace crow --{ --// ---------------------------------------------------------------------------- --// qs_parse (modified) --// https://github.com/bartgrantham/qs_parse --// ---------------------------------------------------------------------------- --/* Similar to strncmp, but handles URL-encoding for either string */ --int qsStrncmp(const char* s, const char* qs, size_t n); -- --/* Finds the beginning of each key/value pair and stores a pointer in qs_kv. -- * Also decodes the value portion of the k/v pair *in-place*. In a future -- * enhancement it will also have a compile-time option of sorting qs_kv -- * alphabetically by key. */ --size_t qsParse(char* qs, char* qs_kv[], size_t qs_kv_size); -- --/* Used by qs_parse to decode the value portion of a k/v pair */ --int qsDecode(char* qs); -- --/* Looks up the value according to the key on a pre-processed query string -- * A future enhancement will be a compile-time option to look up the key -- * in a pre-sorted qs_kv array via a binary search. */ --// char * qs_k2v(const char * key, char * qs_kv[], int qs_kv_size); --char* qsK2v(const char* key, char* const* qs_kv, int qs_kv_size, int nth); -- --/* Non-destructive lookup of value, based on key. User provides the -- * destinaton string and length. */ --char* qsScanvalue(const char* key, const char* qs, char* val, size_t val_len); -- --// TODO: implement sorting of the qs_kv array; for now ensure it's not compiled --#undef _qsSORTING -- --// isxdigit _is_ available in , but let's avoid another header instead --#define BMCWEB_QS_ISHEX(x) \ -- ((((x) >= '0' && (x) <= '9') || ((x) >= 'A' && (x) <= 'F') || \ -- ((x) >= 'a' && (x) <= 'f')) \ -- ? 1 \ -- : 0) --#define BMCWEB_QS_HEX2DEC(x) \ -- (((x) >= '0' && (x) <= '9') \ -- ? (x)-48 \ -- : ((x) >= 'A' && (x) <= 'F') \ -- ? (x)-55 \ -- : ((x) >= 'a' && (x) <= 'f') ? (x)-87 : 0) --#define BMCWEB_QS_ISQSCHR(x) \ -- ((((x) == '=') || ((x) == '#') || ((x) == '&') || ((x) == '\0')) ? 0 : 1) -- --inline int qsStrncmp(const char* s, const char* qs, size_t n) --{ -- int i = 0; -- char u1, u2; -- char unyb, lnyb; -- -- while (n-- > 0) -- { -- u1 = *s++; -- u2 = *qs++; -- -- if (!BMCWEB_QS_ISQSCHR(u1)) -- { -- u1 = '\0'; -- } -- if (!BMCWEB_QS_ISQSCHR(u2)) -- { -- u2 = '\0'; -- } -- -- if (u1 == '+') -- { -- u1 = ' '; -- } -- if (u1 == '%') // easier/safer than scanf -- { -- unyb = static_cast(*s++); -- lnyb = static_cast(*s++); -- if (BMCWEB_QS_ISHEX(unyb) && BMCWEB_QS_ISHEX(lnyb)) -- { -- u1 = static_cast((BMCWEB_QS_HEX2DEC(unyb) * 16) + -- BMCWEB_QS_HEX2DEC(lnyb)); -- } -- else -- { -- u1 = '\0'; -- } -- } -- -- if (u2 == '+') -- { -- u2 = ' '; -- } -- if (u2 == '%') // easier/safer than scanf -- { -- unyb = static_cast(*qs++); -- lnyb = static_cast(*qs++); -- if (BMCWEB_QS_ISHEX(unyb) && BMCWEB_QS_ISHEX(lnyb)) -- { -- u2 = static_cast((BMCWEB_QS_HEX2DEC(unyb) * 16) + -- BMCWEB_QS_HEX2DEC(lnyb)); -- } -- else -- { -- u2 = '\0'; -- } -- } -- -- if (u1 != u2) -- { -- return u1 - u2; -- } -- if (u1 == '\0') -- { -- return 0; -- } -- i++; -- } -- if (BMCWEB_QS_ISQSCHR(*qs)) -- { -- return -1; -- } -- else -- { -- return 0; -- } --} -- --inline size_t qsParse(char* qs, char* qs_kv[], size_t qs_kv_size) --{ -- size_t i; -- size_t j; -- char* substrPtr; -- -- for (i = 0; i < qs_kv_size; i++) -- { -- qs_kv[i] = nullptr; -- } -- -- // find the beginning of the k/v substrings or the fragment -- substrPtr = qs + strcspn(qs, "?#"); -- if (substrPtr[0] != '\0') -- { -- substrPtr++; -- } -- else -- { -- return 0; // no query or fragment -- } -- -- i = 0; -- while (i < qs_kv_size) -- { -- qs_kv[i++] = substrPtr; -- j = strcspn(substrPtr, "&"); -- if (substrPtr[j] == '\0') -- { -- break; -- } -- substrPtr += j + 1; -- } -- -- // we only decode the values in place, the keys could have '='s in them -- // which will hose our ability to distinguish keys from values later -- for (j = 0; j < i; j++) -- { -- substrPtr = qs_kv[j] + strcspn(qs_kv[j], "=&#"); -- if (substrPtr[0] == '&' || substrPtr[0] == '\0') -- { // blank value: skip decoding -- substrPtr[0] = '\0'; -- } -- else -- { -- qsDecode(++substrPtr); -- } -- } -- --#ifdef _qsSORTING --// TODO: qsort qs_kv, using qs_strncmp() for the comparison --#endif -- -- return i; --} -- --inline int qsDecode(char* qs) --{ -- int i = 0, j = 0; -- -- while (BMCWEB_QS_ISQSCHR(qs[j])) -- { -- if (qs[j] == '+') -- { -- qs[i] = ' '; -- } -- else if (qs[j] == '%') // easier/safer than scanf -- { -- if (!BMCWEB_QS_ISHEX(qs[j + 1]) || !BMCWEB_QS_ISHEX(qs[j + 2])) -- { -- qs[i] = '\0'; -- return i; -- } -- qs[i] = static_cast((BMCWEB_QS_HEX2DEC(qs[j + 1]) * 16) + -- BMCWEB_QS_HEX2DEC(qs[j + 2])); -- j += 2; -- } -- else -- { -- qs[i] = qs[j]; -- } -- i++; -- j++; -- } -- qs[i] = '\0'; -- -- return i; --} -- --inline char* qsK2v(const char* key, char* const* qs_kv, int qs_kv_size, -- int nth = 0) --{ -- int i; -- size_t keyLen, skip; -- -- keyLen = strlen(key); -- --#ifdef _qsSORTING --// TODO: binary search for key in the sorted qs_kv --#else // _qsSORTING -- for (i = 0; i < qs_kv_size; i++) -- { -- // we rely on the unambiguous '=' to find the value in our k/v pair -- if (qsStrncmp(key, qs_kv[i], keyLen) == 0) -- { -- skip = strcspn(qs_kv[i], "="); -- if (qs_kv[i][skip] == '=') -- { -- skip++; -- } -- // return (zero-char value) ? ptr to trailing '\0' : ptr to value -- if (nth == 0) -- { -- return qs_kv[i] + skip; -- } -- else -- { -- --nth; -- } -- } -- } --#endif // _qsSORTING -- -- return nullptr; --} -- --inline char* qsScanvalue(const char* key, const char* qs, char* val, -- size_t val_len) --{ -- size_t i, keyLen; -- const char* tmp; -- -- // find the beginning of the k/v substrings -- if ((tmp = strchr(qs, '?')) != nullptr) -- { -- qs = tmp + 1; -- } -- -- keyLen = strlen(key); -- while (qs[0] != '#' && qs[0] != '\0') -- { -- if (qsStrncmp(key, qs, keyLen) == 0) -- { -- break; -- } -- qs += strcspn(qs, "&") + 1; -- } -- -- if (qs[0] == '\0') -- { -- return nullptr; -- } -- -- qs += strcspn(qs, "=&#"); -- if (qs[0] == '=') -- { -- qs++; -- i = strcspn(qs, "&=#"); -- strncpy(val, qs, (val_len - 1) < (i + 1) ? (val_len - 1) : (i + 1)); -- qsDecode(val); -- } -- else -- { -- if (val_len > 0) -- { -- val[0] = '\0'; -- } -- } -- -- return val; --} --} // namespace crow --// ---------------------------------------------------------------------------- -- --namespace crow --{ --class QueryString --{ -- public: -- static const size_t maxKeyValuePairsCount = 256; -- -- QueryString() = default; -- -- QueryString(const QueryString& qs) : url(qs.url) -- { -- for (auto p : qs.keyValuePairs) -- { -- keyValuePairs.push_back( -- const_cast(p - qs.url.c_str() + url.c_str())); -- } -- } -- -- QueryString& operator=(const QueryString& qs) -- { -- if (this == &qs) -- { -- return *this; -- } -- -- url = qs.url; -- keyValuePairs.clear(); -- for (auto p : qs.keyValuePairs) -- { -- keyValuePairs.push_back( -- const_cast(p - qs.url.c_str() + url.c_str())); -- } -- return *this; -- } -- -- QueryString& operator=(QueryString&& qs) -- { -- keyValuePairs = std::move(qs.keyValuePairs); -- auto* oldData = const_cast(qs.url.c_str()); -- url = std::move(qs.url); -- for (auto& p : keyValuePairs) -- { -- p += const_cast(url.c_str()) - oldData; -- } -- return *this; -- } -- -- explicit QueryString(std::string newUrl) : url(std::move(newUrl)) -- { -- if (url.empty()) -- { -- return; -- } -- -- keyValuePairs.resize(maxKeyValuePairsCount); -- -- size_t count = -- qsParse(&url[0], &keyValuePairs[0], maxKeyValuePairsCount); -- keyValuePairs.resize(count); -- } -- -- void clear() -- { -- keyValuePairs.clear(); -- url.clear(); -- } -- -- friend std::ostream& operator<<(std::ostream& os, const QueryString& qs) -- { -- os << "[ "; -- for (size_t i = 0; i < qs.keyValuePairs.size(); ++i) -- { -- if (i != 0u) -- { -- os << ", "; -- } -- os << qs.keyValuePairs[i]; -- } -- os << " ]"; -- return os; -- } -- -- char* get(const std::string& name) const -- { -- char* ret = qsK2v(name.c_str(), keyValuePairs.data(), -- static_cast(keyValuePairs.size())); -- return ret; -- } -- -- std::vector getList(const std::string& name) const -- { -- std::vector ret; -- std::string plus = name + "[]"; -- char* element = nullptr; -- -- int count = 0; -- while (true) -- { -- element = qsK2v(plus.c_str(), keyValuePairs.data(), -- static_cast(keyValuePairs.size()), count++); -- if (element == nullptr) -- { -- break; -- } -- ret.push_back(element); -- } -- return ret; -- } -- -- private: -- std::string url; -- std::vector keyValuePairs; --}; -- --} // namespace crow -diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp -index b27c6e0..8bd30f5 100644 ---- a/redfish-core/lib/event_service.hpp -+++ b/redfish-core/lib/event_service.hpp -@@ -445,13 +445,16 @@ class EventServiceSSE : public Node - subValue->protocol = "Redfish"; - subValue->retryPolicy = "TerminateAfterRetries"; - -- char* filters = req.urlParams.get("$filter"); -- if (filters == nullptr) -+ boost::urls::url_view::params_type::iterator it = -+ req.urlParams.find("$filter"); -+ if (it == req.urlParams.end()) - { - subValue->eventFormatType = "Event"; - } -+ - else - { -+ std::string filters = it->value(); - // Reading from query params. - bool status = readSSEQueryParams( - filters, subValue->eventFormatType, subValue->registryMsgIds, -diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp -index bee1a92..590243c 100644 ---- a/redfish-core/lib/log_services.hpp -+++ b/redfish-core/lib/log_services.hpp -@@ -218,12 +218,14 @@ static bool getEntryTimestamp(sd_journal* journal, std::string& entryTimestamp) - static bool getSkipParam(crow::Response& res, const crow::Request& req, - uint64_t& skip) - { -- char* skipParam = req.urlParams.get("$skip"); -- if (skipParam != nullptr) -+ boost::urls::url_view::params_type::iterator it = -+ req.urlParams.find("$skip"); -+ if (it != req.urlParams.end()) - { -+ std::string skipParam = it->value(); - char* ptr = nullptr; -- skip = std::strtoul(skipParam, &ptr, 10); -- if (*skipParam == '\0' || *ptr != '\0') -+ skip = std::strtoul(skipParam.c_str(), &ptr, 10); -+ if (skipParam.empty() || *ptr != '\0') - { - - messages::queryParameterValueTypeError(res, std::string(skipParam), -@@ -238,12 +240,14 @@ static constexpr const uint64_t maxEntriesPerPage = 1000; - static bool getTopParam(crow::Response& res, const crow::Request& req, - uint64_t& top) - { -- char* topParam = req.urlParams.get("$top"); -- if (topParam != nullptr) -+ boost::urls::url_view::params_type::iterator it = -+ req.urlParams.find("$top"); -+ if (it != req.urlParams.end()) - { -+ std::string topParam = it->value(); - char* ptr = nullptr; -- top = std::strtoul(topParam, &ptr, 10); -- if (*topParam == '\0' || *ptr != '\0') -+ top = std::strtoul(topParam.c_str(), &ptr, 10); -+ if (topParam.empty() || *ptr != '\0') - { - messages::queryParameterValueTypeError(res, std::string(topParam), - "$top"); --- -2.17.1 - diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-bmcweb-handle-device-or-resource-busy-exception.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-bmcweb-handle-device-or-resource-busy-exception.patch index 761caabb7..cd4a5317c 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-bmcweb-handle-device-or-resource-busy-exception.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0004-bmcweb-handle-device-or-resource-busy-exception.patch @@ -1,7 +1,7 @@ -From 5fa2fb4bd766b9c74b9edff4701408a002466b2a Mon Sep 17 00:00:00 2001 +From 17d24c7ff9a533ef6ff0e86554840bf5e4a11782 Mon Sep 17 00:00:00 2001 From: Karol Wachowski Date: Fri, 10 Jul 2020 09:54:06 +0000 -Subject: [PATCH] bmcweb handle device or resource busy exception +Subject: [PATCH 03/10] bmcweb handle device or resource busy exception Use async_method_call_timed() for mount/unmount dbus oprations. Long mount/unmount times are supported by VirtualMedia service, @@ -21,11 +21,11 @@ Tested: Verified that after mounting non-existing HTTPS resource Signed-off-by: Karol Wachowski Change-Id: Ica62c34db0cce24c4c6169fc661edfde49e948d0 --- - redfish-core/lib/virtual_media.hpp | 144 ++++++++++++++++++++++------- + redfish-core/lib/virtual_media.hpp | 144 ++++++++++++++++++++++++++++--------- 1 file changed, 110 insertions(+), 34 deletions(-) diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp -index 0b5eb1a..a0c63ad 100644 +index 1336190..1a4a81d 100644 --- a/redfish-core/lib/virtual_media.hpp +++ b/redfish-core/lib/virtual_media.hpp @@ -23,6 +23,8 @@ @@ -37,7 +37,7 @@ index 0b5eb1a..a0c63ad 100644 namespace redfish { -@@ -109,6 +111,26 @@ static void vmParseInterfaceObject(const DbusInterfaceType& interface, +@@ -121,6 +123,26 @@ static void vmParseInterfaceObject(const DbusInterfaceType& interface, } } @@ -64,7 +64,7 @@ index 0b5eb1a..a0c63ad 100644 /** * @brief Fill template for Virtual Media Item. */ -@@ -806,22 +828,54 @@ class VirtualMediaActionInsertMedia : public Node +@@ -811,22 +833,54 @@ class VirtualMediaActionInsertMedia : public Node } crow::connections::systemBus->async_method_call( @@ -126,7 +126,7 @@ index 0b5eb1a..a0c63ad 100644 } }; -@@ -955,38 +1009,60 @@ class VirtualMediaActionEjectMedia : public Node +@@ -960,38 +1014,60 @@ class VirtualMediaActionEjectMedia : public Node const std::string& service, const std::string& name, bool legacy) { @@ -215,5 +215,5 @@ index 0b5eb1a..a0c63ad 100644 }; -- -2.25.1 +2.16.6 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch index 274dd044a..977a1c6fa 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-EventService-https-client-support.patch @@ -1,7 +1,7 @@ -From f388587781c3d874b13b50ad39e8674f0bc08049 Mon Sep 17 00:00:00 2001 +From f3ae6e96596eadf2a2df4bc723537a47cff13054 Mon Sep 17 00:00:00 2001 From: AppaRao Puli -Date: Mon, 25 May 2020 16:14:39 +0530 -Subject: [PATCH] EventService: https client support +Date: Mon, 19 Oct 2020 13:21:42 +0530 +Subject: [PATCH 04/10] EventService: https client support Add https client support for push style eventing. Using this BMC can push the event @@ -17,35 +17,54 @@ Tested: Change-Id: I44c3918b39baa2eb5fddda9d635f99aa280a422a Signed-off-by: AppaRao Puli --- - http/http_client.hpp | 270 +++++++++++++++++-------- + http/http_client.hpp | 367 ++++++++++++++++++------- redfish-core/include/event_service_manager.hpp | 2 +- - 2 files changed, 186 insertions(+), 86 deletions(-) + 2 files changed, 264 insertions(+), 105 deletions(-) diff --git a/http/http_client.hpp b/http/http_client.hpp -index e6a7db1..27d2af3 100644 +index 5c7b13f..bd1e7b6 100644 --- a/http/http_client.hpp +++ b/http/http_client.hpp -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - #include +@@ -31,12 +31,17 @@ namespace crow + { + + static constexpr uint8_t maxRequestQueueSize = 50; ++static constexpr unsigned int httpReadBodyLimit = 1024; - #include -@@ -49,7 +50,10 @@ enum class ConnState + enum class ConnState + { + initialized, ++ resolveInProgress, ++ resolveFailed, ++ resolved, + connectInProgress, + connectFailed, ++ sslHandshakeInProgress, + connected, + sendInProgress, + sendFailed, +@@ -50,53 +55,124 @@ enum class ConnState class HttpClient : public std::enable_shared_from_this { private: -- boost::beast::tcp_stream conn; -+ boost::asio::io_context& ioc; ++ boost::asio::ip::tcp::resolver resolver; + boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv12_client}; -+ std::shared_ptr> sslConn; -+ std::shared_ptr conn; + boost::beast::tcp_stream conn; ++ std::optional> sslConn; boost::asio::steady_timer timer; - boost::beast::flat_buffer buffer; +- boost::beast::flat_buffer buffer; ++ boost::beast::flat_static_buffer buffer; ++ std::optional< ++ boost::beast::http::response_parser> ++ parser; boost::beast::http::request req; -@@ -62,14 +66,37 @@ class HttpClient : public std::enable_shared_from_this +- boost::beast::http::response res; + boost::asio::ip::tcp::resolver::results_type endpoint; +- std::vector> headers; ++ boost::beast::http::fields fields; + std::queue requestDataQueue; +- ConnState state; + std::string subId; std::string host; std::string port; std::string uri; @@ -55,59 +74,54 @@ index e6a7db1..27d2af3 100644 uint32_t retryIntervalSecs; std::string retryPolicyAction; bool runningTimer; - -+ inline boost::beast::tcp_stream& getConn() ++ ConnState state; ++ ++ void doResolve() + { -+ if (useSsl) ++ BMCWEB_LOG_DEBUG << "Trying to resolve: " << host << ":" << port; ++ if (state == ConnState::resolveInProgress) + { -+ return (boost::beast::get_lowest_layer(*sslConn)); ++ return; + } -+ else ++ state = ConnState::resolveInProgress; ++ // TODO: Use async_resolver. boost asio example ++ // code as is crashing with async_resolve(). ++ try + { -+ return (*conn); ++ endpoint = resolver.resolve(host, port); + } ++ catch (const std::exception& e) ++ { ++ BMCWEB_LOG_ERROR << "Failed to resolve hostname: " << host << " - " ++ << e.what(); ++ state = ConnState::resolveFailed; ++ checkQueue(); ++ return; ++ } ++ state = ConnState::resolved; ++ checkQueue(); + } -+ + void doConnect() { +- if (state == ConnState::connectInProgress) + if (useSsl) + { -+ sslConn = std::make_shared< -+ boost::beast::ssl_stream>(ioc, ctx); -+ } -+ else -+ { -+ conn = std::make_shared(ioc); ++ sslConn.emplace(conn, ctx); + } + - if (state == ConnState::connectInProgress) ++ if ((state == ConnState::connectInProgress) || ++ (state == ConnState::sslHandshakeInProgress)) { return; -@@ -77,25 +104,53 @@ class HttpClient : public std::enable_shared_from_this + } state = ConnState::connectInProgress; BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port; - // Set a timeout on the operation -- conn.expires_after(std::chrono::seconds(30)); -- conn.async_connect(endpoint, [self(shared_from_this())]( -- const boost::beast::error_code& ec, -- const boost::asio::ip::tcp::resolver:: -- results_type::endpoint_type& ep) { -- if (ec) -- { -- BMCWEB_LOG_ERROR << "Connect " << ep -- << " failed: " << ec.message(); -- self->state = ConnState::connectFailed; -- self->checkQueue(); -- return; -- } -- self->state = ConnState::connected; -- BMCWEB_LOG_DEBUG << "Connected to: " << ep; - -- self->checkQueue(); -- }); ++ + auto respHandler = -+ [self(shared_from_this())](const boost::beast::error_code& ec, ++ [self(shared_from_this())](const boost::beast::error_code ec, + const boost::asio::ip::tcp::resolver:: + results_type::endpoint_type& ep) { + if (ec) @@ -119,7 +133,7 @@ index e6a7db1..27d2af3 100644 + return; + } + BMCWEB_LOG_DEBUG << "Connected to: " << ep; -+ if (self->useSsl) ++ if (self->sslConn) + { + self->performHandshake(); + } @@ -130,57 +144,91 @@ index e6a7db1..27d2af3 100644 + } + }; + -+ getConn().expires_after(std::chrono::seconds(30)); -+ getConn().async_connect(endpoint, std::move(respHandler)); + conn.expires_after(std::chrono::seconds(30)); +- conn.async_connect(endpoint, [self(shared_from_this())]( +- const boost::beast::error_code& ec, +- const boost::asio::ip::tcp::resolver:: +- results_type::endpoint_type& ep) { +- if (ec) +- { +- BMCWEB_LOG_ERROR << "Connect " << ep +- << " failed: " << ec.message(); +- self->state = ConnState::connectFailed; +- self->checkQueue(); +- return; +- } +- self->state = ConnState::connected; +- BMCWEB_LOG_DEBUG << "Connected to: " << ep; ++ conn.async_connect(endpoint, std::move(respHandler)); + } + + void performHandshake() + { ++ if (state == ConnState::sslHandshakeInProgress) ++ { ++ return; ++ } ++ state = ConnState::sslHandshakeInProgress; ++ + sslConn->async_handshake( + boost::asio::ssl::stream_base::client, -+ [self(shared_from_this())](const boost::beast::error_code& ec) { ++ [self(shared_from_this())](const boost::beast::error_code ec) { + if (ec) + { + BMCWEB_LOG_ERROR << "SSL handshake failed: " + << ec.message(); -+ self->state = ConnState::connectFailed; -+ self->doCloseAndCheckQueue(); ++ self->doCloseAndCheckQueue(ConnState::connectFailed); + return; + } + self->state = ConnState::connected; -+ BMCWEB_LOG_DEBUG << "SSL Handshake successfull \n"; -+ ++ BMCWEB_LOG_DEBUG << "SSL Handshake successfull"; + +- self->checkQueue(); +- }); + self->checkQueue(); + }); } void sendMessage(const std::string& data) -@@ -108,7 +163,10 @@ class HttpClient : public std::enable_shared_from_this +@@ -107,100 +183,167 @@ class HttpClient : public std::enable_shared_from_this + } + state = ConnState::sendInProgress; - BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; +- BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; ++ BMCWEB_LOG_DEBUG << host << ":" << port; - req.version(static_cast(11)); // HTTP 1.1 +- req.target(uri); +- req.method(boost::beast::http::verb::post); +- +- // Set headers +- for (const auto& [key, value] : headers) + req = {}; -+ res = {}; ++ for (const auto& field : fields) + { +- req.set(key, value); ++ req.set(field.name_string(), field.value()); + } + req.set(boost::beast::http::field::host, host); ++ req.set(boost::beast::http::field::content_type, "text/plain"); + -+ req.version(11); // HTTP 1.1 - req.target(uri); - req.method(boost::beast::http::verb::post); ++ req.version(static_cast(11)); // HTTP 1.1 ++ req.target(uri); ++ req.method(boost::beast::http::verb::post); + req.keep_alive(true); -@@ -123,83 +181,121 @@ class HttpClient : public std::enable_shared_from_this req.body() = data; req.prepare_payload(); - // Set a timeout on the operation - conn.expires_after(std::chrono::seconds(30)); + auto respHandler = [self(shared_from_this())]( -+ const boost::beast::error_code& ec, ++ const boost::beast::error_code ec, + const std::size_t& bytesTransferred) { + if (ec) + { + BMCWEB_LOG_ERROR << "sendMessage() failed: " << ec.message(); -+ self->state = ConnState::sendFailed; -+ self->doCloseAndCheckQueue(); ++ self->doCloseAndCheckQueue(ConnState::sendFailed); + return; + } + BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " @@ -208,15 +256,15 @@ index e6a7db1..27d2af3 100644 - self->recvMessage(); - }); -+ getConn().expires_after(std::chrono::seconds(30)); -+ if (useSsl) ++ conn.expires_after(std::chrono::seconds(30)); ++ if (sslConn) + { + boost::beast::http::async_write(*sslConn, req, + std::move(respHandler)); + } + else + { -+ boost::beast::http::async_write(*conn, req, std::move(respHandler)); ++ boost::beast::http::async_write(conn, req, std::move(respHandler)); + } } @@ -227,109 +275,141 @@ index e6a7db1..27d2af3 100644 - conn, buffer, res, - [self(shared_from_this())](const boost::beast::error_code& ec, - const std::size_t& bytesTransferred) { -- if (ec) -- { -- BMCWEB_LOG_ERROR << "recvMessage() failed: " -- << ec.message(); -- self->state = ConnState::recvFailed; -- self->checkQueue(); -- return; -- } -- BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " -- << bytesTransferred; -- boost::ignore_unused(bytesTransferred); + auto respHandler = [self(shared_from_this())]( -+ const boost::beast::error_code& ec, ++ const boost::beast::error_code ec, + const std::size_t& bytesTransferred) { + if (ec && ec != boost::beast::http::error::partial_message) + { + BMCWEB_LOG_ERROR << "recvMessage() failed: " << ec.message(); -+ self->state = ConnState::recvFailed; -+ self->doCloseAndCheckQueue(); ++ self->doCloseAndCheckQueue(ConnState::recvFailed); + return; + } + BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " + << bytesTransferred; + boost::ignore_unused(bytesTransferred); - -- // Discard received data. We are not interested. -- BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; -+ // Discard received data. We are not interested. -+ BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; - -- // Send is successful, Lets remove data from queue -- // check for next request data in queue. -- self->requestDataQueue.pop(); -- self->state = ConnState::idle; -- self->checkQueue(); -- }); ++ ++ // TODO: check for return status code and perform ++ // retry if fails(Ex: 40x). Take action depending on ++ // retry policy. ++ BMCWEB_LOG_DEBUG << "recvMessage() data: " ++ << self->parser->get().body(); ++ + // Send is successful, Lets remove data from queue + // check for next request data in queue. + self->requestDataQueue.pop(); -+ self->state = ConnState::idle; + -+ if (ec == boost::beast::http::error::partial_message) -+ { -+ // Least bothered about recv message. Partial -+ // message means, already data is sent. Lets close -+ // connection and let next request open connection -+ // to avoid truncated stream. -+ self->state = ConnState::closed; -+ self->doCloseAndCheckQueue(); -+ return; -+ } ++ // Transfer ownership of the response ++ self->parser->release(); + -+ self->checkQueue(); ++ // TODO: Implement the keep-alive connections. ++ // Most of the web servers close connection abruptly ++ // and might be reason due to which its observed that ++ // stream_truncated(Next read) or partial_message ++ // errors. So for now, closing connection and re-open ++ // for all cases. ++ self->doCloseAndCheckQueue(ConnState::closed); + }; + -+ getConn().expires_after(std::chrono::seconds(30)); -+ if (useSsl) ++ parser.emplace(std::piecewise_construct, std::make_tuple()); ++ parser->body_limit(httpReadBodyLimit); ++ buffer.consume(buffer.size()); ++ ++ conn.expires_after(std::chrono::seconds(30)); ++ if (sslConn) + { -+ boost::beast::http::async_read(*sslConn, buffer, res, ++ boost::beast::http::async_read(*sslConn, buffer, *parser, + std::move(respHandler)); + } + else + { -+ boost::beast::http::async_read(*conn, buffer, res, ++ boost::beast::http::async_read(conn, buffer, *parser, + std::move(respHandler)); + } - } - ++ } ++ ++ void doCloseAndCheckQueue(const ConnState setState = ConnState::closed) ++ { ++ if (sslConn) ++ { ++ conn.expires_after(std::chrono::seconds(30)); ++ sslConn->async_shutdown([self = shared_from_this(), ++ setState{std::move(setState)}]( ++ const boost::system::error_code ec) { + if (ec) + { +- BMCWEB_LOG_ERROR << "recvMessage() failed: " +- << ec.message(); +- self->state = ConnState::recvFailed; +- self->checkQueue(); +- return; ++ // Many https server closes connection abruptly ++ // i.e witnout close_notify. More details are at ++ // https://github.com/boostorg/beast/issues/824 ++ if (ec == boost::asio::ssl::error::stream_truncated) ++ { ++ BMCWEB_LOG_ERROR ++ << "doCloseAndCheckQueue(): Connection " ++ "closed by server. "; ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR << "doCloseAndCheckQueue() failed: " ++ << ec.message(); ++ } + } +- BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " +- << bytesTransferred; +- boost::ignore_unused(bytesTransferred); +- +- // Discard received data. We are not interested. +- BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; +- +- // Send is successful, Lets remove data from queue +- // check for next request data in queue. +- self->requestDataQueue.pop(); +- self->state = ConnState::idle; ++ else ++ { ++ BMCWEB_LOG_DEBUG << "Connection closed gracefully..."; ++ } ++ self->conn.cancel(); ++ self->state = setState; + self->checkQueue(); + }); +- } +- - void doClose() -+ void doCloseAndCheckQueue() - { - boost::beast::error_code ec; +- { +- boost::beast::error_code ec; - conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); -+ getConn().cancel(); -+ getConn().expires_after(std::chrono::seconds(30)); -+ getConn().socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, -+ ec); - +- - state = ConnState::closed; - // not_connected happens sometimes so don't bother reporting it. - if (ec && ec != boost::beast::errc::not_connected) -+ if (ec && ec != boost::asio::error::eof) ++ } ++ else { - BMCWEB_LOG_ERROR << "shutdown failed: " << ec.message(); - return; -+ // Many https server closes connection abruptly -+ // i.e witnout close_notify. More details are at -+ // https://github.com/boostorg/beast/issues/824 -+ if (ec == boost::asio::ssl::error::stream_truncated) ++ boost::beast::error_code ec; ++ conn.expires_after(std::chrono::seconds(30)); ++ conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ++ ec); ++ if (ec) + { -+ BMCWEB_LOG_DEBUG -+ << "doCloseAndCheckQueue(): Connection closed by server."; ++ BMCWEB_LOG_ERROR << "doCloseAndCheckQueue() failed: " ++ << ec.message(); + } + else + { -+ BMCWEB_LOG_ERROR << "doCloseAndCheckQueue() failed: " -+ << ec.message(); ++ BMCWEB_LOG_DEBUG << "Connection closed gracefully..."; + } - } + -+ getConn().close(); - BMCWEB_LOG_DEBUG << "Connection closed gracefully"; -+ checkQueue(); ++ conn.close(); ++ state = setState; ++ checkQueue(); + } +- BMCWEB_LOG_DEBUG << "Connection closed gracefully"; + return; } @@ -344,54 +424,112 @@ index e6a7db1..27d2af3 100644 BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n"; return; } -@@ -257,17 +353,20 @@ class HttpClient : public std::enable_shared_from_this - BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs +@@ -232,6 +375,7 @@ class HttpClient : public std::enable_shared_from_this + } + + if ((state == ConnState::connectFailed) || ++ (state == ConnState::resolveFailed) || + (state == ConnState::sendFailed) || + (state == ConnState::recvFailed)) + { +@@ -256,14 +400,18 @@ class HttpClient : public std::enable_shared_from_this << " seconds. RetryCount = " << retryCount; timer.expires_after(std::chrono::seconds(retryIntervalSecs)); -- timer.async_wait([self = shared_from_this()]( -- const boost::system::error_code& ec) { -- self->runningTimer = false; -- self->connStateCheck(); -- }); -+ timer.async_wait( + timer.async_wait( +- [self = shared_from_this()](const boost::system::error_code&) { + [self = shared_from_this()](boost::system::error_code) { -+ self->runningTimer = false; -+ self->connStateCheck(); -+ }); + self->runningTimer = false; + self->connStateCheck(); + }); return; } - else +- // reset retry count. +- retryCount = 0; ++ ++ if (state == ConnState::idle) ++ { ++ // State idle means, previous attempt is successful. ++ retryCount = 0; ++ } + connStateCheck(); + + return; +@@ -273,15 +421,21 @@ class HttpClient : public std::enable_shared_from_this + { + switch (state) { -- // reset retry count. -- retryCount = 0; -+ if (state == ConnState::idle) -+ { -+ // State idle means, previous attempt is successful. -+ retryCount = 0; -+ } ++ case ConnState::initialized: ++ case ConnState::resolveFailed: ++ case ConnState::connectFailed: ++ doResolve(); ++ break; + case ConnState::connectInProgress: ++ case ConnState::resolveInProgress: ++ case ConnState::sslHandshakeInProgress: + case ConnState::sendInProgress: + case ConnState::suspended: + case ConnState::terminated: + // do nothing + break; +- case ConnState::initialized: + case ConnState::closed: +- case ConnState::connectFailed: ++ case ConnState::resolved: + case ConnState::sendFailed: + case ConnState::recvFailed: + { +@@ -297,22 +451,22 @@ class HttpClient : public std::enable_shared_from_this + sendMessage(data); + break; + } ++ default: ++ break; } - connStateCheck(); + } -@@ -310,10 +409,11 @@ class HttpClient : public std::enable_shared_from_this public: explicit HttpClient(boost::asio::io_context& ioc, const std::string& id, const std::string& destIP, const std::string& destPort, - const std::string& destUri) : - conn(ioc), +- timer(ioc), subId(id), host(destIP), port(destPort), uri(destUri), +- retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0), +- retryPolicyAction("TerminateAfterRetries"), runningTimer(false) +- { +- boost::asio::ip::tcp::resolver resolver(ioc); +- endpoint = resolver.resolve(host, port); +- state = ConnState::initialized; +- } + const std::string& destUri, + const bool inUseSsl = true) : -+ ioc(ioc), - timer(ioc), subId(id), host(destIP), port(destPort), uri(destUri), -- retryCount(0), maxRetryAttempts(5), -+ useSsl(inUseSsl), retryCount(0), maxRetryAttempts(5), - retryPolicyAction("TerminateAfterRetries"), runningTimer(false) ++ resolver(ioc), ++ conn(ioc), timer(ioc), subId(id), host(destIP), port(destPort), ++ uri(destUri), useSsl(inUseSsl), retryCount(0), maxRetryAttempts(5), ++ retryPolicyAction("TerminateAfterRetries"), runningTimer(false), ++ state(ConnState::initialized) ++ {} + + void sendData(const std::string& data) + { +@@ -337,7 +491,12 @@ class HttpClient : public std::enable_shared_from_this + void setHeaders( + const std::vector>& httpHeaders) { - boost::asio::ip::tcp::resolver resolver(ioc); +- headers = httpHeaders; ++ // Set headers ++ for (const auto& [key, value] : httpHeaders) ++ { ++ // TODO: Validate the header fileds before assign. ++ fields.set(key, value); ++ } + } + + void setRetryConfig(const uint32_t retryAttempts, diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index 6362112..3ab2605 100644 +index 54dafb4..f68ae1d 100644 --- a/redfish-core/include/event_service_manager.hpp +++ b/redfish-core/include/event_service_manager.hpp -@@ -383,7 +383,7 @@ class Subscription +@@ -387,7 +387,7 @@ class Subscription { conn = std::make_shared( crow::connections::systemBus->get_io_context(), id, host, port, @@ -399,7 +537,7 @@ index 6362112..3ab2605 100644 + path, (uriProto == "https" ? true : false)); } - Subscription(const std::shared_ptr& adaptor) : + Subscription(const std::shared_ptr& adaptor) : -- -2.7.4 +2.16.6 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-VirtualMedia-fixes-for-Redfish-Service-Validator.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-VirtualMedia-fixes-for-Redfish-Service-Validator.patch deleted file mode 100644 index 52ff4e531..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0005-VirtualMedia-fixes-for-Redfish-Service-Validator.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 49dc25100ab8a4220f81bc8f9b54808850fe1267 Mon Sep 17 00:00:00 2001 -From: Przemyslaw Czarnowski -Date: Wed, 8 Jul 2020 15:17:31 +0200 -Subject: [PATCH] VirtualMedia fixes for Redfish Service Validator - -Removes all warnings and errors for VirtualMedia -- rework for OemVirtualMedia -- minor adjustments for jsons - -Tested: -Redfish Service Validator ran with no errors and/or warnings - -Change-Id: Ic027166153a807a8bd3a6c04f042969f16e0dc6a -Signed-off-by: Przemyslaw Czarnowski ---- - redfish-core/lib/virtual_media.hpp | 4 +-- - .../v1/JsonSchemas/OemVirtualMedia/index.json | 28 +++---------------- - .../redfish/v1/schema/OemVirtualMedia_v1.xml | 12 ++++---- - 3 files changed, 12 insertions(+), 32 deletions(-) - -diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp -index 552e255..183abbe 100644 ---- a/redfish-core/lib/virtual_media.hpp -+++ b/redfish-core/lib/virtual_media.hpp -@@ -129,7 +129,7 @@ static nlohmann::json vmItemTemplate(const std::string& name, - item["MediaTypes"] = {"CD", "USBStick"}; - item["TransferMethod"] = "Stream"; - item["TransferProtocolType"] = nullptr; -- item["Oem"]["OpenBmc"]["WebSocketEndpoint"] = nullptr; -+ item["Oem"]["OpenBMC"]["WebSocketEndpoint"] = nullptr; - item["Oem"]["OpenBMC"]["@odata.type"] = - "#OemVirtualMedia.v1_0_0.VirtualMedia"; - -@@ -1039,7 +1039,7 @@ class VirtualMediaCollection : public Node - "#VirtualMediaCollection.VirtualMediaCollection"; - res.jsonValue["Name"] = "Virtual Media Services"; - res.jsonValue["@odata.id"] = -- "/redfish/v1/Managers/" + name + "/VirtualMedia/"; -+ "/redfish/v1/Managers/" + name + "/VirtualMedia"; - - crow::connections::systemBus->async_method_call( - [asyncResp, name](const boost::system::error_code ec, -diff --git a/static/redfish/v1/JsonSchemas/OemVirtualMedia/index.json b/static/redfish/v1/JsonSchemas/OemVirtualMedia/index.json -index 78bd8b7..9ae641a 100644 ---- a/static/redfish/v1/JsonSchemas/OemVirtualMedia/index.json -+++ b/static/redfish/v1/JsonSchemas/OemVirtualMedia/index.json -@@ -3,9 +3,10 @@ - "$schema": "http://redfish.dmtf.org/schemas/v1/redfish-schema-v1.json", - "copyright": "Copyright 2014-2019 DMTF. For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright", - "definitions": { -- "OpenBmc": { -- "additionalProperties": true, -- "description": "Oem properties for OpenBmc.", -+ "VirtualMedia": { -+ "additionalProperties": false, -+ "description": "OEM Extension for VirtualMedia", -+ "longDescription": "OEM Extension for VirtualMedia to support Proxy mode.", - "patternProperties": { - "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": { - "description": "This property shall specify a valid odata or Redfish property.", -@@ -32,27 +33,6 @@ - } - }, - "type": "object" -- }, -- "VirtualMedia": { -- "additionalProperties": false, -- "description": "OEM Extension for VirtualMedia", -- "longDescription": "OEM Extension for VirtualMedia to support Proxy mode.", -- "patternProperties": { -- "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": { -- "description": "This property shall specify a valid odata or Redfish property.", -- "type": [ -- "array", -- "boolean", -- "integer", -- "number", -- "null", -- "object", -- "string" -- ] -- } -- }, -- "properties": {}, -- "type": "object" - } - }, - "owningEntity": "OpenBMC", -diff --git a/static/redfish/v1/schema/OemVirtualMedia_v1.xml b/static/redfish/v1/schema/OemVirtualMedia_v1.xml -index 2b03a67..84afe73 100644 ---- a/static/redfish/v1/schema/OemVirtualMedia_v1.xml -+++ b/static/redfish/v1/schema/OemVirtualMedia_v1.xml -@@ -25,20 +25,20 @@ - - - -- -- -- -- -- -+ - - - - -- - - - - -+ -+ -+ -+ -+ - - - --- -2.25.0 - diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Fix-Image-and-ImageName-values-in-schema.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Fix-Image-and-ImageName-values-in-schema.patch deleted file mode 100644 index c182822a6..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Fix-Image-and-ImageName-values-in-schema.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 15305d3a9db371af924482e5a6959bbf7812cf6c Mon Sep 17 00:00:00 2001 -From: Przemyslaw Czarnowski -Date: Wed, 29 Jul 2020 15:56:57 +0200 -Subject: [PATCH] Fix Image and ImageName values in schema - -According to design document and schema Image shall contain URL of -image location and ImageName only name of the image. - -Change-Id: Ie1a906c66aa2a10113c307eb1e7d2d7da2810fbd -Signed-off-by: Przemyslaw Czarnowski ---- - redfish-core/lib/virtual_media.hpp | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - -diff --git a/redfish-core/lib/virtual_media.hpp b/redfish-core/lib/virtual_media.hpp -index 183abbe..0345e7b 100644 ---- a/redfish-core/lib/virtual_media.hpp -+++ b/redfish-core/lib/virtual_media.hpp -@@ -97,7 +97,15 @@ static void vmParseInterfaceObject(const DbusInterfaceType& interface, - std::get_if(&imageUrlProperty->second); - if (imageUrlValue && !imageUrlValue->empty()) - { -- aResp->res.jsonValue["ImageName"] = *imageUrlValue; -+ std::size_t lastIndex = imageUrlValue->rfind("/"); -+ if (lastIndex == std::string::npos) -+ { -+ aResp->res.jsonValue["ImageName"] = *imageUrlValue; -+ } -+ -+ aResp->res.jsonValue["ImageName"] = -+ imageUrlValue->substr(lastIndex + 1); -+ aResp->res.jsonValue["Image"] = *imageUrlValue; - aResp->res.jsonValue["Inserted"] = *activeValue; - if (*activeValue == true) - { --- -2.25.0 - diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Redfish-TelemetryService-schema-implementation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Redfish-TelemetryService-schema-implementation.patch index 3850c8fa8..9157f1bf1 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Redfish-TelemetryService-schema-implementation.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Redfish-TelemetryService-schema-implementation.patch @@ -1,7 +1,7 @@ -From 7820421433349df28bd393e8d610d1848af0f1c8 Mon Sep 17 00:00:00 2001 +From d8b7e2f4eae85cd76d480970e888a50548523fc2 Mon Sep 17 00:00:00 2001 From: "Wludzik, Jozef" Date: Mon, 27 Apr 2020 17:24:15 +0200 -Subject: [PATCH 1/5] Redfish TelemetryService schema implementation +Subject: [PATCH 05/10] Redfish TelemetryService schema implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -24,6 +24,10 @@ Tested: Signed-off-by: Wludzik, Jozef Signed-off-by: Adrian Ambrożewicz Change-Id: Ie6b0b49f4ef5eeaef07d1209b6c349270c04d570 + +%% original patch: 0001-Redfish-TelemetryService-schema-implementation.patch + +Change-Id: I547073faef9228e8dc5350ea28d06cdd3c5341f6 --- include/dbus_utility.hpp | 21 +++ redfish-core/include/redfish.hpp | 10 ++ @@ -31,10 +35,10 @@ Change-Id: Ie6b0b49f4ef5eeaef07d1209b6c349270c04d570 redfish-core/include/utils/telemetry_utils.hpp | 100 +++++++++++++ redfish-core/include/utils/time_utils.hpp | 97 +++++++++++++ redfish-core/lib/metric_report.hpp | 149 +++++++++++++++++++ - redfish-core/lib/metric_report_definition.hpp | 193 +++++++++++++++++++++++++ + redfish-core/lib/metric_report_definition.hpp | 191 +++++++++++++++++++++++++ redfish-core/lib/service_root.hpp | 2 + redfish-core/lib/telemetry_service.hpp | 92 ++++++++++++ - 9 files changed, 765 insertions(+) + 9 files changed, 763 insertions(+) create mode 100644 redfish-core/include/utils/telemetry_utils.hpp create mode 100644 redfish-core/include/utils/time_utils.hpp create mode 100644 redfish-core/lib/metric_report.hpp @@ -42,10 +46,10 @@ Change-Id: Ie6b0b49f4ef5eeaef07d1209b6c349270c04d570 create mode 100644 redfish-core/lib/telemetry_service.hpp diff --git a/include/dbus_utility.hpp b/include/dbus_utility.hpp -index e1360f7..3df88d8 100644 +index 8ba9a57..ef3438b 100644 --- a/include/dbus_utility.hpp +++ b/include/dbus_utility.hpp -@@ -109,5 +109,26 @@ inline void checkDbusPathExists(const std::string& path, Callback&& callback) +@@ -99,5 +99,26 @@ inline void checkDbusPathExists(const std::string& path, Callback&& callback) std::array()); } @@ -73,19 +77,19 @@ index e1360f7..3df88d8 100644 } // namespace utility } // namespace dbus diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp -index cc98e1a..3d4c117 100644 +index 54d5d0e..2587b37 100644 --- a/redfish-core/include/redfish.hpp +++ b/redfish-core/include/redfish.hpp @@ -25,6 +25,8 @@ - #include "../lib/log_services.hpp" #include "../lib/managers.hpp" + #include "../lib/memory.hpp" #include "../lib/message_registries.hpp" +#include "../lib/metric_report.hpp" +#include "../lib/metric_report_definition.hpp" #include "../lib/network_protocol.hpp" #include "../lib/pcie.hpp" #include "../lib/power.hpp" -@@ -35,6 +37,7 @@ +@@ -36,6 +38,7 @@ #include "../lib/storage.hpp" #include "../lib/systems.hpp" #include "../lib/task.hpp" @@ -93,7 +97,7 @@ index cc98e1a..3d4c117 100644 #include "../lib/thermal.hpp" #include "../lib/update_service.hpp" #ifdef BMCWEB_ENABLE_VM_NBDPROXY -@@ -202,6 +205,13 @@ class RedfishService +@@ -207,6 +210,13 @@ class RedfishService nodes.emplace_back(std::make_unique(app)); nodes.emplace_back(std::make_unique(app)); @@ -108,21 +112,20 @@ index cc98e1a..3d4c117 100644 { node->initPrivileges(); diff --git a/redfish-core/include/utils/json_utils.hpp b/redfish-core/include/utils/json_utils.hpp -index d578de4..fbb259d 100644 +index c355000..c866a2f 100644 --- a/redfish-core/include/utils/json_utils.hpp +++ b/redfish-core/include/utils/json_utils.hpp -@@ -13,15 +13,19 @@ +@@ -13,14 +13,18 @@ // See the License for the specific language governing permissions and // limitations under the License. */ + #pragma once - #include - #include - +#include #include + #include + #include #include #include @@ -131,7 +134,7 @@ index d578de4..fbb259d 100644 namespace redfish { -@@ -436,5 +440,102 @@ bool getValueFromJsonObject(nlohmann::json& jsonData, const std::string& key, +@@ -425,5 +429,102 @@ bool getValueFromJsonObject(nlohmann::json& jsonData, const std::string& key, return details::unpackValue(jsonValue, key, value); } @@ -445,7 +448,7 @@ index 0000000..0256b3f +} // namespace redfish diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp new file mode 100644 -index 0000000..a52d680 +index 0000000..4d1c4e5 --- /dev/null +++ b/redfish-core/lib/metric_report.hpp @@ -0,0 +1,149 @@ @@ -481,7 +484,7 @@ index 0000000..a52d680 +class MetricReportCollection : public Node +{ + public: -+ MetricReportCollection(CrowApp& app) : Node(app, telemetry::metricReportUri) ++ MetricReportCollection(App& app) : Node(app, telemetry::metricReportUri) + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, @@ -493,8 +496,8 @@ index 0000000..a52d680 + } + + private: -+ void doGet(crow::Response& res, const crow::Request& req, -+ const std::vector& params) override ++ void doGet(crow::Response& res, const crow::Request&, ++ const std::vector&) override + { + res.jsonValue["@odata.type"] = + "#MetricReportCollection.MetricReportCollection"; @@ -510,7 +513,7 @@ index 0000000..a52d680 +class MetricReport : public Node +{ + public: -+ MetricReport(CrowApp& app) : ++ MetricReport(App& app) : + Node(app, std::string(telemetry::metricReportUri) + "/", + std::string()) + { @@ -524,7 +527,7 @@ index 0000000..a52d680 + } + + private: -+ void doGet(crow::Response& res, const crow::Request& req, ++ void doGet(crow::Response& res, const crow::Request&, + const std::vector& params) override + { + auto asyncResp = std::make_shared(res); @@ -600,10 +603,10 @@ index 0000000..a52d680 +} // namespace redfish diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp new file mode 100644 -index 0000000..d82ae59 +index 0000000..72e62e9 --- /dev/null +++ b/redfish-core/lib/metric_report_definition.hpp -@@ -0,0 +1,193 @@ +@@ -0,0 +1,191 @@ +/* +// Copyright (c) 2018-2020 Intel Corporation +// @@ -637,7 +640,7 @@ index 0000000..d82ae59 +class MetricReportDefinitionCollection : public Node +{ + public: -+ MetricReportDefinitionCollection(CrowApp& app) : ++ MetricReportDefinitionCollection(App& app) : + Node(app, telemetry::metricReportDefinitionUri) + { + entityPrivileges = { @@ -650,8 +653,8 @@ index 0000000..d82ae59 + } + + private: -+ void doGet(crow::Response& res, const crow::Request& req, -+ const std::vector& params) override ++ void doGet(crow::Response& res, const crow::Request&, ++ const std::vector&) override + { + res.jsonValue["@odata.type"] = "#MetricReportDefinitionCollection." + "MetricReportDefinitionCollection"; @@ -668,7 +671,7 @@ index 0000000..d82ae59 +class MetricReportDefinition : public Node +{ + public: -+ MetricReportDefinition(CrowApp& app) : ++ MetricReportDefinition(App& app) : + Node(app, std::string(telemetry::metricReportDefinitionUri) + "/", + std::string()) + { @@ -682,7 +685,7 @@ index 0000000..d82ae59 + } + + private: -+ void doGet(crow::Response& res, const crow::Request& req, ++ void doGet(crow::Response& res, const crow::Request&, + const std::vector& params) override + { + auto asyncResp = std::make_shared(res); @@ -723,12 +726,10 @@ index 0000000..d82ae59 + using ReadingParameters = + std::vector, + std::string, std::string, std::string>>; -+ using Metrics = std::vector>>>; + -+ static Metrics toMetrics(const ReadingParameters& params) ++ static nlohmann::json toMetrics(const ReadingParameters& params) + { -+ Metrics metrics; ++ nlohmann::json metrics = nlohmann::json::array(); + + for (auto& [sensorPaths, operationType, id, metadata] : params) + { @@ -798,10 +799,10 @@ index 0000000..d82ae59 +}; +} // namespace redfish diff --git a/redfish-core/lib/service_root.hpp b/redfish-core/lib/service_root.hpp -index b6bd6e0..3302390 100644 +index 629280c..3df5ec5 100644 --- a/redfish-core/lib/service_root.hpp +++ b/redfish-core/lib/service_root.hpp -@@ -69,6 +69,8 @@ class ServiceRoot : public Node +@@ -68,6 +68,8 @@ class ServiceRoot : public Node res.jsonValue["Tasks"] = {{"@odata.id", "/redfish/v1/TaskService"}}; res.jsonValue["EventService"] = { {"@odata.id", "/redfish/v1/EventService"}}; @@ -812,7 +813,7 @@ index b6bd6e0..3302390 100644 diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp new file mode 100644 -index 0000000..a410700 +index 0000000..b849781 --- /dev/null +++ b/redfish-core/lib/telemetry_service.hpp @@ -0,0 +1,92 @@ @@ -847,7 +848,7 @@ index 0000000..a410700 +class TelemetryService : public Node +{ + public: -+ TelemetryService(CrowApp& app) : Node(app, "/redfish/v1/TelemetryService/") ++ TelemetryService(App& app) : Node(app, "/redfish/v1/TelemetryService/") + { + entityPrivileges = { + {boost::beast::http::verb::get, {{"Login"}}}, @@ -859,8 +860,8 @@ index 0000000..a410700 + } + + private: -+ void doGet(crow::Response& res, const crow::Request& req, -+ const std::vector& params) override ++ void doGet(crow::Response& res, const crow::Request&, ++ const std::vector&) override + { + res.jsonValue["@odata.type"] = + "#TelemetryService.v1_2_0.TelemetryService"; diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-support-for-POST-in-MetricReportDefinitions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-support-for-POST-in-MetricReportDefinitions.patch index 8a8690bf3..c24352de5 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-support-for-POST-in-MetricReportDefinitions.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-support-for-POST-in-MetricReportDefinitions.patch @@ -1,7 +1,7 @@ -From 941be2c7d819b4a55d5a8b67948e53658d907789 Mon Sep 17 00:00:00 2001 +From 00806052b1e9440809ce727523ffcc66083f6417 Mon Sep 17 00:00:00 2001 From: "Wludzik, Jozef" Date: Mon, 18 May 2020 11:56:57 +0200 -Subject: [PATCH 2/5] Add support for POST in MetricReportDefinitions +Subject: [PATCH 06/10] Add support for POST in MetricReportDefinitions Added POST action in MetricReportDefinitions node to allow user to add new MetricReportDefinition. Using minimal set of @@ -19,6 +19,10 @@ Tested: Signed-off-by: Wludzik, Jozef Signed-off-by: Krzysztof Grobelny Change-Id: I2fed96848594451e22fde686f8c066d7770cc65a + +%% original patch: 0002-Add-support-for-POST-in-MetricReportDefinitions.patch + +Change-Id: I55032bc1086b60800d19bd1c0fa14fdb891f5a5b --- redfish-core/include/utils/time_utils.hpp | 49 +++ .../include/utils/validate_params_length.hpp | 109 +++++++ @@ -208,7 +212,7 @@ index 0000000..c4e0569 + +} // namespace redfish diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp -index d82ae59..ecbab0c 100644 +index 72e62e9..c6b09f8 100644 --- a/redfish-core/lib/metric_report_definition.hpp +++ b/redfish-core/lib/metric_report_definition.hpp @@ -17,16 +17,29 @@ @@ -261,7 +265,7 @@ index d82ae59..ecbab0c 100644 + MetricParams>; + + void doPost(crow::Response& res, const crow::Request& req, -+ const std::vector& params) override ++ const std::vector&) override + { + auto asyncResp = std::make_shared(res); + AddReportArgs addReportArgs; @@ -287,7 +291,7 @@ index d82ae59..ecbab0c 100644 + retrieveUriToDbusMap( + chassis, sensorType, + [asyncResp, addReportReq]( -+ const boost::beast::http::status status, ++ const boost::beast::http::status, + const boost::container::flat_map& + uriToDbus) { *addReportReq += uriToDbus; }); + } @@ -518,7 +522,7 @@ index d82ae59..ecbab0c 100644 + + crow::connections::systemBus->async_method_call( + [asyncResp, name](const boost::system::error_code ec, -+ const std::string ret) { ++ const std::string) { + if (ec == boost::system::errc::file_exists) + { + messages::resourceAlreadyExists( @@ -581,7 +585,7 @@ index d82ae59..ecbab0c 100644 }; class MetricReportDefinition : public Node -@@ -148,6 +494,7 @@ class MetricReportDefinition : public Node +@@ -146,6 +492,7 @@ class MetricReportDefinition : public Node asyncResp->res.jsonValue["MetricReport"]["@odata.id"] = telemetry::metricReportUri + id; asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch index 4c49b0cd3..dee5a158b 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch @@ -1,7 +1,7 @@ -From 8b2f4a6fe57bf2410cdb22f8c3c695e98d583040 Mon Sep 17 00:00:00 2001 +From 5a1eef4a6c74c29d9b9026676e59e6cdf0a7e8bd Mon Sep 17 00:00:00 2001 From: "Wludzik, Jozef" Date: Mon, 18 May 2020 12:40:15 +0200 -Subject: [PATCH 3/5] Add support for DELETE in MetricReportDefinitions/ +Subject: [PATCH 07/10] Add support for DELETE in MetricReportDefinitions/ Added support for DELETE action in MetricReportDefinitions/ node. It allows user to remove MetricReportDefinition together @@ -16,19 +16,23 @@ Tested: Signed-off-by: Wludzik, Jozef Change-Id: Iffde9f7bbf2955376e9714ac8d833967bd25eaa3 + +%% original patch: 0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch + +Change-Id: I2930b9354fd4cf1f8d9a97af33b81c7b689fe0ef --- redfish-core/lib/metric_report_definition.hpp | 32 +++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp -index ecbab0c..8e04ac8 100644 +index c6b09f8..3191a8f 100644 --- a/redfish-core/lib/metric_report_definition.hpp +++ b/redfish-core/lib/metric_report_definition.hpp -@@ -533,6 +533,38 @@ class MetricReportDefinition : public Node +@@ -531,6 +531,38 @@ class MetricReportDefinition : public Node "xyz.openbmc_project.MonitoringService.Report"); } -+ void doDelete(crow::Response& res, const crow::Request& req, ++ void doDelete(crow::Response& res, const crow::Request&, + const std::vector& params) override + { + auto asyncResp = std::make_shared(res); @@ -43,7 +47,7 @@ index ecbab0c..8e04ac8 100644 + } + + static void deleteReport(const std::shared_ptr& asyncResp, -+ const std::string& path, const std::string& id) ++ const std::string& path, const std::string&) + { + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch index e996ac585..c6c6a8f09 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch @@ -1,7 +1,7 @@ -From 9fc7d722b3192df9940062185b40ebb0fabad518 Mon Sep 17 00:00:00 2001 +From d206ea5049057fe4842186777231b9eb8468ec86 Mon Sep 17 00:00:00 2001 From: Krzysztof Grobelny Date: Mon, 8 Jun 2020 15:16:10 +0200 -Subject: [PATCH 4/5] Add support for "OnRequest" in MetricReportDefinition +Subject: [PATCH 08/10] Add support for "OnRequest" in MetricReportDefinition Added support for "OnRequest" of ReportingType property in MetricReportDefinition node. Now user is able to create @@ -14,6 +14,8 @@ Tested: Signed-off-by: Krzysztof Grobelny Change-Id: I1cdfe47e56fdc5ec9753558145d0bf3645160aaf + +%% original patch: 0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch --- include/dbus_utility.hpp | 30 +++++++++++++++ redfish-core/include/utils/telemetry_utils.hpp | 8 ++-- @@ -21,18 +23,18 @@ Change-Id: I1cdfe47e56fdc5ec9753558145d0bf3645160aaf 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/include/dbus_utility.hpp b/include/dbus_utility.hpp -index 3df88d8..029d8d8 100644 +index ef3438b..80f8bcd 100644 --- a/include/dbus_utility.hpp +++ b/include/dbus_utility.hpp -@@ -17,6 +17,7 @@ - +@@ -18,6 +18,7 @@ #include + #include +#include #include namespace dbus -@@ -130,5 +131,34 @@ inline void getAllProperties(Callback&& callback, const std::string& service, +@@ -120,5 +121,34 @@ inline void getAllProperties(Callback&& callback, const std::string& service, interface); } @@ -94,7 +96,7 @@ index 05ed00f..6c4e810 100644 { messages::resourceNotFound(asyncResp->res, schemaType, id); diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp -index a52d680..877e7f1 100644 +index 4d1c4e5..768cce9 100644 --- a/redfish-core/lib/metric_report.hpp +++ b/redfish-core/lib/metric_report.hpp @@ -85,7 +85,7 @@ class MetricReport : public Node diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch index f7da8a556..5b1d93664 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch @@ -1,7 +1,7 @@ -From b1da8901b5985d6a77b63ca9eb0570b46528f0bd Mon Sep 17 00:00:00 2001 +From b369c09460b46902878da10a106e3b3400fd776e Mon Sep 17 00:00:00 2001 From: "Wludzik, Jozef" Date: Mon, 8 Jun 2020 17:15:54 +0200 -Subject: [PATCH 5/5] Add support for MetricDefinition scheme +Subject: [PATCH 09/10] Add support for MetricDefinition scheme Added MetricDefinition node to redfish core. Now user is able to get all possible metrics that are present in system and are @@ -14,6 +14,10 @@ Tested: Signed-off-by: Wludzik, Jozef Signed-off-by: Krzysztof Grobelny Change-Id: I3086e1302e1ba2e5442d1367939fd5507a0cbc00 + +%% original patch: 0005-Add-support-for-MetricDefinition-scheme.patch + +Change-Id: Ibcb7a858c9118c8af5ff1167a055b044f0d8db77 --- redfish-core/include/redfish.hpp | 3 + redfish-core/include/utils/telemetry_utils.hpp | 2 + @@ -25,18 +29,18 @@ Change-Id: I3086e1302e1ba2e5442d1367939fd5507a0cbc00 create mode 100644 redfish-core/lib/metric_definition.hpp diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp -index 3d4c117..2a12bf9 100644 +index 2587b37..705f490 100644 --- a/redfish-core/include/redfish.hpp +++ b/redfish-core/include/redfish.hpp @@ -25,6 +25,7 @@ - #include "../lib/log_services.hpp" #include "../lib/managers.hpp" + #include "../lib/memory.hpp" #include "../lib/message_registries.hpp" +#include "../lib/metric_definition.hpp" #include "../lib/metric_report.hpp" #include "../lib/metric_report_definition.hpp" #include "../lib/network_protocol.hpp" -@@ -206,6 +207,8 @@ class RedfishService +@@ -211,6 +212,8 @@ class RedfishService nodes.emplace_back(std::make_unique(app)); nodes.emplace_back(std::make_unique(app)); @@ -60,7 +64,7 @@ index 6c4e810..bb747c4 100644 static constexpr const char* metricReportUri = diff --git a/redfish-core/lib/metric_definition.hpp b/redfish-core/lib/metric_definition.hpp new file mode 100644 -index 0000000..837a068 +index 0000000..1417efa --- /dev/null +++ b/redfish-core/lib/metric_definition.hpp @@ -0,0 +1,300 @@ @@ -127,7 +131,7 @@ index 0000000..837a068 +class MetricDefinitionCollection : public Node +{ + public: -+ MetricDefinitionCollection(CrowApp& app) : ++ MetricDefinitionCollection(App& app) : + Node(app, "/redfish/v1/TelemetryService/MetricDefinitions") + { + entityPrivileges = { @@ -140,8 +144,8 @@ index 0000000..837a068 + } + + private: -+ void doGet(crow::Response& res, const crow::Request& req, -+ const std::vector& params) override ++ void doGet(crow::Response& res, const crow::Request&, ++ const std::vector&) override + { + res.jsonValue["@odata.type"] = "#MetricDefinitionCollection." + "MetricDefinitionCollection"; @@ -165,7 +169,7 @@ index 0000000..837a068 + retrieveUriToDbusMap( + chassisName, sensorNode.data(), + [asyncResp, collectionReduce]( -+ const boost::beast::http::status status, ++ const boost::beast::http::status, + const boost::container::flat_map< + std::string, std::string>& uriToDbus) { + *collectionReduce += uriToDbus; @@ -219,7 +223,7 @@ index 0000000..837a068 +class MetricDefinition : public Node +{ + public: -+ MetricDefinition(CrowApp& app) : ++ MetricDefinition(App& app) : + Node(app, std::string(telemetry::metricDefinitionUri) + "/", + std::string()) + { @@ -233,7 +237,7 @@ index 0000000..837a068 + } + + private: -+ void doGet(crow::Response& res, const crow::Request& req, ++ void doGet(crow::Response& res, const crow::Request&, + const std::vector& params) override + { + auto asyncResp = std::make_shared(res); @@ -280,7 +284,7 @@ index 0000000..837a068 + retrieveUriToDbusMap( + chassisName, sensorNode.data(), + [asyncResp, definitionGather]( -+ const boost::beast::http::status status, ++ const boost::beast::http::status, + const boost::container::flat_map< + std::string, std::string>& uriToDbus) { + *definitionGather += uriToDbus; @@ -365,7 +369,7 @@ index 0000000..837a068 + +} // namespace redfish diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp -index 877e7f1..be72b18 100644 +index 768cce9..bcb0d3e 100644 --- a/redfish-core/lib/metric_report.hpp +++ b/redfish-core/lib/metric_report.hpp @@ -91,6 +91,9 @@ class MetricReport : public Node @@ -462,10 +466,10 @@ index 877e7f1..be72b18 100644 "xyz.openbmc_project.MonitoringService", reportPath, "xyz.openbmc_project.MonitoringService.Report"); diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp -index f12bbe0..1fa1009 100644 +index 567cb0c..2f7f70b 100644 --- a/redfish-core/lib/sensors.hpp +++ b/redfish-core/lib/sensors.hpp -@@ -53,20 +53,39 @@ static constexpr std::string_view thermal = "Thermal"; +@@ -54,20 +54,39 @@ static constexpr std::string_view thermal = "Thermal"; namespace dbus { @@ -518,7 +522,7 @@ index f12bbe0..1fa1009 100644 /** diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp -index a410700..79e4154 100644 +index b849781..efbef6e 100644 --- a/redfish-core/lib/telemetry_service.hpp +++ b/redfish-core/lib/telemetry_service.hpp @@ -52,6 +52,8 @@ class TelemetryService : public Node diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch deleted file mode 100644 index 75d49b6d6..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Fix-MetricReport-timestamp-for-EventService.patch +++ /dev/null @@ -1,78 +0,0 @@ -From b71f087a173c36a16526156fa34581673e2b860c Mon Sep 17 00:00:00 2001 -From: "Wludzik, Jozef" -Date: Fri, 24 Jul 2020 17:05:38 +0200 -Subject: [PATCH 6/6] Fix MetricReport timestamp for EventService - -Changed MetricReport timestamp type from std::string to int32_t. - -Signed-off-by: Wludzik, Jozef -Change-Id: I0a52b6963e7bedda89a216256f64764cd8799bf1 ---- - redfish-core/include/event_service_manager.hpp | 23 +++++++++++++---------- - 1 file changed, 13 insertions(+), 10 deletions(-) - -diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index d2f4f2a..dc04ccb 100644 ---- a/redfish-core/include/event_service_manager.hpp -+++ b/redfish-core/include/event_service_manager.hpp -@@ -38,7 +38,7 @@ namespace redfish - { - - using ReadingsObjType = -- std::vector>; -+ std::vector>; - using EventServiceConfig = std::tuple; - - static constexpr const char* eventFormatType = "Event"; -@@ -532,10 +532,12 @@ class Subscription - metricValuesArray.push_back({}); - nlohmann::json& entry = metricValuesArray.back(); - -- entry = {{"MetricId", std::get<0>(it)}, -- {"MetricProperty", std::get<1>(it)}, -- {"MetricValue", std::to_string(std::get<2>(it))}, -- {"Timestamp", std::get<3>(it)}}; -+ auto& [id, property, value, timestamp] = it; -+ -+ entry = {{"MetricId", id}, -+ {"MetricProperty", property}, -+ {"MetricValue", value}, -+ {"Timestamp", crow::utility::getDateTime(timestamp)}}; - } - - nlohmann::json msg = { -@@ -1266,7 +1268,7 @@ class EventServiceManager - [idStr{std::move(idStr)}]( - const boost::system::error_code ec, - boost::container::flat_map< -- std::string, std::variant>& -+ std::string, std::variant>& - resp) { - if (ec) - { -@@ -1275,8 +1277,8 @@ class EventServiceManager - return; - } - -- const std::string* timestampPtr = -- std::get_if(&resp["Timestamp"]); -+ const int32_t* timestampPtr = -+ std::get_if(&resp["Timestamp"]); - if (!timestampPtr) - { - BMCWEB_LOG_DEBUG << "Failed to Get timestamp."; -@@ -1303,8 +1305,9 @@ class EventServiceManager - std::shared_ptr entry = it.second; - if (entry->eventFormatType == metricReportFormatType) - { -- entry->filterAndSendReports(idStr, *timestampPtr, -- *readingsPtr); -+ entry->filterAndSendReports( -+ idStr, crow::utility::getDateTime(*timestampPtr), -+ *readingsPtr); - } - } - }, --- -2.16.6 - -- cgit v1.2.3