diff options
Diffstat (limited to 'meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb/0010-Add-smtp-client.patch')
-rw-r--r-- | meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb/0010-Add-smtp-client.patch | 637 |
1 files changed, 637 insertions, 0 deletions
diff --git a/meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb/0010-Add-smtp-client.patch b/meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb/0010-Add-smtp-client.patch new file mode 100644 index 0000000000..7b0172c881 --- /dev/null +++ b/meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb/0010-Add-smtp-client.patch @@ -0,0 +1,637 @@ +From 77a6599736c27aae08f1b91f3b36c9b04808f563 Mon Sep 17 00:00:00 2001 +From: eportnov <eportnov@ibs.ru> +Date: Fri, 2 Sep 2022 15:11:28 +0300 +Subject: [PATCH] Add smtp client + +--- + meson.build | 4 + + redfish-core/include/redfish.hpp | 4 +- + .../include/registries/privilege_registry.hpp | 8 + + .../utils/smtp/change_parameters_parser.hpp | 27 +++ + .../utils/smtp/send_message_parser.hpp | 29 +++ + .../include/utils/smtp/types/iparser.hpp | 21 ++ + redfish-core/lib/service_root.hpp | 1 + + redfish-core/lib/smtp.hpp | 191 ++++++++++++++++++ + .../utils/smtp/change_parameters_parser.cpp | 62 ++++++ + .../src/utils/smtp/send_message_parser.cpp | 76 +++++++ + redfish-core/src/utils/smtp/types/iparser.cpp | 35 ++++ + redfish-core/ut/smtp_reader_parser_test.cpp | 45 +++++ + 12 files changed, 502 insertions(+), 1 deletion(-) + create mode 100644 redfish-core/include/utils/smtp/change_parameters_parser.hpp + create mode 100644 redfish-core/include/utils/smtp/send_message_parser.hpp + create mode 100644 redfish-core/include/utils/smtp/types/iparser.hpp + create mode 100644 redfish-core/lib/smtp.hpp + create mode 100644 redfish-core/src/utils/smtp/change_parameters_parser.cpp + create mode 100644 redfish-core/src/utils/smtp/send_message_parser.cpp + create mode 100644 redfish-core/src/utils/smtp/types/iparser.cpp + create mode 100644 redfish-core/ut/smtp_reader_parser_test.cpp + +diff --git a/meson.build b/meson.build +index 45d440ef..3787e145 100644 +--- a/meson.build ++++ b/meson.build +@@ -367,6 +367,9 @@ install_subdir('static', install_dir : 'share/www', strip_directory : true) + srcfiles_bmcweb = [ + 'redfish-core/src/error_messages.cpp', + 'redfish-core/src/utils/json_utils.cpp', ++ 'redfish-core/src/utils/smtp/send_message_parser.cpp', ++ 'redfish-core/src/utils/smtp/change_parameters_parser.cpp', ++ 'redfish-core/src/utils/smtp/types/iparser.cpp', + 'src/boost_asio_ssl.cpp', + 'src/boost_asio.cpp', + 'src/boost_beast.cpp', +@@ -409,6 +412,7 @@ srcfiles_unittest = [ + 'redfish-core/ut/hex_utils_test.cpp', + 'redfish-core/ut/ip_utils_test.cpp', + 'redfish-core/ut/json_utils_test.cpp', ++ 'redfish-core/ut/smtp_reader_parser_test.cpp', + 'redfish-core/ut/lock_test.cpp', + 'redfish-core/ut/privileges_test.cpp', + 'redfish-core/ut/registries_test.cpp', +diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp +index ab635f91..2854a745 100644 +--- a/redfish-core/include/redfish.hpp ++++ b/redfish-core/include/redfish.hpp +@@ -47,6 +47,7 @@ + #include "../lib/trigger.hpp" + #include "../lib/update_service.hpp" + #include "../lib/virtual_media.hpp" ++#include "../lib/smtp.hpp" + + namespace redfish + { +@@ -222,7 +223,8 @@ class RedfishService + requestRoutesMetricReport(app); + requestRoutesTriggerCollection(app); + requestRoutesTrigger(app); +- ++ requestRoutesSmtp(app); ++ requestSmtpFunctions(app); + // Note, this must be the last route registered + requestRoutesRedfish(app); + } +diff --git a/redfish-core/include/registries/privilege_registry.hpp b/redfish-core/include/registries/privilege_registry.hpp +index 035aee4a..5ec62749 100644 +--- a/redfish-core/include/registries/privilege_registry.hpp ++++ b/redfish-core/include/registries/privilege_registry.hpp +@@ -1363,6 +1363,14 @@ const static auto& postSimpleStorageCollection = privilegeSetConfigureComponents + const static auto& putSimpleStorageCollection = privilegeSetConfigureComponents; + const static auto& deleteSimpleStorageCollection = privilegeSetConfigureComponents; + ++// SmtpCollection ++const static auto& getSmtpCollection = privilegeSetLogin; ++const static auto& headSmtpCollection = privilegeSetLogin; ++const static auto& patchSmtpCollection = privilegeSetConfigureComponents; ++const static auto& postSmtpCollection = privilegeSetConfigureComponents; ++const static auto& putSmtpCollection = privilegeSetConfigureComponents; ++const static auto& deleteSmtpCollection = privilegeSetConfigureComponents; ++ + // SoftwareInventory + const static auto& getSoftwareInventory = privilegeSetLogin; + const static auto& headSoftwareInventory = privilegeSetLogin; +diff --git a/redfish-core/include/utils/smtp/change_parameters_parser.hpp b/redfish-core/include/utils/smtp/change_parameters_parser.hpp +new file mode 100644 +index 00000000..ee18b57b +--- /dev/null ++++ b/redfish-core/include/utils/smtp/change_parameters_parser.hpp +@@ -0,0 +1,27 @@ ++#pragma once ++ ++#include "types/iparser.hpp" ++ ++namespace redfish::smtp::parser ++{ ++ class ChangeParameters : public types::IParser ++ { ++ public: ++ explicit ChangeParameters( std::string const& function_with_parameters ); ++ ~ChangeParameters() override = default; ++ ++ std::string GetUser() const; ++ std::string GetPassword() const; ++ std::string GetHost() const; ++ std::string GetPort() const; ++ ++ std::string GetMethodName() const override; ++ private: ++ void FillParams( types::ParserResult const& params ); ++ ++ std::string mUser; ++ std::string mPassword; ++ std::string mHost; ++ std::string mPort; ++ }; ++} +diff --git a/redfish-core/include/utils/smtp/send_message_parser.hpp b/redfish-core/include/utils/smtp/send_message_parser.hpp +new file mode 100644 +index 00000000..8ae009cf +--- /dev/null ++++ b/redfish-core/include/utils/smtp/send_message_parser.hpp +@@ -0,0 +1,29 @@ ++#pragma once ++ ++#include "types/iparser.hpp" ++ ++namespace redfish::smtp::parser ++{ ++ class SendMessage : public types::IParser ++ { ++ public: ++ explicit SendMessage( std::string const& function_with_parameters ); ++ ~SendMessage() override = default; ++ ++ std::string GetFrom() const; ++ std::string GetTo() const; ++ std::list<std::string> GetCc() const; ++ std::string GetSubject() const; ++ std::string GetText() const; ++ ++ std::string GetMethodName() const override; ++ private: ++ void FillParams( types::ParserResult const& params ); ++ ++ std::string mFrom; ++ std::string mTo; ++ std::list<std::string> mCc; ++ std::string mSubject; ++ std::string mText; ++ }; ++} +diff --git a/redfish-core/include/utils/smtp/types/iparser.hpp b/redfish-core/include/utils/smtp/types/iparser.hpp +new file mode 100644 +index 00000000..0d9fe511 +--- /dev/null ++++ b/redfish-core/include/utils/smtp/types/iparser.hpp +@@ -0,0 +1,21 @@ ++#pragma once ++ ++#include <string> ++#include <list> ++#include <unordered_map> ++ ++namespace redfish::smtp::parser::types ++{ ++ using ParserResult = std::unordered_multimap<std::string, std::string>; ++ ++ class IParser ++ { ++ public: ++ virtual ~IParser() = default; ++ ++ virtual std::string GetMethodName() const = 0; ++ protected: ++ std::list<std::string> ParseLine( std::string const& line, std::string const& delimiter ); ++ ParserResult BuildParams(std::list<std::string> const& parsed_data); ++ }; ++} +diff --git a/redfish-core/lib/service_root.hpp b/redfish-core/lib/service_root.hpp +index 387b6141..aa97c91d 100644 +--- a/redfish-core/lib/service_root.hpp ++++ b/redfish-core/lib/service_root.hpp +@@ -63,6 +63,7 @@ inline void + asyncResp->res.jsonValue["TelemetryService"]["@odata.id"] = + "/redfish/v1/TelemetryService"; + asyncResp->res.jsonValue["Cables"]["@odata.id"] = "/redfish/v1/Cables"; ++ asyncResp->res.jsonValue["Smtp"]["@odata.id"] = "/redfish/v1/Smtp"; + + nlohmann::json& protocolFeatures = + asyncResp->res.jsonValue["ProtocolFeaturesSupported"]; +diff --git a/redfish-core/lib/smtp.hpp b/redfish-core/lib/smtp.hpp +new file mode 100644 +index 00000000..1bd798f7 +--- /dev/null ++++ b/redfish-core/lib/smtp.hpp +@@ -0,0 +1,191 @@ ++#include <app.hpp> ++#include <registries/privilege_registry.hpp> ++#include <query.hpp> ++ ++#include <iostream> ++ ++#include "utils/smtp/send_message_parser.hpp" ++#include "utils/smtp/change_parameters_parser.hpp" ++ ++namespace redfish ++{ ++ constexpr const char* SERVICE_PATH = "xyz.openbmc_project.SMTP"; ++ constexpr const char* OBJECT_PATH = "/xyz/openbmc_project/SMTP"; ++ constexpr const char* INTERFACE_PATH = "xyz.openbmc_project.SMTP"; ++ ++ namespace smtp ++ { ++ inline std::optional<std::string> GetFunctionName( std::string const& function_with_parameters ) ++ { ++ static constexpr char FIRST_DELIMITER = '&'; ++ static constexpr int ZERO_POSITION = 0; ++ ++ auto position = function_with_parameters.find(FIRST_DELIMITER); ++ if( position == std::string::npos ) ++ { ++ return {}; ++ } ++ return function_with_parameters.substr( ZERO_POSITION, position ); ++ } ++ ++ inline void SendMail( std::string const& function_with_parameters, std::shared_ptr<bmcweb::AsyncResp> const& asyncResp ) ++ { ++ auto parsing_result = parser::SendMessage{function_with_parameters}; ++ ++ crow::connections::systemBus->async_method_call([asyncResp](const boost::system::error_code& error_code, bool result){ ++ if (error_code.value() == EBADR || ++ error_code == boost::system::errc::host_unreachable) ++ { ++ BMCWEB_LOG_ERROR << "host unreachable " << error_code; ++ std::cout << "host unreachabler" << std::endl; ++ return; ++ } ++ if (error_code) ++ { ++ BMCWEB_LOG_ERROR << "respHandler DBus error " << error_code; ++ std::cout << "respHandler DBus error" << std::endl; ++ return; ++ } ++ asyncResp->res.jsonValue["result"] = result; ++ }, ++ SERVICE_PATH, OBJECT_PATH, INTERFACE_PATH, ++ parsing_result.GetMethodName(), ++ parsing_result.GetFrom(), ++ parsing_result.GetTo(), ++ parsing_result.GetCc(), ++ parsing_result.GetSubject(), ++ parsing_result.GetText()); ++ } ++ ++ inline void ChangeParameters( std::string const& function_with_parameters, std::shared_ptr<bmcweb::AsyncResp> const& asyncResp ) ++ { ++ auto parsing_result = parser::ChangeParameters{function_with_parameters}; ++ ++ crow::connections::systemBus->async_method_call([asyncResp](const boost::system::error_code& error_code, bool result){ ++ if (error_code.value() == EBADR || ++ error_code == boost::system::errc::host_unreachable) ++ { ++ BMCWEB_LOG_ERROR << "host unreachable " << error_code; ++ std::cout << "host unreachable" << std::endl; ++ return; ++ } ++ if (error_code) ++ { ++ BMCWEB_LOG_ERROR << "respHandler DBus error " << error_code; ++ std::cout << "respHandler DBus error" << std::endl; ++ return; ++ } ++ asyncResp->res.jsonValue["result"] = result; ++ }, ++ SERVICE_PATH, OBJECT_PATH, INTERFACE_PATH, ++ parsing_result.GetMethodName(), ++ parsing_result.GetUser(), ++ parsing_result.GetPassword(), ++ parsing_result.GetHost(), ++ parsing_result.GetPort()); ++ } ++ } ++ ++ inline void FillResp(crow::Response& resp, const dbus::utility::DBusPropertiesMap& properties) ++ { ++ for (const auto& [propKey, propVariant] : properties) ++ { ++ if (propKey == "Host" ) ++ { ++ auto host_as_string = std::get_if<std::string>(&propVariant); ++ if(host_as_string) ++ { ++ resp.jsonValue["host"] = *host_as_string; ++ } ++ } ++ if (propKey == "Port" ) ++ { ++ auto port_as_string = std::get_if<std::string>(&propVariant); ++ if(port_as_string) ++ { ++ resp.jsonValue["port"] = *port_as_string; ++ } ++ } ++ if (propKey == "User" ) ++ { ++ auto user_as_string = std::get_if<std::string>(&propVariant); ++ if(user_as_string) ++ { ++ resp.jsonValue["user"] = *user_as_string; ++ } ++ } ++ } ++ } ++ ++ inline void requestRoutesSmtp(App& app) ++ { ++ BMCWEB_ROUTE(app, "/redfish/v1/Smtp/") ++ .privileges(redfish::privileges::getSmtpCollection) ++ .methods(boost::beast::http::verb::get)( ++ [&app](const crow::Request& req, ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) ++ { ++ if (!redfish::setUpRedfishRoute(app, req, asyncResp)) ++ { ++ return; ++ } ++ ++ crow::connections::systemBus->async_method_call([asyncResp](const boost::system::error_code& error_code, ++ const dbus::utility::DBusPropertiesMap& properties) ++ { ++ if (error_code) ++ { ++ BMCWEB_LOG_DEBUG << "DBUS response error " << error_code; ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ ++ FillResp(asyncResp->res, properties); ++ }, SERVICE_PATH, OBJECT_PATH, "org.freedesktop.DBus.Properties", ++ "GetAll", "xyz.openbmc_project.SMTP"); ++ ++ asyncResp->res.jsonValue["@odata.type"] ="#SmtpCollection"; ++ asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Smtp"; ++ asyncResp->res.jsonValue["Name"] = "Smtp Collection"; ++ }); ++ } ++ ++ ++ ++ inline void requestSmtpFunctions(App& app) ++ { ++ BMCWEB_ROUTE(app, "/redfish/v1/Smtp/<str>/") ++ .privileges(redfish::privileges::getSmtpCollection) ++ .methods(boost::beast::http::verb::get)( ++ [&app](const crow::Request& req, ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, ++ const std::string& function_with_parameters) ++ { ++ static constexpr std::string_view SEND_MAIL_METHOD_NAME = "SendMail"; ++ static constexpr std::string_view CHANGE_PARAMETERS_METHOD_NAME = "ChangeParameters"; ++ ++ if (!redfish::setUpRedfishRoute(app, req, asyncResp)) ++ { ++ return; ++ } ++ auto function_name = smtp::GetFunctionName(function_with_parameters); ++ if(!function_name) ++ { ++ return; ++ } ++ ++ asyncResp->res.jsonValue["@odata.type"] ="#SmtpCollection"; ++ asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Smtp/" + *function_name; ++ asyncResp->res.jsonValue["Name"] = "Smtp Collection"; ++ ++ if(*function_name == SEND_MAIL_METHOD_NAME) ++ { ++ smtp::SendMail(function_with_parameters, asyncResp); ++ } ++ else if(*function_name == CHANGE_PARAMETERS_METHOD_NAME) ++ { ++ smtp::ChangeParameters(function_with_parameters, asyncResp); ++ } ++ }); ++ } ++} +diff --git a/redfish-core/src/utils/smtp/change_parameters_parser.cpp b/redfish-core/src/utils/smtp/change_parameters_parser.cpp +new file mode 100644 +index 00000000..f78b9482 +--- /dev/null ++++ b/redfish-core/src/utils/smtp/change_parameters_parser.cpp +@@ -0,0 +1,62 @@ ++#include "utils/smtp/change_parameters_parser.hpp" ++ ++namespace redfish::smtp::parser ++{ ++ ChangeParameters::ChangeParameters( std::string const& function_with_parameters ) ++ { ++ static const std::string DELIMITER_ON_LINE = "&"; ++ ++ auto params = BuildParams(ParseLine(function_with_parameters, DELIMITER_ON_LINE)); ++ FillParams( params ); ++ } ++ ++ std::string ChangeParameters::GetUser() const ++ { ++ return mUser; ++ } ++ std::string ChangeParameters::GetPassword() const ++ { ++ return mPassword; ++ } ++ std::string ChangeParameters::GetHost() const ++ { ++ return mHost; ++ } ++ std::string ChangeParameters::GetPort() const ++ { ++ return mPort; ++ } ++ ++ std::string ChangeParameters::GetMethodName() const ++ { ++ constexpr const char* CHANGE_METHOD_NAME = "ChangeParameters"; ++ return CHANGE_METHOD_NAME; ++ } ++ ++ void ChangeParameters::FillParams( types::ParserResult const& params ) ++ { ++ auto user = params.find("user"); ++ if(user != params.end()) ++ { ++ mUser = (*user).second; ++ } ++ ++ auto password = params.find("password"); ++ if(password != params.end()) ++ { ++ mPassword = (*password).second; ++ } ++ ++ auto host = params.find("host"); ++ if(host != params.end()) ++ { ++ mHost = (*host).second; ++ } ++ ++ auto port = params.find("port"); ++ if(port != params.end()) ++ { ++ mPort = (*port).second; ++ } ++ } ++} +diff --git a/redfish-core/src/utils/smtp/send_message_parser.cpp b/redfish-core/src/utils/smtp/send_message_parser.cpp +new file mode 100644 +index 00000000..0904a3e4 +--- /dev/null ++++ b/redfish-core/src/utils/smtp/send_message_parser.cpp +@@ -0,0 +1,76 @@ ++#include "utils/smtp/send_message_parser.hpp" ++ ++namespace redfish::smtp::parser ++{ ++ SendMessage::SendMessage( std::string const& function_with_parameters ) ++ { ++ static const std::string DELIMITER_ON_LINE = "&"; ++ ++ auto params = BuildParams(ParseLine(function_with_parameters, DELIMITER_ON_LINE)); ++ FillParams( params ); ++ } ++ ++ std::string SendMessage::GetFrom() const ++ { ++ return mFrom; ++ } ++ ++ std::string SendMessage::GetTo() const ++ { ++ return mTo; ++ } ++ ++ std::list<std::string> SendMessage::GetCc() const ++ { ++ return mCc; ++ } ++ ++ std::string SendMessage::GetSubject() const ++ { ++ return mSubject; ++ } ++ ++ std::string SendMessage::GetText() const ++ { ++ return mText; ++ } ++ ++ std::string SendMessage::GetMethodName() const ++ { ++ constexpr const char* SEND_METHOD_NAME = "SendMail"; ++ return SEND_METHOD_NAME; ++ } ++ ++ void SendMessage::FillParams( types::ParserResult const& params ) ++ { ++ auto from = params.find("from"); ++ if(from != params.end()) ++ { ++ mFrom = (*from).second; ++ } ++ ++ auto to = params.find("to"); ++ if(to != params.end()) ++ { ++ mTo = (*to).second; ++ } ++ ++ auto cc = params.equal_range("cc"); ++ for(auto it = cc.first; it != cc.second; ++it) ++ { ++ mCc.push_back( (*it).second ); ++ } ++ ++ auto subject = params.find("subject"); ++ if(subject != params.end()) ++ { ++ mSubject = (*subject).second; ++ } ++ ++ auto text = params.find("text"); ++ if(text != params.end()) ++ { ++ mText = (*text).second; ++ } ++ } ++} +diff --git a/redfish-core/src/utils/smtp/types/iparser.cpp b/redfish-core/src/utils/smtp/types/iparser.cpp +new file mode 100644 +index 00000000..ac95b967 +--- /dev/null ++++ b/redfish-core/src/utils/smtp/types/iparser.cpp +@@ -0,0 +1,35 @@ ++#include "utils/smtp/types/iparser.hpp" ++ ++namespace redfish::smtp::parser::types ++{ ++ std::list<std::string> IParser::ParseLine( std::string const& line, std::string const& delimiter ) ++ { ++ std::list<std::string> result; ++ ++ auto start = 0U; ++ auto end = line.find(delimiter); ++ while(end != std::string::npos) ++ { ++ auto parsed = line.substr(start, end - start); ++ result.push_back(parsed); ++ start = end + delimiter.length(); ++ end = line.find(delimiter, start); ++ } ++ auto parsed = line.substr(start, end); ++ result.push_back(parsed); ++ return result; ++ } ++ ++ ParserResult IParser::BuildParams(std::list<std::string> const& parsed_data) ++ { ++ static const std::string DELIMITER_ON_PARAMETER = "="; ++ ++ std::unordered_multimap<std::string, std::string> result; ++ for(const auto& not_parsed_param : parsed_data) ++ { ++ auto param_pair = ParseLine( not_parsed_param, DELIMITER_ON_PARAMETER ); ++ result.insert( {param_pair.front(), param_pair.back()} ); ++ } ++ return result; ++ } ++} +diff --git a/redfish-core/ut/smtp_reader_parser_test.cpp b/redfish-core/ut/smtp_reader_parser_test.cpp +new file mode 100644 +index 00000000..67a6645c +--- /dev/null ++++ b/redfish-core/ut/smtp_reader_parser_test.cpp +@@ -0,0 +1,45 @@ ++#include "utils/smtp/send_message_parser.hpp" ++#include "utils/smtp/change_parameters_parser.hpp" ++#include "smtp.hpp" ++ ++#include <string> ++ ++#include <gmock/gmock.h> ++#include <gtest/gtest.h> ++ ++namespace redfish::json_util ++{ ++namespace ++{ ++ ++using ::testing::ElementsAre; ++ ++TEST(SmtpReaderParser, SendMessage) ++{ ++ smtp::parser::SendMessage message_parser{"SendMail&from=claiff@mail.ru&to=claiff1990@gmail.com&cc=claiff@mail.ru&cc=claiff@mail.com&subject=theme&text=text"}; ++ EXPECT_EQ(message_parser.GetFrom(), "claiff@mail.ru"); ++ ASSERT_THAT(message_parser.GetCc(), ElementsAre("claiff@mail.com", "claiff@mail.ru")); ++ EXPECT_EQ(message_parser.GetTo(), "claiff1990@gmail.com"); ++ EXPECT_EQ(message_parser.GetSubject(), "theme"); ++ EXPECT_EQ(message_parser.GetText(), "text"); ++ EXPECT_EQ(message_parser.GetMethodName(), "SendMail"); ++} ++ ++TEST(SmtpReaderParser, ChangeParameters) ++{ ++ smtp::parser::ChangeParameters message_parser{"ChangeParameters&user=claiff@mail.ru&password=32311&host=smtp.mail.ru&port=465"}; ++ EXPECT_EQ(message_parser.GetUser(), "claiff@mail.ru"); ++ EXPECT_EQ(message_parser.GetPassword(), "32311"); ++ EXPECT_EQ(message_parser.GetHost(), "smtp.mail.ru"); ++ EXPECT_EQ(message_parser.GetPort(), "465"); ++} ++ ++TEST(SmtpReaderParser, GetFunctionName) ++{ ++ static constexpr std::string_view MESSAGE = "ChangeParameters&user=claiff@mail.ru&password=32311&host=smtp.mail.ru&port=465"; ++ auto result = smtp::GetFunctionName(MESSAGE.data()); ++ EXPECT_EQ(result, "ChangeParameters"); ++} ++ ++} // namespace ++} // namespace redfish::json_util |