summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Dague <sean@dague.net>2017-02-27 10:08:48 -0500
committerSean Dague <sean@dague.net>2017-02-27 10:08:48 -0500
commitc5626f3b4bef206c704f4be871526f1907a6a39a (patch)
tree692bbcb9551c97d4adb02b59abebb6d6ccfe2859
parentae73f278a1a6d71bcd67dca2b8f7dd2fbe5a8d2a (diff)
support local.conf files with no [[local]] section yet0.3.0
Previously if we tried to added content to a local.conf file without a local section, we actually inserted that content in the wrong place at the end of the file. This fixes that, with unit tests. Change-Id: Ib886d78ce5f3718def784db59ba9abf41bdb0e7b
Notes
Notes (review): Code-Review+2: Matthew Treinish <mtreinish@kortar.org> Code-Review+2: Sean Dague <sean@dague.net> Workflow+1: Sean Dague <sean@dague.net> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Mon, 27 Feb 2017 15:27:12 +0000 Reviewed-on: https://review.openstack.org/438540 Project: openstack/devstack-tools Branch: refs/heads/master
-rw-r--r--devstack/dsconf.py39
-rw-r--r--devstack/tests/test_localconf_set_local.py39
2 files changed, 74 insertions, 4 deletions
diff --git a/devstack/dsconf.py b/devstack/dsconf.py
index 217db1c..43bf3f4 100644
--- a/devstack/dsconf.py
+++ b/devstack/dsconf.py
@@ -175,6 +175,12 @@ class LocalConf(object):
175 if in_section: 175 if in_section:
176 yield line 176 yield line
177 177
178 def _has_local_section(self):
179 for group in self.groups():
180 if group == ("local", "localrc"):
181 return True
182 return False
183
178 def extract(self, group, conf, target): 184 def extract(self, group, conf, target):
179 ini_file = IniFile(target) 185 ini_file = IniFile(target)
180 for section, name, value in self._conf(group, conf): 186 for section, name, value in self._conf(group, conf):
@@ -186,9 +192,28 @@ class LocalConf(object):
186 f.write(line) 192 f.write(line)
187 193
188 def _at_insert_point_local(self, name, func): 194 def _at_insert_point_local(self, name, func):
195 """Run function when we are at the right insertion point in file.
196
197 This lets us process an arbitrary file and insert content at
198 the correct point. It has a few different state flags that we
199 are looking for.
200
201 Does this file have a local section at all? If not, we need to
202 write one early in the file (this means we work with an empty
203 file, as well as a file that has only post-config sections.
204
205 Are we currently in a local section, if so, we need to write
206 out content to the end, because items added to local always
207 have to be added at the end.
208
209 Did we write out the work that we expected? If so, just blast
210 all lines to the end of the file.
211
212 """
189 temp = tempfile.NamedTemporaryFile(mode='r') 213 temp = tempfile.NamedTemporaryFile(mode='r')
190 shutil.copyfile(self.fname, temp.name) 214 shutil.copyfile(self.fname, temp.name)
191 in_meta = False 215 in_local = False
216 has_local = self._has_local_section()
192 done = False 217 done = False
193 with open(self.fname, "w+") as writer: 218 with open(self.fname, "w+") as writer:
194 with open(temp.name) as reader: 219 with open(temp.name) as reader:
@@ -198,11 +223,17 @@ class LocalConf(object):
198 continue 223 continue
199 224
200 if re.match(re.escape("[[local|localrc]]"), line): 225 if re.match(re.escape("[[local|localrc]]"), line):
201 in_meta = True 226 in_local = True
202 elif in_meta and re.match(re.escape("[["), line): 227 elif in_local and re.match(re.escape("[["), line):
203 func(writer, None) 228 func(writer, None)
204 done = True 229 done = True
205 in_meta = False 230 in_local = False
231 elif not has_local and re.match(re.escape("[["), line):
232 writer.write("[[local|localrc]]\n")
233 func(writer, None)
234 done = True
235 in_local = False
236 has_local = True
206 237
207 # otherwise, just write what we found 238 # otherwise, just write what we found
208 writer.write(line) 239 writer.write(line)
diff --git a/devstack/tests/test_localconf_set_local.py b/devstack/tests/test_localconf_set_local.py
index d508563..0ae8a3a 100644
--- a/devstack/tests/test_localconf_set_local.py
+++ b/devstack/tests/test_localconf_set_local.py
@@ -35,6 +35,15 @@ global_physnet_mtu=1450
35compute = auto 35compute = auto
36""" 36"""
37 37
38BASIC_NO_LOCAL = """
39[[post-config|$NEUTRON_CONF]]
40[DEFAULT]
41global_physnet_mtu=1450
42[[post-config|$NOVA_CONF]]
43[upgrade_levels]
44compute = auto
45"""
46
38RESULT1 = """ 47RESULT1 = """
39[[local|localrc]] 48[[local|localrc]]
40a=b 49a=b
@@ -78,6 +87,18 @@ global_physnet_mtu=1450
78compute = auto 87compute = auto
79""" 88"""
80 89
90RESULT_NO_LOCAL = """
91[[local|localrc]]
92a=b
93c=d
94[[post-config|$NEUTRON_CONF]]
95[DEFAULT]
96global_physnet_mtu=1450
97[[post-config|$NOVA_CONF]]
98[upgrade_levels]
99compute = auto
100"""
101
81 102
82class TestLcSet(testtools.TestCase): 103class TestLcSet(testtools.TestCase):
83 104
@@ -117,3 +138,21 @@ class TestLcSet(testtools.TestCase):
117 with open(self._path) as f: 138 with open(self._path) as f:
118 content = f.read() 139 content = f.read()
119 self.assertEqual(content, RESULT3) 140 self.assertEqual(content, RESULT3)
141
142
143class TestNoLocal(testtools.TestCase):
144
145 def setUp(self):
146 super(TestNoLocal, self).setUp()
147 self._path = self.useFixture(fixtures.TempDir()).path
148 self._path += "/local.conf"
149 with open(self._path, "w") as f:
150 f.write(BASIC_NO_LOCAL)
151
152 def test_set_new(self):
153 conf = dsconf.LocalConf(self._path)
154 conf.set_local("a=b")
155 conf.set_local("c=d")
156 with open(self._path) as f:
157 content = f.read()
158 self.assertEqual(content, RESULT_NO_LOCAL)