PEL: Python3 module support for UserData parsing

This change enables the calling of python3 parsers for UserData section.
Modules will be searched under the namespace "udparsers" from python3
sys.path directories (including the current directory).

Example:

  /usr/lib/python3.8/site-packages/udparsers/bxxxx/bxxxx.py

  or

  ./udparsers/bxxxx/bxxxx.py

  where

  b = Creator Subsystem ID for Hostboot
  xxxx = Component ID of UserData section

The parsers will need to provide a function called "parseUDToJson" with
input parameters:

1. (int) Sub-section type
2. (int) Section version
3. (memoryview): Data

The return value needs to be a valid JSON string.

Signed-off-by: Harisuddin Mohamed Isa <harisuddin@gmail.com>
Change-Id: I4d3523083bc48ad0c329c525d83c4a61d36ff611
diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp
index 0845aba..3295123 100644
--- a/extensions/openpower-pels/pel.cpp
+++ b/extensions/openpower-pels/pel.cpp
@@ -265,7 +265,9 @@
 
 void PEL::printSectionInJSON(const Section& section, std::string& buf,
                              std::map<uint16_t, size_t>& pluralSections,
-                             message::Registry& registry) const
+                             message::Registry& registry,
+                             const std::vector<std::string>& plugins,
+                             uint8_t creatorID) const
 {
     char tmpB[5];
     uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
@@ -286,9 +288,26 @@
 
     if (section.valid())
     {
-        auto json = (sectionID == "PS" || sectionID == "SS")
-                        ? section.getJSON(registry)
-                        : section.getJSON();
+        std::optional<std::string> json;
+        if (sectionID == "PS" || sectionID == "SS")
+        {
+            json = section.getJSON(registry);
+        }
+        else if (sectionID == "UD")
+        {
+            std::string subsystem = getNumberString("%c", tolower(creatorID));
+            std::string component =
+                getNumberString("%04x", section.header().componentID);
+            if (std::find(plugins.begin(), plugins.end(),
+                          subsystem + component) != plugins.end())
+            {
+                json = section.getJSON(creatorID);
+            }
+        }
+        else
+        {
+            json = section.getJSON();
+        }
 
         buf += "\"" + sectionName + "\": {\n";
 
@@ -355,16 +374,18 @@
     return sections;
 }
 
-void PEL::toJSON(message::Registry& registry) const
+void PEL::toJSON(message::Registry& registry,
+                 const std::vector<std::string>& plugins) const
 {
     auto sections = getPluralSections();
 
     std::string buf = "{\n";
-    printSectionInJSON(*(_ph.get()), buf, sections, registry);
-    printSectionInJSON(*(_uh.get()), buf, sections, registry);
+    printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins);
+    printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins);
     for (auto& section : this->optionalSections())
     {
-        printSectionInJSON(*(section.get()), buf, sections, registry);
+        printSectionInJSON(*(section.get()), buf, sections, registry, plugins,
+                           _ph->creatorID());
     }
     buf += "}";
     std::size_t found = buf.rfind(",");