Repository: RedHatInsights/insights-core

Issue:
parse_systemd_ini relies on implementation details of ConfigParser
The way line continuations were handled by config parser in python2.6 changed in 2.7, and this change is being exploited by the parse_systemd_ini function.  Because of this, the function fails on python2.6.  To work around this @kylape is including the python2.7 version of ConfigParser.py.  This is undesirable.  The function should be rewritten to work in python2.6.  The current implementation also seems to conflate multi-line strings (those with line continuation characters) and the presence of a key multiple times (like multiple After= lines) in a way that makes it impossible to distinguish the two situations.

You can see the relevant commit here: https://github.com/RedHatInsights/insights-core/commit/b2a0df88311a3ec67b9bf93230e9e5ece825ba41


Discussion:
PR: https://github.com/RedHatInsights/insights-core/pull/333
Hey @wushiqinlou, does the PR fix this issue entirely? Or is there more work to do?
Hello @jhjaggars, PR 333 fix the issue that multi-line strings are in a way that makes it impossible to distinguish the two situations. However, I have no good idea to handle difference of ConfigParser.py between python 2.6 and 2.7.

Resolving patch:
diff --git a/insights/configtree/__init__.py b/insights/configtree/__init__.py
--- a/insights/configtree/__init__.py
+++ b/insights/configtree/__init__.py
@@ -455,7 +455,7 @@ def _next(self):
         while l.endswith("\\"):
             self.pos += 1
             l = l.rstrip("\\")
-            l += next(self.stream)
+            l += next(self.stream).lstrip()
 
         return l.strip() if self.strip else l.rstrip()
 
diff --git a/insights/parsers/systemd/config.py b/insights/parsers/systemd/config.py
--- a/insights/parsers/systemd/config.py
+++ b/insights/parsers/systemd/config.py
@@ -18,15 +18,9 @@
 
 """
 
-try:
-    from StringIO import StringIO
-except ImportError:
-    from io import StringIO
-
+from insights.configtree.iniconfig import parse_doc
 from insights.core import Parser, LegacyItemAccess
 from insights.core.plugins import parser
-from insights.parsers import unsplit_lines
-from insights.contrib.ConfigParser import RawConfigParser as cp
 from insights.specs import Specs
 
 
@@ -180,18 +174,15 @@ def __setitem__(self, key, value):
 def parse_systemd_ini(content):
     """Function to parse config format file, the result format is dictionary"""
 
-    Config = cp(dict_type=MultiOrderedDict)
-    Config.optionxform = str
-    Config.readfp(StringIO('\n'.join(content)))
+    doc = parse_doc(content)
 
     dict_all = {}
-    for section in Config.sections():
-        dict_section = {}
-        for option in Config.options(section):
-            value = Config.get(section, option).splitlines()
-            value = list(unsplit_lines(value))
-            # If the len of value is 1, then set the value as string
-            dict_section[option] = value[0] if len(value) == 1 else value if len(value) > 1 else ''
-        dict_all[section] = dict_section
+    for section in doc:
+        section_dict = {}
+        option_names = set(o.name for o in section)
+        for name in option_names:
+            options = [str(o.value) for o in section[name]]
+            section_dict[name] = options[0] if len(options) == 1 else options
+        dict_all[section.name] = section_dict
 
     return dict_all


Test patch: