summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces
diff options
context:
space:
mode:
authorJason M. Bills <jason.m.bills@linux.intel.com>2021-01-27 22:47:14 +0300
committerJason M. Bills <jason.m.bills@linux.intel.com>2021-01-28 02:23:52 +0300
commit7c5f8839ec3d71a2170b8f3514a16a67c69d1c7c (patch)
tree729dbf87ba33bf4d83b5d95496ce18f99a61ef03 /meta-openbmc-mods/meta-common/recipes-phosphor/interfaces
parent98cc5cd6483975b64d80e8323f7f659dd1337d75 (diff)
downloadopenbmc-7c5f8839ec3d71a2170b8f3514a16a67c69d1c7c.tar.xz
Update to internal 0.29
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Define-Redfish-interface-Registries-Bios.patch850
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-BIOS-config-Add-support-for-PATCH-operation.patch154
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-Add-support-to-ResetBios-action.patch62
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Add-support-to-ChangePassword-action.patch139
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch57
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0034-recommended-fixes-by-crypto-review-team.patch75
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Redfish-TelemetryService-schema-implementation.patch813
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-POST-and-DELETE-in-MetricReportDefinitions.patch683
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-support-for-POST-in-MetricReportDefinitions.patch598
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch72
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch709
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch171
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Sync-Telmetry-service-with-EventService.patch330
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch539
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend17
16 files changed, 3386 insertions, 1902 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Define-Redfish-interface-Registries-Bios.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Define-Redfish-interface-Registries-Bios.patch
new file mode 100644
index 000000000..dd2f3483d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0006-Define-Redfish-interface-Registries-Bios.patch
@@ -0,0 +1,850 @@
+From 5e3b0c1f8add50acca911a927ba8a1f4864cb315 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Fri, 4 Sep 2020 19:24:25 +0800
+Subject: [PATCH] Define Redfish interface "/Registries/Bios" and enable
+ Attributes property
+
+1. Define Redfish interface "/Registries/Bios" for BIOS Attribute Registry
+ RBC Daemon provide method to get BIOS attribute registry.
+2. Eanble Attributes property for BIOS resource
+3. Define Redfish interface "/Systems/system/Bios/Settings" for BIOS
+settings
+4. RBC daemon is at
+https://gerrit.openbmc-project.xyz/#/c/openbmc/bios-settings-mgr/+/35563/
+5. IPMI command implementation is at
+https://gerrit.openbmc-project.xyz/#/c/openbmc/intel-ipmi-oem/+/30827/
+6. Property design is at
+https://github.com/openbmc/phosphor-dbus-interfaces/tree/master/xyz/openbmc_project/BIOSConfig
+7. Design doc is at
+https://github.com/openbmc/docs/blob/master/designs/remote-bios-configuration.md
+8. There will be 95 test cases for this feature in the validation team.
+
+Tested:
+
+1. Use postman (Redfish tool) could get all the attributes in bios
+resouce, get bios settings, get bios attribute
+registry.
+https://IP_ADDR/redfish/v1/Systems/system/Bios
+{
+ "@Redfish.Settings": {
+ "@odata.type": "#Settings.v1_3_0.Settings",
+ "SettingsObject": {
+ "@odata.id": "/redfish/v1/Systems/system/Bios/Settings"
+ }
+ },
+ "@odata.id": "/redfish/v1/Systems/system/Bios",
+ "@odata.type": "#Bios.v1_1_0.Bios",
+ "Actions": {
+ "#Bios.ChangePassword": {
+ "target": "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword"
+ },
+ "#Bios.ResetBios": {
+ "target": "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios"
+ }
+ },
+ "AttributeRegistry": "BiosAttributeRegistry",
+ "Attributes": {
+ "attr0": "current value"
+ },
+ "Description": "BIOS Configuration Service",
+ "Id": "BIOS",
+ "Links": {
+ "ActiveSoftwareImage": {
+ "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bios_active"
+ },
+ "SoftwareImages": [
+ {
+ "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/bios_active"
+ }
+ ],
+ "SoftwareImages@odata.count": 1
+ },
+ "Name": "BIOS Configuration"
+}
+
+Redfish interface: https://BMCIP/redfish/v1/Registries/BiosAttributeRegistry
+{
+ "@odata.id": "/redfish/v1/Registries/BiosAttributeRegistry",
+ "@odata.type": "#MessageRegistryFile.v1_1_0.MessageRegistryFile",
+ "Description": "BiosAttributeRegistry Message Registry File Location",
+ "Id": "BiosAttributeRegistry",
+ "Languages": [
+ "en"
+ ],
+ "Languages@odata.count": 1,
+ "Location": [
+ {
+ "Language": "en",
+ "Uri": "/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry"
+ }
+ ],
+ "Location@odata.count": 1,
+ "Name": "BiosAttributeRegistry Message Registry File",
+ "Registry": "BiosAttributeRegistry.1.0.0"
+}
+
+Redfish interface: https://BMCIP/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry
+{
+ "@odata.id": "/redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry",
+ "@odata.type": "#AttributeRegistry.v1_3_2.AttributeRegistry",
+ "Id": "BiosAttributeRegistry",
+ "Language": "en",
+ "Name": "Bios Attribute Registry",
+ "OwningEntity": "OpenBMC",
+ "RegistryEntries": {
+ "Attributes": [
+ {
+ "AttributeName": "attr0",
+ "CurrentValue": "current value",
+ "DefaultValue": "default value",
+ "DisplayName": "display name for attr0",
+ "HelpText": "description for attr0",
+ "MenuPath": "./menu/path/for/attr0",
+ "ReadOnly": false,
+ "Type": "String",
+ "Value": []
+ }
+ ]
+ },
+ "RegistryVersion": "1.0.0"
+}
+
+https://BMC_IPADDR/redfish/v1/Systems/system/Bios/Settings
+{
+ "@odata.id": "/redfish/v1/Systems/system/Bios/Settings",
+ "@odata.type": "#Bios.v1_1_0.Bios",
+ "AttributeRegistry": "BiosAttributeRegistry",
+ "Attributes": {
+ "QuietBoot": "0x0"
+ },
+ "Id": "BiosSettingsV1",
+ "Name": "Bios Settings Version 1"
+}
+
+2. Passed Validator check for bios resource and bios attribute registry
+*** /redfish/v1/Systems/system/Bios
+INFO - Type (#Bios.v1_1_0.Bios), GET SUCCESS (time: 1.57377)
+INFO - PASS
+*** /redfish/v1/Registries/BiosAttributeRegistry
+INFO - Type (#MessageRegistryFile.v1_1_0.MessageRegistryFile), GET SUCCESS (time: 0.075438)
+INFO - PASS
+INFO -
+*** /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry
+INFO - Type (#AttributeRegistry.v1_3_2.AttributeRegistry), GET SUCCESS (time: 0.075751)
+INFO - PASS
+
+@odata.id /redfish/v1/Systems/system/Bios odata Exists PASS
+@odata.type #Settings.v1_3_0.Settings odata Exists PASS
+Links [JSON Object] Bios.v1_1_0.Links Yes complex
+Links.ActiveSoftwareImage Link: /redfish/v1/UpdateService/FirmwareInventory/bios_active link to: SoftwareInventory Yes PASS
+Links.SoftwareImages Array (size: 1) array of: SoftwareInventory Yes ...
+Links.SoftwareImages[0] Link: /redfish/v1/UpdateService/FirmwareInventory/bios_active SoftwareInventory Yes PASS
+Links.Oem - Resource.Oem No Optional
+SoftwareImages@odata.count 1 odata Exists PASS
+AttributeRegistry BiosAttributeRegistry string Yes PASS
+Actions [JSON Object] Bios.v1_0_0.Actions Yes complex
+Actions.#Bios.ResetBios Action - Yes PASS
+Actions.#Bios.ChangePassword Action - Yes PASS
+Attributes [JSON Object] Bios.v1_0_0.Attributes Yes complex
+Attributes.attr0 current value primitive Yes PASS
+Id BIOS string Yes PASS
+Description BIOS Configuration Service string Yes PASS
+Name BIOS Configuration string Yes PASS
+Oem - Resource.Oem No Optional
+@Redfish.Settings [JSON Object] Settings.Settings Yes complex
+@Redfish.Settings.MaintenanceWindowResource - link to: ItemOrCollection No Optional
+@Redfish.Settings.SupportedApplyTimes - string (enum) No Optional
+@Redfish.Settings.Time - date No Optional
+@Redfish.Settings.ETag - string No Optional
+@Redfish.Settings.SettingsObject Link: /redfish/v1/Systems/system/Bios/Settings link to: Item Yes PASS
+@Redfish.Settings.Messages - Message No Optional
+
+@odata.id /redfish/v1/Registries/BiosAttributeRegistry odata Exists PASS
+@odata.type #MessageRegistryFile.v1_1_0.MessageRegistryFile odata Exists PASS
+Languages@odata.count 1 odata Exists PASS
+Location@odata.count 1 odata Exists PASS
+Actions - MessageRegistryFile.v1_1_0.Actions No Optional
+Languages Array (size: 1) string Yes ...
+Languages[0] en string Yes PASS
+Registry BiosAttributeRegistry.1.0.0 string Yes PASS
+Location Array (size: 1) array of: Location Yes ...
+Location[0] [JSON Object] Location Yes complex
+Location[0].Language en string Yes PASS
+Location[0].Uri /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry string Yes PASS
+Location[0].ArchiveUri - string No Optional
+Location[0].PublicationUri - string No Optional
+Location[0].ArchiveFile - string No Optional
+Id BiosAttributeRegistry string Yes PASS
+Description BiosAttributeRegistry Message Registry File Location string Yes PASS
+Name BiosAttributeRegistry Message Registry File string Yes PASS
+Oem - Resource.Oem No Optional
+
+@odata.id /redfish/v1/Registries/BiosAttributeRegistry/BiosAttributeRegistry odata Exists PASS
+@odata.type #AttributeRegistry.v1_3_2.AttributeRegistry odata Exists PASS
+Actions - AttributeRegistry.v1_1_0.Actions No Optional
+Language en string Yes PASS
+RegistryVersion 1.0.0 string Yes PASS
+OwningEntity OpenBMC string Yes PASS
+SupportedSystems - SupportedSystems No Optional
+RegistryEntries [JSON Object] AttributeRegistry.v1_0_0.RegistryEntries Yes complex
+RegistryEntries.Attributes Array (size: 1) array of: Attributes Yes ...
+RegistryEntries.Attributes[0] [JSON Object] Attributes Yes complex
+RegistryEntries.Attributes[0].Oem - Resource.Oem No Optional
+RegistryEntries.Attributes[0].ResetRequired - boolean No Optional
+RegistryEntries.Attributes[0].UefiDevicePath - string No Optional
+RegistryEntries.Attributes[0].UefiKeywordName - string No Optional
+RegistryEntries.Attributes[0].UefiNamespaceId - string No Optional
+RegistryEntries.Attributes[0].AttributeName attr0 string Yes PASS
+RegistryEntries.Attributes[0].Type String string (enum) Yes PASS
+RegistryEntries.Attributes[0].Value Array (size: 0) array of: AttributeValue Yes ...
+RegistryEntries.Attributes[0].DisplayName display name for attr0 string Yes PASS
+RegistryEntries.Attributes[0].HelpText description for attr0 string Yes PASS
+RegistryEntries.Attributes[0].WarningText - string No Optional
+RegistryEntries.Attributes[0].CurrentValue current value primitive Yes PASS
+RegistryEntries.Attributes[0].DefaultValue default value primitive Yes PASS
+RegistryEntries.Attributes[0].DisplayOrder - number No Optional
+RegistryEntries.Attributes[0].MenuPath ./menu/path/for/attr0 string Yes PASS
+RegistryEntries.Attributes[0].ReadOnly False boolean Yes PASS
+RegistryEntries.Attributes[0].WriteOnly - boolean No Optional
+RegistryEntries.Attributes[0].GrayOut - boolean No Optional
+RegistryEntries.Attributes[0].Hidden - boolean No Optional
+RegistryEntries.Attributes[0].Immutable - boolean No Optional
+RegistryEntries.Attributes[0].IsSystemUniqueProperty - boolean No Optional
+RegistryEntries.Attributes[0].MaxLength - number No Optional
+RegistryEntries.Attributes[0].MinLength - number No Optional
+RegistryEntries.Attributes[0].ScalarIncrement - number No Optional
+RegistryEntries.Attributes[0].UpperBound - number No Optional
+RegistryEntries.Attributes[0].LowerBound - number No Optional
+RegistryEntries.Attributes[0].ValueExpression - string No Optional
+RegistryEntries.Menus - Menus No Optional
+RegistryEntries.Dependencies - Dependencies No Optional
+Id BiosAttributeRegistry string Yes PASS
+Description - string No Optional
+Name Bios Attribute Registry string Yes PASS
+Oem - Resource.Oem No Optional
+
+Change-Id: Iecc61018c350f0b8c89df59b2864b941508b1916
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ redfish-core/include/redfish.hpp | 2 +
+ .../include/registries/bios_registry.hpp | 31 ++
+ redfish-core/lib/bios.hpp | 503 ++++++++++++++++++
+ redfish-core/lib/message_registries.hpp | 9 +-
+ 4 files changed, 544 insertions(+), 1 deletion(-)
+ create mode 100644 redfish-core/include/registries/bios_registry.hpp
+
+diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
+index 5d5eb7b..a8e5cf2 100644
+--- a/redfish-core/include/redfish.hpp
++++ b/redfish-core/include/redfish.hpp
+@@ -157,6 +157,8 @@ class RedfishService
+ nodes.emplace_back(std::make_unique<SystemActionsReset>(app));
+ nodes.emplace_back(std::make_unique<SystemResetActionInfo>(app));
+ nodes.emplace_back(std::make_unique<BiosService>(app));
++ nodes.emplace_back(std::make_unique<BiosSettings>(app));
++ nodes.emplace_back(std::make_unique<BiosAttributeRegistry>(app));
+ nodes.emplace_back(std::make_unique<BiosReset>(app));
+ #ifdef BMCWEB_ENABLE_VM_NBDPROXY
+ nodes.emplace_back(std::make_unique<VirtualMedia>(app));
+diff --git a/redfish-core/include/registries/bios_registry.hpp b/redfish-core/include/registries/bios_registry.hpp
+new file mode 100644
+index 0000000..88ef782
+--- /dev/null
++++ b/redfish-core/include/registries/bios_registry.hpp
+@@ -0,0 +1,31 @@
++/*
++// Copyright (c) 2020 Intel Corporation
++//
++// Licensed under the Apache License, Version 2.0 (the "License");
++// you may not use this file except in compliance with the License.
++// You may obtain a copy of the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS,
++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++// See the License for the specific language governing permissions and
++// limitations under the License.
++*/
++#pragma once
++
++namespace redfish::message_registries::bios
++{
++const Header header = {
++ "Copyright 2020 OpenBMC. All rights reserved.",
++ "#MessageRegistry.v1_4_0.MessageRegistry",
++ "BiosAttributeRegistry.1.0.0",
++ "Bios Attribute Registry",
++ "en",
++ "This registry defines the messages for bios attribute registry.",
++ "BiosAttributeRegistry",
++ "1.0.0",
++ "OpenBMC",
++};
++} // namespace redfish::message_registries::bios
+\ No newline at end of file
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index 2c31077..5f8c91b 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -3,8 +3,140 @@
+ #include "node.hpp"
+
+ #include <utils/fw_utils.hpp>
++
+ namespace redfish
+ {
++
++/*baseBIOSTable
++map{attributeName,struct{attributeType,readonlyStatus,displayname,
++ description,menuPath,current,default,
++ array{struct{optionstring,optionvalue}}}}
++*/
++using BiosBaseTableType = std::vector<std::pair<
++ std::string,
++ std::tuple<
++ std::string, bool, std::string, std::string, std::string,
++ std::variant<int64_t, std::string>, std::variant<int64_t, std::string>,
++ std::vector<
++ std::tuple<std::string, std::variant<int64_t, std::string>>>>>>;
++using BiosBaseTableItemType = std::pair<
++ std::string,
++ std::tuple<
++ std::string, bool, std::string, std::string, std::string,
++ std::variant<int64_t, std::string>, std::variant<int64_t, std::string>,
++ std::vector<
++ std::tuple<std::string, std::variant<int64_t, std::string>>>>>;
++using OptionsItemType =
++ std::tuple<std::string, std::variant<int64_t, std::string>>;
++
++enum BiosBaseTableIndex
++{
++ biosBaseAttrType = 0,
++ biosBaseReadonlyStatus,
++ biosBaseDisplayName,
++ biosBaseDescription,
++ biosBaseMenuPath,
++ biosBaseCurrValue,
++ biosBaseDefaultValue,
++ biosBaseOptions
++};
++enum OptionsItemIndex
++{
++ optItemType = 0,
++ optItemValue
++};
++/*
++ The Pending attribute name and new value.
++ ex- { {"QuietBoot",Type.Integer, 0x1},
++ { "DdrFreqLimit",Type.String,"2933"}
++ }
++*/
++using PendingAttributesType = std::vector<std::pair<
++ std::string, std::tuple<std::string, std::variant<int64_t, std::string>>>>;
++using PendingAttributesItemType =
++ std::pair<std::string,
++ std::tuple<std::string, std::variant<int64_t, std::string>>>;
++enum PendingAttributesIndex
++{
++ pendingAttrType = 0,
++ pendingAttrValue
++};
++static std::string mapAttrTypeToRedfish(const std::string_view typeDbus)
++{
++ std::string ret;
++ if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager."
++ "AttributeType.Enumeration")
++ {
++ ret = "Enumeration";
++ }
++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.String")
++ {
++ ret = "String";
++ }
++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.Password")
++ {
++ ret = "Password";
++ }
++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.Integer")
++ {
++ ret = "Integer";
++ }
++ else if (typeDbus == "xyz.openbmc_project.BIOSConfig."
++ "Manager.AttributeType.Boolean")
++ {
++ ret = "Boolean";
++ }
++ else
++ {
++ ret = "UNKNOWN";
++ }
++
++ return ret;
++}
++static std::string mapBoundTypeToRedfish(const std::string_view typeDbus)
++{
++ std::string ret;
++ if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.ScalarIncrement")
++ {
++ ret = "ScalarIncrement";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.LowerBound")
++ {
++ ret = "LowerBound";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.UpperBound")
++ {
++ ret = "UpperBound";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.MinStringLength")
++ {
++ ret = "MinStringLength";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.MaxStringLength")
++ {
++ ret = "MaxStringLength";
++ }
++ else if (typeDbus ==
++ "xyz.openbmc_project.BIOSConfig.Manager.BoundType.OneOf")
++ {
++ ret = "OneOf";
++ }
++ else
++ {
++ ret = "UNKNOWN";
++ }
++
++ return ret;
++}
++
+ /**
+ * BiosService class supports handle get method for bios.
+ */
+@@ -35,6 +167,377 @@ class BiosService : public Node
+ // Get the ActiveSoftwareImage and SoftwareImages
+ fw_util::populateFirmwareInformation(asyncResp, fw_util::biosPurpose,
+ "", true);
++ asyncResp->res.jsonValue["@Redfish.Settings"] = {
++ {"@odata.type", "#Settings.v1_3_0.Settings"},
++ {"SettingsObject",
++ {{"@odata.id", "/redfish/v1/Systems/system/Bios/Settings"}}}};
++ asyncResp->res.jsonValue["AttributeRegistry"] = "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["Attributes"] = {};
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
++ << ec;
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++ const std::string& service = getObjectType.begin()->first;
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](
++ const boost::system::error_code ec,
++ const std::variant<BiosBaseTableType>& retBiosTable) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "getBiosAttributes DBUS error: "
++ << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ const BiosBaseTableType* baseBiosTable =
++ std::get_if<BiosBaseTableType>(&retBiosTable);
++ nlohmann::json& attributesJson =
++ asyncResp->res.jsonValue["Attributes"];
++ if (baseBiosTable == nullptr)
++ {
++ BMCWEB_LOG_ERROR << "baseBiosTable == nullptr ";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ for (const BiosBaseTableItemType& item : *baseBiosTable)
++ {
++ const std::string& key = item.first;
++ const std::string& itemType =
++ std::get<biosBaseAttrType>(item.second);
++ std::string attrType =
++ mapAttrTypeToRedfish(itemType);
++ if (attrType == "String")
++ {
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<biosBaseCurrValue>(
++ item.second));
++ attributesJson.emplace(key, currValue != nullptr
++ ? *currValue
++ : "");
++ }
++ else if (attrType == "Integer")
++ {
++ const int64_t* currValue = std::get_if<int64_t>(
++ &std::get<biosBaseCurrValue>(item.second));
++ attributesJson.emplace(
++ key, currValue != nullptr ? *currValue : 0);
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR
++ << "Unsupported attribute type.";
++ messages::internalError(asyncResp->res);
++ }
++ }
++ },
++ service, "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.BIOSConfig.Manager", "BaseBIOSTable");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/bios_config/manager",
++ std::array<const char*, 0>());
++ }
++};
++
++/**
++ * BiosSettings class supports handle GET/PATCH method for
++ * BIOS configuration pending settings.
++ */
++class BiosSettings : public Node
++{
++ public:
++ BiosSettings(App& app) :
++ Node(app, "/redfish/v1/Systems/system/Bios/Settings")
++ {
++ entityPrivileges = {{boost::beast::http::verb::get, {{"Login"}}}};
++ }
++
++ private:
++ void doGet(crow::Response& res, const crow::Request&,
++ const std::vector<std::string>&) override
++ {
++ auto asyncResp = std::make_shared<AsyncResp>(res);
++ asyncResp->res.jsonValue["@odata.id"] =
++ "/redfish/v1/Systems/system/Bios/Settings";
++ asyncResp->res.jsonValue["@odata.type"] = "#Bios.v1_1_0.Bios";
++ asyncResp->res.jsonValue["Name"] = "Bios Settings Version 1";
++ asyncResp->res.jsonValue["Id"] = "BiosSettingsV1";
++ asyncResp->res.jsonValue["AttributeRegistry"] = "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["Attributes"] = {};
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
++ << ec;
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++ std::string service = getObjectType.begin()->first;
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const std::variant<PendingAttributesType>&
++ retPendingAttributes) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "getBiosSettings DBUS error: "
++ << ec;
++ messages::resourceNotFound(asyncResp->res,
++ "Systems/system/Bios",
++ "Settings");
++ return;
++ }
++ const PendingAttributesType* pendingAttributes =
++ std::get_if<PendingAttributesType>(
++ &retPendingAttributes);
++ nlohmann::json& attributesJson =
++ asyncResp->res.jsonValue["Attributes"];
++ if (pendingAttributes == nullptr)
++ {
++ BMCWEB_LOG_ERROR << "pendingAttributes == nullptr ";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ for (const PendingAttributesItemType& item :
++ *pendingAttributes)
++ {
++ const std::string& key = item.first;
++ const std::string& itemType =
++ std::get<pendingAttrType>(item.second);
++ std::string attrType =
++ mapAttrTypeToRedfish(itemType);
++ if (attrType == "String")
++ {
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<pendingAttrValue>(
++ item.second));
++ attributesJson.emplace(key, currValue != nullptr
++ ? *currValue
++ : "");
++ }
++ else if (attrType == "Integer")
++ {
++ const int64_t* currValue = std::get_if<int64_t>(
++ &std::get<pendingAttrValue>(item.second));
++ attributesJson.emplace(
++ key, currValue != nullptr ? *currValue : 0);
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR
++ << "Unsupported attribute type.";
++ messages::internalError(asyncResp->res);
++ }
++ }
++ },
++ service, "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.BIOSConfig.Manager",
++ "PendingAttributes");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/bios_config/manager",
++ std::array<const char*, 0>());
++ }
++};
++/**
++ * BiosAttributeRegistry class supports handle get method for BIOS attribute
++ * registry.
++ */
++class BiosAttributeRegistry : public Node
++{
++ public:
++ BiosAttributeRegistry(App& app) :
++ Node(app, "/redfish/v1/Registries/BiosAttributeRegistry/"
++ "BiosAttributeRegistry")
++ {
++ entityPrivileges = {{boost::beast::http::verb::get, {{"Login"}}}};
++ }
++
++ private:
++ void doGet(crow::Response& res, const crow::Request&,
++ const std::vector<std::string>&) override
++ {
++ auto asyncResp = std::make_shared<AsyncResp>(res);
++ asyncResp->res.jsonValue["@odata.id"] =
++ "/redfish/v1/Registries/BiosAttributeRegistry/"
++ "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["@odata.type"] =
++ "#AttributeRegistry.v1_3_2.AttributeRegistry";
++ asyncResp->res.jsonValue["Name"] = "Bios Attribute Registry";
++ asyncResp->res.jsonValue["Id"] = "BiosAttributeRegistry";
++ asyncResp->res.jsonValue["RegistryVersion"] = "1.0.0";
++ asyncResp->res.jsonValue["Language"] = "en";
++ asyncResp->res.jsonValue["OwningEntity"] = "OpenBMC";
++ asyncResp->res.jsonValue["RegistryEntries"]["Attributes"] =
++ nlohmann::json::array();
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec,
++ const GetObjectType& getObjectType) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
++ << ec;
++ messages::internalError(asyncResp->res);
++
++ return;
++ }
++ std::string service = getObjectType.begin()->first;
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](
++ const boost::system::error_code ec,
++ const std::variant<BiosBaseTableType>& retBiosTable) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR
++ << "getBiosAttributeRegistry DBUS error: "
++ << ec;
++ messages::resourceNotFound(
++ asyncResp->res, "Registries/Bios", "Bios");
++ return;
++ }
++ const BiosBaseTableType* baseBiosTable =
++ std::get_if<BiosBaseTableType>(&retBiosTable);
++ nlohmann::json& attributeArray =
++ asyncResp->res
++ .jsonValue["RegistryEntries"]["Attributes"];
++ nlohmann::json optionsArray = nlohmann::json::array();
++ if (baseBiosTable == nullptr)
++ {
++ BMCWEB_LOG_ERROR << "baseBiosTable == nullptr ";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ for (const BiosBaseTableItemType& item : *baseBiosTable)
++ {
++ const std::string& itemType =
++ std::get<biosBaseAttrType>(item.second);
++ std::string attrType =
++ mapAttrTypeToRedfish(itemType);
++ if (attrType == "UNKNOWN")
++ {
++ BMCWEB_LOG_ERROR << "attrType == UNKNOWN";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ nlohmann::json attributeItem;
++ attributeItem["AttributeName"] = item.first;
++ attributeItem["Type"] = attrType;
++ attributeItem["ReadOnly"] =
++ std::get<biosBaseReadonlyStatus>(item.second);
++ attributeItem["DisplayName"] =
++ std::get<biosBaseDisplayName>(item.second);
++ attributeItem["HelpText"] =
++ std::get<biosBaseDescription>(item.second);
++ attributeItem["MenuPath"] =
++ std::get<biosBaseMenuPath>(item.second);
++
++ if (attrType == "String")
++ {
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<biosBaseCurrValue>(
++ item.second));
++ const std::string* defValue =
++ std::get_if<std::string>(
++ &std::get<biosBaseDefaultValue>(
++ item.second));
++ attributeItem["CurrentValue"] =
++ currValue != nullptr ? *currValue : "";
++ attributeItem["DefaultValue"] =
++ defValue != nullptr ? *defValue : "";
++ }
++ else if (attrType == "Integer")
++ {
++ const int64_t* currValue = std::get_if<int64_t>(
++ &std::get<biosBaseCurrValue>(item.second));
++ const int64_t* defValue = std::get_if<int64_t>(
++ &std::get<biosBaseDefaultValue>(
++ item.second));
++ attributeItem["CurrentValue"] =
++ currValue != nullptr ? *currValue : 0;
++ attributeItem["DefaultValue"] =
++ defValue != nullptr ? *defValue : 0;
++ }
++ else
++ {
++ BMCWEB_LOG_ERROR
++ << "Unsupported attribute type.";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ const std::vector<OptionsItemType>& optionsVector =
++ std::get<biosBaseOptions>(item.second);
++ for (const OptionsItemType& optItem : optionsVector)
++ {
++ nlohmann::json optItemJson;
++ const std::string& strOptItemType =
++ std::get<optItemType>(optItem);
++ std::string optItemTypeRedfish =
++ mapBoundTypeToRedfish(strOptItemType);
++ if (optItemTypeRedfish == "UNKNOWN")
++ {
++ BMCWEB_LOG_ERROR
++ << "optItemTypeRedfish == UNKNOWN";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ if (optItemTypeRedfish == "OneOf")
++ {
++ const std::string* currValue =
++ std::get_if<std::string>(
++ &std::get<optItemValue>(optItem));
++ optItemJson[optItemTypeRedfish] =
++ currValue != nullptr ? *currValue : "";
++ }
++ else
++ {
++ const int64_t* currValue =
++ std::get_if<int64_t>(
++ &std::get<optItemValue>(optItem));
++ optItemJson[optItemTypeRedfish] =
++ currValue != nullptr ? *currValue : 0;
++ }
++
++ optionsArray.push_back(optItemJson);
++ }
++
++ attributeItem["Value"] = optionsArray;
++ attributeArray.push_back(attributeItem);
++ }
++ },
++ service, "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Get",
++ "xyz.openbmc_project.BIOSConfig.Manager", "BaseBIOSTable");
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject",
++ "/xyz/openbmc_project/bios_config/manager",
++ std::array<const char*, 0>());
+ }
+ };
+ /**
+diff --git a/redfish-core/lib/message_registries.hpp b/redfish-core/lib/message_registries.hpp
+index 77fc10e..0caf01c 100644
+--- a/redfish-core/lib/message_registries.hpp
++++ b/redfish-core/lib/message_registries.hpp
+@@ -18,6 +18,7 @@
+ #include "node.hpp"
+ #include "registries.hpp"
+ #include "registries/base_message_registry.hpp"
++#include "registries/bios_registry.hpp"
+ #include "registries/openbmc_message_registry.hpp"
+ #include "registries/resource_event_message_registry.hpp"
+ #include "registries/task_event_message_registry.hpp"
+@@ -56,11 +57,12 @@ class MessageRegistryFileCollection : public Node
+ {"@odata.id", "/redfish/v1/Registries"},
+ {"Name", "MessageRegistryFile Collection"},
+ {"Description", "Collection of MessageRegistryFiles"},
+- {"Members@odata.count", 4},
++ {"Members@odata.count", 5},
+ {"Members",
+ {{{"@odata.id", "/redfish/v1/Registries/Base"}},
+ {{"@odata.id", "/redfish/v1/Registries/TaskEvent"}},
+ {{"@odata.id", "/redfish/v1/Registries/ResourceEvent"}},
++ {{"@odata.id", "/redfish/v1/Registries/BiosAttributeRegistry"}},
+ {{"@odata.id", "/redfish/v1/Registries/OpenBMC"}}}}};
+
+ res.end();
+@@ -118,6 +120,11 @@ class MessageRegistryFile : public Node
+ header = &message_registries::resource_event::header;
+ url = message_registries::resource_event::url;
+ }
++ else if (registry == "BiosAttributeRegistry")
++ {
++ header = &message_registries::bios::header;
++ dmtf.clear();
++ }
+ else
+ {
+ messages::resourceNotFound(
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-BIOS-config-Add-support-for-PATCH-operation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-BIOS-config-Add-support-for-PATCH-operation.patch
new file mode 100755
index 000000000..18403446d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0007-BIOS-config-Add-support-for-PATCH-operation.patch
@@ -0,0 +1,154 @@
+From 8f823ad555b67b228413a0fcb46771d86108dcb3 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Wed, 23 Dec 2020 16:50:45 +0800
+Subject: [PATCH] BaseBiosTable: Add support for PATCH operation
+
+This commit brings in support for PATCH operation of the
+bios variables that updates the BaseBiosTable.
+
+Tested-By:
+* Passed Redfish validator
+
+* Single Attribute:
+PATCH https://${bmc}/redfish/v1/Systems/system/Bios/Settings -d
+'{"data":[{"AttributeName": <attribute name>, "AttributeType":
+<attribute type>, "AttributeValue": <attribute value>}]}'
+
+* Multiple Attributes:
+PATCH https://${bmc}/redfish/v1/Systems/system/Bios/Settings -d
+'{"data":[{"AttributeName": <attribute name>, "AttributeType":
+<attribute type>, "AttributeValue": <attribute value>},
+{"AttributeName": <attribute name>, "AttributeType":
+<attribute type>, "AttributeValue": <attribute value>}]}'
+
+This makes use of the "Set" of "PendingAttributes" in the
+backend and that updates the BaseBiosTable.
+
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ redfish-core/lib/bios.hpp | 94 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 93 insertions(+), 1 deletion(-)
+
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index 9fe8c6e..e9c8969 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -96,6 +96,29 @@ static std::string mapAttrTypeToRedfish(const std::string_view typeDbus)
+
+ return ret;
+ }
++static std::string mapRedfishToAttrType(const std::string_view type)
++{
++ std::string ret;
++ if (type == "string")
++ {
++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String";
++ }
++ else if (type == "int")
++ {
++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer";
++ }
++ else if (type == "enum")
++ {
++ ret = "xyz.openbmc_project.BIOSConfig.Manager.AttributeType."
++ "Enumeration";
++ }
++ else
++ {
++ ret = "UNKNOWN";
++ }
++
++ return ret;
++}
+ static std::string mapBoundTypeToRedfish(const std::string_view typeDbus)
+ {
+ std::string ret;
+@@ -263,7 +286,9 @@ class BiosSettings : public Node
+ BiosSettings(App& app) :
+ Node(app, "/redfish/v1/Systems/system/Bios/Settings")
+ {
+- entityPrivileges = {{boost::beast::http::verb::get, {{"Login"}}}};
++ entityPrivileges = {
++ {boost::beast::http::verb::get, {{"Login"}}},
++ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}};
+ }
+
+ private:
+@@ -361,6 +386,73 @@ class BiosSettings : public Node
+ "/xyz/openbmc_project/bios_config/manager",
+ std::array<const char*, 0>());
+ }
++
++ void doPatch(crow::Response& res, const crow::Request& req,
++ const std::vector<std::string>&) override
++ {
++ auto asyncResp = std::make_shared<AsyncResp>(res);
++
++ nlohmann::json inpJson;
++
++ if (!redfish::json_util::readJson(req, asyncResp->res, "data", inpJson))
++ {
++ return;
++ }
++
++ for (auto& attrInfo : inpJson)
++ {
++ std::optional<std::string> attrName;
++ std::optional<std::string> attrType;
++ std::optional<std::string> attrValue;
++ if (!json_util::getValueFromJsonObject(attrInfo, "AttributeName",
++ attrName))
++ {
++ messages::propertyMissing(asyncResp->res, "AttributeName");
++ return;
++ }
++ if (!json_util::getValueFromJsonObject(attrInfo, "AttributeType",
++ attrType))
++ {
++ messages::propertyMissing(asyncResp->res, "AttributeType");
++ return;
++ }
++ if (!json_util::getValueFromJsonObject(attrInfo, "AttributeValue",
++ attrValue))
++ {
++ messages::propertyMissing(asyncResp->res, "AttributeValue");
++ return;
++ }
++ std::string biosAttrType = mapRedfishToAttrType(*attrType);
++
++ if (biosAttrType == "UNKNOWN")
++ {
++ BMCWEB_LOG_ERROR << "Invalid attribute type";
++ messages::propertyValueNotInList(asyncResp->res,
++ "AttributeType", *attrType);
++ return;
++ }
++
++ PendingAttributesType pendingAttributes;
++ pendingAttributes.emplace_back(std::make_pair(
++ *attrName, std::make_tuple(biosAttrType, *attrValue)));
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "doPatch resp_handler got error "
++ << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ },
++ "xyz.openbmc_project.BIOSConfigManager",
++ "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Set",
++ "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes",
++ std::variant<PendingAttributesType>(pendingAttributes));
++ }
++ }
+ };
+ /**
+ * BiosAttributeRegistry class supports handle get method for BIOS attribute
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-Add-support-to-ResetBios-action.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-Add-support-to-ResetBios-action.patch
new file mode 100644
index 000000000..983eb170a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0008-Add-support-to-ResetBios-action.patch
@@ -0,0 +1,62 @@
+From 2f5b401bb36be7a1f800bea20fb489a7b2ac6d45 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Wed, 23 Dec 2020 22:47:56 +0800
+Subject: [PATCH] Add support to ResetBios action
+
+Tested:
+
+Bios reset flag can be modified throw redfish
+POST https://IP_ADDR/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios
+
+Change-Id: I5e5fbdd70d4a3ce3b976cc2eb0a7d9a2a3adb124
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+
+---
+ redfish-core/lib/bios.hpp | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index 4727ef2..888c511 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -663,7 +663,7 @@ class BiosReset : public Node
+ Node(app, "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios/")
+ {
+ entityPrivileges = {
+- {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
++ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ }
+
+ private:
+@@ -675,19 +675,23 @@ class BiosReset : public Node
+ const std::vector<std::string>&) override
+ {
+ auto asyncResp = std::make_shared<AsyncResp>(res);
+-
++ std::string resetFlag =
++ "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag.FactoryDefaults";
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+ {
+- BMCWEB_LOG_ERROR << "Failed to reset bios: " << ec;
++ BMCWEB_LOG_ERROR << "doPost bios reset got error " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
++ BMCWEB_LOG_DEBUG << "bios reset action is done";
+ },
+- "org.open_power.Software.Host.Updater",
+- "/xyz/openbmc_project/software",
+- "xyz.openbmc_project.Common.FactoryReset", "Reset");
++ "xyz.openbmc_project.BIOSConfigManager",
++ "/xyz/openbmc_project/bios_config/manager",
++ "org.freedesktop.DBus.Properties", "Set",
++ "xyz.openbmc_project.BIOSConfig.Manager", "ResetBIOSSettings",
++ std::variant<std::string>(resetFlag));
+ }
+ };
+ } // namespace redfish
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Add-support-to-ChangePassword-action.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Add-support-to-ChangePassword-action.patch
new file mode 100644
index 000000000..c603615f1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0009-Add-support-to-ChangePassword-action.patch
@@ -0,0 +1,139 @@
+From 0192a2217eda578ca058cdc3a289ada3ee39e47a Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Wed, 23 Dec 2020 14:41:23 +0800
+Subject: [PATCH] Add support to ChangePassword action
+
+Tested:
+
+Passed Redfish validator.
+Bios change password:
+root@intel-obmc:~# cat /var/lib/bios-settings-manager/seedData
+{
+"UserPwdHash": "08D91157785366CDC3AA64D87E5E3C621EDAB13E26B6E484397EBA5E459E54C567BF5B1FFB36A43B6142B18F8D642E9D",
+"AdminPwdHash": "08D91157785366CDC3AA64D87E5E3C621EDAB13E26B6E484397EBA5E459E54C567BF5B1FFB36A43B6142B18F8D642E9D",
+"Seed": "123456",
+"HashAlgo": "SHA384"
+}
+POST https://IP_ADDR/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword
+{
+ "NewPassword": "12345678",
+ "OldPassword": "1234567890",
+ "PasswordName": "Administrator"
+}
+root@intel-obmc:~# cat /var/lib/bios-settings-manager/passwordData
+{
+ "CurrentPassword": "1234567890",
+ "IsAdminPwdChanged": 1,
+ "IsUserPwdChanged": 0,
+ "NewPassword": "2DD65D57EB60B1D92C5F3D2DC84724FCEE7BC02E57AA75E834712266ED94CAC704047B2FF7CEC1C36BED280B36BB5AC6",
+ "UserName": "Administrator"
+}
+
+Change-Id: I90319a68da0b0a7f9c5cd65a8cb8cf52269a5f52
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ redfish-core/include/redfish.hpp | 1 +
+ redfish-core/lib/bios.hpp | 70 ++++++++++++++++++++++++++++++++
+ 2 files changed, 71 insertions(+)
+
+diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
+index a8e5cf2..dabf78e 100644
+--- a/redfish-core/include/redfish.hpp
++++ b/redfish-core/include/redfish.hpp
+@@ -160,6 +160,7 @@ class RedfishService
+ nodes.emplace_back(std::make_unique<BiosSettings>(app));
+ nodes.emplace_back(std::make_unique<BiosAttributeRegistry>(app));
+ nodes.emplace_back(std::make_unique<BiosReset>(app));
++ nodes.emplace_back(std::make_unique<BiosChangePassword>(app));
+ #ifdef BMCWEB_ENABLE_VM_NBDPROXY
+ nodes.emplace_back(std::make_unique<VirtualMedia>(app));
+ nodes.emplace_back(std::make_unique<VirtualMediaCollection>(app));
+diff --git a/redfish-core/lib/bios.hpp b/redfish-core/lib/bios.hpp
+index 7b4306b..52ee356 100644
+--- a/redfish-core/lib/bios.hpp
++++ b/redfish-core/lib/bios.hpp
+@@ -186,6 +186,9 @@ class BiosService : public Node
+ asyncResp->res.jsonValue["Actions"]["#Bios.ResetBios"] = {
+ {"target",
+ "/redfish/v1/Systems/system/Bios/Actions/Bios.ResetBios"}};
++ asyncResp->res.jsonValue["Actions"]["#Bios.ChangePassword"] = {
++ {"target",
++ "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword"}};
+
+ // Get the ActiveSoftwareImage and SoftwareImages
+ fw_util::populateFirmwareInformation(asyncResp, fw_util::biosPurpose,
+@@ -674,4 +677,71 @@ class BiosReset : public Node
+ std::variant<std::string>(resetFlag));
+ }
+ };
++
++/**
++ * BiosChangePassword class supports handle POST method for change bios
++ * password. The class retrieves and sends data directly to D-Bus.
++ */
++class BiosChangePassword : public Node
++{
++ public:
++ BiosChangePassword(App& app) :
++ Node(app,
++ "/redfish/v1/Systems/system/Bios/Actions/Bios.ChangePassword/")
++ {
++ entityPrivileges = {
++ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
++ }
++
++ private:
++ /**
++ * Function handles POST method request.
++ * Analyzes POST body message before sends Reset request data to D-Bus.
++ */
++ void doPost(crow::Response& res, const crow::Request& req,
++ const std::vector<std::string>&) override
++ {
++ auto asyncResp = std::make_shared<AsyncResp>(res);
++ std::string currentPassword, newPassword, userName;
++ if (!json_util::readJson(req, res, "NewPassword", newPassword,
++ "OldPassword", currentPassword, "PasswordName",
++ userName))
++ {
++ return;
++ }
++ if (currentPassword.empty())
++ {
++ messages::actionParameterUnknown(asyncResp->res, "ChangePassword",
++ "OldPassword");
++ return;
++ }
++ if (newPassword.empty())
++ {
++ messages::actionParameterUnknown(asyncResp->res, "ChangePassword",
++ "NewPassword");
++ return;
++ }
++ if (userName.empty())
++ {
++ messages::actionParameterUnknown(asyncResp->res, "ChangePassword",
++ "PasswordName");
++ return;
++ }
++ crow::connections::systemBus->async_method_call(
++ [asyncResp](const boost::system::error_code ec) {
++ if (ec)
++ {
++ BMCWEB_LOG_CRITICAL << "Failed in doPost(BiosChangePassword) "
++ << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ },
++ "xyz.openbmc_project.BIOSConfigPassword",
++ "/xyz/openbmc_project/bios_config/password",
++ "xyz.openbmc_project.BIOSConfig.Password", "ChangePassword",
++ userName, currentPassword, newPassword);
++ }
++};
++
+ } // namespace redfish
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch
new file mode 100644
index 000000000..520007d41
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0010-managers-add-attributes-for-Manager.CommandShell.patch
@@ -0,0 +1,57 @@
+From 01a5c12e350c04f8ed94c7e49a6030a4699eac6e Mon Sep 17 00:00:00 2001
+From: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+Date: Mon, 28 Dec 2020 18:55:57 +0000
+Subject: [PATCH] managers: add attributes for Manager.CommandShell
+
+Issue: ConnectTypesSupported, ServiceEnabled and
+ MaxConcurrentSessions Attributes are missing for
+ Manager.CommandShell, though Requirement mandates it.
+
+Fix: Added missing attributes to Manager.CommandShell
+
+Tested:
+1. Verified redfish validator passed
+2. Get bmc details from Redfish
+Redfish URI: https://<BMC IP>/redfish/v1/Managers/bmc
+Response:
+{
+ "@odata.id": "/redfish/v1/Managers/bmc",
+ "@odata.type": "#Manager.v1_9_0.Manager",
+....
+....
+ "CommandShell": {
+ "ConnectTypesSupported": [
+ "SSH",
+ "IPMI"
+ ],
+ "MaxConcurrentSessions": 4,
+ "ServiceEnabled": true
+ },
+....
+....
+
+Signed-off-by: Jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+---
+ redfish-core/lib/managers.hpp | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
+index 6347caf..c401ca9 100644
+--- a/redfish-core/lib/managers.hpp
++++ b/redfish-core/lib/managers.hpp
+@@ -1767,6 +1767,12 @@ class Manager : public Node
+ res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15;
+ res.jsonValue["SerialConsole"]["ConnectTypesSupported"] = {"IPMI",
+ "SSH"};
++ // Fill in CommandShell info
++ res.jsonValue["CommandShell"]["ServiceEnabled"] = true;
++ res.jsonValue["CommandShell"]["MaxConcurrentSessions"] = 4;
++ res.jsonValue["CommandShell"]["ConnectTypesSupported"] = {"SSH",
++ "IPMI"};
++
+ #ifdef BMCWEB_ENABLE_KVM
+ // Fill in GraphicalConsole info
+ res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true;
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0034-recommended-fixes-by-crypto-review-team.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0034-recommended-fixes-by-crypto-review-team.patch
new file mode 100644
index 000000000..f3235c7cf
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0034-recommended-fixes-by-crypto-review-team.patch
@@ -0,0 +1,75 @@
+From a170675fafc1ee8bfee502672e65be9ad379a3d1 Mon Sep 17 00:00:00 2001
+From: Radivoje Jovanovic <radivoje.jovanovic@intel.com>
+Date: Thu, 10 Dec 2020 13:42:20 -0800
+Subject: [PATCH] recommended fixes by crypto review team
+
+some curves/cyphers are forbiden to be used by
+Intel crypto team.
+Only enable approved ones.
+the patch was created by aleksandr.v.tereschenko@intel.com
+
+Signed-off-by: Radivoje Jovanovic <radivoje.jovanovic@intel.com>
+---
+ include/ssl_key_handler.hpp | 39 ++++++++++++++++++++-----------------
+ 1 file changed, 21 insertions(+), 18 deletions(-)
+
+diff --git a/include/ssl_key_handler.hpp b/include/ssl_key_handler.hpp
+index deb3a76..8063858 100644
+--- a/include/ssl_key_handler.hpp
++++ b/include/ssl_key_handler.hpp
+@@ -326,31 +326,34 @@ inline std::shared_ptr<boost::asio::ssl::context>
+ mSslContext->use_private_key_file(ssl_pem_file,
+ boost::asio::ssl::context::pem);
+
+- // Set up EC curves to auto (boost asio doesn't have a method for this)
+- // There is a pull request to add this. Once this is included in an asio
+- // drop, use the right way
+- // http://stackoverflow.com/questions/18929049/boost-asio-with-ecdsa-certificate-issue
+- if (SSL_CTX_set_ecdh_auto(mSslContext->native_handle(), 1) != 1)
++ std::string handshakeCurves = "P-384:P-521:X448";
++ if (SSL_CTX_set1_groups_list(mSslContext->native_handle(), handshakeCurves.c_str()) != 1)
+ {
+- BMCWEB_LOG_ERROR << "Error setting tmp ecdh list\n";
++ BMCWEB_LOG_ERROR << "Error setting ECDHE group list\n";
+ }
+
+- std::string mozillaModern = "ECDHE-ECDSA-AES256-GCM-SHA384:"
+- "ECDHE-RSA-AES256-GCM-SHA384:"
+- "ECDHE-ECDSA-CHACHA20-POLY1305:"
+- "ECDHE-RSA-CHACHA20-POLY1305:"
+- "ECDHE-ECDSA-AES128-GCM-SHA256:"
+- "ECDHE-RSA-AES128-GCM-SHA256:"
+- "ECDHE-ECDSA-AES256-SHA384:"
+- "ECDHE-RSA-AES256-SHA384:"
+- "ECDHE-ECDSA-AES128-SHA256:"
+- "ECDHE-RSA-AES128-SHA256";
++ std::string tls12Ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384:"
++ "ECDHE-RSA-AES256-GCM-SHA384";
++ std::string tls13Ciphers = "TLS_AES_256_GCM_SHA384";
+
+ if (SSL_CTX_set_cipher_list(mSslContext->native_handle(),
+- mozillaModern.c_str()) != 1)
++ tls12Ciphers.c_str()) != 1)
+ {
+- BMCWEB_LOG_ERROR << "Error setting cipher list\n";
++ BMCWEB_LOG_ERROR << "Error setting TLS 1.2 cipher list\n";
+ }
++
++ if (SSL_CTX_set_ciphersuites(mSslContext->native_handle(),
++ tls13Ciphers.c_str()) != 1)
++ {
++ BMCWEB_LOG_ERROR << "Error setting TLS 1.3 cipher list\n";
++ }
++
++ if ((SSL_CTX_set_options(mSslContext->native_handle(),
++ SSL_OP_CIPHER_SERVER_PREFERENCE) & SSL_OP_CIPHER_SERVER_PREFERENCE) == 0)
++ {
++ BMCWEB_LOG_ERROR << "Error setting TLS server preference option\n";
++ }
++
+ return mSslContext;
+ }
+ } // namespace ensuressl
+--
+2.17.1
+
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 9157f1bf1..b1334a420 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 d8b7e2f4eae85cd76d480970e888a50548523fc2 Mon Sep 17 00:00:00 2001
+From c7fce288802ece4a6e1ff71ee060a44e0b8fe992 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 05/10] Redfish TelemetryService schema implementation
+Subject: [PATCH 1/4] Redfish TelemetryService schema implementation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
@@ -9,73 +9,41 @@ Content-Transfer-Encoding: 8bit
Added TelemetryService, MetricReports, MetricReportCollection,
MetricReportDefinition and MetricReportDefinitionCollection schemas
with GET method support. Added TelemetryService URI to root service.
-Implemented communication with backend - MonitoringService.
-Added schemes attributes that are supported by MonitoringService
+Implemented communication with backend - Telemetry.
+Added schemes attributes that are supported by Telemetry service
design. User is able to fetch basic information about reports if
-MonitoringService is present in OpenBMC.
+Telemetry service is present in OpenBMC.
+Added util function that converts decimal value into duration format
+that is described by ISO 8601 and Redfish specification.
Tested:
- - Succesfully passed RedfishServiceValidator.py
- - Validated conversion to duration format using whole
- range of uint32_t type
- - Validated assigning value to JSON response using different
- closures and std::functions types
+ - Succesfully passed RedfishServiceValidator.py
+ - Verified DBus method calls to Telemetry service
+ - Verified all possible pages that are displayed to user when:
+ - Reports are fully defined in Telemetry
+ - Reports are partially available in Telemetry
+ - Telemetry is disabled
+ - Verified time_utils::toDurationString() output
Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
Signed-off-by: Adrian Ambrożewicz <adrian.ambrozewicz@linux.intel.com>
+Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@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 ++
- redfish-core/include/utils/json_utils.hpp | 101 +++++++++++++
- 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 | 191 +++++++++++++++++++++++++
+ redfish-core/include/utils/telemetry_utils.hpp | 71 ++++++++++
+ redfish-core/include/utils/time_utils.hpp | 78 +++++++++++
+ redfish-core/lib/metric_report.hpp | 162 +++++++++++++++++++++
+ redfish-core/lib/metric_report_definition.hpp | 186 +++++++++++++++++++++++++
redfish-core/lib/service_root.hpp | 2 +
- redfish-core/lib/telemetry_service.hpp | 92 ++++++++++++
- 9 files changed, 763 insertions(+)
+ redfish-core/lib/telemetry_service.hpp | 93 +++++++++++++
+ 7 files changed, 602 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
create mode 100644 redfish-core/lib/metric_report_definition.hpp
create mode 100644 redfish-core/lib/telemetry_service.hpp
-diff --git a/include/dbus_utility.hpp b/include/dbus_utility.hpp
-index 8ba9a57..ef3438b 100644
---- a/include/dbus_utility.hpp
-+++ b/include/dbus_utility.hpp
-@@ -99,5 +99,26 @@ inline void checkDbusPathExists(const std::string& path, Callback&& callback)
- std::array<std::string, 0>());
- }
-
-+template <typename Array, typename Callback>
-+inline void getSubTreePaths(Callback&& callback, const std::string& path,
-+ int depth, Array& interfaces)
-+{
-+ crow::connections::systemBus->async_method_call(
-+ callback, "xyz.openbmc_project.ObjectMapper",
-+ "/xyz/openbmc_project/object_mapper",
-+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", path, depth,
-+ interfaces);
-+}
-+
-+template <typename Callback>
-+inline void getAllProperties(Callback&& callback, const std::string& service,
-+ const std::string& path,
-+ const std::string& interface)
-+{
-+ crow::connections::systemBus->async_method_call(
-+ callback, service, path, "org.freedesktop.DBus.Properties", "GetAll",
-+ interface);
-+}
-+
- } // namespace utility
- } // namespace dbus
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index 54d5d0e..2587b37 100644
--- a/redfish-core/include/redfish.hpp
@@ -111,154 +79,12 @@ index 54d5d0e..2587b37 100644
for (const auto& node : nodes)
{
node->initPrivileges();
-diff --git a/redfish-core/include/utils/json_utils.hpp b/redfish-core/include/utils/json_utils.hpp
-index c355000..c866a2f 100644
---- a/redfish-core/include/utils/json_utils.hpp
-+++ b/redfish-core/include/utils/json_utils.hpp
-@@ -13,14 +13,18 @@
- // See the License for the specific language governing permissions and
- // limitations under the License.
- */
-+
- #pragma once
-
-+#include <boost/container/flat_map.hpp>
- #include <error_messages.hpp>
- #include <http_request.hpp>
- #include <http_response.hpp>
- #include <nlohmann/json.hpp>
-
- #include <bitset>
-+#include <string>
-+#include <variant>
-
- namespace redfish
- {
-@@ -425,5 +429,102 @@ bool getValueFromJsonObject(nlohmann::json& jsonData, const std::string& key,
- return details::unpackValue(jsonValue, key, value);
- }
-
-+template <class T>
-+struct IsStdFunction
-+{
-+ static constexpr bool value = false;
-+};
-+
-+template <class T>
-+struct IsStdFunction<std::function<T>>
-+{
-+ static constexpr bool value = true;
-+};
-+
-+template <class T>
-+constexpr bool is_std_function_v = IsStdFunction<T>::value;
-+
-+/**
-+ * @brief Assign dbus property to http response attribute if property is stored
-+ * on the map.
-+ */
-+template <typename T, typename S, typename... V>
-+bool assignIfPresent(
-+ const boost::container::flat_map<std::string, std::variant<V...>>& ret,
-+ const char* propertyName, nlohmann::json& attribute, const S& convert)
-+{
-+ if constexpr (is_std_function_v<S>)
-+ {
-+ if (!convert)
-+ {
-+ BMCWEB_LOG_ERROR << "Passed empty target as convert argument";
-+ return false;
-+ }
-+ }
-+
-+ auto found = ret.find(propertyName);
-+ if (found != ret.end())
-+ {
-+ auto property = std::get_if<T>(&found->second);
-+ if (property)
-+ {
-+ attribute = convert(*property);
-+ return true;
-+ }
-+ else
-+ {
-+ BMCWEB_LOG_ERROR << "Variant does not contain this type";
-+ }
-+ }
-+ else
-+ {
-+ BMCWEB_LOG_ERROR << "Element not found in map";
-+ }
-+
-+ return false;
-+}
-+
-+template <typename T, typename... V>
-+bool assignIfPresent(
-+ const boost::container::flat_map<std::string, std::variant<V...>>& ret,
-+ const char* propertyName, nlohmann::json& attribute)
-+{
-+ return assignIfPresent<T>(ret, propertyName, attribute,
-+ [](const T& v) -> T { return v; });
-+}
-+
-+template <typename T, typename... V>
-+bool assignIfPresent(
-+ const boost::container::flat_map<std::string, std::variant<V...>>& ret,
-+ const char* attributeName, crow::Response& res)
-+{
-+ return assignIfPresent<T>(ret, attributeName, res.jsonValue[attributeName]);
-+}
-+
-+/**
-+ * @brief Translate dbusPaths received from ObjectMapper into Redfish
-+ * collection members and fill http response with those information.
-+ */
-+inline void dbusPathsToMembersArray(crow::Response& res,
-+ const std::vector<std::string>& reports,
-+ const char* path)
-+{
-+ nlohmann::json& members = res.jsonValue["Members"];
-+ members = nlohmann::json::array();
-+
-+ for (const std::string& objpath : reports)
-+ {
-+ std::size_t lastPos = objpath.rfind("/");
-+ if (lastPos == std::string::npos)
-+ {
-+ BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
-+ continue;
-+ }
-+ members.push_back({{"@odata.id", path + objpath.substr(lastPos + 1)}});
-+ }
-+
-+ res.jsonValue["Members@odata.count"] = members.size();
-+}
-+
- } // namespace json_util
- } // namespace redfish
diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp
new file mode 100644
-index 0000000..05ed00f
+index 0000000..8caee2d
--- /dev/null
+++ b/redfish-core/include/utils/telemetry_utils.hpp
-@@ -0,0 +1,100 @@
-+/*
-+// Copyright (c) 2018-2020 Intel Corporation
-+//
-+// Licensed under the Apache License, Version 2.0 (the "License");
-+// you may not use this file except in compliance with the License.
-+// You may obtain a copy of the License at
-+//
-+// http://www.apache.org/licenses/LICENSE-2.0
-+//
-+// Unless required by applicable law or agreed to in writing, software
-+// distributed under the License is distributed on an "AS IS" BASIS,
-+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+// See the License for the specific language governing permissions and
-+// limitations under the License.
-+*/
-+
+@@ -0,0 +1,71 @@
+#pragma once
+
+namespace redfish
@@ -267,112 +93,79 @@ index 0000000..05ed00f
+namespace telemetry
+{
+
-+static constexpr const char* metricReportDefinitionUri =
++constexpr const char* service = "xyz.openbmc_project.Telemetry";
++constexpr const char* reportInterface = "xyz.openbmc_project.Telemetry.Report";
++constexpr const char* metricReportDefinitionUri =
+ "/redfish/v1/TelemetryService/MetricReportDefinitions/";
-+static constexpr const char* metricReportUri =
++constexpr const char* metricReportUri =
+ "/redfish/v1/TelemetryService/MetricReports/";
-+static constexpr const char* reportInterface =
-+ "xyz.openbmc_project.MonitoringService.Report";
-+static constexpr const char* telemetryPath =
-+ "/xyz/openbmc_project/MonitoringService/Reports/TelemetryService";
+
-+static void getReportCollection(const std::shared_ptr<AsyncResp>& asyncResp,
-+ const char* uri)
++inline void getReportCollection(const std::shared_ptr<AsyncResp>& asyncResp,
++ const std::string& uri)
+{
+ const std::array<const char*, 1> interfaces = {reportInterface};
+
-+ dbus::utility::getSubTreePaths(
++ crow::connections::systemBus->async_method_call(
+ [asyncResp, uri](const boost::system::error_code ec,
-+ const std::vector<std::string>& reports) {
-+ if (ec == boost::system::errc::no_such_file_or_directory)
++ const std::vector<std::string>& reportPaths) {
++ if (ec)
+ {
+ asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
+ asyncResp->res.jsonValue["Members@odata.count"] = 0;
+ return;
+ }
+
-+ if (ec)
++ nlohmann::json& members = asyncResp->res.jsonValue["Members"];
++ members = nlohmann::json::array();
++
++ for (const std::string& path : reportPaths)
+ {
-+ messages::internalError(asyncResp->res);
-+ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
-+ return;
++ std::size_t pos = path.rfind('/');
++ if (pos == std::string::npos)
++ {
++ BMCWEB_LOG_ERROR << "Failed to find '/' in " << path;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ if (path.size() <= (pos + 1))
++ {
++ BMCWEB_LOG_ERROR << "Failed to parse path " << path;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ members.push_back({{"@odata.id", uri + path.substr(pos + 1)}});
+ }
+
-+ json_util::dbusPathsToMembersArray(asyncResp->res, reports, uri);
++ asyncResp->res.jsonValue["Members@odata.count"] = members.size();
+ },
-+ telemetryPath, 1, interfaces);
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService", 1,
++ interfaces);
+}
+
-+template <typename Callback>
-+static void getReport(const std::shared_ptr<AsyncResp>& asyncResp,
-+ const std::string& id, const char* schemaType,
-+ const Callback&& callback)
++inline std::string getDbusReportPath(const std::string& id)
+{
-+ const std::array<const char*, 1> interfaces = {reportInterface};
-+
-+ dbus::utility::getSubTreePaths(
-+ [asyncResp, id, schemaType,
-+ callback](const boost::system::error_code ec,
-+ const std::vector<std::string>& reports) {
-+ if (ec == boost::system::errc::no_such_file_or_directory)
-+ {
-+ messages::resourceNotFound(asyncResp->res, schemaType, id);
-+ return;
-+ }
-+
-+ if (ec)
-+ {
-+ messages::internalError(asyncResp->res);
-+ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
-+ return;
-+ }
-+
-+ const std::string target = "/xyz/openbmc_project/"
-+ "MonitoringService/Reports/"
-+ "TelemetryService/" +
-+ id;
-+ auto path = std::find(reports.begin(), reports.end(), target);
-+ if (path == std::end(reports))
-+ {
-+ messages::resourceNotFound(asyncResp->res, schemaType, id);
-+ return;
-+ }
-+ callback(asyncResp, *path, id);
-+ },
-+ telemetryPath, 1, interfaces);
++ std::string path =
++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id;
++ dbus::utility::escapePathForDbus(path);
++ return path;
+}
++
+} // namespace telemetry
+} // namespace redfish
diff --git a/redfish-core/include/utils/time_utils.hpp b/redfish-core/include/utils/time_utils.hpp
new file mode 100644
-index 0000000..0256b3f
+index 0000000..dd4ea75
--- /dev/null
+++ b/redfish-core/include/utils/time_utils.hpp
-@@ -0,0 +1,97 @@
-+/*
-+// Copyright (c) 2020 Intel Corporation
-+//
-+// Licensed under the Apache License, Version 2.0 (the "License");
-+// you may not use this file except in compliance with the License.
-+// You may obtain a copy of the License at
-+//
-+// http://www.apache.org/licenses/LICENSE-2.0
-+//
-+// Unless required by applicable law or agreed to in writing, software
-+// distributed under the License is distributed on an "AS IS" BASIS,
-+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+// See the License for the specific language governing permissions and
-+// limitations under the License.
-+*/
-+
+@@ -0,0 +1,78 @@
+#pragma once
+
-+#include <boost/algorithm/string/trim.hpp>
-+
+#include <chrono>
-+#include <cstdint>
+#include <string>
-+#include <type_traits>
+
+namespace redfish
+{
@@ -383,63 +176,64 @@ index 0000000..0256b3f
+namespace details
+{
+
-+template <typename T>
-+std::string toDurationFormatItem(std::chrono::milliseconds& duration,
-+ const char* postfix)
++inline void leftZeroPadding(std::string& str, const std::size_t padding)
+{
-+ const auto t = std::chrono::duration_cast<T>(duration);
-+ if (t.count() == 0)
-+ {
-+ return "";
-+ }
-+
-+ std::stringstream ss;
-+ if constexpr (std::is_same<T, std::chrono::milliseconds>::value)
++ if (str.size() < padding)
+ {
-+ ss << static_cast<float>(t.count()) /
-+ static_cast<float>(std::chrono::milliseconds::period::den);
++ str.insert(0, padding - str.size(), '0');
+ }
-+ else
-+ {
-+ ss << t.count();
-+ }
-+ ss << postfix;
-+ duration -= t;
-+ return ss.str();
+}
-+
+} // namespace details
+
+/**
+ * @brief Convert time value into duration format that is based on ISO 8601.
-+ * Pattern: "-?P(\\d+D)?(T(\\d+H)?(\\d+M)?(\\d+(.\\d+)?S)?)?"
-+ * Reference: "Redfish Telemetry White Paper".
++ * Example output: "P12DT1M5.5S"
++ * Ref: Redfish Specification, Section 9.4.4. Duration values
+ */
-+std::string toDurationFormat(const uint32_t ms)
++std::string toDurationString(std::chrono::milliseconds ms)
+{
-+ std::chrono::milliseconds duration(ms);
-+ if (duration.count() == 0)
++ if (ms < std::chrono::milliseconds::zero())
+ {
-+ return "PT0S";
++ return "";
+ }
+
+ std::string fmt;
-+ fmt.reserve(sizeof("PxxxDTxxHxxMxx.xxxxxxS"));
++ fmt.reserve(sizeof("PxxxxxxxxxxxxDTxxHxxMxx.xxxxxxS"));
++
++ using Days = std::chrono::duration<long, std::ratio<24 * 60 * 60>>;
++ Days days = std::chrono::floor<Days>(ms);
++ ms -= days;
++
++ std::chrono::hours hours = std::chrono::floor<std::chrono::hours>(ms);
++ ms -= hours;
++
++ std::chrono::minutes minutes = std::chrono::floor<std::chrono::minutes>(ms);
++ ms -= minutes;
+
-+ using Days = std::chrono::duration<int, std::ratio<24 * 60 * 60>>;
++ std::chrono::seconds seconds = std::chrono::floor<std::chrono::seconds>(ms);
++ ms -= seconds;
+
-+ fmt += "P";
-+ fmt += details::toDurationFormatItem<Days>(duration, "D");
-+ if (duration.count() == 0)
++ fmt = "P";
++ if (days.count() > 0)
+ {
-+ return fmt;
++ fmt += std::to_string(days.count()) + "D";
+ }
-+
+ fmt += "T";
-+ fmt += details::toDurationFormatItem<std::chrono::hours>(duration, "H");
-+ fmt += details::toDurationFormatItem<std::chrono::minutes>(duration, "M");
-+ fmt +=
-+ details::toDurationFormatItem<std::chrono::milliseconds>(duration, "S");
++ if (hours.count() > 0)
++ {
++ fmt += std::to_string(hours.count()) + "H";
++ }
++ if (minutes.count() > 0)
++ {
++ fmt += std::to_string(minutes.count()) + "M";
++ }
++ if (seconds.count() != 0 || ms.count() != 0)
++ {
++ fmt += std::to_string(seconds.count()) + ".";
++ std::string msStr = std::to_string(ms.count());
++ details::leftZeroPadding(msStr, 3);
++ fmt += msStr + "S";
++ }
+
+ return fmt;
+}
@@ -448,43 +242,23 @@ 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..4d1c4e5
+index 0000000..050304c
--- /dev/null
+++ b/redfish-core/lib/metric_report.hpp
-@@ -0,0 +1,149 @@
-+/*
-+// Copyright (c) 2018-2020 Intel Corporation
-+//
-+// Licensed under the Apache License, Version 2.0 (the "License");
-+// you may not use this file except in compliance with the License.
-+// You may obtain a copy of the License at
-+//
-+// http://www.apache.org/licenses/LICENSE-2.0
-+//
-+// Unless required by applicable law or agreed to in writing, software
-+// distributed under the License is distributed on an "AS IS" BASIS,
-+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+// See the License for the specific language governing permissions and
-+// limitations under the License.
-+*/
-+
+@@ -0,0 +1,162 @@
+#pragma once
+
+#include "node.hpp"
+#include "utils/telemetry_utils.hpp"
+
-+#include <boost/container/flat_map.hpp>
-+
-+#include <system_error>
-+#include <variant>
-+
+namespace redfish
+{
+
+class MetricReportCollection : public Node
+{
+ public:
-+ MetricReportCollection(App& app) : Node(app, telemetry::metricReportUri)
++ MetricReportCollection(App& app) :
++ Node(app, "/redfish/v1/TelemetryService/MetricReports/")
+ {
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
@@ -514,7 +288,7 @@ index 0000000..4d1c4e5
+{
+ public:
+ MetricReport(App& app) :
-+ Node(app, std::string(telemetry::metricReportUri) + "<str>/",
++ Node(app, "/redfish/v1/TelemetryService/MetricReports/<str>/",
+ std::string())
+ {
+ entityPrivileges = {
@@ -539,33 +313,74 @@ index 0000000..4d1c4e5
+ }
+
+ const std::string& id = params[0];
-+ telemetry::getReport(asyncResp, id, schemaType, getReportProperties);
++ const std::string reportPath = telemetry::getDbusReportPath(id);
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp, id, reportPath](const boost::system::error_code& ec) {
++ if (ec.value() == EBADR)
++ {
++ messages::resourceNotFound(asyncResp->res, schemaType, id);
++ return;
++ }
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp,
++ id](const boost::system::error_code ec,
++ const std::variant<TimestampReadings>& ret) {
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ fillReport(asyncResp, id, ret);
++ },
++ telemetry::service, reportPath,
++ "org.freedesktop.DBus.Properties", "Get",
++ telemetry::reportInterface, "Readings");
++ },
++ telemetry::service, reportPath, telemetry::reportInterface,
++ "Update");
+ }
+
+ using Readings =
-+ std::vector<std::tuple<std::string, std::string, double, int32_t>>;
-+ using MetricValues = std::vector<std::map<std::string, std::string>>;
++ std::vector<std::tuple<std::string, std::string, double, uint64_t>>;
++ using TimestampReadings = std::tuple<uint64_t, Readings>;
+
-+ static MetricValues toMetricValues(const Readings& readings)
++ static nlohmann::json toMetricValues(const Readings& readings)
+ {
-+ MetricValues metricValues;
++ nlohmann::json metricValues = nlohmann::json::array_t();
+
+ for (auto& [id, metadata, sensorValue, timestamp] : readings)
+ {
++ nlohmann::json metadataJson = nlohmann::json::parse(metadata);
+ metricValues.push_back({
+ {"MetricId", id},
-+ {"MetricProperty", metadata},
++ {"MetricDefinition", metadataJson.contains("MetricDefinition")
++ ? metadataJson["MetricDefinition"]
++ : nlohmann::json()},
++ {"MetricProperty", metadataJson.contains("MetricProperty")
++ ? metadataJson["MetricProperty"]
++ : nlohmann::json()},
+ {"MetricValue", std::to_string(sensorValue)},
-+ {"Timestamp", crow::utility::getDateTime(timestamp)},
++ {"Timestamp",
++ crow::utility::getDateTime(static_cast<time_t>(timestamp))},
+ });
+ }
+
+ return metricValues;
+ }
+
-+ static void getReportProperties(const std::shared_ptr<AsyncResp> asyncResp,
-+ const std::string& reportPath,
-+ const std::string& id)
++ static void fillReport(const std::shared_ptr<AsyncResp>& asyncResp,
++ const std::string& id,
++ const std::variant<TimestampReadings>& var)
+ {
+ asyncResp->res.jsonValue["@odata.type"] = schemaType;
+ asyncResp->res.jsonValue["@odata.id"] = telemetry::metricReportUri + id;
@@ -574,27 +389,19 @@ index 0000000..4d1c4e5
+ asyncResp->res.jsonValue["MetricReportDefinition"]["@odata.id"] =
+ telemetry::metricReportDefinitionUri + id;
+
-+ dbus::utility::getAllProperties(
-+ [asyncResp](
-+ const boost::system::error_code ec,
-+ const boost::container::flat_map<
-+ std::string, std::variant<Readings, int32_t>>& ret) {
-+ if (ec)
-+ {
-+ messages::internalError(asyncResp->res);
-+ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
-+ return;
-+ }
++ const TimestampReadings* timestampReadings =
++ std::get_if<TimestampReadings>(&var);
++ if (!timestampReadings)
++ {
++ BMCWEB_LOG_ERROR << "Property type mismatch or property is missing";
++ messages::internalError(asyncResp->res);
++ return;
++ }
+
-+ json_util::assignIfPresent<int32_t>(
-+ ret, "Timestamp", asyncResp->res.jsonValue["Timestamp"],
-+ crow::utility::getDateTime);
-+ json_util::assignIfPresent<Readings>(
-+ ret, "Readings", asyncResp->res.jsonValue["MetricValues"],
-+ toMetricValues);
-+ },
-+ "xyz.openbmc_project.MonitoringService", reportPath,
-+ "xyz.openbmc_project.MonitoringService.Report");
++ const auto& [timestamp, readings] = *timestampReadings;
++ asyncResp->res.jsonValue["Timestamp"] =
++ crow::utility::getDateTime(static_cast<time_t>(timestamp));
++ asyncResp->res.jsonValue["MetricValues"] = toMetricValues(readings);
+ }
+
+ static constexpr const char* schemaType =
@@ -603,35 +410,17 @@ index 0000000..4d1c4e5
+} // 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..72e62e9
+index 0000000..48c56e6
--- /dev/null
+++ b/redfish-core/lib/metric_report_definition.hpp
-@@ -0,0 +1,191 @@
-+/*
-+// Copyright (c) 2018-2020 Intel Corporation
-+//
-+// Licensed under the Apache License, Version 2.0 (the "License");
-+// you may not use this file except in compliance with the License.
-+// You may obtain a copy of the License at
-+//
-+// http://www.apache.org/licenses/LICENSE-2.0
-+//
-+// Unless required by applicable law or agreed to in writing, software
-+// distributed under the License is distributed on an "AS IS" BASIS,
-+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+// See the License for the specific language governing permissions and
-+// limitations under the License.
-+*/
-+
+@@ -0,0 +1,186 @@
+#pragma once
+
+#include "node.hpp"
+#include "utils/telemetry_utils.hpp"
+#include "utils/time_utils.hpp"
+
-+#include <boost/container/flat_map.hpp>
-+
-+#include <system_error>
++#include <tuple>
+#include <variant>
+
+namespace redfish
@@ -641,7 +430,7 @@ index 0000000..72e62e9
+{
+ public:
+ MetricReportDefinitionCollection(App& app) :
-+ Node(app, telemetry::metricReportDefinitionUri)
++ Node(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/")
+ {
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
@@ -672,7 +461,7 @@ index 0000000..72e62e9
+{
+ public:
+ MetricReportDefinition(App& app) :
-+ Node(app, std::string(telemetry::metricReportDefinitionUri) + "<str>/",
++ Node(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/",
+ std::string())
+ {
+ entityPrivileges = {
@@ -697,55 +486,40 @@ index 0000000..72e62e9
+ }
+
+ const std::string& id = params[0];
++ crow::connections::systemBus->async_method_call(
++ [asyncResp,
++ id](const boost::system::error_code ec,
++ const std::vector<std::pair<
++ std::string, std::variant<bool, ReadingParameters,
++ std::string, uint64_t>>>& ret) {
++ if (ec.value() == EBADR)
++ {
++ messages::resourceNotFound(asyncResp->res, schemaType, id);
++ return;
++ }
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
+
-+ telemetry::getReport(asyncResp, id, schemaType,
-+ getReportDefinitonProperties);
-+ }
-+
-+ static std::vector<std::string>
-+ toReportActions(const std::vector<std::string>& actions)
-+ {
-+ const boost::container::flat_map<std::string, std::string>
-+ reportActions = {
-+ {"Event", "RedfishEvent"},
-+ {"Log", "LogToMetricReportsCollection"},
-+ };
-+
-+ std::vector<std::string> out;
-+ for (auto& action : actions)
-+ {
-+ auto found = reportActions.find(action);
-+ if (found != reportActions.end())
-+ {
-+ out.emplace_back(found->second);
-+ }
-+ }
-+ return out;
++ fillReportDefinition(asyncResp, id, ret);
++ },
++ telemetry::service, telemetry::getDbusReportPath(id),
++ "org.freedesktop.DBus.Properties", "GetAll",
++ telemetry::reportInterface);
+ }
+
+ using ReadingParameters =
+ std::vector<std::tuple<std::vector<sdbusplus::message::object_path>,
+ std::string, std::string, std::string>>;
+
-+ static nlohmann::json toMetrics(const ReadingParameters& params)
-+ {
-+ nlohmann::json metrics = nlohmann::json::array();
-+
-+ for (auto& [sensorPaths, operationType, id, metadata] : params)
-+ {
-+ metrics.push_back({
-+ {"MetricId", id},
-+ {"MetricProperties", std::vector<std::string>() = {metadata}},
-+ });
-+ }
-+
-+ return metrics;
-+ }
-+
-+ static void
-+ getReportDefinitonProperties(const std::shared_ptr<AsyncResp> asyncResp,
-+ const std::string& reportPath,
-+ const std::string& id)
++ static void fillReportDefinition(
++ const std::shared_ptr<AsyncResp>& asyncResp, const std::string& id,
++ const std::vector<
++ std::pair<std::string, std::variant<bool, ReadingParameters,
++ std::string, uint64_t>>>& ret)
+ {
+ asyncResp->res.jsonValue["@odata.type"] = schemaType;
+ asyncResp->res.jsonValue["@odata.id"] =
@@ -755,45 +529,73 @@ index 0000000..72e62e9
+ asyncResp->res.jsonValue["MetricReport"]["@odata.id"] =
+ telemetry::metricReportUri + id;
+ asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
++ asyncResp->res.jsonValue["ReportUpdates"] = "Overwrite";
++
++ const bool* emitsReadingsUpdate = nullptr;
++ const bool* logToMetricReportsCollection = nullptr;
++ const ReadingParameters* readingParams = nullptr;
++ const std::string* reportingType = nullptr;
++ const uint64_t* interval = nullptr;
++ for (const auto& [key, var] : ret)
++ {
++ if (key == "EmitsReadingsUpdate")
++ {
++ emitsReadingsUpdate = std::get_if<bool>(&var);
++ }
++ else if (key == "LogToMetricReportsCollection")
++ {
++ logToMetricReportsCollection = std::get_if<bool>(&var);
++ }
++ else if (key == "ReadingParameters")
++ {
++ readingParams = std::get_if<ReadingParameters>(&var);
++ }
++ else if (key == "ReportingType")
++ {
++ reportingType = std::get_if<std::string>(&var);
++ }
++ else if (key == "Interval")
++ {
++ interval = std::get_if<uint64_t>(&var);
++ }
++ }
++ if (!emitsReadingsUpdate || !logToMetricReportsCollection ||
++ !readingParams || !reportingType || !interval)
++ {
++ BMCWEB_LOG_ERROR << "Property type mismatch or property is missing";
++ messages::internalError(asyncResp->res);
++ return;
++ }
+
-+ dbus::utility::getAllProperties(
-+ [asyncResp](const boost::system::error_code ec,
-+ const boost::container::flat_map<
-+ std::string,
-+ std::variant<std::string, std::vector<std::string>,
-+ uint32_t, ReadingParameters>>& ret) {
-+ if (ec)
-+ {
-+ messages::internalError(asyncResp->res);
-+ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
-+ return;
-+ }
++ std::vector<std::string> redfishReportActions;
++ redfishReportActions.reserve(2);
++ if (*emitsReadingsUpdate)
++ {
++ redfishReportActions.emplace_back("RedfishEvent");
++ }
++ if (*logToMetricReportsCollection)
++ {
++ redfishReportActions.emplace_back("LogToMetricReportsCollection");
++ }
+
-+ json_util::assignIfPresent<std::vector<std::string>>(
-+ ret, "ReportAction",
-+ asyncResp->res.jsonValue["ReportActions"], toReportActions);
-+ auto assigned = json_util::assignIfPresent<std::string>(
-+ ret, "ReportingType",
-+ asyncResp->res.jsonValue["MetricReportDefinitionType"]);
-+ if (assigned &&
-+ asyncResp->res.jsonValue["MetricReportDefinitionType"] ==
-+ "Periodic")
-+ {
-+ json_util::assignIfPresent<uint32_t>(
-+ ret, "ScanPeriod",
-+ asyncResp->res
-+ .jsonValue["Schedule"]["RecurrenceInterval"],
-+ time_utils::toDurationFormat);
-+ }
-+ json_util::assignIfPresent<ReadingParameters>(
-+ ret, "ReadingParameters",
-+ asyncResp->res.jsonValue["Metrics"], toMetrics);
-+ },
-+ "xyz.openbmc_project.MonitoringService", reportPath,
-+ "xyz.openbmc_project.MonitoringService.Report");
++ nlohmann::json metrics = nlohmann::json::array();
++ for (auto& [sensorPaths, operationType, id, metadata] : *readingParams)
++ {
++ nlohmann::json metadataJson = nlohmann::json::parse(metadata);
++ metrics.push_back({
++ {"MetricId", id},
++ {"MetricProperties", metadataJson.contains("MetricProperties")
++ ? metadataJson["MetricProperties"]
++ : nlohmann::json()},
++ });
++ }
++ asyncResp->res.jsonValue["Metrics"] = metrics;
++ asyncResp->res.jsonValue["MetricReportDefinitionType"] = *reportingType;
++ asyncResp->res.jsonValue["ReportActions"] = redfishReportActions;
++ asyncResp->res.jsonValue["Schedule"]["RecurrenceInterval"] =
++ time_utils::toDurationString(std::chrono::milliseconds(*interval));
+ }
+
-+ public:
+ static constexpr const char* schemaType =
+ "#MetricReportDefinition.v1_3_0.MetricReportDefinition";
+};
@@ -813,32 +615,14 @@ index 629280c..3df5ec5 100644
diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp
new file mode 100644
-index 0000000..b849781
+index 0000000..a6acc34
--- /dev/null
+++ b/redfish-core/lib/telemetry_service.hpp
-@@ -0,0 +1,92 @@
-+/*
-+// Copyright (c) 2018-2020 Intel Corporation
-+//
-+// Licensed under the Apache License, Version 2.0 (the "License");
-+// you may not use this file except in compliance with the License.
-+// You may obtain a copy of the License at
-+//
-+// http://www.apache.org/licenses/LICENSE-2.0
-+//
-+// Unless required by applicable law or agreed to in writing, software
-+// distributed under the License is distributed on an "AS IS" BASIS,
-+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+// See the License for the specific language governing permissions and
-+// limitations under the License.
-+*/
-+
+@@ -0,0 +1,93 @@
+#pragma once
+
+#include "node.hpp"
-+#include "utils/time_utils.hpp"
-+
-+#include <boost/container/flat_map.hpp>
++#include "utils/telemetry_utils.hpp"
+
+#include <variant>
+
@@ -864,7 +648,7 @@ index 0000000..b849781
+ const std::vector<std::string>&) override
+ {
+ res.jsonValue["@odata.type"] =
-+ "#TelemetryService.v1_2_0.TelemetryService";
++ "#TelemetryService.v1_2_1.TelemetryService";
+ res.jsonValue["@odata.id"] = "/redfish/v1/TelemetryService";
+ res.jsonValue["Id"] = "TelemetryService";
+ res.jsonValue["Name"] = "Telemetry Service";
@@ -876,36 +660,55 @@ index 0000000..b849781
+ res.jsonValue["MetricReports"]["@odata.id"] =
+ "/redfish/v1/TelemetryService/MetricReports";
+
-+ getMonitoringServiceProperties(res);
-+ }
-+
-+ void getMonitoringServiceProperties(crow::Response& res)
-+ {
+ auto asyncResp = std::make_shared<AsyncResp>(res);
-+ dbus::utility::getAllProperties(
++ crow::connections::systemBus->async_method_call(
+ [asyncResp](
+ const boost::system::error_code ec,
-+ const boost::container::flat_map<std::string,
-+ std::variant<uint32_t>>& ret) {
-+ if (ec)
++ const std::vector<std::pair<
++ std::string, std::variant<uint32_t, uint64_t>>>& ret) {
++ if (ec == boost::system::errc::host_unreachable)
+ {
+ asyncResp->res.jsonValue["Status"]["State"] = "Absent";
++ return;
++ }
++ if (ec)
++ {
+ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
++ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
+
-+ json_util::assignIfPresent<uint32_t>(ret, "MaxReports",
-+ asyncResp->res);
-+ json_util::assignIfPresent<uint32_t>(
-+ ret, "PollRateResolution",
-+ asyncResp->res.jsonValue["MinCollectionInterval"],
-+ time_utils::toDurationFormat);
++ const size_t* maxReports = nullptr;
++ const uint64_t* minInterval = nullptr;
++ for (const auto& [key, var] : ret)
++ {
++ if (key == "MaxReports")
++ {
++ maxReports = std::get_if<size_t>(&var);
++ }
++ else if (key == "MinInterval")
++ {
++ minInterval = std::get_if<uint64_t>(&var);
++ }
++ }
++ if (!maxReports || !minInterval)
++ {
++ BMCWEB_LOG_ERROR
++ << "Property type mismatch or property is missing";
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ asyncResp->res.jsonValue["MaxReports"] = *maxReports;
++ asyncResp->res.jsonValue["MinCollectionInterval"] =
++ time_utils::toDurationString(std::chrono::milliseconds(
++ static_cast<time_t>(*minInterval)));
+ },
-+ "xyz.openbmc_project.MonitoringService",
-+ "/xyz/openbmc_project/MonitoringService/Reports",
-+ "xyz.openbmc_project.MonitoringService.ReportsManagement");
++ telemetry::service, "/xyz/openbmc_project/Telemetry/Reports",
++ "org.freedesktop.DBus.Properties", "GetAll",
++ "xyz.openbmc_project.Telemetry.ReportManager");
+ }
+};
+} // namespace redfish
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-POST-and-DELETE-in-MetricReportDefinitions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-POST-and-DELETE-in-MetricReportDefinitions.patch
new file mode 100644
index 000000000..b04a72c9f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-POST-and-DELETE-in-MetricReportDefinitions.patch
@@ -0,0 +1,683 @@
+From 0784af276b72e5df9c545d83bc989833ac2935c4 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/4] Add POST and DELETE in MetricReportDefinitions
+
+Added POST action in MetricReportDefinitions node to allow user
+to add new MetricReportDefinition. Using minimal set of
+MetricReportDefinition parameters from user bmcweb converts it to
+DBus call "AddReport" to Telemetry that serves as a backend
+for Redfish TelemetryService.
+Added DELETE request in MetricReportDefinitions node to allow user
+to remove report from Telemetry.
+Added conversion from string that represents duration format into
+its numeric equivalent.
+
+Tested:
+ - Succesfully passed RedfishServiceValidator.py
+ - Validated good cases with different parameters for POST action
+ - Validated bad cases with different parameters for POST action
+ - Verified time_utils::fromDurationString()
+ - Verified that reports are removed on DELETE request
+
+Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
+Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Change-Id: I2fed96848594451e22fde686f8c066d7770cc65a
+---
+ redfish-core/include/utils/telemetry_utils.hpp | 5 +-
+ redfish-core/include/utils/time_utils.hpp | 145 +++++++++-
+ redfish-core/lib/metric_report_definition.hpp | 382 ++++++++++++++++++++++++-
+ 3 files changed, 516 insertions(+), 16 deletions(-)
+
+diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp
+index 8caee2d..acb739d 100644
+--- a/redfish-core/include/utils/telemetry_utils.hpp
++++ b/redfish-core/include/utils/telemetry_utils.hpp
+@@ -12,6 +12,8 @@ constexpr const char* metricReportDefinitionUri =
+ "/redfish/v1/TelemetryService/MetricReportDefinitions/";
+ constexpr const char* metricReportUri =
+ "/redfish/v1/TelemetryService/MetricReports/";
++constexpr const char* reportDir =
++ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/";
+
+ inline void getReportCollection(const std::shared_ptr<AsyncResp>& asyncResp,
+ const std::string& uri)
+@@ -61,8 +63,7 @@ inline void getReportCollection(const std::shared_ptr<AsyncResp>& asyncResp,
+
+ inline std::string getDbusReportPath(const std::string& id)
+ {
+- std::string path =
+- "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/" + id;
++ std::string path = reportDir + id;
+ dbus::utility::escapePathForDbus(path);
+ return path;
+ }
+diff --git a/redfish-core/include/utils/time_utils.hpp b/redfish-core/include/utils/time_utils.hpp
+index dd4ea75..d8985ab 100644
+--- a/redfish-core/include/utils/time_utils.hpp
++++ b/redfish-core/include/utils/time_utils.hpp
+@@ -1,7 +1,12 @@
+ #pragma once
+
++#include "logging.hpp"
++
++#include <charconv>
+ #include <chrono>
++#include <optional>
+ #include <string>
++#include <system_error>
+
+ namespace redfish
+ {
+@@ -12,6 +17,8 @@ namespace time_utils
+ namespace details
+ {
+
++using Days = std::chrono::duration<long long, std::ratio<24 * 60 * 60>>;
++
+ inline void leftZeroPadding(std::string& str, const std::size_t padding)
+ {
+ if (str.size() < padding)
+@@ -19,8 +26,143 @@ inline void leftZeroPadding(std::string& str, const std::size_t padding)
+ str.insert(0, padding - str.size(), '0');
+ }
+ }
++
++inline bool fromChars(const char* start, const char* end,
++ std::chrono::milliseconds::rep& val)
++{
++ auto [ptr, ec] = std::from_chars(start, end, val);
++ if (ptr != end)
++ {
++ BMCWEB_LOG_ERROR
++ << "Failed to convert string to decimal because of unexpected sign";
++ return false;
++ }
++ if (ec != std::errc())
++ {
++ BMCWEB_LOG_ERROR << "Failed to convert string to decimal with err: "
++ << static_cast<int>(ec) << "("
++ << std::make_error_code(ec).message() << ")";
++ return false;
++ }
++ return true;
++}
++
++template <typename T>
++bool fromDurationItem(std::string_view& fmt, const char postfix,
++ std::chrono::milliseconds& out)
++{
++ const size_t pos = fmt.find(postfix);
++ if (pos == std::string::npos)
++ {
++ return true;
++ }
++ if ((pos + 1U) > fmt.size())
++ {
++ return false;
++ }
++
++ std::chrono::milliseconds::rep v = 0;
++ if constexpr (std::is_same_v<T, std::chrono::milliseconds>)
++ {
++ std::string str(fmt.data(), std::min<size_t>(pos, 3U));
++ while (str.size() < 3U)
++ {
++ str += '0';
++ }
++ if (!fromChars(str.data(), str.data() + str.size(), v))
++ {
++ return false;
++ }
++ }
++ else
++ {
++ if (!fromChars(fmt.data(), fmt.data() + pos, v))
++ {
++ return false;
++ }
++ }
++
++ out += T(v);
++ if (out < T(v) ||
++ std::chrono::duration_cast<T>(std::chrono::milliseconds::max())
++ .count() < v)
++ {
++ return false;
++ }
++
++ fmt.remove_prefix(pos + 1U);
++ return true;
++}
+ } // namespace details
+
++/**
++ * @brief Convert string that represents value in Duration Format to its numeric
++ * equivalent.
++ */
++std::optional<std::chrono::milliseconds>
++ fromDurationString(const std::string& str)
++{
++ std::chrono::milliseconds out = std::chrono::milliseconds::zero();
++ std::string_view v = str;
++
++ if (v.empty())
++ {
++ return out;
++ }
++ if (v.front() != 'P')
++ {
++ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
++ return std::nullopt;
++ }
++
++ v.remove_prefix(1);
++ if (!details::fromDurationItem<details::Days>(v, 'D', out))
++ {
++ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
++ return std::nullopt;
++ }
++
++ if (v.empty())
++ {
++ return out;
++ }
++ if (v.front() != 'T')
++ {
++ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
++ return std::nullopt;
++ }
++
++ v.remove_prefix(1);
++ if (!details::fromDurationItem<std::chrono::hours>(v, 'H', out) ||
++ !details::fromDurationItem<std::chrono::minutes>(v, 'M', out))
++ {
++ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
++ return std::nullopt;
++ }
++
++ if (v.find('.') != std::string::npos && v.find('S') != std::string::npos)
++ {
++ if (!details::fromDurationItem<std::chrono::seconds>(v, '.', out) ||
++ !details::fromDurationItem<std::chrono::milliseconds>(v, 'S', out))
++ {
++ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
++ return std::nullopt;
++ }
++ }
++ else if (!details::fromDurationItem<std::chrono::seconds>(v, 'S', out))
++ {
++ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
++ return std::nullopt;
++ }
++
++ if (!v.empty())
++ {
++ BMCWEB_LOG_ERROR << "Invalid duration format: " << str;
++ return std::nullopt;
++ }
++ return out;
++}
++
+ /**
+ * @brief Convert time value into duration format that is based on ISO 8601.
+ * Example output: "P12DT1M5.5S"
+@@ -36,8 +178,7 @@ std::string toDurationString(std::chrono::milliseconds ms)
+ std::string fmt;
+ fmt.reserve(sizeof("PxxxxxxxxxxxxDTxxHxxMxx.xxxxxxS"));
+
+- using Days = std::chrono::duration<long, std::ratio<24 * 60 * 60>>;
+- Days days = std::chrono::floor<Days>(ms);
++ details::Days days = std::chrono::floor<details::Days>(ms);
+ ms -= days;
+
+ std::chrono::hours hours = std::chrono::floor<std::chrono::hours>(ms);
+diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp
+index 48c56e6..d5a540d 100644
+--- a/redfish-core/lib/metric_report_definition.hpp
++++ b/redfish-core/lib/metric_report_definition.hpp
+@@ -1,15 +1,26 @@
+ #pragma once
+
+ #include "node.hpp"
++#include "sensors.hpp"
+ #include "utils/telemetry_utils.hpp"
+ #include "utils/time_utils.hpp"
+
++#include <boost/container/flat_map.hpp>
++
+ #include <tuple>
+ #include <variant>
+
+ namespace redfish
+ {
+
++namespace telemetry
++{
++
++using ReadingParameters =
++ std::vector<std::tuple<std::vector<sdbusplus::message::object_path>,
++ std::string, std::string, std::string>>;
++} // namespace telemetry
++
+ class MetricReportDefinitionCollection : public Node
+ {
+ public:
+@@ -39,6 +50,318 @@ class MetricReportDefinitionCollection : public Node
+ telemetry::getReportCollection(asyncResp,
+ telemetry::metricReportDefinitionUri);
+ }
++
++ struct AddReportArgs
++ {
++ std::string name;
++ std::string reportingType;
++ bool emitsReadingsUpdate = false;
++ bool logToMetricReportsCollection = false;
++ uint64_t interval = 0;
++ std::vector<std::pair<std::string, std::vector<std::string>>> metrics;
++ };
++
++ void doPost(crow::Response& res, const crow::Request& req,
++ const std::vector<std::string>&) override
++ {
++ auto asyncResp = std::make_shared<AsyncResp>(res);
++ AddReportArgs args;
++ if (!getUserParameters(res, req, args))
++ {
++ return;
++ }
++
++ boost::container::flat_set<std::pair<std::string, std::string>>
++ chassisSensors;
++ if (!getChassisSensorNode(asyncResp, args.metrics, chassisSensors))
++ {
++ return;
++ }
++
++ auto addReportReq =
++ std::make_shared<AddReport>(std::move(args), asyncResp);
++ for (const auto& [chassis, sensorType] : chassisSensors)
++ {
++ retrieveUriToDbusMap(
++ chassis, sensorType,
++ [asyncResp, addReportReq](
++ const boost::beast::http::status status,
++ const boost::container::flat_map<std::string, std::string>&
++ uriToDbus) {
++ if (status != boost::beast::http::status::ok)
++ {
++ BMCWEB_LOG_ERROR << "Failed to retrieve URI to dbus "
++ "sensors map with err "
++ << static_cast<unsigned>(status);
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ addReportReq->insert(uriToDbus);
++ });
++ }
++ }
++
++ static bool toDbusReportActions(crow::Response& res,
++ std::vector<std::string>& actions,
++ AddReportArgs& args)
++ {
++ size_t index = 0;
++ for (auto& action : actions)
++ {
++ if (action == "RedfishEvent")
++ {
++ args.emitsReadingsUpdate = true;
++ }
++ else if (action == "LogToMetricReportsCollection")
++ {
++ args.logToMetricReportsCollection = true;
++ }
++ else
++ {
++ messages::propertyValueNotInList(
++ res, action, "ReportActions/" + std::to_string(index));
++ return false;
++ }
++ index++;
++ }
++ return true;
++ }
++
++ static bool getUserParameters(crow::Response& res, const crow::Request& req,
++ AddReportArgs& args)
++ {
++ std::vector<nlohmann::json> metrics;
++ std::vector<std::string> reportActions;
++ std::optional<nlohmann::json> schedule;
++ if (!json_util::readJson(req, res, "Id", args.name, "Metrics", metrics,
++ "MetricReportDefinitionType",
++ args.reportingType, "ReportActions",
++ reportActions, "Schedule", schedule))
++ {
++ return false;
++ }
++
++ constexpr const char* allowedCharactersInName =
++ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
++ if (args.name.empty() ||
++ args.name.find_first_not_of(allowedCharactersInName) !=
++ std::string::npos)
++ {
++ BMCWEB_LOG_ERROR << "Failed to match " << args.name
++ << " with allowed character "
++ << allowedCharactersInName;
++ messages::propertyValueIncorrect(res, "Id", args.name);
++ return false;
++ }
++
++ if (args.reportingType != "Periodic" &&
++ args.reportingType != "OnRequest")
++ {
++ messages::propertyValueNotInList(res, args.reportingType,
++ "MetricReportDefinitionType");
++ return false;
++ }
++
++ if (!toDbusReportActions(res, reportActions, args))
++ {
++ return false;
++ }
++
++ if (args.reportingType == "Periodic")
++ {
++ if (!schedule)
++ {
++ messages::createFailedMissingReqProperties(res, "Schedule");
++ return false;
++ }
++
++ std::string durationStr;
++ if (!json_util::readJson(*schedule, res, "RecurrenceInterval",
++ durationStr))
++ {
++ return false;
++ }
++
++ std::optional<std::chrono::milliseconds> durationNum =
++ time_utils::fromDurationString(durationStr);
++ if (!durationNum)
++ {
++ messages::propertyValueIncorrect(res, "RecurrenceInterval",
++ durationStr);
++ return false;
++ }
++ args.interval = static_cast<uint64_t>(durationNum->count());
++ }
++
++ args.metrics.reserve(metrics.size());
++ for (auto& m : metrics)
++ {
++ std::string id;
++ std::vector<std::string> uris;
++ if (!json_util::readJson(m, res, "MetricId", id, "MetricProperties",
++ uris))
++ {
++ return false;
++ }
++
++ args.metrics.emplace_back(std::move(id), std::move(uris));
++ }
++
++ return true;
++ }
++
++ static bool getChassisSensorNode(
++ const std::shared_ptr<AsyncResp>& asyncResp,
++ const std::vector<std::pair<std::string, std::vector<std::string>>>&
++ metrics,
++ boost::container::flat_set<std::pair<std::string, std::string>>&
++ matched)
++ {
++ for (const auto& [id, uris] : metrics)
++ {
++ for (size_t i = 0; i < uris.size(); i++)
++ {
++ const std::string& uri = uris[i];
++ std::string chassis;
++ std::string node;
++
++ if (!boost::starts_with(uri, "/redfish/v1/Chassis/") ||
++ !dbus::utility::getNthStringFromPath(uri, 3, chassis) ||
++ !dbus::utility::getNthStringFromPath(uri, 4, node))
++ {
++ BMCWEB_LOG_ERROR << "Failed to get chassis and sensor Node "
++ "from "
++ << uri;
++ messages::propertyValueIncorrect(asyncResp->res, uri,
++ "MetricProperties/" +
++ std::to_string(i));
++ return false;
++ }
++
++ if (boost::ends_with(node, "#"))
++ {
++ node.pop_back();
++ }
++
++ matched.emplace(std::move(chassis), std::move(node));
++ }
++ }
++ return true;
++ }
++
++ class AddReport
++ {
++ public:
++ AddReport(AddReportArgs argsIn, std::shared_ptr<AsyncResp> asyncResp) :
++ asyncResp{std::move(asyncResp)}, args{std::move(argsIn)}
++ {}
++ ~AddReport()
++ {
++ if (asyncResp->res.result() != boost::beast::http::status::ok)
++ {
++ return;
++ }
++
++ telemetry::ReadingParameters readingParams;
++ readingParams.reserve(args.metrics.size());
++
++ for (const auto& [id, uris] : args.metrics)
++ {
++ std::vector<sdbusplus::message::object_path> dbusPaths;
++ dbusPaths.reserve(uris.size());
++
++ for (size_t i = 0; i < uris.size(); i++)
++ {
++ const std::string& uri = uris[i];
++ auto el = uriToDbus.find(uri);
++ if (el == uriToDbus.end())
++ {
++ BMCWEB_LOG_ERROR << "Failed to find DBus sensor "
++ "corresponding to URI "
++ << uri;
++ messages::propertyValueNotInList(asyncResp->res, uri,
++ "MetricProperties/" +
++ std::to_string(i));
++ return;
++ }
++
++ dbusPaths.emplace_back(el->second);
++ }
++
++ nlohmann::json metadata;
++ metadata["MetricProperties"] = uris;
++ if (uris.size() == 1)
++ {
++ metadata["MetricProperty"] = uris[0];
++ }
++ readingParams.emplace_back(std::move(dbusPaths), "SINGLE", id,
++ metadata.dump());
++ }
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp = asyncResp, name = args.name](
++ const boost::system::error_code ec, const std::string&) {
++ if (ec == boost::system::errc::file_exists)
++ {
++ messages::resourceAlreadyExists(
++ asyncResp->res, "MetricReportDefinition", "Id",
++ name);
++ return;
++ }
++ if (ec == boost::system::errc::too_many_files_open)
++ {
++ messages::createLimitReachedForResource(asyncResp->res);
++ return;
++ }
++ if (ec == boost::system::errc::argument_list_too_long)
++ {
++ messages::propertyValueNotInList(
++ asyncResp->res, "/Exceeds supported size/",
++ "Metrics");
++ return;
++ }
++ if (ec == boost::system::errc::not_supported)
++ {
++ messages::propertyValueNotInList(
++ asyncResp->res,
++ "/Only single property per metric is supported/",
++ "MetricProperties");
++ return;
++ }
++ if (ec == boost::system::errc::invalid_argument)
++ {
++ messages::propertyValueNotInList(
++ asyncResp->res, "/Less then MinInterval/",
++ "RecurrenceInterval");
++ return;
++ }
++ if (ec)
++ {
++ messages::internalError(asyncResp->res);
++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
++ return;
++ }
++
++ messages::created(asyncResp->res);
++ },
++ telemetry::service, "/xyz/openbmc_project/Telemetry/Reports",
++ "xyz.openbmc_project.Telemetry.ReportManager", "AddReport",
++ "TelemetryService/" + args.name, args.reportingType,
++ args.emitsReadingsUpdate, args.logToMetricReportsCollection,
++ args.interval, readingParams);
++ }
++
++ void insert(
++ const boost::container::flat_map<std::string, std::string>& el)
++ {
++ uriToDbus.insert(el.begin(), el.end());
++ }
++
++ private:
++ std::shared_ptr<AsyncResp> asyncResp;
++ AddReportArgs args;
++ boost::container::flat_map<std::string, std::string> uriToDbus{};
++ };
+ };
+
+ class MetricReportDefinition : public Node
+@@ -73,9 +396,10 @@ class MetricReportDefinition : public Node
+ crow::connections::systemBus->async_method_call(
+ [asyncResp,
+ id](const boost::system::error_code ec,
+- const std::vector<std::pair<
+- std::string, std::variant<bool, ReadingParameters,
+- std::string, uint64_t>>>& ret) {
++ const std::vector<
++ std::pair<std::string,
++ std::variant<bool, telemetry::ReadingParameters,
++ std::string, uint64_t>>>& ret) {
+ if (ec.value() == EBADR)
+ {
+ messages::resourceNotFound(asyncResp->res, schemaType, id);
+@@ -95,15 +419,11 @@ class MetricReportDefinition : public Node
+ telemetry::reportInterface);
+ }
+
+- using ReadingParameters =
+- std::vector<std::tuple<std::vector<sdbusplus::message::object_path>,
+- std::string, std::string, std::string>>;
+-
+ static void fillReportDefinition(
+ const std::shared_ptr<AsyncResp>& asyncResp, const std::string& id,
+- const std::vector<
+- std::pair<std::string, std::variant<bool, ReadingParameters,
+- std::string, uint64_t>>>& ret)
++ const std::vector<std::pair<
++ std::string, std::variant<bool, telemetry::ReadingParameters,
++ std::string, uint64_t>>>& ret)
+ {
+ asyncResp->res.jsonValue["@odata.type"] = schemaType;
+ asyncResp->res.jsonValue["@odata.id"] =
+@@ -117,7 +437,7 @@ class MetricReportDefinition : public Node
+
+ const bool* emitsReadingsUpdate = nullptr;
+ const bool* logToMetricReportsCollection = nullptr;
+- const ReadingParameters* readingParams = nullptr;
++ const telemetry::ReadingParameters* readingParams = nullptr;
+ const std::string* reportingType = nullptr;
+ const uint64_t* interval = nullptr;
+ for (const auto& [key, var] : ret)
+@@ -132,7 +452,7 @@ class MetricReportDefinition : public Node
+ }
+ else if (key == "ReadingParameters")
+ {
+- readingParams = std::get_if<ReadingParameters>(&var);
++ readingParams = std::get_if<telemetry::ReadingParameters>(&var);
+ }
+ else if (key == "ReportingType")
+ {
+@@ -180,6 +500,44 @@ class MetricReportDefinition : public Node
+ time_utils::toDurationString(std::chrono::milliseconds(*interval));
+ }
+
++ void doDelete(crow::Response& res, const crow::Request&,
++ const std::vector<std::string>& params) override
++ {
++ auto asyncResp = std::make_shared<AsyncResp>(res);
++ if (params.size() != 1)
++ {
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ const std::string& id = params[0];
++ const std::string reportPath = telemetry::getDbusReportPath(id);
++
++ crow::connections::systemBus->async_method_call(
++ [asyncResp, id](const boost::system::error_code ec) {
++ /*
++ * boost::system::errc and std::errc are missing value for
++ * EBADR error that is defined in Linux.
++ */
++ if (ec.value() == EBADR)
++ {
++ messages::resourceNotFound(asyncResp->res, schemaType, id);
++ return;
++ }
++
++ if (ec)
++ {
++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ asyncResp->res.result(boost::beast::http::status::no_content);
++ },
++ telemetry::service, reportPath, "xyz.openbmc_project.Object.Delete",
++ "Delete");
++ }
++
+ static constexpr const char* schemaType =
+ "#MetricReportDefinition.v1_3_0.MetricReportDefinition";
+ };
+--
+2.16.6
+
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
deleted file mode 100644
index c24352de5..000000000
--- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Add-support-for-POST-in-MetricReportDefinitions.patch
+++ /dev/null
@@ -1,598 +0,0 @@
-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 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
-MetricReportDefinition parameters from user bmcweb converts it to
-DBus call "AddReport" to MonitoringService that serves as a backend
-for TelemetryService.
-
-Tested:
- - Succesfully passed RedfishServiceValidator.py
- - Validated good cases with different parameters for POST action
- - Validated bad cases with different parameters for POST action
- - Validated fromDurationFormat() with range of arguments starting
- from PT0.0S up to P49D (it is an upper limit for uint32_t)
-
-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 +++++++
- redfish-core/lib/metric_report_definition.hpp | 347 +++++++++++++++++++++
- 3 files changed, 505 insertions(+)
- create mode 100644 redfish-core/include/utils/validate_params_length.hpp
-
-diff --git a/redfish-core/include/utils/time_utils.hpp b/redfish-core/include/utils/time_utils.hpp
-index 0256b3f..c365585 100644
---- a/redfish-core/include/utils/time_utils.hpp
-+++ b/redfish-core/include/utils/time_utils.hpp
-@@ -57,6 +57,32 @@ std::string toDurationFormatItem(std::chrono::milliseconds& duration,
- return ss.str();
- }
-
-+template <typename T>
-+static long long fromDurationFormatItem(std::string_view& fmt,
-+ const char* postfix)
-+{
-+ auto pos = fmt.find(postfix);
-+ if (pos == std::string::npos)
-+ {
-+ return 0;
-+ }
-+
-+ long out;
-+ if constexpr (std::is_same<T, std::chrono::milliseconds>::value)
-+ {
-+ /* Half point is added to avoid numeric error on rounding */
-+ out = static_cast<long>(std::strtof(fmt.data(), nullptr) *
-+ std::chrono::milliseconds::period::den +
-+ 0.5f);
-+ }
-+ else
-+ {
-+ out = std::strtol(fmt.data(), nullptr, 10);
-+ }
-+ fmt.remove_prefix(pos + 1);
-+ return std::chrono::milliseconds(T(out)).count();
-+}
-+
- } // namespace details
-
- /**
-@@ -93,5 +119,28 @@ std::string toDurationFormat(const uint32_t ms)
- return fmt;
- }
-
-+static uint32_t fromDurationFormat(std::string_view fmt)
-+{
-+ if (fmt.empty() || fmt[0] != 'P')
-+ {
-+ return 0;
-+ }
-+ using Days = std::chrono::duration<int, std::ratio<24 * 60 * 60>>;
-+
-+ fmt.remove_prefix(1);
-+ auto out = details::fromDurationFormatItem<Days>(fmt, "D");
-+ if (fmt[0] != 'T')
-+ {
-+ return static_cast<uint32_t>(out);
-+ }
-+
-+ fmt.remove_prefix(1);
-+ out += details::fromDurationFormatItem<std::chrono::hours>(fmt, "H");
-+ out += details::fromDurationFormatItem<std::chrono::minutes>(fmt, "M");
-+ out += details::fromDurationFormatItem<std::chrono::milliseconds>(fmt, "S");
-+
-+ return static_cast<uint32_t>(out);
-+}
-+
- } // namespace time_utils
- } // namespace redfish
-diff --git a/redfish-core/include/utils/validate_params_length.hpp b/redfish-core/include/utils/validate_params_length.hpp
-new file mode 100644
-index 0000000..c4e0569
---- /dev/null
-+++ b/redfish-core/include/utils/validate_params_length.hpp
-@@ -0,0 +1,109 @@
-+#pragma once
-+
-+namespace redfish
-+{
-+namespace detail
-+{
-+template <class Limits, size_t... Seq>
-+bool validateParamsLength(crow::Response& res, Limits&& limits,
-+ std::index_sequence<Seq...>)
-+{
-+ return (... && std::get<Seq>(limits).validate(res));
-+}
-+} // namespace detail
-+
-+template <class T>
-+struct ItemSizeValidator
-+{
-+ ItemSizeValidator(const T&& item, std::string_view name, size_t limit) :
-+ item(std::forward<const T>(item)), name(name), limit(limit)
-+ {}
-+
-+ bool validate(crow::Response& res) const
-+ {
-+ return ItemSizeValidator<T>::validateItem(res, item, name, limit);
-+ }
-+
-+ private:
-+ static bool validateItem(crow::Response& res, size_t item,
-+ std::string_view name, size_t limit)
-+ {
-+ if (item > static_cast<size_t>(limit))
-+ {
-+ messages::stringValueTooLong(res, std::string(name),
-+ static_cast<int>(limit));
-+ return false;
-+ }
-+ return true;
-+ }
-+
-+ static bool validateItem(crow::Response& res, std::string_view item,
-+ std::string_view name, size_t limit)
-+ {
-+ return validateItem(res, item.size(), name, limit);
-+ }
-+
-+ static bool validateItem(crow::Response& res, const std::string& item,
-+ std::string_view name, size_t limit)
-+ {
-+ return validateItem(res, item.size(), name, limit);
-+ }
-+
-+ static bool validateItem(crow::Response& res,
-+ const sdbusplus::message::object_path& item,
-+ std::string_view name, size_t limit)
-+ {
-+ return validateItem(res, item.str.size(), name, limit);
-+ }
-+
-+ T item;
-+ std::string_view name;
-+ size_t limit;
-+};
-+
-+template <class T>
-+ItemSizeValidator(const T&, std::string_view, size_t)
-+ -> ItemSizeValidator<const T&>;
-+
-+ItemSizeValidator(const char*, std::string_view, size_t)
-+ ->ItemSizeValidator<std::string_view>;
-+
-+template <class ContainerT>
-+struct ArrayItemsValidator
-+{
-+ ArrayItemsValidator(const ContainerT& item, std::string_view name,
-+ size_t limit) :
-+ item(item),
-+ name(name), limit(limit)
-+ {}
-+
-+ bool validate(crow::Response& res) const
-+ {
-+ return std::all_of(
-+ item.begin(), item.end(), [&res, this](const auto& item) {
-+ return ItemSizeValidator(item, name, limit).validate(res);
-+ });
-+ }
-+
-+ private:
-+ const ContainerT& item;
-+ std::string_view name;
-+ size_t limit;
-+};
-+
-+template <class T>
-+bool validateParamLength(crow::Response& res, T&& item, std::string_view name,
-+ size_t limit)
-+{
-+ return ItemSizeValidator(std::forward<T>(item), name, limit).validate(res);
-+}
-+
-+template <class Limits>
-+bool validateParamsLength(crow::Response& res, Limits&& limits)
-+{
-+ return detail::validateParamsLength(
-+ res, std::forward<Limits>(limits),
-+ std::make_index_sequence<std::tuple_size_v<std::decay_t<Limits>>>());
-+}
-+
-+} // namespace redfish
-diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp
-index 72e62e9..c6b09f8 100644
---- a/redfish-core/lib/metric_report_definition.hpp
-+++ b/redfish-core/lib/metric_report_definition.hpp
-@@ -17,16 +17,29 @@
- #pragma once
-
- #include "node.hpp"
-+#include "sensors.hpp"
- #include "utils/telemetry_utils.hpp"
- #include "utils/time_utils.hpp"
-+#include "utils/validate_params_length.hpp"
-
-+#include <boost/algorithm/string/join.hpp>
-+#include <boost/algorithm/string/split.hpp>
- #include <boost/container/flat_map.hpp>
-
-+#include <regex>
- #include <system_error>
-+#include <tuple>
- #include <variant>
-
- namespace redfish
- {
-+static constexpr size_t maxShortParamLength = 255;
-+static constexpr size_t maxLongParamLength = 1024;
-+static constexpr size_t maxDbusNameLength = 255;
-+static constexpr size_t maxArraySize = 100;
-+static constexpr size_t maxReportIdLen =
-+ maxDbusNameLength - std::string_view(telemetry::telemetryPath).size() -
-+ std::string_view("/").size();
-
- class MetricReportDefinitionCollection : public Node
- {
-@@ -57,6 +70,339 @@ class MetricReportDefinitionCollection : public Node
- telemetry::getReportCollection(asyncResp,
- telemetry::metricReportDefinitionUri);
- }
-+
-+ using ChassisSensorNode = std::pair<std::string, std::string>;
-+ using DbusSensor = sdbusplus::message::object_path;
-+ using DbusSensors = std::vector<DbusSensor>;
-+ using MetricParam =
-+ std::tuple<DbusSensors, std::string, std::string, std::string>;
-+ using MetricParams = std::vector<MetricParam>;
-+ /*
-+ * AddReportArgs misses "Domain" parameter because it is constant for
-+ * TelemetryService and equals "TelemetryService".
-+ */
-+ using AddReportArgs =
-+ std::tuple<std::string, std::string, std::vector<std::string>, uint32_t,
-+ MetricParams>;
-+
-+ void doPost(crow::Response& res, const crow::Request& req,
-+ const std::vector<std::string>&) override
-+ {
-+ auto asyncResp = std::make_shared<AsyncResp>(res);
-+ AddReportArgs addReportArgs;
-+ if (!getUserParameters(res, req, addReportArgs))
-+ {
-+ return;
-+ }
-+
-+ boost::container::flat_set<ChassisSensorNode> chassisSensorSet;
-+ auto unmatched = getChassisSensorNode(
-+ std::get<MetricParams>(addReportArgs), chassisSensorSet);
-+ if (unmatched)
-+ {
-+ messages::resourceNotFound(asyncResp->res, "MetricProperties",
-+ *unmatched);
-+ return;
-+ }
-+
-+ auto addReportReq =
-+ std::make_shared<AddReport>(addReportArgs, asyncResp);
-+ for (auto& [chassis, sensorType] : chassisSensorSet)
-+ {
-+ retrieveUriToDbusMap(
-+ chassis, sensorType,
-+ [asyncResp, addReportReq](
-+ const boost::beast::http::status,
-+ const boost::container::flat_map<std::string, std::string>&
-+ uriToDbus) { *addReportReq += uriToDbus; });
-+ }
-+ }
-+
-+ static std::optional<std::string>
-+ replaceReportActions(std::vector<std::string>& actions)
-+ {
-+ const boost::container::flat_map<std::string, std::string>
-+ reportActions = {
-+ {"RedfishEvent", "Event"},
-+ {"LogToMetricReportsCollection", "Log"},
-+ };
-+
-+ for (auto& action : actions)
-+ {
-+ auto found = reportActions.find(action);
-+ if (found == reportActions.end())
-+ {
-+ return action;
-+ }
-+ action = found->second;
-+ }
-+ return std::nullopt;
-+ }
-+
-+ static constexpr const std::array<const char*, 2> supportedDefinitionType =
-+ {"Periodic", "OnRequest"};
-+
-+ static bool getUserParameters(crow::Response& res, const crow::Request& req,
-+ AddReportArgs& params)
-+ {
-+ std::vector<nlohmann::json> metrics;
-+ std::optional<nlohmann::json> schedule;
-+ auto& [name, reportingType, reportActions, scanPeriod, metricParams] =
-+ params;
-+ if (!json_util::readJson(req, res, "Id", name, "Metrics", metrics,
-+ "MetricReportDefinitionType", reportingType,
-+ "ReportActions", reportActions, "Schedule",
-+ schedule))
-+ {
-+ return false;
-+ }
-+
-+ auto limits = std::make_tuple(
-+ ItemSizeValidator(name, "Id", maxReportIdLen),
-+ ItemSizeValidator(reportingType, "MetricReportDefinitionType",
-+ maxShortParamLength),
-+ ItemSizeValidator(reportActions.size(), "ReportActions.size()",
-+ maxArraySize),
-+ ArrayItemsValidator(reportActions, "ReportActions",
-+ maxShortParamLength),
-+ ItemSizeValidator(metrics.size(), "Metrics.size()", maxArraySize));
-+
-+ if (!validateParamsLength(res, std::move(limits)))
-+ {
-+ return false;
-+ }
-+
-+ constexpr const char* allowedCharactersInName =
-+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
-+ "_";
-+ if (name.empty() || name.find_first_not_of(allowedCharactersInName) !=
-+ std::string::npos)
-+ {
-+ BMCWEB_LOG_ERROR << "Failed to match " << name
-+ << " with allowed character "
-+ << allowedCharactersInName;
-+ messages::propertyValueFormatError(res, name, "Id");
-+ return false;
-+ }
-+
-+ if (!std::any_of(
-+ supportedDefinitionType.begin(), supportedDefinitionType.end(),
-+ [reportingType](auto& x) { return reportingType == x; }))
-+ {
-+ messages::propertyValueNotInList(res, reportingType,
-+ "MetricReportDefinitionType");
-+ return false;
-+ }
-+
-+ auto unmatched = replaceReportActions(reportActions);
-+ if (unmatched)
-+ {
-+ messages::propertyValueNotInList(res, *unmatched, "ReportActions");
-+ return false;
-+ }
-+
-+ if (reportingType == "Periodic")
-+ {
-+ if (!schedule)
-+ {
-+ messages::createFailedMissingReqProperties(res, "Schedule");
-+ return false;
-+ }
-+
-+ std::string interval;
-+ if (!json_util::readJson(*schedule, res, "RecurrenceInterval",
-+ interval))
-+ {
-+ return false;
-+ }
-+
-+ if (!validateParamLength(res, interval, "RecurrenceInterval",
-+ maxShortParamLength))
-+ {
-+ return false;
-+ }
-+
-+ constexpr const char* durationPattern =
-+ "-?P(\\d+D)?(T(\\d+H)?(\\d+M)?(\\d+(.\\d+)?S)?)?";
-+ if (!std::regex_match(interval, std::regex(durationPattern)))
-+ {
-+ messages::propertyValueFormatError(res, interval,
-+ "RecurrenceInterval");
-+ return false;
-+ }
-+
-+ scanPeriod = time_utils::fromDurationFormat(interval);
-+ }
-+
-+ return fillMetricParams(metrics, res, metricParams);
-+ }
-+
-+ static bool fillMetricParams(std::vector<nlohmann::json>& metrics,
-+ crow::Response& res,
-+ MetricParams& metricParams)
-+ {
-+ metricParams.reserve(metrics.size());
-+ for (auto& m : metrics)
-+ {
-+ std::string metricId;
-+ std::vector<std::string> metricProperties;
-+ if (!json_util::readJson(m, res, "MetricId", metricId,
-+ "MetricProperties", metricProperties))
-+ {
-+ return false;
-+ }
-+
-+ auto limits = std::make_tuple(
-+ ItemSizeValidator(metricId, "MetricId", maxLongParamLength),
-+ ItemSizeValidator(metricProperties.size(),
-+ "MetricProperties.size()", maxArraySize),
-+ ArrayItemsValidator(metricProperties, "MetricProperties",
-+ maxLongParamLength));
-+
-+ if (!validateParamsLength(res, std::move(limits)))
-+ {
-+ return false;
-+ }
-+
-+ DbusSensors dbusSensors;
-+ dbusSensors.reserve(metricProperties.size());
-+ std::for_each(
-+ metricProperties.begin(), metricProperties.end(),
-+ [&dbusSensors](auto& x) { dbusSensors.emplace_back(x); });
-+
-+ metricParams.emplace_back(
-+ dbusSensors, "SINGLE", metricId,
-+ boost::algorithm::join(metricProperties, ", "));
-+ }
-+ return true;
-+ }
-+
-+ static std::optional<std::string> getChassisSensorNode(
-+ const MetricParams& metricParams,
-+ boost::container::flat_set<ChassisSensorNode>& matched)
-+ {
-+ for (const auto& metricParam : metricParams)
-+ {
-+ const auto& sensors = std::get<DbusSensors>(metricParam);
-+ for (const auto& sensor : sensors)
-+ {
-+ /*
-+ * Support only following paths:
-+ * "/redfish/v1/Chassis/<chassis>/Power#/..."
-+ * "/redfish/v1/Chassis/<chassis>/Sensors/..."
-+ * "/redfish/v1/Chassis/<chassis>/Thermal#/..."
-+ */
-+ constexpr const char* uriPattern =
-+ "\\/redfish\\/v1\\/Chassis\\/(\\w+)\\/"
-+ "(Power|Sensors|Thermal)[#]?\\/.*";
-+ std::smatch m;
-+ if (!std::regex_match(sensor.str, m, std::regex(uriPattern)) ||
-+ m.size() != 3)
-+ {
-+ BMCWEB_LOG_ERROR << "Failed to match " << sensor.str
-+ << " with pattern " << uriPattern;
-+ return sensor;
-+ }
-+
-+ BMCWEB_LOG_DEBUG << "Chassis=" << m[1] << ", Type=" << m[2];
-+ matched.emplace(m[1], m[2]);
-+ }
-+ }
-+ return std::nullopt;
-+ }
-+
-+ static std::optional<std::string> replaceUriWithDbus(
-+ const boost::container::flat_map<std::string, std::string>& uriToDbus,
-+ MetricParams& metricParams)
-+ {
-+ for (auto& metricParam : metricParams)
-+ {
-+ auto& dbusSensors = std::get<DbusSensors>(metricParam);
-+ for (auto& uri : dbusSensors)
-+ {
-+ auto dbus = uriToDbus.find(uri);
-+ if (dbus == uriToDbus.end())
-+ {
-+ BMCWEB_LOG_ERROR << "Failed to find DBus sensor "
-+ "corresponding to URI "
-+ << uri.str;
-+ return uri;
-+ }
-+ uri = dbus->second;
-+ }
-+ }
-+ return std::nullopt;
-+ }
-+
-+ static void addReport(std::shared_ptr<AsyncResp> asyncResp,
-+ AddReportArgs args)
-+ {
-+ constexpr const char* domain = "TelemetryService";
-+ auto& [name, reportingType, reportActions, scanPeriod, metricParams] =
-+ args;
-+
-+ crow::connections::systemBus->async_method_call(
-+ [asyncResp, name](const boost::system::error_code ec,
-+ const std::string) {
-+ if (ec == boost::system::errc::file_exists)
-+ {
-+ messages::resourceAlreadyExists(
-+ asyncResp->res, "MetricReportDefinition", "Id", name);
-+ return;
-+ }
-+ if (ec == boost::system::errc::too_many_files_open)
-+ {
-+ messages::createLimitReachedForResource(asyncResp->res);
-+ return;
-+ }
-+ if (ec)
-+ {
-+ messages::internalError(asyncResp->res);
-+ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
-+ return;
-+ }
-+
-+ messages::created(asyncResp->res);
-+ },
-+ "xyz.openbmc_project.MonitoringService",
-+ "/xyz/openbmc_project/MonitoringService/Reports",
-+ "xyz.openbmc_project.MonitoringService.ReportsManagement",
-+ "AddReport", name, domain, reportingType, reportActions, scanPeriod,
-+ metricParams);
-+ }
-+
-+ class AddReport
-+ {
-+ public:
-+ AddReport(AddReportArgs& args, std::shared_ptr<AsyncResp>& asyncResp) :
-+ asyncResp{asyncResp}, addReportArgs{args}
-+ {}
-+ ~AddReport()
-+ {
-+ auto unmatched = replaceUriWithDbus(
-+ uriToDbus, std::get<MetricParams>(addReportArgs));
-+ if (unmatched)
-+ {
-+ messages::resourceNotFound(asyncResp->res, "MetricProperties",
-+ *unmatched);
-+ return;
-+ }
-+
-+ addReport(asyncResp, addReportArgs);
-+ }
-+
-+ AddReport& operator+=(
-+ const boost::container::flat_map<std::string, std::string>& rhs)
-+ {
-+ this->uriToDbus.insert(rhs.begin(), rhs.end());
-+ return *this;
-+ }
-+
-+ private:
-+ std::shared_ptr<AsyncResp> asyncResp;
-+ AddReportArgs addReportArgs;
-+ boost::container::flat_map<std::string, std::string> uriToDbus{};
-+ };
- };
-
- 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";
-+ asyncResp->res.jsonValue["ReportUpdates"] = "Overwrite";
-
- dbus::utility::getAllProperties(
- [asyncResp](const boost::system::error_code ec,
---
-2.16.6
-
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
deleted file mode 100644
index dee5a158b..000000000
--- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-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 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
-with MetricReport connected to it.
-
-Tested:
- - Succesfully passed RedfishServiceValidator.py
- - Validated DELETE action by removing exisiting
- MetricReportDefinitions from MonitoringService
- - Validated DELETE action with negative cases when
- MetricReportDefinition does not exist
-
-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 c6b09f8..3191a8f 100644
---- a/redfish-core/lib/metric_report_definition.hpp
-+++ b/redfish-core/lib/metric_report_definition.hpp
-@@ -531,6 +531,38 @@ class MetricReportDefinition : public Node
- "xyz.openbmc_project.MonitoringService.Report");
- }
-
-+ void doDelete(crow::Response& res, const crow::Request&,
-+ const std::vector<std::string>& params) override
-+ {
-+ auto asyncResp = std::make_shared<AsyncResp>(res);
-+ if (params.size() != 1)
-+ {
-+ messages::internalError(asyncResp->res);
-+ return;
-+ }
-+
-+ const std::string& id = params[0];
-+ telemetry::getReport(asyncResp, id, schemaType, deleteReport);
-+ }
-+
-+ static void deleteReport(const std::shared_ptr<AsyncResp>& asyncResp,
-+ const std::string& path, const std::string&)
-+ {
-+ crow::connections::systemBus->async_method_call(
-+ [asyncResp](const boost::system::error_code ec) {
-+ if (ec)
-+ {
-+ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
-+ messages::internalError(asyncResp->res);
-+ return;
-+ }
-+
-+ asyncResp->res.result(boost::beast::http::status::no_content);
-+ },
-+ "xyz.openbmc_project.MonitoringService", path,
-+ "xyz.openbmc_project.Object.Delete", "Delete");
-+ }
-+
- public:
- static constexpr const char* schemaType =
- "#MetricReportDefinition.v1_3_0.MetricReportDefinition";
---
-2.16.6
-
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch
new file mode 100644
index 000000000..d81d654f1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch
@@ -0,0 +1,709 @@
+From b074a84560349fdbd46604ab0b8c75804de09fef 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 3/4] 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
+supported by TelemetryService.
+Added generic function to fill ReadingUnits and ReadingType
+in Sensor scheme.
+
+Tested:
+ - Succesfully passed RedfishServiceValidator.py
+ - Validated a presence of MetricDefinition members
+
+Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
+Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
+Change-Id: I3086e1302e1ba2e5442d1367939fd5507a0cbc00
+---
+ redfish-core/include/redfish.hpp | 3 +
+ redfish-core/include/utils/telemetry_utils.hpp | 56 ++---
+ redfish-core/lib/metric_definition.hpp | 269 +++++++++++++++++++++++++
+ redfish-core/lib/metric_report_definition.hpp | 22 ++
+ redfish-core/lib/power.hpp | 4 +-
+ redfish-core/lib/sensors.hpp | 104 +++++++---
+ redfish-core/lib/telemetry_service.hpp | 2 +
+ redfish-core/lib/thermal.hpp | 4 +-
+ 8 files changed, 410 insertions(+), 54 deletions(-)
+ create mode 100644 redfish-core/lib/metric_definition.hpp
+
+diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
+index 2587b37..705f490 100644
+--- a/redfish-core/include/redfish.hpp
++++ b/redfish-core/include/redfish.hpp
+@@ -25,6 +25,7 @@
+ #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"
+@@ -211,6 +212,8 @@ class RedfishService
+ nodes.emplace_back(std::make_unique<HypervisorSystem>(app));
+
+ nodes.emplace_back(std::make_unique<TelemetryService>(app));
++ nodes.emplace_back(std::make_unique<MetricDefinitionCollection>(app));
++ nodes.emplace_back(std::make_unique<MetricDefinition>(app));
+ nodes.emplace_back(
+ std::make_unique<MetricReportDefinitionCollection>(app));
+ nodes.emplace_back(std::make_unique<MetricReportDefinition>(app));
+diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp
+index acb739d..c13a79b 100644
+--- a/redfish-core/include/utils/telemetry_utils.hpp
++++ b/redfish-core/include/utils/telemetry_utils.hpp
+@@ -8,6 +8,8 @@ namespace telemetry
+
+ constexpr const char* service = "xyz.openbmc_project.Telemetry";
+ constexpr const char* reportInterface = "xyz.openbmc_project.Telemetry.Report";
++constexpr const char* metricDefinitionUri =
++ "/redfish/v1/TelemetryService/MetricDefinitions/";
+ constexpr const char* metricReportDefinitionUri =
+ "/redfish/v1/TelemetryService/MetricReportDefinitions/";
+ constexpr const char* metricReportUri =
+@@ -15,6 +17,36 @@ constexpr const char* metricReportUri =
+ constexpr const char* reportDir =
+ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService/";
+
++inline void dbusPathsToMembers(const std::shared_ptr<AsyncResp>& asyncResp,
++ const std::vector<std::string>& paths,
++ const std::string& uri)
++{
++ nlohmann::json& members = asyncResp->res.jsonValue["Members"];
++ members = nlohmann::json::array();
++
++ for (const std::string& path : paths)
++ {
++ std::size_t pos = path.rfind('/');
++ if (pos == std::string::npos)
++ {
++ BMCWEB_LOG_ERROR << "Failed to find '/' in " << path;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ if (path.size() <= (pos + 1))
++ {
++ BMCWEB_LOG_ERROR << "Failed to parse path " << path;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ members.push_back({{"@odata.id", uri + path.substr(pos + 1)}});
++ }
++
++ asyncResp->res.jsonValue["Members@odata.count"] = members.size();
++}
++
+ inline void getReportCollection(const std::shared_ptr<AsyncResp>& asyncResp,
+ const std::string& uri)
+ {
+@@ -30,29 +62,7 @@ inline void getReportCollection(const std::shared_ptr<AsyncResp>& asyncResp,
+ return;
+ }
+
+- nlohmann::json& members = asyncResp->res.jsonValue["Members"];
+- members = nlohmann::json::array();
+-
+- for (const std::string& path : reportPaths)
+- {
+- std::size_t pos = path.rfind('/');
+- if (pos == std::string::npos)
+- {
+- BMCWEB_LOG_ERROR << "Failed to find '/' in " << path;
+- messages::internalError(asyncResp->res);
+- return;
+- }
+- if (path.size() <= (pos + 1))
+- {
+- BMCWEB_LOG_ERROR << "Failed to parse path " << path;
+- messages::internalError(asyncResp->res);
+- return;
+- }
+-
+- members.push_back({{"@odata.id", uri + path.substr(pos + 1)}});
+- }
+-
+- asyncResp->res.jsonValue["Members@odata.count"] = members.size();
++ dbusPathsToMembers(asyncResp, reportPaths, uri);
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+diff --git a/redfish-core/lib/metric_definition.hpp b/redfish-core/lib/metric_definition.hpp
+new file mode 100644
+index 0000000..f037ed2
+--- /dev/null
++++ b/redfish-core/lib/metric_definition.hpp
+@@ -0,0 +1,269 @@
++#pragma once
++
++#include "node.hpp"
++#include "sensors.hpp"
++#include "utils/telemetry_utils.hpp"
++
++namespace redfish
++{
++
++namespace utils
++{
++
++template <typename F>
++inline void getChassisNames(F&& cb)
++{
++ const std::array<const char*, 2> interfaces = {
++ "xyz.openbmc_project.Inventory.Item.Board",
++ "xyz.openbmc_project.Inventory.Item.Chassis"};
++
++ crow::connections::systemBus->async_method_call(
++ [callback = std::move(cb)](const boost::system::error_code ec,
++ std::vector<std::string>& chassisList) {
++ if (ec)
++ {
++ BMCWEB_LOG_DEBUG << "DBus call error: " << ec.value();
++ return;
++ }
++
++ std::vector<std::string> chassisNames;
++ chassisNames.reserve(chassisList.size());
++ for (const std::string& chassisPath : chassisList)
++ {
++ size_t pos = chassisPath.rfind('/');
++ if (pos == std::string::npos)
++ {
++ continue;
++ }
++ chassisNames.push_back(chassisPath.substr(pos + 1));
++ }
++
++ callback(chassisNames);
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
++ "/xyz/openbmc_project/inventory", 0, interfaces);
++}
++} // namespace utils
++
++class MetricDefinitionCollection : public Node
++{
++ public:
++ MetricDefinitionCollection(App& app) :
++ Node(app, "/redfish/v1/TelemetryService/MetricDefinitions/")
++ {
++ entityPrivileges = {
++ {boost::beast::http::verb::get, {{"Login"}}},
++ {boost::beast::http::verb::head, {{"Login"}}},
++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
++ }
++
++ private:
++ void doGet(crow::Response& res, const crow::Request&,
++ const std::vector<std::string>&) override
++ {
++ res.jsonValue["@odata.type"] = "#MetricDefinitionCollection."
++ "MetricDefinitionCollection";
++ res.jsonValue["@odata.id"] =
++ "/redfish/v1/TelemetryService/MetricDefinitions";
++ res.jsonValue["Name"] = "Metric Definition Collection";
++ res.jsonValue["Members"] = nlohmann::json::array();
++ res.jsonValue["Members@odata.count"] = 0;
++
++ auto asyncResp = std::make_shared<AsyncResp>(res);
++ auto collectionReduce = std::make_shared<CollectionGather>(asyncResp);
++ utils::getChassisNames(
++ [asyncResp,
++ collectionReduce](const std::vector<std::string>& chassisNames) {
++ for (const std::string& chassisName : chassisNames)
++ {
++ for (const auto& [sensorNode, _] : sensors::dbus::paths)
++ {
++ BMCWEB_LOG_INFO << "Chassis: " << chassisName
++ << " sensor: " << sensorNode;
++ retrieveUriToDbusMap(
++ chassisName, sensorNode.data(),
++ [asyncResp, collectionReduce](
++ const boost::beast::http::status status,
++ const boost::container::flat_map<
++ std::string, std::string>& uriToDbus) {
++ if (status != boost::beast::http::status::ok)
++ {
++ BMCWEB_LOG_ERROR
++ << "Failed to retrieve URI to dbus "
++ "sensors map with err "
++ << static_cast<unsigned>(status);
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ collectionReduce->insert(uriToDbus);
++ });
++ }
++ }
++ });
++ }
++
++ class CollectionGather
++ {
++ public:
++ CollectionGather(const std::shared_ptr<AsyncResp>& asyncResp) :
++ asyncResp{asyncResp}
++ {}
++
++ ~CollectionGather()
++ {
++ if (asyncResp->res.result() != boost::beast::http::status::ok)
++ {
++ return;
++ }
++
++ telemetry::dbusPathsToMembers(
++ asyncResp,
++ std::vector<std::string>(dbusTypes.begin(), dbusTypes.end()),
++ telemetry::metricDefinitionUri);
++ }
++
++ void insert(
++ const boost::container::flat_map<std::string, std::string>& el)
++ {
++ for (const auto& [_, dbusSensor] : el)
++ {
++ size_t pos = dbusSensor.rfind('/');
++ if (pos == std::string::npos)
++ {
++ BMCWEB_LOG_ERROR << "Received invalid DBus Sensor Path = "
++ << dbusSensor;
++ continue;
++ }
++
++ dbusTypes.insert(dbusSensor.substr(0, pos));
++ }
++ }
++
++ private:
++ const std::shared_ptr<AsyncResp> asyncResp;
++ boost::container::flat_set<std::string> dbusTypes;
++ };
++};
++
++class MetricDefinition : public Node
++{
++ public:
++ MetricDefinition(App& app) :
++ Node(app, "/redfish/v1/TelemetryService/MetricDefinitions/<str>/",
++ std::string())
++ {
++ entityPrivileges = {
++ {boost::beast::http::verb::get, {{"Login"}}},
++ {boost::beast::http::verb::head, {{"Login"}}},
++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
++ }
++
++ private:
++ void doGet(crow::Response& res, const crow::Request&,
++ const std::vector<std::string>& params) override
++ {
++ auto asyncResp = std::make_shared<AsyncResp>(res);
++ if (params.size() != 1)
++ {
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ const std::string& id = params[0];
++ auto definitionGather =
++ std::make_shared<DefinitionGather>(asyncResp, id);
++ utils::getChassisNames(
++ [asyncResp,
++ definitionGather](const std::vector<std::string>& chassisNames) {
++ for (const std::string& chassisName : chassisNames)
++ {
++ for (const auto& [sensorNode, dbusPaths] :
++ sensors::dbus::paths)
++ {
++ retrieveUriToDbusMap(
++ chassisName, sensorNode.data(),
++ [asyncResp, definitionGather](
++ const boost::beast::http::status status,
++ const boost::container::flat_map<
++ std::string, std::string>& uriToDbus) {
++ if (status != boost::beast::http::status::ok)
++ {
++ BMCWEB_LOG_ERROR
++ << "Failed to retrieve URI to dbus "
++ "sensors map with err "
++ << static_cast<unsigned>(status);
++ messages::internalError(asyncResp->res);
++ return;
++ }
++ definitionGather->insert(uriToDbus);
++ });
++ }
++ }
++ });
++ }
++
++ class DefinitionGather
++ {
++ public:
++ DefinitionGather(const std::shared_ptr<AsyncResp>& asyncResp,
++ const std::string& id) :
++ id(id),
++ pattern{'/' + id + '/'}, asyncResp{asyncResp}
++ {}
++ ~DefinitionGather()
++ {
++ if (asyncResp->res.result() != boost::beast::http::status::ok)
++ {
++ return;
++ }
++ if (redfishSensors.empty())
++ {
++ messages::resourceNotFound(asyncResp->res, schemaType, id);
++ return;
++ }
++
++ asyncResp->res.jsonValue["MetricProperties"] = redfishSensors;
++ asyncResp->res.jsonValue["Id"] = id;
++ asyncResp->res.jsonValue["Name"] = id;
++ asyncResp->res.jsonValue["@odata.id"] =
++ telemetry::metricDefinitionUri + id;
++ asyncResp->res.jsonValue["@odata.type"] = schemaType;
++ asyncResp->res.jsonValue["MetricDataType"] = "Decimal";
++ asyncResp->res.jsonValue["MetricType"] = "Numeric";
++ asyncResp->res.jsonValue["IsLinear"] = true;
++ asyncResp->res.jsonValue["Units"] = sensors::toReadingUnits(id);
++ }
++
++ void insert(
++ const boost::container::flat_map<std::string, std::string>& el)
++ {
++ for (const auto& [redfishSensor, dbusSensor] : el)
++ {
++ if (dbusSensor.find(pattern) != std::string::npos)
++ {
++ redfishSensors.push_back(redfishSensor);
++ }
++ }
++ }
++
++ const std::string id;
++ const std::string pattern;
++
++ private:
++ const std::shared_ptr<AsyncResp> asyncResp;
++ std::vector<std::string> redfishSensors;
++ };
++
++ static constexpr const char* schemaType =
++ "#MetricDefinition.v1_0_3.MetricDefinition";
++};
++
++} // namespace redfish
+diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp
+index d5a540d..03f0b82 100644
+--- a/redfish-core/lib/metric_report_definition.hpp
++++ b/redfish-core/lib/metric_report_definition.hpp
+@@ -269,6 +269,8 @@ class MetricReportDefinitionCollection : public Node
+ {
+ std::vector<sdbusplus::message::object_path> dbusPaths;
+ dbusPaths.reserve(uris.size());
++ std::string sensorType;
++ bool invalidType = false;
+
+ for (size_t i = 0; i < uris.size(); i++)
+ {
+@@ -286,6 +288,21 @@ class MetricReportDefinitionCollection : public Node
+ }
+
+ dbusPaths.emplace_back(el->second);
++
++ if (invalidType)
++ {
++ continue;
++ }
++ std::string tmp;
++ dbus::utility::getNthStringFromPath(el->second, 3, tmp);
++ if (sensorType.empty())
++ {
++ sensorType = std::move(tmp);
++ }
++ else if (sensorType != tmp)
++ {
++ invalidType = true;
++ }
+ }
+
+ nlohmann::json metadata;
+@@ -294,6 +311,11 @@ class MetricReportDefinitionCollection : public Node
+ {
+ metadata["MetricProperty"] = uris[0];
+ }
++ if (!sensorType.empty() && !invalidType)
++ {
++ metadata["MetricDefinition"]["@odata.id"] =
++ telemetry::metricDefinitionUri + sensorType;
++ }
+ readingParams.emplace_back(std::move(dbusPaths), "SINGLE", id,
+ metadata.dump());
+ }
+diff --git a/redfish-core/lib/power.hpp b/redfish-core/lib/power.hpp
+index 1c7a009..99c45ef 100644
+--- a/redfish-core/lib/power.hpp
++++ b/redfish-core/lib/power.hpp
+@@ -153,7 +153,7 @@ class Power : public Node
+ res.jsonValue["PowerControl"] = nlohmann::json::array();
+
+ auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
+- res, chassisName, sensors::dbus::types.at(sensors::node::power),
++ res, chassisName, sensors::dbus::paths.at(sensors::node::power),
+ sensors::node::power);
+
+ getChassisData(sensorAsyncResp);
+@@ -336,7 +336,7 @@ class Power : public Node
+
+ const std::string& chassisName = params[0];
+ auto asyncResp = std::make_shared<SensorsAsyncResp>(
+- res, chassisName, sensors::dbus::types.at(sensors::node::power),
++ res, chassisName, sensors::dbus::paths.at(sensors::node::power),
+ sensors::node::power);
+
+ std::optional<std::vector<nlohmann::json>> voltageCollections;
+diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
+index 567cb0c..363713d 100644
+--- a/redfish-core/lib/sensors.hpp
++++ b/redfish-core/lib/sensors.hpp
+@@ -54,9 +54,10 @@ static constexpr std::string_view thermal = "Thermal";
+
+ namespace dbus
+ {
++
+ static const boost::container::flat_map<std::string_view,
+ std::vector<const char*>>
+- types = {{node::power,
++ paths = {{node::power,
+ {"/xyz/openbmc_project/sensors/voltage",
+ "/xyz/openbmc_project/sensors/power"}},
+ {node::sensors,
+@@ -67,6 +68,64 @@ static const boost::container::flat_map<std::string_view,
+ {"/xyz/openbmc_project/sensors/fan_tach",
+ "/xyz/openbmc_project/sensors/temperature",
+ "/xyz/openbmc_project/sensors/fan_pwm"}}};
++} // namespace dbus
++
++inline const char* toReadingType(const std::string& sensorType)
++{
++ if (sensorType == "voltage")
++ {
++ return "Voltage";
++ }
++ if (sensorType == "power")
++ {
++ return "Power";
++ }
++ if (sensorType == "current")
++ {
++ return "Current";
++ }
++ if (sensorType == "fan_tach")
++ {
++ return "Rotational";
++ }
++ if (sensorType == "temperature")
++ {
++ return "Temperature";
++ }
++ if (sensorType == "fan_pwm" || sensorType == "utilization")
++ {
++ return "Percent";
++ }
++ return "";
++}
++
++inline const char* toReadingUnits(const std::string& sensorType)
++{
++ if (sensorType == "voltage")
++ {
++ return "V";
++ }
++ if (sensorType == "power")
++ {
++ return "W";
++ }
++ if (sensorType == "current")
++ {
++ return "A";
++ }
++ if (sensorType == "fan_tach")
++ {
++ return "RPM";
++ }
++ if (sensorType == "temperature")
++ {
++ return "Cel";
++ }
++ if (sensorType == "fan_pwm" || sensorType == "utilization")
++ {
++ return "%";
++ }
++ return "";
+ }
+ } // namespace sensors
+
+@@ -90,19 +149,20 @@ class SensorsAsyncResp
+ };
+
+ SensorsAsyncResp(crow::Response& response, const std::string& chassisIdIn,
+- const std::vector<const char*>& typesIn,
++ const std::vector<const char*>& matchPathsIn,
+ const std::string_view& subNode) :
+ res(response),
+- chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode)
++ chassisId(chassisIdIn), matchPaths(matchPathsIn),
++ chassisSubNode(subNode)
+ {}
+
+ // Store extra data about sensor mapping and return it in callback
+ SensorsAsyncResp(crow::Response& response, const std::string& chassisIdIn,
+- const std::vector<const char*>& typesIn,
++ const std::vector<const char*>& matchPathsIn,
+ const std::string_view& subNode,
+ DataCompleteCb&& creationComplete) :
+ res(response),
+- chassisId(chassisIdIn), types(typesIn),
++ chassisId(chassisIdIn), matchPaths(matchPathsIn),
+ chassisSubNode(subNode), metadata{std::vector<SensorData>()},
+ dataComplete{std::move(creationComplete)}
+ {}
+@@ -161,7 +221,7 @@ class SensorsAsyncResp
+
+ crow::Response& res;
+ const std::string chassisId;
+- const std::vector<const char*> types;
++ const std::vector<const char*> matchPaths;
+ const std::string chassisSubNode;
+
+ private:
+@@ -320,20 +380,20 @@ void getConnections(
+ * made, and eliminate Power sensors when a Thermal request is made.
+ */
+ inline void reduceSensorList(
+- const std::shared_ptr<SensorsAsyncResp>& SensorsAsyncResp,
++ const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
+ const std::vector<std::string>* allSensors,
+ const std::shared_ptr<boost::container::flat_set<std::string>>&
+ activeSensors)
+ {
+- if (SensorsAsyncResp == nullptr)
++ if (sensorsAsyncResp == nullptr)
+ {
+ return;
+ }
+ if ((allSensors == nullptr) || (activeSensors == nullptr))
+ {
+ messages::resourceNotFound(
+- SensorsAsyncResp->res, SensorsAsyncResp->chassisSubNode,
+- SensorsAsyncResp->chassisSubNode == sensors::node::thermal
++ sensorsAsyncResp->res, sensorsAsyncResp->chassisSubNode,
++ sensorsAsyncResp->chassisSubNode == sensors::node::thermal
+ ? "Temperatures"
+ : "Voltages");
+
+@@ -345,11 +405,11 @@ inline void reduceSensorList(
+ return;
+ }
+
+- for (const char* type : SensorsAsyncResp->types)
++ for (const char* path : sensorsAsyncResp->matchPaths)
+ {
+ for (const std::string& sensor : *allSensors)
+ {
+- if (boost::starts_with(sensor, type))
++ if (boost::starts_with(sensor, path))
+ {
+ activeSensors->emplace(sensor);
+ }
+@@ -853,18 +913,8 @@ inline void objectInterfacesToJson(
+ if (sensorsAsyncResp->chassisSubNode == sensors::node::sensors)
+ {
+ sensor_json["@odata.type"] = "#Sensor.v1_0_0.Sensor";
+- if (sensorType == "power")
+- {
+- sensor_json["ReadingUnits"] = "Watts";
+- }
+- else if (sensorType == "current")
+- {
+- sensor_json["ReadingUnits"] = "Amperes";
+- }
+- else if (sensorType == "utilization")
+- {
+- sensor_json["ReadingUnits"] = "Percent";
+- }
++ sensor_json["ReadingType"] = sensors::toReadingType(sensorType);
++ sensor_json["ReadingUnits"] = sensors::toReadingUnits(sensorType);
+ }
+ else if (sensorType == "temperature")
+ {
+@@ -2976,8 +3026,8 @@ inline void retrieveUriToDbusMap(const std::string& chassis,
+ const std::string& node,
+ SensorsAsyncResp::DataCompleteCb&& mapComplete)
+ {
+- auto typesIt = sensors::dbus::types.find(node);
+- if (typesIt == sensors::dbus::types.end())
++ auto typesIt = sensors::dbus::paths.find(node);
++ if (typesIt == sensors::dbus::paths.end())
+ {
+ BMCWEB_LOG_ERROR << "Wrong node provided : " << node;
+ mapComplete(boost::beast::http::status::bad_request, {});
+@@ -3027,7 +3077,7 @@ class SensorCollection : public Node
+ const std::string& chassisId = params[0];
+ std::shared_ptr<SensorsAsyncResp> asyncResp =
+ std::make_shared<SensorsAsyncResp>(
+- res, chassisId, sensors::dbus::types.at(sensors::node::sensors),
++ res, chassisId, sensors::dbus::paths.at(sensors::node::sensors),
+ sensors::node::sensors);
+
+ auto getChassisCb =
+diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp
+index a6acc34..8105d86 100644
+--- a/redfish-core/lib/telemetry_service.hpp
++++ b/redfish-core/lib/telemetry_service.hpp
+@@ -34,6 +34,8 @@ class TelemetryService : public Node
+
+ res.jsonValue["LogService"]["@odata.id"] =
+ "/redfish/v1/Managers/bmc/LogServices/Journal";
++ res.jsonValue["MetricDefinitions"]["@odata.id"] =
++ "/redfish/v1/TelemetryService/MetricDefinitions";
+ res.jsonValue["MetricReportDefinitions"]["@odata.id"] =
+ "/redfish/v1/TelemetryService/MetricReportDefinitions";
+ res.jsonValue["MetricReports"]["@odata.id"] =
+diff --git a/redfish-core/lib/thermal.hpp b/redfish-core/lib/thermal.hpp
+index 8e01bee..00acdf9 100644
+--- a/redfish-core/lib/thermal.hpp
++++ b/redfish-core/lib/thermal.hpp
+@@ -48,7 +48,7 @@ class Thermal : public Node
+ }
+ const std::string& chassisName = params[0];
+ auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
+- res, chassisName, sensors::dbus::types.at(sensors::node::thermal),
++ res, chassisName, sensors::dbus::paths.at(sensors::node::thermal),
+ sensors::node::thermal);
+
+ // TODO Need to get Chassis Redundancy information.
+@@ -71,7 +71,7 @@ class Thermal : public Node
+ allCollections;
+
+ auto asyncResp = std::make_shared<SensorsAsyncResp>(
+- res, chassisName, sensors::dbus::types.at(sensors::node::thermal),
++ res, chassisName, sensors::dbus::paths.at(sensors::node::thermal),
+ sensors::node::thermal);
+
+ if (!json_util::readJson(req, asyncResp->res, "Temperatures",
+--
+2.16.6
+
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
deleted file mode 100644
index c6c6a8f09..000000000
--- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch
+++ /dev/null
@@ -1,171 +0,0 @@
-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 08/10] Add support for "OnRequest" in MetricReportDefinition
-
-Added support for "OnRequest" of ReportingType property in
-MetricReportDefinition node. Now user is able to create
-MetricReportDefinition that is updated on every GET request
-on MetricReport.
-
-Tested:
- - Succesfully passed RedfishServiceValidator.py
- - Manually tested via curl
-
-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 ++--
- redfish-core/lib/metric_report.hpp | 53 +++++++++++++++++++++++++-
- 3 files changed, 87 insertions(+), 4 deletions(-)
-
-diff --git a/include/dbus_utility.hpp b/include/dbus_utility.hpp
-index ef3438b..80f8bcd 100644
---- a/include/dbus_utility.hpp
-+++ b/include/dbus_utility.hpp
-@@ -18,6 +18,7 @@
- #include <sdbusplus/message.hpp>
-
- #include <filesystem>
-+#include <functional>
- #include <regex>
-
- namespace dbus
-@@ -120,5 +121,34 @@ inline void getAllProperties(Callback&& callback, const std::string& service,
- interface);
- }
-
-+template <typename T>
-+static void getProperty(
-+ std::function<void(const boost::system::error_code&, const T&)> callback,
-+ const std::string& service, const std::string& path,
-+ const std::string& interface, const std::string& property)
-+{
-+ crow::connections::systemBus->async_method_call(
-+ [callback](const boost::system::error_code ec,
-+ const std::variant<T>& value) {
-+ if (ec)
-+ {
-+ callback(ec, T{});
-+ return;
-+ }
-+
-+ if (auto v = std::get_if<T>(&value))
-+ {
-+ callback(ec, *v);
-+ return;
-+ }
-+
-+ callback(boost::system::errc::make_error_code(
-+ boost::system::errc::io_error),
-+ T{});
-+ },
-+ service, path, "org.freedesktop.DBus.Properties", "Get", interface,
-+ property);
-+}
-+
- } // namespace utility
- } // namespace dbus
-diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp
-index 05ed00f..6c4e810 100644
---- a/redfish-core/include/utils/telemetry_utils.hpp
-+++ b/redfish-core/include/utils/telemetry_utils.hpp
-@@ -26,6 +26,8 @@ static constexpr const char* metricReportDefinitionUri =
- "/redfish/v1/TelemetryService/MetricReportDefinitions/";
- static constexpr const char* metricReportUri =
- "/redfish/v1/TelemetryService/MetricReports/";
-+static constexpr const char* monitoringService =
-+ "xyz.openbmc_project.MonitoringService";
- static constexpr const char* reportInterface =
- "xyz.openbmc_project.MonitoringService.Report";
- static constexpr const char* telemetryPath =
-@@ -66,9 +68,9 @@ static void getReport(const std::shared_ptr<AsyncResp>& asyncResp,
- const std::array<const char*, 1> interfaces = {reportInterface};
-
- dbus::utility::getSubTreePaths(
-- [asyncResp, id, schemaType,
-- callback](const boost::system::error_code ec,
-- const std::vector<std::string>& reports) {
-+ [asyncResp, id, schemaType, callback = std::move(callback)](
-+ const boost::system::error_code ec,
-+ const std::vector<std::string>& reports) {
- if (ec == boost::system::errc::no_such_file_or_directory)
- {
- messages::resourceNotFound(asyncResp->res, schemaType, id);
-diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp
-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
- }
-
- const std::string& id = params[0];
-- telemetry::getReport(asyncResp, id, schemaType, getReportProperties);
-+ telemetry::getReport(asyncResp, id, schemaType, updateReportIfRequired);
- }
-
- using Readings =
-@@ -143,6 +143,57 @@ class MetricReport : public Node
- "xyz.openbmc_project.MonitoringService.Report");
- }
-
-+ template <typename Callback>
-+ static void updateReport(Callback&& callback,
-+ const std::shared_ptr<AsyncResp>& asyncResp,
-+ const std::string& path)
-+ {
-+ crow::connections::systemBus->async_method_call(
-+ [asyncResp, callback{std::move(callback)}](
-+ const boost::system::error_code& ec) {
-+ if (ec)
-+ {
-+ messages::internalError(asyncResp->res);
-+ return;
-+ }
-+
-+ callback();
-+ },
-+ telemetry::monitoringService, path, telemetry::reportInterface,
-+ "Update");
-+ }
-+
-+ static void
-+ updateReportIfRequired(const std::shared_ptr<AsyncResp> asyncResp,
-+ const std::string& reportPath,
-+ const std::string& id)
-+ {
-+ dbus::utility::getProperty<std::string>(
-+ [asyncResp, id, reportPath](const boost::system::error_code& ec,
-+ const std::string& reportingType) {
-+ if (ec)
-+ {
-+ messages::internalError(asyncResp->res);
-+ return;
-+ }
-+
-+ if (reportingType == "OnRequest")
-+ {
-+ updateReport(
-+ [asyncResp, reportPath, id] {
-+ getReportProperties(asyncResp, reportPath, id);
-+ },
-+ asyncResp, reportPath);
-+ }
-+ else
-+ {
-+ getReportProperties(asyncResp, reportPath, id);
-+ }
-+ },
-+ telemetry::monitoringService, reportPath,
-+ telemetry::reportInterface, "ReportingType");
-+ }
-+
- static constexpr const char* schemaType =
- "#MetricReport.v1_3_0.MetricReport";
- };
---
-2.16.6
-
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Sync-Telmetry-service-with-EventService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Sync-Telmetry-service-with-EventService.patch
new file mode 100644
index 000000000..08dcb385d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Sync-Telmetry-service-with-EventService.patch
@@ -0,0 +1,330 @@
+From 5b775e33221638a34c4aad0e2edeffc447d50fab Mon Sep 17 00:00:00 2001
+From: "Wludzik, Jozef" <jozef.wludzik@intel.com>
+Date: Fri, 4 Dec 2020 14:48:41 +0100
+Subject: [PATCH 4/4] Sync Telmetry service with EventService
+
+Now assembling MetricReport is done properly and is
+covered in one place - MetricReport node.
+Updated method of fetching Readings from Telemetry by
+EventService. Using ReportUpdate signal is no longer
+supported.
+
+Tested:
+ - Received MetricReport in EventListener server after
+ adding subscription to EventService.
+
+Change-Id: I2fc1841a6c9259a8bff30b34bddc0d4aabd41912
+Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
+---
+ redfish-core/include/event_service_manager.hpp | 156 +++++++++----------------
+ redfish-core/lib/metric_report.hpp | 35 +++---
+ 2 files changed, 74 insertions(+), 117 deletions(-)
+
+diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
+index 54dafb4..1cdb9a6 100644
+--- a/redfish-core/include/event_service_manager.hpp
++++ b/redfish-core/include/event_service_manager.hpp
+@@ -14,6 +14,7 @@
+ // limitations under the License.
+ */
+ #pragma once
++#include "metric_report.hpp"
+ #include "node.hpp"
+ #include "registries.hpp"
+ #include "registries/base_message_registry.hpp"
+@@ -510,48 +511,29 @@ class Subscription
+ }
+ #endif
+
+- void filterAndSendReports(const std::string& id2,
+- const std::string& readingsTs,
+- const ReadingsObjType& readings)
++ void filterAndSendReports(
++ const std::string& id,
++ const std::variant<MetricReport::TimestampReadings>& var)
+ {
+- std::string metricReportDef =
+- "/redfish/v1/TelemetryService/MetricReportDefinitions/" + id2;
++ std::string mrdUri = telemetry::metricReportDefinitionUri + id;
+
+ // Empty list means no filter. Send everything.
+ if (metricReportDefinitions.size())
+ {
+ if (std::find(metricReportDefinitions.begin(),
+ metricReportDefinitions.end(),
+- metricReportDef) == metricReportDefinitions.end())
++ mrdUri) == metricReportDefinitions.end())
+ {
+ return;
+ }
+ }
+
+- nlohmann::json metricValuesArray = nlohmann::json::array();
+- for (const auto& it : readings)
++ nlohmann::json json;
++ if (!MetricReport::fillReport(json, id, var))
+ {
+- metricValuesArray.push_back({});
+- nlohmann::json& entry = metricValuesArray.back();
+-
+- auto& [id, property, value, timestamp] = it;
+-
+- entry = {{"MetricId", id},
+- {"MetricProperty", property},
+- {"MetricValue", std::to_string(value)},
+- {"Timestamp", crow::utility::getDateTime(timestamp)}};
++ return;
+ }
+-
+- nlohmann::json msg = {
+- {"@odata.id", "/redfish/v1/TelemetryService/MetricReports/" + id},
+- {"@odata.type", "#MetricReport.v1_3_0.MetricReport"},
+- {"Id", id2},
+- {"Name", id2},
+- {"Timestamp", readingsTs},
+- {"MetricReportDefinition", {{"@odata.id", metricReportDef}}},
+- {"MetricValues", metricValuesArray}};
+-
+- this->sendEvent(msg.dump());
++ this->sendEvent(json.dump());
+ }
+
+ void updateRetryConfig(const uint32_t retryAttempts,
+@@ -1342,56 +1324,71 @@ class EventServiceManager
+ }
+
+ #endif
+-
+- void getMetricReading(const std::string& service,
+- const std::string& objPath, const std::string& intf)
++ void unregisterMetricReportSignal()
+ {
+- std::size_t found = objPath.find_last_of('/');
+- if (found == std::string::npos)
++ if (matchTelemetryMonitor)
+ {
+- BMCWEB_LOG_DEBUG << "Invalid objPath received";
+- return;
++ BMCWEB_LOG_DEBUG << "Metrics report signal - Unregister";
++ matchTelemetryMonitor.reset();
++ matchTelemetryMonitor = nullptr;
+ }
++ }
+
+- std::string idStr = objPath.substr(found + 1);
+- if (idStr.empty())
++ void registerMetricReportSignal()
++ {
++ if (!serviceEnabled || matchTelemetryMonitor)
+ {
+- BMCWEB_LOG_DEBUG << "Invalid ID in objPath";
++ BMCWEB_LOG_DEBUG << "Not registering metric report signal.";
+ return;
+ }
+
+- crow::connections::systemBus->async_method_call(
+- [idStr{std::move(idStr)}](
+- const boost::system::error_code ec,
+- boost::container::flat_map<
+- std::string, std::variant<int32_t, ReadingsObjType>>&
+- resp) {
+- if (ec)
++ BMCWEB_LOG_DEBUG << "Metrics report signal - Register";
++ std::string matchStr = "type='signal',member='PropertiesChanged',"
++ "interface='org.freedesktop.DBus.Properties',"
++ "path_namespace=/xyz/openbmc_project/Telemetry/"
++ "Reports/TelemetryService,"
++ "arg0=xyz.openbmc_project.Telemetry.Report";
++
++ matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match::match>(
++ *crow::connections::systemBus, matchStr,
++ [this](sdbusplus::message::message& msg) {
++ if (msg.is_method_error())
+ {
+- BMCWEB_LOG_DEBUG
+- << "D-Bus call failed to GetAll metric readings.";
++ BMCWEB_LOG_ERROR << "TelemetryMonitor Signal error";
+ return;
+ }
+
+- const int32_t* timestampPtr =
+- std::get_if<int32_t>(&resp["Timestamp"]);
+- if (!timestampPtr)
++ std::string intf;
++ std::vector<std::pair<
++ std::string, std::variant<MetricReport::TimestampReadings>>>
++ props;
++ std::vector<std::string> invalidProp;
++
++ msg.read(intf, props, invalidProp);
++ if (intf != "xyz.openbmc_project.Telemetry.Report")
+ {
+- BMCWEB_LOG_DEBUG << "Failed to Get timestamp.";
+ return;
+ }
+
+- ReadingsObjType* readingsPtr =
+- std::get_if<ReadingsObjType>(&resp["Readings"]);
+- if (!readingsPtr)
++ const std::variant<MetricReport::TimestampReadings>* varPtr =
++ nullptr;
++ for (const auto& [key, var] : props)
++ {
++ if (key == "Readings")
++ {
++ varPtr = &var;
++ break;
++ }
++ }
++ if (!varPtr)
+ {
+- BMCWEB_LOG_DEBUG << "Failed to Get Readings property.";
+ return;
+ }
+
+- if (!readingsPtr->size())
++ std::string id;
++ if (!dbus::utility::getNthStringFromPath(msg.get_path(), 5, id))
+ {
+- BMCWEB_LOG_DEBUG << "No metrics report to be transferred";
++ BMCWEB_LOG_ERROR << "Failed to get Id from path";
+ return;
+ }
+
+@@ -1401,52 +1398,9 @@ class EventServiceManager
+ std::shared_ptr<Subscription> entry = it.second;
+ if (entry->eventFormatType == metricReportFormatType)
+ {
+- entry->filterAndSendReports(
+- idStr, crow::utility::getDateTime(*timestampPtr),
+- *readingsPtr);
++ entry->filterAndSendReports(id, *varPtr);
+ }
+ }
+- },
+- service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
+- intf);
+- }
+-
+- void unregisterMetricReportSignal()
+- {
+- if (matchTelemetryMonitor)
+- {
+- BMCWEB_LOG_DEBUG << "Metrics report signal - Unregister";
+- matchTelemetryMonitor.reset();
+- matchTelemetryMonitor = nullptr;
+- }
+- }
+-
+- void registerMetricReportSignal()
+- {
+- if (!serviceEnabled || matchTelemetryMonitor)
+- {
+- BMCWEB_LOG_DEBUG << "Not registering metric report signal.";
+- return;
+- }
+-
+- BMCWEB_LOG_DEBUG << "Metrics report signal - Register";
+- std::string matchStr(
+- "type='signal',member='ReportUpdate', "
+- "interface='xyz.openbmc_project.MonitoringService.Report'");
+-
+- matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match::match>(
+- *crow::connections::systemBus, matchStr,
+- [this](sdbusplus::message::message& msg) {
+- if (msg.is_method_error())
+- {
+- BMCWEB_LOG_ERROR << "TelemetryMonitor Signal error";
+- return;
+- }
+-
+- std::string service = msg.get_sender();
+- std::string objPath = msg.get_path();
+- std::string intf = msg.get_interface();
+- getMetricReading(service, objPath, intf);
+ });
+ }
+
+diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp
+index 050304c..c2013cc 100644
+--- a/redfish-core/lib/metric_report.hpp
++++ b/redfish-core/lib/metric_report.hpp
+@@ -52,6 +52,10 @@ class MetricReport : public Node
+ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
+ }
+
++ using Readings =
++ std::vector<std::tuple<std::string, std::string, double, uint64_t>>;
++ using TimestampReadings = std::tuple<uint64_t, Readings>;
++
+ private:
+ void doGet(crow::Response& res, const crow::Request&,
+ const std::vector<std::string>& params) override
+@@ -92,7 +96,10 @@ class MetricReport : public Node
+ return;
+ }
+
+- fillReport(asyncResp, id, ret);
++ if (!fillReport(asyncResp->res.jsonValue, id, ret))
++ {
++ messages::internalError(asyncResp->res);
++ }
+ },
+ telemetry::service, reportPath,
+ "org.freedesktop.DBus.Properties", "Get",
+@@ -102,10 +109,6 @@ class MetricReport : public Node
+ "Update");
+ }
+
+- using Readings =
+- std::vector<std::tuple<std::string, std::string, double, uint64_t>>;
+- using TimestampReadings = std::tuple<uint64_t, Readings>;
+-
+ static nlohmann::json toMetricValues(const Readings& readings)
+ {
+ nlohmann::json metricValues = nlohmann::json::array_t();
+@@ -130,15 +133,15 @@ class MetricReport : public Node
+ return metricValues;
+ }
+
+- static void fillReport(const std::shared_ptr<AsyncResp>& asyncResp,
+- const std::string& id,
++ public:
++ static bool fillReport(nlohmann::json& json, const std::string& id,
+ const std::variant<TimestampReadings>& var)
+ {
+- asyncResp->res.jsonValue["@odata.type"] = schemaType;
+- asyncResp->res.jsonValue["@odata.id"] = telemetry::metricReportUri + id;
+- asyncResp->res.jsonValue["Id"] = id;
+- asyncResp->res.jsonValue["Name"] = id;
+- asyncResp->res.jsonValue["MetricReportDefinition"]["@odata.id"] =
++ json["@odata.type"] = schemaType;
++ json["@odata.id"] = telemetry::metricReportUri + id;
++ json["Id"] = id;
++ json["Name"] = id;
++ json["MetricReportDefinition"]["@odata.id"] =
+ telemetry::metricReportDefinitionUri + id;
+
+ const TimestampReadings* timestampReadings =
+@@ -146,14 +149,14 @@ class MetricReport : public Node
+ if (!timestampReadings)
+ {
+ BMCWEB_LOG_ERROR << "Property type mismatch or property is missing";
+- messages::internalError(asyncResp->res);
+- return;
++ return false;
+ }
+
+ const auto& [timestamp, readings] = *timestampReadings;
+- asyncResp->res.jsonValue["Timestamp"] =
++ json["Timestamp"] =
+ crow::utility::getDateTime(static_cast<time_t>(timestamp));
+- asyncResp->res.jsonValue["MetricValues"] = toMetricValues(readings);
++ json["MetricValues"] = toMetricValues(readings);
++ return true;
+ }
+
+ static constexpr const char* schemaType =
+--
+2.16.6
+
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
deleted file mode 100644
index 5b1d93664..000000000
--- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch
+++ /dev/null
@@ -1,539 +0,0 @@
-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 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
-supported by TelemetryService.
-
-Tested:
- - Succesfully passed RedfishServiceValidator.py
- - Validated a presence of MetricDefinition members
-
-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 +
- redfish-core/lib/metric_definition.hpp | 300 +++++++++++++++++++++++++
- redfish-core/lib/metric_report.hpp | 65 +++++-
- redfish-core/lib/sensors.hpp | 43 +++-
- redfish-core/lib/telemetry_service.hpp | 2 +
- 6 files changed, 402 insertions(+), 13 deletions(-)
- create mode 100644 redfish-core/lib/metric_definition.hpp
-
-diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
-index 2587b37..705f490 100644
---- a/redfish-core/include/redfish.hpp
-+++ b/redfish-core/include/redfish.hpp
-@@ -25,6 +25,7 @@
- #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"
-@@ -211,6 +212,8 @@ class RedfishService
- nodes.emplace_back(std::make_unique<HypervisorSystem>(app));
-
- nodes.emplace_back(std::make_unique<TelemetryService>(app));
-+ nodes.emplace_back(std::make_unique<MetricDefinitionCollection>(app));
-+ nodes.emplace_back(std::make_unique<MetricDefinition>(app));
- nodes.emplace_back(
- std::make_unique<MetricReportDefinitionCollection>(app));
- nodes.emplace_back(std::make_unique<MetricReportDefinition>(app));
-diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp
-index 6c4e810..bb747c4 100644
---- a/redfish-core/include/utils/telemetry_utils.hpp
-+++ b/redfish-core/include/utils/telemetry_utils.hpp
-@@ -22,6 +22,8 @@ namespace redfish
- namespace telemetry
- {
-
-+static constexpr const char* metricDefinitionUri =
-+ "/redfish/v1/TelemetryService/MetricDefinitions/";
- static constexpr const char* metricReportDefinitionUri =
- "/redfish/v1/TelemetryService/MetricReportDefinitions/";
- 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..1417efa
---- /dev/null
-+++ b/redfish-core/lib/metric_definition.hpp
-@@ -0,0 +1,300 @@
-+/*
-+// Copyright (c) 2018-2020 Intel Corporation
-+//
-+// Licensed under the Apache License, Version 2.0 (the "License");
-+// you may not use this file except in compliance with the License.
-+// You may obtain a copy of the License at
-+//
-+// http://www.apache.org/licenses/LICENSE-2.0
-+//
-+// Unless required by applicable law or agreed to in writing, software
-+// distributed under the License is distributed on an "AS IS" BASIS,
-+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+// See the License for the specific language governing permissions and
-+// limitations under the License.
-+*/
-+
-+#pragma once
-+
-+#include "node.hpp"
-+#include "sensors.hpp"
-+#include "utils/telemetry_utils.hpp"
-+
-+namespace redfish
-+{
-+
-+namespace chassis
-+{
-+template <typename F>
-+static inline void getChassisNames(F&& callback)
-+{
-+ const std::array<const char*, 2> interfaces = {
-+ "xyz.openbmc_project.Inventory.Item.Board",
-+ "xyz.openbmc_project.Inventory.Item.Chassis"};
-+
-+ dbus::utility::getSubTreePaths(
-+ [callback{std::move(callback)}](const boost::system::error_code ec,
-+ std::vector<std::string>& chassisList) {
-+ if (ec)
-+ {
-+ return;
-+ }
-+
-+ std::vector<std::string> chassisNames;
-+ chassisNames.reserve(chassisList.size());
-+ for (auto& chassisPath : chassisList)
-+ {
-+ auto pos = chassisPath.rfind("/");
-+ if (pos == std::string::npos)
-+ {
-+ continue;
-+ }
-+ chassisNames.push_back(chassisPath.substr(pos + 1));
-+ }
-+
-+ callback(chassisNames);
-+ },
-+ "/xyz/openbmc_project/inventory", 0, interfaces);
-+}
-+} // namespace chassis
-+
-+class MetricDefinitionCollection : public Node
-+{
-+ public:
-+ MetricDefinitionCollection(App& app) :
-+ Node(app, "/redfish/v1/TelemetryService/MetricDefinitions")
-+ {
-+ entityPrivileges = {
-+ {boost::beast::http::verb::get, {{"Login"}}},
-+ {boost::beast::http::verb::head, {{"Login"}}},
-+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
-+ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
-+ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
-+ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
-+ }
-+
-+ private:
-+ void doGet(crow::Response& res, const crow::Request&,
-+ const std::vector<std::string>&) override
-+ {
-+ res.jsonValue["@odata.type"] = "#MetricDefinitionCollection."
-+ "MetricDefinitionCollection";
-+ res.jsonValue["@odata.id"] =
-+ "/redfish/v1/TelemetryService/MetricDefinitions";
-+ res.jsonValue["Name"] = "Metric Definition Collection";
-+ res.jsonValue["Members"] = nlohmann::json::array();
-+ res.jsonValue["Members@odata.count"] = sensors::dbus::types.size();
-+
-+ auto asyncResp = std::make_shared<AsyncResp>(res);
-+ auto collectionReduce = std::make_shared<CollectionGather>(asyncResp);
-+ chassis::getChassisNames(
-+ [asyncResp,
-+ collectionReduce](const std::vector<std::string>& chassisNames) {
-+ for (auto& chassisName : chassisNames)
-+ {
-+ for (auto& [sensorNode, _] : sensors::dbus::types)
-+ {
-+ BMCWEB_LOG_INFO << "Chassis: " << chassisName
-+ << " sensor: " << sensorNode;
-+ retrieveUriToDbusMap(
-+ chassisName, sensorNode.data(),
-+ [asyncResp, collectionReduce](
-+ const boost::beast::http::status,
-+ const boost::container::flat_map<
-+ std::string, std::string>& uriToDbus) {
-+ *collectionReduce += uriToDbus;
-+ });
-+ }
-+ }
-+ });
-+ }
-+
-+ class CollectionGather
-+ {
-+ public:
-+ CollectionGather(const std::shared_ptr<AsyncResp>& asyncResp) :
-+ asyncResp{asyncResp}
-+ {
-+ dbusTypes.reserve(sensors::dbus::paths.size());
-+ }
-+
-+ ~CollectionGather()
-+ {
-+ json_util::dbusPathsToMembersArray(
-+ asyncResp->res,
-+ std::vector<std::string>(dbusTypes.begin(), dbusTypes.end()),
-+ telemetry::metricDefinitionUri);
-+ }
-+
-+ CollectionGather& operator+=(
-+ const boost::container::flat_map<std::string, std::string>& rhs)
-+ {
-+ for (auto& [_, dbusSensor] : rhs)
-+ {
-+ auto pos = dbusSensor.rfind("/");
-+ if (pos == std::string::npos)
-+ {
-+ BMCWEB_LOG_ERROR << "Received invalid DBus Sensor Path = "
-+ << dbusSensor;
-+ continue;
-+ }
-+
-+ this->dbusTypes.insert(dbusSensor.substr(0, pos));
-+ }
-+ return *this;
-+ }
-+
-+ private:
-+ const std::shared_ptr<AsyncResp> asyncResp;
-+ boost::container::flat_set<std::string> dbusTypes;
-+ };
-+};
-+
-+class MetricDefinition : public Node
-+{
-+ public:
-+ MetricDefinition(App& app) :
-+ Node(app, std::string(telemetry::metricDefinitionUri) + "<str>/",
-+ std::string())
-+ {
-+ entityPrivileges = {
-+ {boost::beast::http::verb::get, {{"Login"}}},
-+ {boost::beast::http::verb::head, {{"Login"}}},
-+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
-+ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
-+ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
-+ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
-+ }
-+
-+ private:
-+ void doGet(crow::Response& res, const crow::Request&,
-+ const std::vector<std::string>& params) override
-+ {
-+ auto asyncResp = std::make_shared<AsyncResp>(res);
-+ if (params.size() != 1)
-+ {
-+ messages::internalError(asyncResp->res);
-+ return;
-+ }
-+
-+ const std::string& id = params[0];
-+
-+ size_t sensorIndex = 0;
-+ for (auto& name : sensors::dbus::names)
-+ {
-+ if (name == id)
-+ {
-+ break;
-+ }
-+ sensorIndex++;
-+ }
-+ if (sensorIndex >= sensors::dbus::max)
-+ {
-+ messages::resourceNotFound(asyncResp->res, schemaType, id);
-+ return;
-+ }
-+
-+ auto definitionGather =
-+ std::make_shared<DefinitionGather>(asyncResp, id);
-+ chassis::getChassisNames(
-+ [asyncResp, definitionGather,
-+ sensorIndex](const std::vector<std::string>& chassisNames) {
-+ for (auto& chassisName : chassisNames)
-+ {
-+ for (auto& [sensorNode, dbusPaths] : sensors::dbus::types)
-+ {
-+ auto found =
-+ std::find(dbusPaths.begin(), dbusPaths.end(),
-+ sensors::dbus::paths[sensorIndex]);
-+ if (found == dbusPaths.end())
-+ {
-+ continue;
-+ }
-+
-+ retrieveUriToDbusMap(
-+ chassisName, sensorNode.data(),
-+ [asyncResp, definitionGather](
-+ const boost::beast::http::status,
-+ const boost::container::flat_map<
-+ std::string, std::string>& uriToDbus) {
-+ *definitionGather += uriToDbus;
-+ });
-+ }
-+ }
-+ });
-+ }
-+
-+ class DefinitionGather
-+ {
-+ public:
-+ DefinitionGather(const std::shared_ptr<AsyncResp>& asyncResp,
-+ const std::string& id) :
-+ id(id),
-+ asyncResp{asyncResp}
-+ {}
-+ ~DefinitionGather()
-+ {
-+ if (redfishSensors.empty())
-+ {
-+ messages::resourceNotFound(asyncResp->res, schemaType, id);
-+ return;
-+ }
-+
-+ asyncResp->res.jsonValue["MetricProperties"] =
-+ nlohmann::json::array();
-+ auto& members = asyncResp->res.jsonValue["MetricProperties"];
-+ for (auto& redfishSensor : redfishSensors)
-+ {
-+ members.push_back(redfishSensor);
-+ }
-+
-+ asyncResp->res.jsonValue["Id"] = id;
-+ asyncResp->res.jsonValue["Name"] = id;
-+ asyncResp->res.jsonValue["@odata.id"] =
-+ telemetry::metricDefinitionUri + id;
-+ asyncResp->res.jsonValue["@odata.type"] = schemaType;
-+ asyncResp->res.jsonValue["MetricDataType"] = "Decimal";
-+ asyncResp->res.jsonValue["MetricType"] = "Numeric";
-+ asyncResp->res.jsonValue["Implementation"] = "PhysicalSensor";
-+ asyncResp->res.jsonValue["IsLinear"] = true;
-+ asyncResp->res.jsonValue["TimestampAccuracy"] = "PT0.1S";
-+ auto unit = sensorUnits.find(id);
-+ if (unit != sensorUnits.end())
-+ {
-+ asyncResp->res.jsonValue["Units"] = unit->second;
-+ }
-+ }
-+
-+ DefinitionGather& operator+=(
-+ const boost::container::flat_map<std::string, std::string>& rhs)
-+ {
-+ for (auto& [redfishSensor, dbusSensor] : rhs)
-+ {
-+ if (dbusSensor.find(id) != std::string::npos)
-+ {
-+ this->redfishSensors.push_back(redfishSensor);
-+ }
-+ }
-+ return *this;
-+ }
-+
-+ const std::string id;
-+
-+ private:
-+ const std::shared_ptr<AsyncResp> asyncResp;
-+ std::vector<std::string> redfishSensors;
-+ const boost::container::flat_map<std::string, std::string> sensorUnits =
-+ {{sensors::dbus::names[sensors::dbus::voltage], "V"},
-+ {sensors::dbus::names[sensors::dbus::power], "W"},
-+ {sensors::dbus::names[sensors::dbus::current], "A"},
-+ {sensors::dbus::names[sensors::dbus::fan_tach], "RPM"},
-+ {sensors::dbus::names[sensors::dbus::temperature], "Cel"},
-+ {sensors::dbus::names[sensors::dbus::utilization], "%"},
-+ {sensors::dbus::names[sensors::dbus::fan_pwm], "Duty cycle"}};
-+ };
-+
-+ static constexpr const char* schemaType =
-+ "#MetricDefinition.v1_0_3.MetricDefinition";
-+};
-+
-+} // namespace redfish
-diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp
-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
- using Readings =
- std::vector<std::tuple<std::string, std::string, double, int32_t>>;
- using MetricValues = std::vector<std::map<std::string, std::string>>;
-+ using ReadingParameters =
-+ std::vector<std::tuple<std::vector<sdbusplus::message::object_path>,
-+ std::string, std::string, std::string>>;
-
- static MetricValues toMetricValues(const Readings& readings)
- {
-@@ -109,6 +112,49 @@ class MetricReport : public Node
- return metricValues;
- }
-
-+ static void addMetricDefinition(nlohmann::json& metrics,
-+ const ReadingParameters& params)
-+ {
-+ for (auto& metric : metrics)
-+ {
-+ if (!metric.contains("MetricId"))
-+ {
-+ continue;
-+ }
-+
-+ auto& id = metric["MetricId"].get_ref<std::string&>();
-+ auto param =
-+ std::find_if(params.begin(), params.end(), [id](const auto& x) {
-+ return id == std::get<2>(x);
-+ });
-+ if (param == params.end())
-+ {
-+ continue;
-+ }
-+
-+ auto& dbusPaths =
-+ std::get<std::vector<sdbusplus::message::object_path>>(*param);
-+ if (dbusPaths.size() > 1)
-+ {
-+ continue;
-+ }
-+
-+ auto dbusPath = dbusPaths.begin();
-+ for (size_t i = 0; i < sensors::dbus::paths.size(); i++)
-+ {
-+ if (dbusPath->str.find(sensors::dbus::paths[i]) ==
-+ std::string::npos)
-+ {
-+ continue;
-+ }
-+ metric["MetricDefinition"]["@odata.id"] =
-+ telemetry::metricDefinitionUri +
-+ std::string(sensors::dbus::names[i]);
-+ break;
-+ }
-+ }
-+ }
-+
- static void getReportProperties(const std::shared_ptr<AsyncResp> asyncResp,
- const std::string& reportPath,
- const std::string& id)
-@@ -124,7 +170,8 @@ class MetricReport : public Node
- [asyncResp](
- const boost::system::error_code ec,
- const boost::container::flat_map<
-- std::string, std::variant<Readings, int32_t>>& ret) {
-+ std::string,
-+ std::variant<Readings, int32_t, ReadingParameters>>& ret) {
- if (ec)
- {
- messages::internalError(asyncResp->res);
-@@ -138,6 +185,22 @@ class MetricReport : public Node
- json_util::assignIfPresent<Readings>(
- ret, "Readings", asyncResp->res.jsonValue["MetricValues"],
- toMetricValues);
-+
-+ auto found = ret.find("ReadingParameters");
-+ if (found != ret.end())
-+ {
-+ auto params =
-+ std::get_if<ReadingParameters>(&found->second);
-+ if (params)
-+ {
-+ auto& jsonValue = asyncResp->res.jsonValue;
-+ if (jsonValue.contains("MetricValues"))
-+ {
-+ addMetricDefinition(jsonValue["MetricValues"],
-+ *params);
-+ }
-+ }
-+ }
- },
- "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 567cb0c..2f7f70b 100644
---- a/redfish-core/lib/sensors.hpp
-+++ b/redfish-core/lib/sensors.hpp
-@@ -54,20 +54,39 @@ static constexpr std::string_view thermal = "Thermal";
-
- namespace dbus
- {
-+
-+enum Index
-+{
-+ voltage = 0,
-+ power,
-+ current,
-+ fan_tach,
-+ temperature,
-+ fan_pwm,
-+ utilization,
-+ max
-+};
-+
-+static constexpr std::array<const char*, max> names = {
-+ "voltage", "power", "current", "fan_tach",
-+ "temperature", "fan_pwm", "utilization"};
-+
-+static constexpr std::array<const char*, max> paths = {
-+ "/xyz/openbmc_project/sensors/voltage",
-+ "/xyz/openbmc_project/sensors/power",
-+ "/xyz/openbmc_project/sensors/current",
-+ "/xyz/openbmc_project/sensors/fan_tach",
-+ "/xyz/openbmc_project/sensors/temperature",
-+ "/xyz/openbmc_project/sensors/fan_pwm",
-+ "/xyz/openbmc_project/sensors/utilization"};
-+
- static const boost::container::flat_map<std::string_view,
- std::vector<const char*>>
-- types = {{node::power,
-- {"/xyz/openbmc_project/sensors/voltage",
-- "/xyz/openbmc_project/sensors/power"}},
-- {node::sensors,
-- {"/xyz/openbmc_project/sensors/power",
-- "/xyz/openbmc_project/sensors/current",
-- "/xyz/openbmc_project/sensors/utilization"}},
-- {node::thermal,
-- {"/xyz/openbmc_project/sensors/fan_tach",
-- "/xyz/openbmc_project/sensors/temperature",
-- "/xyz/openbmc_project/sensors/fan_pwm"}}};
--}
-+ types = {
-+ {node::power, {paths[voltage], paths[power]}},
-+ {node::sensors, {paths[power], paths[current], paths[utilization]}},
-+ {node::thermal, {paths[fan_tach], paths[temperature], paths[fan_pwm]}}};
-+} // namespace dbus
- } // namespace sensors
-
- /**
-diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp
-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
-
- res.jsonValue["LogService"]["@odata.id"] =
- "/redfish/v1/Managers/bmc/LogServices/Journal";
-+ res.jsonValue["MetricDefinitions"]["@odata.id"] =
-+ "/redfish/v1/TelemetryService/MetricDefinitions";
- res.jsonValue["MetricReportDefinitions"]["@odata.id"] =
- "/redfish/v1/TelemetryService/MetricReportDefinitions";
- res.jsonValue["MetricReports"]["@odata.id"] =
---
-2.16.6
-
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README
index 2929b0aec..833fabfec 100644
--- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README
@@ -3,19 +3,14 @@ Until change is integrated they will be manually merged here to enable feature i
Current revisions:
- Redfish TelemetryService schema implementation
- https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/31692/29
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/31692/54
-- Add support for POST in MetricReportDefinitions
- https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/32536/24
-
-- Add support for DELETE in MetricReportDefinitions/<str>
- https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/32537/23
-
-- Add support for "OnRequest" in MetricReportDefinition
- https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/33358/17
+- Add POST and DELETE in MetricReportDefinitions
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/32536/46
- Add support for MetricDefinition scheme
- https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/33363/20
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/33363/42
+
+- Sync Telmetry service with EventService
+ https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/38798/9
-- Temporary patch for EventService because of change in design
- 0006-Fix-MetricReport-timestamp-for-EventService.patch
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend
index 80005f5cd..ac095ba61 100644
--- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend
@@ -1,7 +1,8 @@
SRC_URI = "git://github.com/openbmc/bmcweb.git"
-SRCREV = "a8fe54f09be1deefc119d8dcf100da922496d46d"
+SRCREV = "f16f62633a64f386fd0382703ff0949ea177f457"
DEPENDS += "boost-url"
+RDEPENDS_${PN} += "phosphor-nslcd-authority-cert-config"
FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
@@ -15,14 +16,20 @@ SRC_URI += "file://0001-Firmware-update-configuration-changes.patch \
file://0002-Use-chip-id-based-UUID-for-Service-Root.patch \
file://0004-bmcweb-handle-device-or-resource-busy-exception.patch \
file://0005-EventService-https-client-support.patch \
+ file://0006-Define-Redfish-interface-Registries-Bios.patch \
+ file://0007-BIOS-config-Add-support-for-PATCH-operation.patch \
+ file://0008-Add-support-to-ResetBios-action.patch \
+ file://0009-Add-support-to-ChangePassword-action.patch \
+ file://0010-managers-add-attributes-for-Manager.CommandShell.patch \
+ file://0034-recommended-fixes-by-crypto-review-team.patch \
"
+
# Temporary downstream mirror of upstream patches, see telemetry\README for details
SRC_URI += "file://telemetry/0001-Redfish-TelemetryService-schema-implementation.patch \
- file://telemetry/0002-Add-support-for-POST-in-MetricReportDefinitions.patch \
- file://telemetry/0003-Add-support-for-DELETE-in-MetricReportDefinitions-st.patch \
- file://telemetry/0004-Add-support-for-OnRequest-in-MetricReportDefinition.patch \
- file://telemetry/0005-Add-support-for-MetricDefinition-scheme.patch \
+ file://telemetry/0002-Add-POST-and-DELETE-in-MetricReportDefinitions.patch \
+ file://telemetry/0003-Add-support-for-MetricDefinition-scheme.patch \
+ file://telemetry/0004-Sync-Telmetry-service-with-EventService.patch \
"
# Temporary fix: Move it to service file