summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Dague <sean@dague.net>2017-01-16 14:20:58 -0500
committerSean Dague <sean@dague.net>2017-01-16 14:20:58 -0500
commitde574dc6a8a5ff32f140b803fb0e3edd5239892b (patch)
tree1201487294e8e3cc239e36c4202f28182f16b2f6
parent925b1bc68267e0588f62b2a13a4fa92a30db805c (diff)
support localconf set
-rw-r--r--devstack/dsconf.py59
-rw-r--r--devstack/tests/test_localconf_set.py115
2 files changed, 174 insertions, 0 deletions
diff --git a/devstack/dsconf.py b/devstack/dsconf.py
index 8d64b4e..a1f88b9 100644
--- a/devstack/dsconf.py
+++ b/devstack/dsconf.py
@@ -211,3 +211,62 @@ class LocalConf(object):
211 def _do_set(writer, line): 211 def _do_set(writer, line):
212 writer.write("%s = %s\n" % (name, value)) 212 writer.write("%s = %s\n" % (name, value))
213 self._at_insert_point_local(name, _do_set) 213 self._at_insert_point_local(name, _do_set)
214
215 def _at_insert_point(self, group, conf, section, name, func):
216 temp = tempfile.NamedTemporaryFile(mode='r')
217 shutil.copyfile(self.fname, temp.name)
218 in_meta = False
219 in_section = False
220 done = False
221 with open(self.fname, "w+") as writer:
222 with open(temp.name) as reader:
223 for line in reader.readlines():
224 if done:
225 writer.write(line)
226 continue
227
228 if re.match(re.escape("[[%s|%s]]" % (group, conf)), line):
229 in_meta = True
230 writer.write(line)
231 elif re.match("\[\[.*\|.*\]\]", line):
232 # if we're not done yet, we
233 if in_meta:
234 if not in_section:
235 # if we've not found the section yet,
236 # write out section as well.
237 writer.write("[%s]\n" % section)
238 func(writer, None)
239 done = True
240 writer.write(line)
241 in_meta = False
242 in_section = False
243 elif re.match(re.escape("[%s]" % section), line):
244 # we found a relevant section
245 writer.write(line)
246 in_section = True
247 elif re.match("\[[^\[\]]+\]", line):
248 if in_meta and in_section:
249 # We've ended our section, in our meta,
250 # never found the key. Time to add it.
251 func(writer, None)
252 done = True
253 in_section = False
254 writer.write(line)
255 elif (in_meta and in_section and
256 re.match("\s*%s\s*\=" % re.escape(name), line)):
257 # we found our match point
258 func(writer, line)
259 done = True
260 else:
261 # write out whatever we find
262 writer.write(line)
263 if not done:
264 # we never found meta with a relevant section
265 writer.write("[[%s|%s]]\n" % (group, conf))
266 writer.write("[%s]\n" % (section))
267 func(writer, None)
268
269 def set(self, group, conf, section, name, value):
270 def _do_set(writer, line):
271 writer.write("%s = %s\n" % (name, value))
272 self._at_insert_point(group, conf, section, name, _do_set)
diff --git a/devstack/tests/test_localconf_set.py b/devstack/tests/test_localconf_set.py
new file mode 100644
index 0000000..23af330
--- /dev/null
+++ b/devstack/tests/test_localconf_set.py
@@ -0,0 +1,115 @@
1# Copyright 2017 IBM
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15# Implementation of ini add / remove for devstack. We don't use the
16# python ConfigFile parser because that ends up rewriting the entire
17# file and doesn't ensure comments remain.
18
19import fixtures
20import os.path
21import testtools
22
23from devstack import dsconf
24
25
26BASIC = """
27[[local|localrc]]
28a = b
29c = d
30f = 1
31[[post-config|$NEUTRON_CONF]]
32[DEFAULT]
33global_physnet_mtu=1450
34[[post-config|$NOVA_CONF]]
35[upgrade_levels]
36compute = auto
37"""
38
39RESULT1 = """
40[[local|localrc]]
41a = b
42c = d
43f = 1
44[[post-config|$NEUTRON_CONF]]
45[DEFAULT]
46global_physnet_mtu = 1400
47[[post-config|$NOVA_CONF]]
48[upgrade_levels]
49compute = auto
50"""
51
52RESULT2 = """
53[[local|localrc]]
54a = b
55c = d
56f = 1
57[[post-config|$NEUTRON_CONF]]
58[DEFAULT]
59global_physnet_mtu=1450
60[oslo_policy]
61policy_file = /etc/neutron/policy.json
62[[post-config|$NOVA_CONF]]
63[upgrade_levels]
64compute = auto
65"""
66
67RESULT3 = """
68[[local|localrc]]
69a = b
70c = d
71f = 1
72[[post-config|$NEUTRON_CONF]]
73[DEFAULT]
74global_physnet_mtu=1450
75[[post-config|$NOVA_CONF]]
76[upgrade_levels]
77compute = auto
78[[post-config|$GLANCE_CONF]]
79[DEFAULT]
80graceful_shutdown_timeout = 5
81"""
82
83
84class TestLcSet(testtools.TestCase):
85
86 def setUp(self):
87 super(TestLcSet, self).setUp()
88 self._path = self.useFixture(fixtures.TempDir()).path
89 self._path += "/local.conf"
90 with open(self._path, "w") as f:
91 f.write(BASIC)
92
93 def test_set_existing(self):
94 conf = dsconf.LocalConf(self._path)
95 conf.set("post-config", "$NEUTRON_CONF", "DEFAULT",
96 "global_physnet_mtu", "1400")
97 with open(self._path) as f:
98 content = f.read()
99 self.assertEqual(content, RESULT1)
100
101 def test_set_new(self):
102 conf = dsconf.LocalConf(self._path)
103 conf.set("post-config", "$NEUTRON_CONF", "oslo_policy",
104 "policy_file", "/etc/neutron/policy.json")
105 with open(self._path) as f:
106 content = f.read()
107 self.assertEqual(content, RESULT2)
108
109 def test_set_new_section(self):
110 conf = dsconf.LocalConf(self._path)
111 conf.set("post-config", "$GLANCE_CONF", "DEFAULT",
112 "graceful_shutdown_timeout", "5")
113 with open(self._path) as f:
114 content = f.read()
115 self.assertEqual(content, RESULT3)