Implement led assert and deassert based on faults
Change-Id: I28378b155da15282b1b5bf0403075b55bda5b70d
Signed-off-by: Dhruvaraj Subhashchandran <dhruvaraj@in.ibm.com>
diff --git a/configure.ac b/configure.ac
index c0fc04a..ba1a152 100644
--- a/configure.ac
+++ b/configure.ac
@@ -45,6 +45,10 @@
PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging],, [AC_MSG_ERROR([Could not find phosphor-logging...openbmc/phosphor-logging package required])])
PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces],, [AC_MSG_ERROR([Could not find phosphor-dbus-interfaces...openbmc/phosphor-dbus-interfaces package required])])
+# Check for sdbus++ tool
+AC_PATH_PROG([SDBUSPLUSPLUS], [sdbus++])
+AS_IF([test "x$SDBUSPLUSPLUS" == "x"], AC_MSG_ERROR([Cannot find sdbus++]))
+
# Dbus service name
AC_ARG_VAR(BUSNAME, [The Dbus busname to own])
AS_IF([test "x$BUSNAME" == "x"], [BUSNAME="xyz.openbmc_project.LED.GroupManager"])
@@ -63,6 +67,8 @@
AC_DEFINE(CALLOUT_FWD_ASSOCIATION, "callout", [The name of the callout's forward association.])
AC_DEFINE(CALLOUT_REV_ASSOCIATION, "fault", [The name of the callout's reverse association.])
+AC_DEFINE(ELOG_ENTRY, "entry", [Path element indicates an error log entry under logging namespace.])
+AC_DEFINE(LED_FAULT, "fault", [Path element to indicates a fault led under led groups.])
# Create configured output
AC_CONFIG_FILES([Makefile test/Makefile fault-monitor/Makefile])
diff --git a/elog-errors.hpp b/elog-errors.hpp
new file mode 100644
index 0000000..1cc6f4a
--- /dev/null
+++ b/elog-errors.hpp
@@ -0,0 +1,402 @@
+// This file was autogenerated. Do not edit!
+// See elog-gen.py for more details
+#pragma once
+
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <sdbusplus/exception.hpp>
+#include <phosphor-logging/log.hpp>
+#include <phosphor-logging/elog.hpp>
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Fru
+{
+namespace Monitor
+{
+namespace Error
+{
+ struct AssociationRetrieveError;
+} // namespace Error
+} // namespace Monitor
+} // namespace Fru
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Fru
+{
+namespace Monitor
+{
+namespace Error
+{
+ struct InventoryPathError;
+} // namespace Error
+} // namespace Monitor
+} // namespace Fru
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Mapper
+{
+namespace Error
+{
+ struct ObjectNotFoundError;
+} // namespace Error
+} // namespace Mapper
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Mapper
+{
+namespace Error
+{
+ struct MethodError;
+} // namespace Error
+} // namespace Mapper
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+
+
+namespace phosphor
+{
+
+namespace logging
+{
+
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Fru
+{
+namespace Monitor
+{
+namespace _InventoryPathError
+{
+
+struct PATH
+{
+ static constexpr auto str = "PATH=%s";
+ static constexpr auto str_short = "PATH";
+ using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+ explicit constexpr PATH(const char* a) : _entry(entry(str, a)) {};
+ type _entry;
+};
+
+} // namespace _InventoryPathError
+
+struct InventoryPathError : public sdbusplus::exception_t
+{
+ static constexpr auto errName = "xyz.openbmc_project.Led.Fru.Monitor.InventoryPathError";
+ static constexpr auto errDesc = "Invalid Inventory Path.";
+ static constexpr auto L = level::INFO;
+ using PATH = _InventoryPathError::PATH;
+ using metadata_types = std::tuple<PATH>;
+
+ const char* name() const noexcept
+ {
+ return errName;
+ }
+
+ const char* description() const noexcept
+ {
+ return errDesc;
+ }
+
+ const char* what() const noexcept
+ {
+ return errName;
+ }
+};
+
+} // namespace Monitor
+} // namespace Fru
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+
+
+namespace details
+{
+
+template <>
+struct map_exception_type<sdbusplus::xyz::openbmc_project::Led::Fru::Monitor::Error::InventoryPathError>
+{
+ using type = xyz::openbmc_project::Led::Fru::Monitor::InventoryPathError;
+};
+
+}
+
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Fru
+{
+namespace Monitor
+{
+namespace _AssociationRetrieveError
+{
+
+struct ELOG_ENTRY_PATH
+{
+ static constexpr auto str = "ELOG_ENTRY_PATH=%s";
+ static constexpr auto str_short = "ELOG_ENTRY_PATH";
+ using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+ explicit constexpr ELOG_ENTRY_PATH(const char* a) : _entry(entry(str, a)) {};
+ type _entry;
+};
+
+} // namespace _AssociationRetrieveError
+
+struct AssociationRetrieveError : public sdbusplus::exception_t
+{
+ static constexpr auto errName = "xyz.openbmc_project.Led.Fru.Monitor.AssociationRetrieveError";
+ static constexpr auto errDesc = "Error in retrieving the associations from elog entry.";
+ static constexpr auto L = level::INFO;
+ using ELOG_ENTRY_PATH = _AssociationRetrieveError::ELOG_ENTRY_PATH;
+ using metadata_types = std::tuple<ELOG_ENTRY_PATH>;
+
+ const char* name() const noexcept
+ {
+ return errName;
+ }
+
+ const char* description() const noexcept
+ {
+ return errDesc;
+ }
+
+ const char* what() const noexcept
+ {
+ return errName;
+ }
+};
+
+} // namespace Monitor
+} // namespace Fru
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+
+
+namespace details
+{
+
+template <>
+struct map_exception_type<sdbusplus::xyz::openbmc_project::Led::Fru::Monitor::Error::AssociationRetrieveError>
+{
+ using type = xyz::openbmc_project::Led::Fru::Monitor::AssociationRetrieveError;
+};
+
+}
+
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Mapper
+{
+namespace _MethodError
+{
+
+struct METHOD_NAME
+{
+ static constexpr auto str = "METHOD_NAME=%s";
+ static constexpr auto str_short = "METHOD_NAME";
+ using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+ explicit constexpr METHOD_NAME(const char* a) : _entry(entry(str, a)) {};
+ type _entry;
+};
+struct PATH
+{
+ static constexpr auto str = "PATH=%s";
+ static constexpr auto str_short = "PATH";
+ using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+ explicit constexpr PATH(const char* a) : _entry(entry(str, a)) {};
+ type _entry;
+};
+struct INTERFACE
+{
+ static constexpr auto str = "INTERFACE=%s";
+ static constexpr auto str_short = "INTERFACE";
+ using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+ explicit constexpr INTERFACE(const char* a) : _entry(entry(str, a)) {};
+ type _entry;
+};
+
+} // namespace _MethodError
+
+struct MethodError : public sdbusplus::exception_t
+{
+ static constexpr auto errName = "xyz.openbmc_project.Led.Mapper.MethodError";
+ static constexpr auto errDesc = "Failed to invoke ObjectMapper method";
+ static constexpr auto L = level::INFO;
+ using METHOD_NAME = _MethodError::METHOD_NAME;
+ using PATH = _MethodError::PATH;
+ using INTERFACE = _MethodError::INTERFACE;
+ using metadata_types = std::tuple<METHOD_NAME, PATH, INTERFACE>;
+
+ const char* name() const noexcept
+ {
+ return errName;
+ }
+
+ const char* description() const noexcept
+ {
+ return errDesc;
+ }
+
+ const char* what() const noexcept
+ {
+ return errName;
+ }
+};
+
+} // namespace Mapper
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+
+
+namespace details
+{
+
+template <>
+struct map_exception_type<sdbusplus::xyz::openbmc_project::Led::Mapper::Error::MethodError>
+{
+ using type = xyz::openbmc_project::Led::Mapper::MethodError;
+};
+
+}
+
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace Led
+{
+namespace Mapper
+{
+namespace _ObjectNotFoundError
+{
+
+struct METHOD_NAME
+{
+ static constexpr auto str = "METHOD_NAME=%s";
+ static constexpr auto str_short = "METHOD_NAME";
+ using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+ explicit constexpr METHOD_NAME(const char* a) : _entry(entry(str, a)) {};
+ type _entry;
+};
+struct PATH
+{
+ static constexpr auto str = "PATH=%s";
+ static constexpr auto str_short = "PATH";
+ using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+ explicit constexpr PATH(const char* a) : _entry(entry(str, a)) {};
+ type _entry;
+};
+struct INTERFACE
+{
+ static constexpr auto str = "INTERFACE=%s";
+ static constexpr auto str_short = "INTERFACE";
+ using type = std::tuple<std::decay_t<decltype(str)>,const char*>;
+ explicit constexpr INTERFACE(const char* a) : _entry(entry(str, a)) {};
+ type _entry;
+};
+
+} // namespace _ObjectNotFoundError
+
+struct ObjectNotFoundError : public sdbusplus::exception_t
+{
+ static constexpr auto errName = "xyz.openbmc_project.Led.Mapper.ObjectNotFoundError";
+ static constexpr auto errDesc = "Failed to get response from the method.";
+ static constexpr auto L = level::INFO;
+ using METHOD_NAME = _ObjectNotFoundError::METHOD_NAME;
+ using PATH = _ObjectNotFoundError::PATH;
+ using INTERFACE = _ObjectNotFoundError::INTERFACE;
+ using metadata_types = std::tuple<METHOD_NAME, PATH, INTERFACE>;
+
+ const char* name() const noexcept
+ {
+ return errName;
+ }
+
+ const char* description() const noexcept
+ {
+ return errDesc;
+ }
+
+ const char* what() const noexcept
+ {
+ return errName;
+ }
+};
+
+} // namespace Mapper
+} // namespace Led
+} // namespace openbmc_project
+} // namespace xyz
+
+
+namespace details
+{
+
+template <>
+struct map_exception_type<sdbusplus::xyz::openbmc_project::Led::Mapper::Error::ObjectNotFoundError>
+{
+ using type = xyz::openbmc_project::Led::Mapper::ObjectNotFoundError;
+};
+
+}
+
+
+} // namespace logging
+
+} // namespace phosphor
diff --git a/fault-monitor/Makefile.am b/fault-monitor/Makefile.am
index ba7603f..044b638 100644
--- a/fault-monitor/Makefile.am
+++ b/fault-monitor/Makefile.am
@@ -7,7 +7,16 @@
phosphor_fru_fault_monitor_SOURCES = \
fru-fault-monitor.cpp \
- monitor-main.cpp
+ monitor-main.cpp \
+ xyz/openbmc_project/Led/Mapper/error.cpp \
+ xyz/openbmc_project/Led/Fru/Monitor/error.cpp
+
+BUILT_SOURCES = xyz/openbmc_project/Led/Mapper/error.hpp \
+ xyz/openbmc_project/Led/Mapper/error.cpp \
+ xyz/openbmc_project/Led/Fru/Monitor/error.hpp \
+ xyz/openbmc_project/Led/Fru/Monitor/error.cpp
+
+CLEANFILES = ${BUILT_SOURCES}
phosphor_fru_fault_monitor_LDFLAGS = $(SDBUSPLUS_LIBS) \
$(PHOSPHOR_LOGGING_LIBS) \
@@ -15,3 +24,19 @@
phosphor_fru_fault_monitor_CFLAGS = $(SDBUSPLUS_CFLAGS) \
$(PHOSPHOR_LOGGING_CFLAGS) \
$(PHOSPHOR_DBUS_INTERFACES_CFLAGS)
+
+xyz/openbmc_project/Led/Mapper/error.hpp: ${top_srcdir}/xyz/openbmc_project/Led/Mapper.errors.yaml
+ @mkdir -p `dirname $@`
+ $(SDBUSPLUSPLUS) -r $(top_srcdir) error exception-header xyz.openbmc_project.Led.Mapper > $@
+
+xyz/openbmc_project/Led/Mapper/error.cpp: ${top_srcdir}/xyz/openbmc_project/Led/Mapper.errors.yaml
+ @mkdir -p `dirname $@`
+ $(SDBUSPLUSPLUS) -r $(top_srcdir) error exception-cpp xyz.openbmc_project.Led.Mapper > $@
+
+xyz/openbmc_project/Led/Fru/Monitor/error.hpp: ${top_srcdir}/xyz/openbmc_project/Led/Fru/Monitor.errors.yaml
+ @mkdir -p `dirname $@`
+ $(SDBUSPLUSPLUS) -r $(top_srcdir) error exception-header xyz.openbmc_project.Led.Fru.Monitor > $@
+
+xyz/openbmc_project/Led/Fru/Monitor/error.cpp: ${top_srcdir}/xyz/openbmc_project/Led/Fru/Monitor.errors.yaml
+ @mkdir -p `dirname $@`
+ $(SDBUSPLUSPLUS) -r $(top_srcdir) error exception-cpp xyz.openbmc_project.Led.Fru.Monitor > $@
diff --git a/fault-monitor/fru-fault-monitor.cpp b/fault-monitor/fru-fault-monitor.cpp
index 1213128..e21727b 100644
--- a/fault-monitor/fru-fault-monitor.cpp
+++ b/fault-monitor/fru-fault-monitor.cpp
@@ -1,4 +1,9 @@
+#include <phosphor-logging/elog.hpp>
+#include "xyz/openbmc_project/Led/Fru/Monitor/error.hpp"
+#include "xyz/openbmc_project/Led/Mapper/error.hpp"
+#include "elog-errors.hpp"
#include "fru-fault-monitor.hpp"
+
namespace phosphor
{
namespace led
@@ -10,10 +15,105 @@
namespace monitor
{
+using namespace phosphor::logging;
+
+constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
+constexpr auto MAPPER_OBJ_PATH = "/xyz/openbmc_project/object_mapper";
+constexpr auto MAPPER_IFACE = "xyz.openbmc_project.ObjectMapper";
+constexpr auto OBJMGR_IFACE = "org.freedesktop.DBus.ObjectManager";
+constexpr auto LED_GROUPS = "/xyz/openbmc_project/led/groups/";
+constexpr auto LOG_PATH = "/xyz/openbmc_project/logging";
+
+using AssociationList = std::vector<std::tuple<
+ std::string, std::string, std::string>>;
+using MethodErr =
+ sdbusplus::xyz::openbmc_project::Led::Mapper::Error::MethodError;
+using ObjectNotFoundErr =
+ sdbusplus::xyz::openbmc_project::Led::Mapper::Error::ObjectNotFoundError;
+using AssociationRetrieveErr =
+ sdbusplus::xyz::openbmc_project::
+ Led::Fru::Monitor::Error::AssociationRetrieveError;
+using InventoryPathErr =
+ sdbusplus::xyz::openbmc_project::
+ Led::Fru::Monitor::Error::InventoryPathError;
+
+std::string getService(sdbusplus::bus::bus& bus,
+ const std::string& path)
+{
+ auto mapper = bus.new_method_call(MAPPER_BUSNAME,
+ MAPPER_OBJ_PATH,
+ MAPPER_IFACE, "GetObject");
+ mapper.append(path.c_str(), std::vector<std::string>({OBJMGR_IFACE}));
+ auto mapperResponseMsg = bus.call(mapper);
+ if (mapperResponseMsg.is_method_error())
+ {
+ using namespace xyz::openbmc_project::Led::Mapper;
+ elog<MethodErr>(
+ MethodError::METHOD_NAME("GetObject"),
+ MethodError::PATH(path.c_str()),
+ MethodError::INTERFACE(
+ OBJMGR_IFACE));
+ }
+
+ std::map<std::string, std::vector<std::string>> mapperResponse;
+ mapperResponseMsg.read(mapperResponse);
+ if (mapperResponse.empty())
+ {
+ using namespace xyz::openbmc_project::Led::Mapper;
+ elog<ObjectNotFoundErr>(
+ ObjectNotFoundError::METHOD_NAME("GetObject"),
+ ObjectNotFoundError::PATH(path.c_str()),
+ ObjectNotFoundError::INTERFACE(
+ OBJMGR_IFACE));
+ }
+
+ return mapperResponse.cbegin()->first;
+}
+
void action(sdbusplus::bus::bus& bus,
- const std::string& unit,
+ const std::string& path,
bool assert)
{
+ std::string service;
+ try
+ {
+ service = getService(bus, LED_GROUPS);
+ }
+ catch (MethodErr& e)
+ {
+ commit<MethodErr>();
+ return;
+ }
+ catch (ObjectNotFoundErr& e)
+ {
+ commit<ObjectNotFoundErr>();
+ return;
+ }
+
+ auto pos = path.rfind("/");
+ if (pos == std::string::npos)
+ {
+ using namespace xyz::openbmc_project::Led::Fru::Monitor;
+ report<InventoryPathErr>(
+ InventoryPathError::PATH(
+ path.c_str()));
+ return;
+ }
+ auto unit = path.substr(pos + 1);
+
+ std::string ledPath = LED_GROUPS +
+ unit + '_' + LED_FAULT;
+
+ auto method = bus.new_method_call(service.c_str(),
+ ledPath.c_str(),
+ "org.freedesktop.DBus.Properties",
+ "Set");
+ method.append("xyz.openbmc_project.Led.Group");
+ method.append("Asserted");
+
+ method.append(sdbusplus::message::variant<bool>(assert));
+ bus.call_noreply(method);
+
return;
}
@@ -21,6 +121,72 @@
void* data,
sd_bus_error* retError)
{
+ auto m = sdbusplus::message::message(msg);
+ auto bus = m.get_bus();
+
+ sdbusplus::message::object_path obPath;
+ m.read(obPath);
+ std::string objectPath(std::move(obPath));
+
+ std::size_t found = objectPath.find(ELOG_ENTRY);
+ if (found == std::string::npos)
+ {
+ //Not a new error entry skip
+ return 0;
+ }
+
+ std::string service;
+ try
+ {
+ service = getService(bus, LOG_PATH);
+ }
+ catch (MethodErr& e)
+ {
+ commit<MethodErr>();
+ return 0;
+ }
+ catch (ObjectNotFoundErr& e)
+ {
+ commit<ObjectNotFoundErr>();
+ return 0;
+ }
+
+ auto method = bus.new_method_call(service.c_str(), objectPath.c_str(),
+ "org.freedesktop.DBus.Properties",
+ "Get");
+
+ method.append("org.openbmc.Associations");
+ method.append("associations");
+ auto reply = bus.call(method);
+ if (reply.is_method_error())
+ {
+ using namespace xyz::openbmc_project::Led::Fru::Monitor;
+ report<AssociationRetrieveErr>(
+ AssociationRetrieveError::ELOG_ENTRY_PATH(
+ objectPath.c_str()));
+ return 0;
+ }
+
+ sdbusplus::message::variant<AssociationList> assoc;
+ reply.read(assoc);
+
+ auto assocs =
+ sdbusplus::message::variant_ns::get<AssociationList>(assoc);
+ if (assocs.empty())
+ {
+ //No associations skip
+ return 0;
+ }
+
+ for (const auto& item : assocs)
+ {
+ if (std::get<1>(item).compare(CALLOUT_REV_ASSOCIATION) == 0)
+ {
+ action(bus, std::get<2>(item), true);
+ static_cast<Add*>(data)->removeWatches.emplace_back(
+ std::make_unique<Remove>(bus, std::get<2>(item)));
+ }
+ }
return 0;
}
@@ -28,6 +194,34 @@
void* data,
sd_bus_error* retError)
{
+ auto m = sdbusplus::message::message(msg);
+ auto bus = m.get_bus();
+ std::string assoc;
+ m.read(assoc);
+
+ if (assoc.compare("org.openbmc.Association"))
+ {
+ //Skip if not about association
+ return 0;
+ }
+
+ std::map<std::string, std::vector<std::string>> endPoints;
+ m.read(endPoints);
+ auto it = endPoints.find("endpoints");
+
+ if (it == endPoints.end())
+ {
+ //No end points,skip
+ return 0;
+ }
+
+ if (!((*it).second.empty()))
+ {
+ //Skip, end points are not empty
+ return 0;
+ }
+
+ action(bus, static_cast<Remove*>(data)->inventoryPath, false);
return 0;
}
diff --git a/xyz/openbmc_project/Led/Fru/Monitor.errors.yaml b/xyz/openbmc_project/Led/Fru/Monitor.errors.yaml
new file mode 100644
index 0000000..bb77f45
--- /dev/null
+++ b/xyz/openbmc_project/Led/Fru/Monitor.errors.yaml
@@ -0,0 +1,7 @@
+#xyz.openbmc_project.Led.Fru.Monitor.InventoryPathError
+- name: InventoryPathError
+ description: Invalid Inventory Path.
+
+#xyz.openbmc_project.Led.Fru.Monitor.AssociationRetrieveError
+- name: AssociationRetrieveError
+ description: Error in retrieving the associations from elog entry.
diff --git a/xyz/openbmc_project/Led/Fru/Monitor.metadata.yaml b/xyz/openbmc_project/Led/Fru/Monitor.metadata.yaml
new file mode 100644
index 0000000..bd59e5f
--- /dev/null
+++ b/xyz/openbmc_project/Led/Fru/Monitor.metadata.yaml
@@ -0,0 +1,9 @@
+- name: InventoryPathError
+ meta:
+ - str: "PATH=%s"
+ type: string
+
+- name: AssociationRetrieveError
+ meta:
+ - str: "ELOG_ENTRY_PATH=%s"
+ type: string
diff --git a/xyz/openbmc_project/Led/Mapper.errors.yaml b/xyz/openbmc_project/Led/Mapper.errors.yaml
new file mode 100644
index 0000000..c1cbd0f
--- /dev/null
+++ b/xyz/openbmc_project/Led/Mapper.errors.yaml
@@ -0,0 +1,9 @@
+#xyz.openbmc_project.Led.Mapper.MethodError
+- name: MethodError
+ description: Failed to invoke ObjectMapper method
+
+#xyz.openbmc_project.Led.Mapper.ObjectNotFoundError
+- name: ObjectNotFoundError
+ description: Failed to get response from the method.
+
+
diff --git a/xyz/openbmc_project/Led/Mapper.metadata.yaml b/xyz/openbmc_project/Led/Mapper.metadata.yaml
new file mode 100644
index 0000000..0eb5c7f
--- /dev/null
+++ b/xyz/openbmc_project/Led/Mapper.metadata.yaml
@@ -0,0 +1,17 @@
+- name: MethodError
+ meta:
+ - str: "METHOD_NAME=%s"
+ type: string
+ - str: "PATH=%s"
+ type: string
+ - str: "INTERFACE=%s"
+ type: string
+
+- name: ObjectNotFoundError
+ meta:
+ - str: "METHOD_NAME=%s"
+ type: string
+ - str: "PATH=%s"
+ type: string
+ - str: "INTERFACE=%s"
+ type: string