diff --git a/ansible/action_plugins/merge_configs.py b/ansible/action_plugins/merge_configs.py index 11462f4b3b..556bfa83b1 100644 --- a/ansible/action_plugins/merge_configs.py +++ b/ansible/action_plugins/merge_configs.py @@ -25,6 +25,8 @@ from six import StringIO from oslo_config import iniparser +_ORPHAN_SECTION = 'TEMPORARY_ORPHAN_VARIABLE_SECTION' + class OverrideConfigParser(iniparser.BaseParser): @@ -34,6 +36,8 @@ class OverrideConfigParser(iniparser.BaseParser): self._cur_section = None def assignment(self, key, value): + if self._cur_section is None: + self.new_section(_ORPHAN_SECTION) cur_value = self._cur_section.get(key) if len(value) == 1 and value[0] == '': value = [] @@ -44,6 +48,7 @@ class OverrideConfigParser(iniparser.BaseParser): def parse(self, lineiter): self._cur_sections = collections.OrderedDict() + self._cur_section = None super(OverrideConfigParser, self).parse(lineiter) # merge _cur_sections into _sections @@ -77,7 +82,8 @@ class OverrideConfigParser(iniparser.BaseParser): write_key_value(key, values) for section in self._sections: - fp.write('[{}]\n'.format(section)) + if section != _ORPHAN_SECTION: + fp.write('[{}]\n'.format(section)) write_section(self._sections[section]) fp.write('\n') diff --git a/tests/test_merge_config.py b/tests/test_merge_config.py index b972cc9bf7..21a4a0f576 100644 --- a/tests/test_merge_config.py +++ b/tests/test_merge_config.py @@ -86,11 +86,68 @@ c_key2 = 1 2 3 ''' +TESTA_NO_SECTIONS = '''key1 = a +key2 = b + +''' + +TESTB_NO_SECTIONS = '''key3 = c + +''' + +# TESTA_NO_SECTIONS and TESTB_NO_SECTIONS combined +TESTC_NO_SECTIONS = '''key1 = a +key2 = b +key3 = c + +''' + +TESTA_NO_DEFAULT_SECTION = '''key1 = a +key2 = b + +[a] +key1 = not_a + +[b] +key3 = not_c + +''' + +TESTB_NO_DEFAULT_SECTION = '''key3 = c + +[b] +key2 = not_b +key3 = override + +''' + +# TESTA_NO_DEFAULT_SECTION and TESTB_NO_DEFAULT_SECTION combined +TESTC_NO_DEFAULT_SECTION = '''key1 = a +key2 = b +key3 = c + +[a] +key1 = not_a + +[b] +key3 = override +key2 = not_b + +''' + class OverrideConfigParserTest(base.BaseTestCase): def test_read_write(self): - for ini in [TESTA, TESTB, TESTC]: + for ini in [TESTA, + TESTB, + TESTC, + TESTA_NO_SECTIONS, + TESTB_NO_SECTIONS, + TESTC_NO_SECTIONS, + TESTA_NO_DEFAULT_SECTION, + TESTB_NO_DEFAULT_SECTION, + TESTC_NO_DEFAULT_SECTION]: parser = merge_configs.OverrideConfigParser() parser.parse(StringIO(ini)) output = StringIO() @@ -106,3 +163,21 @@ class OverrideConfigParserTest(base.BaseTestCase): parser.write(output) self.assertEqual(TESTC, output.getvalue()) output.close() + + def test_merge_no_sections(self): + parser = merge_configs.OverrideConfigParser() + parser.parse(StringIO(TESTA_NO_SECTIONS)) + parser.parse(StringIO(TESTB_NO_SECTIONS)) + output = StringIO() + parser.write(output) + self.assertEqual(TESTC_NO_SECTIONS, output.getvalue()) + output.close() + + def test_merge_no_default_section(self): + parser = merge_configs.OverrideConfigParser() + parser.parse(StringIO(TESTA_NO_DEFAULT_SECTION)) + parser.parse(StringIO(TESTB_NO_DEFAULT_SECTION)) + output = StringIO() + parser.write(output) + self.assertEqual(TESTC_NO_DEFAULT_SECTION, output.getvalue()) + output.close()