diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb')
14 files changed, 677 insertions, 1417 deletions
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-configuration-changes.patch index 3895424ac..022ffdc76 100644 --- 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-configuration-changes.patch @@ -1,13 +1,23 @@ -From 98c57392535227f1906fdc2d6f65980267b5d97c Mon Sep 17 00:00:00 2001 +From 98a84ed284fe71e276d425dbe67a447b6fca1eff Mon Sep 17 00:00:00 2001 From: Vikram Bodireddy <vikram.bodireddy@intel.com> -Date: Tue, 30 Jun 2020 21:47:55 +0530 -Subject: [PATCH] Firmware update support for StandBySpare +Date: Wed, 18 Nov 2020 17:14:41 +0530 +Subject: [PATCH 01/10] Firmware update configuration changes -Firmware update support for StandBySpare. This will -have support for adding 'HttpPushUriTargets' and +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 ......... @@ -24,15 +34,24 @@ Tested: - 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 <vikram.bodireddy@intel.com> + +%% original patch: 0001-Firmware-update-configuration-changes.patch --- - redfish-core/lib/update_service.hpp | 276 ++++++++++++++++++++++++---- - 1 file changed, 243 insertions(+), 33 deletions(-) + 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 8dae2fb..86ddd8a 100644 +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<sdbusplus::bus::match::match> fwUpdateErrorMatcher; @@ -178,12 +197,12 @@ index 8dae2fb..86ddd8a 100644 // 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> asyncResp, + static void softwareInterfaceAdded(const std::shared_ptr<AsyncResp>& asyncResp, + const std::vector<std::string> imgUriTargets, sdbusplus::message::message& m, const crow::Request& req) { -@@ -73,25 +176,27 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, +@@ -73,22 +176,24 @@ static void softwareInterfaceAdded(const std::shared_ptr<AsyncResp>& asyncResp, m.read(objPath, interfacesProperties); @@ -196,9 +215,6 @@ index 8dae2fb..86ddd8a 100644 - 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, @@ -215,7 +231,7 @@ index 8dae2fb..86ddd8a 100644 BMCWEB_LOG_DEBUG << "error msg = " << error_code.message(); if (asyncResp) -@@ -118,7 +223,7 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, +@@ -115,7 +220,7 @@ static void softwareInterfaceAdded(const std::shared_ptr<AsyncResp>& asyncResp, // is added fwAvailableTimer = nullptr; @@ -224,7 +240,7 @@ index 8dae2fb..86ddd8a 100644 if (asyncResp) { std::shared_ptr<task::TaskData> task = -@@ -248,18 +353,17 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, +@@ -245,8 +350,7 @@ static void softwareInterfaceAdded(const std::shared_ptr<AsyncResp>& asyncResp, "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper", "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, @@ -234,21 +250,17 @@ index 8dae2fb..86ddd8a 100644 } } } - - // Note that asyncResp can be either a valid pointer or nullptr. If nullptr +@@ -255,7 +359,8 @@ static void softwareInterfaceAdded(const std::shared_ptr<AsyncResp>& asyncResp, // then no asyncResp updates will occur --static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, -- const crow::Request& req, -- const std::string& url, -- int timeoutTimeSeconds = 5) -+static void monitorForSoftwareAvailable( -+ std::shared_ptr<AsyncResp> asyncResp, const crow::Request& req, + static void monitorForSoftwareAvailable( + const std::shared_ptr<AsyncResp>& asyncResp, const crow::Request& req, +- const std::string& url, int timeoutTimeSeconds = 10) + const std::string& url, const std::vector<std::string>& imgUriTargets, -+ int timeoutTimeSeconds = 5) ++ int timeoutTimeSeconds = 10) { // Only allow one FW update at a time if (fwUpdateInProgress != false) -@@ -299,9 +403,10 @@ static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, +@@ -295,9 +400,10 @@ static void monitorForSoftwareAvailable( } }); @@ -261,7 +273,7 @@ index 8dae2fb..86ddd8a 100644 }; fwUpdateInProgress = true; -@@ -467,12 +572,15 @@ class UpdateServiceActionsSimpleUpdate : public Node +@@ -463,12 +569,15 @@ class UpdateServiceActionsSimpleUpdate : public Node std::string fwFile = imageURI.substr(separator + 1); BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile; @@ -269,36 +281,35 @@ index 8dae2fb..86ddd8a 100644 + std::vector<std::string> httpUriTargets; + // Setup callback for when new software detected - // Give TFTP 2 minutes to complete + // Give TFTP 10 minutes to complete monitorForSoftwareAvailable( nullptr, req, "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate", -- 120); -+ httpUriTargets, 120); +- 600); ++ httpUriTargets, 600); - // TFTP can take up to 2 minutes depending on image size and + // TFTP can take up to 10 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 +@@ -502,7 +611,8 @@ class UpdateServiceActionsSimpleUpdate : public Node class UpdateService : public Node { public: -- UpdateService(CrowApp& app) : Node(app, "/redfish/v1/UpdateService/") -+ UpdateService(CrowApp& app) : +- 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"}}}, -@@ -518,6 +627,9 @@ class UpdateService : public Node +@@ -514,6 +624,8 @@ class UpdateService : public Node } private: + std::vector<std::string> httpPushUriTargets; + bool httpPushUriTargetBusy; -+ - void doGet(crow::Response& res, const crow::Request& req, - const std::vector<std::string>& params) override + void doGet(crow::Response& res, const crow::Request&, + const std::vector<std::string>&) override { -@@ -528,6 +640,8 @@ class UpdateService : public Node +@@ -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"; @@ -307,7 +318,37 @@ index 8dae2fb..86ddd8a 100644 // UpdateService cannot be disabled res.jsonValue["ServiceEnabled"] = true; res.jsonValue["FirmwareInventory"] = { -@@ -587,9 +701,14 @@ class UpdateService : public Node +@@ -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<bool> applyOption) { ++ if (ec) ++ { ++ BMCWEB_LOG_DEBUG << "DBUS response error " << ec; ++ messages::internalError(aResp->res); ++ return; ++ } ++ ++ const bool* b = std::get_if<bool>(&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> asyncResp = std::make_shared<AsyncResp>(res); std::optional<nlohmann::json> pushUriOptions; @@ -315,16 +356,63 @@ index 8dae2fb..86ddd8a 100644 - pushUriOptions)) + std::optional<std::vector<std::string>> imgTargets; + std::optional<bool> imgTargetBusy; ++ std::optional<nlohmann::json> 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; } -@@ -657,6 +776,98 @@ class UpdateService : public Node ++ if (oemProps) ++ { ++ std::optional<nlohmann::json> applyOptions; ++ ++ if (!json_util::readJson(*oemProps, res, "ApplyOptions", ++ applyOptions)) ++ { ++ return; ++ } ++ ++ if (applyOptions) ++ { ++ std::optional<bool> 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<bool>{*clearConfig}); ++ } ++ } ++ } ++ + if (pushUriOptions) + { + std::optional<nlohmann::json> pushUriApplyTime; +@@ -653,6 +839,98 @@ class UpdateService : public Node } } } @@ -423,7 +511,7 @@ index 8dae2fb..86ddd8a 100644 } void doPost(crow::Response& res, const crow::Request& req, -@@ -667,8 +878,8 @@ class UpdateService : public Node +@@ -663,8 +941,8 @@ class UpdateService : public Node std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); // Setup callback for when new software detected @@ -434,7 +522,7 @@ index 8dae2fb..86ddd8a 100644 std::string filepath( "/tmp/images/" + -@@ -754,7 +965,7 @@ class SoftwareInventoryCollection : public Node +@@ -749,7 +1027,7 @@ class SoftwareInventoryCollection : public Node "/xyz/openbmc_project/object_mapper", "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/xyz/openbmc_project/software", static_cast<int32_t>(0), @@ -443,7 +531,7 @@ index 8dae2fb..86ddd8a 100644 } }; -@@ -937,7 +1148,7 @@ class SoftwareInventory : public Node +@@ -931,7 +1209,7 @@ class SoftwareInventory : public Node }, obj.second[0].first, obj.first, "org.freedesktop.DBus.Properties", "GetAll", @@ -452,7 +540,7 @@ index 8dae2fb..86ddd8a 100644 } if (!found) { -@@ -958,8 +1169,7 @@ class SoftwareInventory : public Node +@@ -952,8 +1230,7 @@ class SoftwareInventory : public Node "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper", "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", @@ -462,6 +550,127 @@ index 8dae2fb..86ddd8a 100644 } }; +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 @@ ++<?xml version="1.0" encoding="UTF-8"?> ++<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0"> ++ <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/errata03/csd01/complete/vocabularies/Org.OData.Core.V1.xml"> ++ <edmx:Include Namespace="Org.OData.Core.V1" Alias="OData" /> ++ </edmx:Reference> ++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/RedfishExtensions_v1.xml"> ++ <edmx:Include Namespace="Validation.v1_0_0" Alias="Validation"/> ++ <edmx:Include Namespace="RedfishExtensions.v1_0_0" Alias="Redfish"/> ++ </edmx:Reference> ++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/UpdateService_v1.xml"> ++ <edmx:Include Namespace="UpdateService"/> ++ <edmx:Include Namespace="UpdateService.v1_4_0"/> ++ </edmx:Reference> ++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/Resource_v1.xml"> ++ <edmx:Include Namespace="Resource"/> ++ <edmx:Include Namespace="Resource.v1_0_0"/> ++ </edmx:Reference> ++ ++ <edmx:DataServices> ++ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="OemUpdateService"> ++ <ComplexType Name="Oem" BaseType="Resource.OemObject"> ++ <Annotation Term="OData.AdditionalProperties" Bool="true" /> ++ <Annotation Term="OData.Description" String="OemUpdateService Oem properties." /> ++ <Annotation Term="OData.AutoExpand"/> ++ <Property Name="ApplyOptions" Type="OemUpdateService.ApplyOptions"/> ++ </ComplexType> ++ ++ <ComplexType Name="ApplyOptions" BaseType="Resource.OemObject"> ++ <Annotation Term="OData.AdditionalProperties" Bool="false" /> ++ <Annotation Term="OData.Description" String="An indication by boolean value whether to update firmware configuration along with firmware image update." /> ++ <Property Name="ClearConfig" Type="Edm.Boolean"> ++ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/ReadWrite"/> ++ <Annotation Term="OData.Description" String="This indicates whether to update firmware configuration or not."/> ++ <Annotation Term="OData.LongDescription" String="The value of this property is used to indicate the firmware configuration update."/> ++ </Property> ++ </ComplexType> ++ ++ </Schema> ++ </edmx:DataServices> ++</edmx:Edmx> -- -2.17.1 +2.16.6 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 <wiktor.golgowski@linux.intel.com> 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 <wiktor.golgowski@linux.intel.com> - --- - 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 <vikram.bodireddy@intel.com> -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 <vikram.bodireddy@intel.com> ---- - 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<bool> applyOption) { -+ if (ec) -+ { -+ BMCWEB_LOG_DEBUG << "DBUS response error " << ec; -+ messages::internalError(aResp->res); -+ return; -+ } -+ -+ const bool* b = std::get_if<bool>(&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<nlohmann::json> pushUriOptions; - std::optional<std::vector<std::string>> imgTargets; - std::optional<bool> imgTargetBusy; -+ std::optional<nlohmann::json> 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<nlohmann::json> applyOptions; -+ -+ if (!json_util::readJson(*oemProps, res, "ApplyOptions", -+ applyOptions)) -+ { -+ return; -+ } -+ -+ if (applyOptions) -+ { -+ std::optional<bool> 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<bool>{*clearConfig}); -+ } -+ } -+ } -+ - if (pushUriOptions) - { - std::optional<nlohmann::json> 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 @@ -+<?xml version="1.0" encoding="UTF-8"?> -+<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0"> -+ <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/errata03/csd01/complete/vocabularies/Org.OData.Core.V1.xml"> -+ <edmx:Include Namespace="Org.OData.Core.V1" Alias="OData" /> -+ </edmx:Reference> -+ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/RedfishExtensions_v1.xml"> -+ <edmx:Include Namespace="Validation.v1_0_0" Alias="Validation"/> -+ <edmx:Include Namespace="RedfishExtensions.v1_0_0" Alias="Redfish"/> -+ </edmx:Reference> -+ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/UpdateService_v1.xml"> -+ <edmx:Include Namespace="UpdateService"/> -+ <edmx:Include Namespace="UpdateService.v1_4_0"/> -+ </edmx:Reference> -+ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/Resource_v1.xml"> -+ <edmx:Include Namespace="Resource"/> -+ <edmx:Include Namespace="Resource.v1_0_0"/> -+ </edmx:Reference> -+ -+ <edmx:DataServices> -+ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="OemUpdateService"> -+ <ComplexType Name="Oem" BaseType="Resource.OemObject"> -+ <Annotation Term="OData.AdditionalProperties" Bool="true" /> -+ <Annotation Term="OData.Description" String="OemUpdateService Oem properties." /> -+ <Annotation Term="OData.AutoExpand"/> -+ <Property Name="ApplyOptions" Type="OemUpdateService.ApplyOptions"/> -+ </ComplexType> -+ -+ <ComplexType Name="ApplyOptions" BaseType="Resource.OemObject"> -+ <Annotation Term="OData.AdditionalProperties" Bool="false" /> -+ <Annotation Term="OData.Description" String="An indication by boolean value whether to update firmware configuration along with firmware image update." /> -+ <Property Name="ClearConfig" Type="Edm.Boolean"> -+ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/ReadWrite"/> -+ <Annotation Term="OData.Description" String="This indicates whether to update firmware configuration or not."/> -+ <Annotation Term="OData.LongDescription" String="The value of this property is used to indicate the firmware configuration update."/> -+ </Property> -+ </ComplexType> -+ -+ </Schema> -+ </edmx:DataServices> -+</edmx:Edmx> --- -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 <james.feist@linux.intel.com> -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 <james.feist@linux.intel.com> ---- - 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 <boost/beast/http.hpp> - #include <boost/beast/ssl/ssl_stream.hpp> - #include <boost/beast/websocket.hpp> -+#include <boost/url/url_view.hpp> - - namespace crow - { -@@ -24,7 +24,8 @@ struct Request - boost::beast::http::request<boost::beast::http::string_body>& 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 <cstdio> --#include <cstring> --#include <iostream> --#include <string> --#include <vector> -- --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 <ctype.h>, 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<char>(*s++); -- lnyb = static_cast<char>(*s++); -- if (BMCWEB_QS_ISHEX(unyb) && BMCWEB_QS_ISHEX(lnyb)) -- { -- u1 = static_cast<char>((BMCWEB_QS_HEX2DEC(unyb) * 16) + -- BMCWEB_QS_HEX2DEC(lnyb)); -- } -- else -- { -- u1 = '\0'; -- } -- } -- -- if (u2 == '+') -- { -- u2 = ' '; -- } -- if (u2 == '%') // easier/safer than scanf -- { -- unyb = static_cast<char>(*qs++); -- lnyb = static_cast<char>(*qs++); -- if (BMCWEB_QS_ISHEX(unyb) && BMCWEB_QS_ISHEX(lnyb)) -- { -- u2 = static_cast<char>((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<char>((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<char*>(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<char*>(p - qs.url.c_str() + url.c_str())); -- } -- return *this; -- } -- -- QueryString& operator=(QueryString&& qs) -- { -- keyValuePairs = std::move(qs.keyValuePairs); -- auto* oldData = const_cast<char*>(qs.url.c_str()); -- url = std::move(qs.url); -- for (auto& p : keyValuePairs) -- { -- p += const_cast<char*>(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<int>(keyValuePairs.size())); -- return ret; -- } -- -- std::vector<char*> getList(const std::string& name) const -- { -- std::vector<char*> ret; -- std::string plus = name + "[]"; -- char* element = nullptr; -- -- int count = 0; -- while (true) -- { -- element = qsK2v(plus.c_str(), keyValuePairs.data(), -- static_cast<int>(keyValuePairs.size()), count++); -- if (element == nullptr) -- { -- break; -- } -- ret.push_back(element); -- } -- return ret; -- } -- -- private: -- std::string url; -- std::vector<char*> 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 <karol.wachowski@intel.com> 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 <karol.wachowski@intel.com> 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 <apparao.puli@linux.intel.com> -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 <apparao.puli@linux.intel.com> --- - 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 <boost/asio/strand.hpp> - #include <boost/beast/core.hpp> - #include <boost/beast/http.hpp> -+#include <boost/beast/ssl.hpp> - #include <boost/beast/version.hpp> +@@ -31,12 +31,17 @@ namespace crow + { + + static constexpr uint8_t maxRequestQueueSize = 50; ++static constexpr unsigned int httpReadBodyLimit = 1024; - #include <cstdlib> -@@ -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<HttpClient> { 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<boost::beast::ssl_stream<boost::beast::tcp_stream>> sslConn; -+ std::shared_ptr<boost::beast::tcp_stream> conn; + boost::beast::tcp_stream conn; ++ std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream&>> sslConn; boost::asio::steady_timer timer; - boost::beast::flat_buffer buffer; +- boost::beast::flat_buffer buffer; ++ boost::beast::flat_static_buffer<httpReadBodyLimit> buffer; ++ std::optional< ++ boost::beast::http::response_parser<boost::beast::http::string_body>> ++ parser; boost::beast::http::request<boost::beast::http::string_body> req; -@@ -62,14 +66,37 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +- boost::beast::http::response<boost::beast::http::string_body> res; + boost::asio::ip::tcp::resolver::results_type endpoint; +- std::vector<std::pair<std::string, std::string>> headers; ++ boost::beast::http::fields fields; + std::queue<std::string> 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<boost::beast::tcp_stream>>(ioc, ctx); -+ } -+ else -+ { -+ conn = std::make_shared<boost::beast::tcp_stream>(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<HttpClient> + } 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<HttpClient> +@@ -107,100 +183,167 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + } + state = ConnState::sendInProgress; - BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; +- BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; ++ BMCWEB_LOG_DEBUG << host << ":" << port; - req.version(static_cast<int>(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<int>(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<HttpClient> 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<HttpClient> - BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs +@@ -232,6 +375,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + } + + 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<HttpClient> << " 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<HttpClient> + { + 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<HttpClient> + sendMessage(data); + break; + } ++ default: ++ break; } - connStateCheck(); + } -@@ -310,10 +409,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> 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<HttpClient> + void setHeaders( + const std::vector<std::pair<std::string, std::string>>& 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::HttpClient>( 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<crow::Request::Adaptor>& adaptor) : + Subscription(const std::shared_ptr<boost::beast::tcp_stream>& 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 <przemyslaw.hawrylewicz.czarnowski@intel.com> -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 <przemyslaw.hawrylewicz.czarnowski@intel.com> ---- - 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 @@ - <Annotation Term="Redfish.OwningEntity" String="OpenBMC"/> - <Annotation Term="Redfish.Release" String="1.0"/> - -- <ComplexType Name="OpenBmc" BaseType="Resource.OemObject"> -- <Annotation Term="OData.AdditionalProperties" Bool="true"/> -- <Annotation Term="OData.Description" String="Oem properties for OpenBmc." /> -- -- <Property Name="WebSocketEndpoint" Type="Edm.String"> -+ <Property Name="WebSocketEndpoint" Type="Edm.String"> - <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> - <Annotation Term="OData.Description" String="Indicates endpoint socket name and location."/> - <Annotation Term="OData.LongDescription" String="The value of this property shall be a structure ring indicating location and name of the socket used to communicate with nbd server."/> - </Property> -- </ComplexType> - - <EntityType Name="VirtualMedia" BaseType="Resource.OemObject" Abstract="true"> - <Annotation Term="OData.Description" String="OEM Extension for VirtualMedia"/> - <Annotation Term="OData.LongDescription" String="OEM Extension for VirtualMedia to support Proxy mode."/> -+ <Property Name="WebSocketEndpoint" Type="Edm.String"> -+ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> -+ <Annotation Term="OData.Description" String="Indicates endpoint socket name and location."/> -+ <Annotation Term="OData.LongDescription" String="The value of this property shall be a structure ring indicating location and name of the socket used to communicate with nbd server."/> -+ </Property> - </EntityType> - </Schema> - --- -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 <przemyslaw.hawrylewicz.czarnowski@intel.com> -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 <przemyslaw.hawrylewicz.czarnowski@intel.com> ---- - 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<std::string>(&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" <jozef.wludzik@intel.com> 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 <jozef.wludzik@intel.com> Signed-off-by: Adrian Ambrożewicz <adrian.ambrozewicz@linux.intel.com> 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<std::string, 0>()); } @@ -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<HypervisorInterface>(app)); nodes.emplace_back(std::make_unique<HypervisorSystem>(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 <http_request.h> - #include <http_response.h> - +#include <boost/container/flat_map.hpp> #include <error_messages.hpp> + #include <http_request.hpp> + #include <http_response.hpp> #include <nlohmann/json.hpp> #include <bitset> @@ -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<std::string>& params) override ++ void doGet(crow::Response& res, const crow::Request&, ++ const std::vector<std::string>&) 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) + "<str>/", + 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<std::string>& params) override + { + auto asyncResp = std::make_shared<AsyncResp>(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<std::string>& params) override ++ void doGet(crow::Response& res, const crow::Request&, ++ const std::vector<std::string>&) 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) + "<str>/", + 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<std::string>& params) override + { + auto asyncResp = std::make_shared<AsyncResp>(res); @@ -723,12 +726,10 @@ index 0000000..d82ae59 + using ReadingParameters = + std::vector<std::tuple<std::vector<sdbusplus::message::object_path>, + std::string, std::string, std::string>>; -+ using Metrics = std::vector<std::map< -+ std::string, std::variant<std::string, std::vector<std::string>>>>; + -+ 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<std::string>& params) override ++ void doGet(crow::Response& res, const crow::Request&, ++ const std::vector<std::string>&) 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" <jozef.wludzik@intel.com> 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 <jozef.wludzik@intel.com> Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com> 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<std::string>& params) override ++ const std::vector<std::string>&) override + { + auto asyncResp = std::make_shared<AsyncResp>(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<std::string, std::string>& + 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" <jozef.wludzik@intel.com> Date: Mon, 18 May 2020 12:40:15 +0200 -Subject: [PATCH 3/5] Add support for DELETE in MetricReportDefinitions/<str> +Subject: [PATCH 07/10] Add support for DELETE in MetricReportDefinitions/<str> Added support for DELETE action in MetricReportDefinitions/<str> node. It allows user to remove MetricReportDefinition together @@ -16,19 +16,23 @@ Tested: Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com> 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<std::string>& params) override + { + auto asyncResp = std::make_shared<AsyncResp>(res); @@ -43,7 +47,7 @@ index ecbab0c..8e04ac8 100644 + } + + static void deleteReport(const std::shared_ptr<AsyncResp>& 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 <krzysztof.grobelny@intel.com> 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 <krzysztof.grobelny@intel.com> 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 <sdbusplus/message.hpp> + #include <filesystem> +#include <functional> #include <regex> 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" <jozef.wludzik@intel.com> 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 <jozef.wludzik@intel.com> Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com> 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<HypervisorSystem>(app)); nodes.emplace_back(std::make_unique<TelemetryService>(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<std::string>& params) override ++ void doGet(crow::Response& res, const crow::Request&, ++ const std::vector<std::string>&) 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) + "<str>/", + 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<std::string>& params) override + { + auto asyncResp = std::make_shared<AsyncResp>(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" <jozef.wludzik@intel.com> -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 <jozef.wludzik@intel.com> -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::tuple<std::string, std::string, double, std::string>>; -+ std::vector<std::tuple<std::string, std::string, double, int32_t>>; - using EventServiceConfig = std::tuple<bool, uint32_t, uint32_t>; - - 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, ReadingsObjType>>& -+ std::string, std::variant<int32_t, ReadingsObjType>>& - resp) { - if (ec) - { -@@ -1275,8 +1277,8 @@ class EventServiceManager - return; - } - -- const std::string* timestampPtr = -- std::get_if<std::string>(&resp["Timestamp"]); -+ const int32_t* timestampPtr = -+ std::get_if<int32_t>(&resp["Timestamp"]); - if (!timestampPtr) - { - BMCWEB_LOG_DEBUG << "Failed to Get timestamp."; -@@ -1303,8 +1305,9 @@ class EventServiceManager - std::shared_ptr<Subscription> entry = it.second; - if (entry->eventFormatType == metricReportFormatType) - { -- entry->filterAndSendReports(idStr, *timestampPtr, -- *readingsPtr); -+ entry->filterAndSendReports( -+ idStr, crow::utility::getDateTime(*timestampPtr), -+ *readingsPtr); - } - } - }, --- -2.16.6 - |