Support multi key in merge_config module

Change-Id: Ibf9ee55c48a5181c5ba3aa46bef485cd3468f14c
Closes-Bug: #1647065
This commit is contained in:
Jeffrey Zhang 2016-12-18 01:00:32 +08:00 committed by Jeffrey Zhang
parent c5124f98df
commit 910a50d888
2 changed files with 170 additions and 4 deletions

View File

@ -1,6 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
# Copyright 2015 Sam Yaple # Copyright 2015 Sam Yaple
# Copyright 2017 99Cloud Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -14,12 +15,71 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import ConfigParser
import collections
import inspect import inspect
import os import os
from six import StringIO
from ansible.plugins import action from ansible.plugins import action
from six import StringIO
from oslo_config import iniparser
class OverrideConfigParser(iniparser.BaseParser):
def __init__(self):
self._cur_sections = collections.OrderedDict()
self._sections = collections.OrderedDict()
self._cur_section = None
def assignment(self, key, value):
cur_value = self._cur_section.get(key)
if len(value) == 1 and value[0] == '':
value = []
if not cur_value:
self._cur_section[key] = [value]
else:
self._cur_section[key].append(value)
def parse(self, lineiter):
self._cur_sections = collections.OrderedDict()
super(OverrideConfigParser, self).parse(lineiter)
# merge _cur_sections into _sections
for section, values in self._cur_sections.items():
if section not in self._sections:
self._sections[section] = collections.OrderedDict()
for key, value in values.items():
self._sections[section][key] = value
def new_section(self, section):
cur_section = self._cur_sections.get(section)
if not cur_section:
cur_section = collections.OrderedDict()
self._cur_sections[section] = cur_section
self._cur_section = cur_section
return cur_section
def write(self, fp):
def write_key_value(key, values):
for v in values:
if not v:
fp.write('{} =\n'.format(key))
for index, value in enumerate(v):
if index == 0:
fp.write('{} = {}\n'.format(key, value))
else:
fp.write('{} {}\n'.format(len(key)*' ', value))
def write_section(section):
for key, values in section.items():
write_key_value(key, values)
for section in self._sections:
fp.write('[{}]\n'.format(section))
write_section(self._sections[section])
fp.write('\n')
class ActionModule(action.ActionBase): class ActionModule(action.ActionBase):
@ -33,7 +93,7 @@ class ActionModule(action.ActionBase):
template_data = f.read() template_data = f.read()
result = self._templar.template(template_data) result = self._templar.template(template_data)
fakefile = StringIO(result) fakefile = StringIO(result)
config.readfp(fakefile) config.parse(fakefile)
fakefile.close() fakefile.close()
def run(self, tmp=None, task_vars=None): def run(self, tmp=None, task_vars=None):
@ -62,7 +122,7 @@ class ActionModule(action.ActionBase):
temp_vars = task_vars.copy() temp_vars = task_vars.copy()
temp_vars.update(extra_vars) temp_vars.update(extra_vars)
config = ConfigParser.ConfigParser() config = OverrideConfigParser()
old_vars = self._templar._available_variables old_vars = self._templar._available_variables
self._templar.set_available_variables(temp_vars) self._templar.set_available_variables(temp_vars)

106
tests/test_merge_config.py Normal file
View File

@ -0,0 +1,106 @@
#!/usr/bin/python
# Copyright 2016 99cloud Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import imp
import os
import sys
import mock
from oslotest import base
from six import StringIO
PROJECT_DIR = os.path.abspath(os.path.join(os. path.dirname(__file__), '../'))
MERGE_CONFIG_FILE = os.path.join(PROJECT_DIR,
'ansible/action_plugins/merge_configs.py')
sys.modules['ansible.plugins'] = mock.MagicMock()
merge_configs = imp.load_source('merge_configs', MERGE_CONFIG_FILE)
TESTA = '''[DEFAULT]
key1 = b
c
key2 = v1
v2
key3 = v3
key3 = v4
key4 = v5
[b]
b_key1 = 1
b_key2 = 1
2
[c]
c_key1 =
c_key2 = 1 2 3
4 5 6
'''
TESTB = '''[DEFAULT]
key2 = v3
v4
v5
key4 = v4
key4 =
[b]
b_key2 = 2
'''
# TESTC is TESTA + TESTB
TESTC = '''[DEFAULT]
key1 = b
c
key2 = v3
v4
v5
key3 = v3
key3 = v4
key4 = v4
key4 =
[b]
b_key1 = 1
b_key2 = 2
[c]
c_key1 =
c_key2 = 1 2 3
4 5 6
'''
class OverrideConfigParserTest(base.BaseTestCase):
def test_read_write(self):
for ini in [TESTA, TESTB, TESTC]:
parser = merge_configs.OverrideConfigParser()
parser.parse(StringIO(ini))
output = StringIO()
parser.write(output)
self.assertEqual(ini, output.getvalue())
def test_merge(self):
parser = merge_configs.OverrideConfigParser()
parser.parse(StringIO(TESTA))
parser.parse(StringIO(TESTB))
output = StringIO()
parser.write(output)
self.assertEqual(TESTC, output.getvalue())