Change in vdsm[master]: configfile utility for common config file editing operations.
mtayer at redhat.com
mtayer at redhat.com
Mon Apr 28 08:06:57 UTC 2014
mooli tayer has uploaded a new change for review.
Change subject: configfile utility for common config file editing operations.
......................................................................
configfile utility for common config file editing operations.
Add utility to edit config files that is backward compatible
with libvirt_configure.sh. Support for common operations used
by vdsm tool. Context managed and commits file upon __exit__
by replacing original file with a temporary file.
Change-Id: If8c7ae2b562650e403fc39024f3531d44b2b9c4f
Signed-off-by: Mooli Tayer <mtayer at redhat.com>
---
A lib/vdsm/tool/configfile.py
M tests/toolTests.py
2 files changed, 199 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/29/27129/1
diff --git a/lib/vdsm/tool/configfile.py b/lib/vdsm/tool/configfile.py
new file mode 100644
index 0000000..c008def
--- /dev/null
+++ b/lib/vdsm/tool/configfile.py
@@ -0,0 +1,132 @@
+# Copyright 2013 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+import os
+import tempfile
+import re
+import selinux
+
+
+class ConfigFile(object):
+
+ def __init__(self, filename, confstart=None, confend=None):
+ self.filename = filename
+ self.context = OUT
+ if confstart is None or confend is None:
+ raise RuntimeError("argument missing")
+ self.confstart = confstart
+ self.confend = confend
+
+ def __enter__(self):
+ if self.context == IN:
+ raise RuntimeError("Internal error")
+ self.entries = {}
+ self.context = IN
+ self.prefix = None
+ self.section = None
+ self.oldmod = os.stat(self.filename).st_mode
+ self.remove = None
+ self.rmstate = BEFORE
+ return self
+
+ def getOldContent(self):
+ confpat = re.compile(r'^\s*([^=\s]*)\s*=')
+ oldlines = []
+ oldentries = set()
+ with open(self.filename, 'r') as f:
+ for line in f:
+ if self.remove:
+ if self.rmstate == BEFORE and\
+ line.startswith(self.confstart):
+ self.rmstate = WITHIN
+ elif self.rmstate == WITHIN and\
+ line.startswith(self.confend):
+ self.rmstate = AFTER
+ continue
+ if not self.remove or self.rmstate != WITHIN:
+ m = confpat.match(line.rstrip())
+ if m:
+ oldentries.add(m.group(1))
+ if self.prefix:
+ line = self.prefix + line
+ oldlines.append(line)
+ return oldlines, oldentries
+
+ def __exit__(self, exec_ty, exec_val, tb):
+
+ self.context = OUT
+ if exec_ty is None:
+ fd, tname = tempfile.mkstemp(dir=os.path.dirname(self.filename))
+ oldlines, oldentries = self.getOldContent()
+ with os.fdopen(fd, 'w') as f:
+ if self.section:
+ f.write(self.confstart)
+ f.write(self.section)
+ f.write(self.confend)
+ f.writelines(oldlines)
+ if self.entries:
+ f.write(self.confstart)
+ for key, val in self.entries.iteritems():
+ if key not in oldentries:
+ f.write("{k}={v}\n".format(k=key, v=val))
+ f.write(self.confend)
+ os.rename(tname, self.filename)
+ if self.oldmod != os.stat(self.filename).st_mode:
+ os.chmod(self.filename, self.oldmod)
+ if selinux.is_selinux_enabled:
+ try:
+ selinux.restorecon(self.filename)
+ except OSError:
+ pass # No default label for file
+
+ def addEntry(self, key, val):
+ """
+ add key=value unless key is already in the file.
+ """
+ if self.context == IN:
+ self.entries[key] = val
+ else:
+ raise RuntimeError("Internal error")
+
+ def prependSection(self, section):
+ """
+ add 'section' in the beginning of the file.
+ section is wrapped with confstart and confend.
+ Only one section is currently allowed.
+ """
+ if self.context == IN:
+ self.section = section
+ else:
+ raise RuntimeError("Internal error")
+
+ def prefixLines(self, prefix):
+ """
+ prefix each line originaly included in the file (not including
+ 'prependedSection' lines) with 'prefix'.
+ """
+ if self.context == IN:
+ self.prefix = prefix
+ else:
+ raise RuntimeError("Internal error")
+
+ def removeConf(self):
+ if self.context == IN:
+ self.remove = True
+ else:
+ raise RuntimeError("Internal error")
diff --git a/tests/toolTests.py b/tests/toolTests.py
index 2fc8c61..1ce5a27 100644
--- a/tests/toolTests.py
+++ b/tests/toolTests.py
@@ -18,6 +18,7 @@
# Refer to the README and COPYING files for full details of the license
#
from vdsm.tool import configurator
+from vdsm.tool.configfile import ConfigFile
from vdsm import utils
import monkeypatch
from unittest import TestCase
@@ -174,3 +175,69 @@
self.assertFalse(libvirtConfigure.isconfigured())
libvirtConfigure.configure()
self.assertTrue(libvirtConfigure.isconfigured())
+
+
+class ConfigFileTests(TestCase):
+ def setUp(self):
+ fd, self.tname = tempfile.mkstemp()
+
+ def tearDown(self):
+ os.remove(self.tname)
+
+ # helper function
+ def writeConf(self, text):
+ with open(self.tname, 'w') as f:
+ f.write(text)
+
+ def testAddExistingConf(self):
+ self.writeConf("key1=val1\n"
+ " key2 =val2\n")
+ conf_file = ConfigFile(self.tname,
+ confstart="# start conf-3.4.4\n",
+ confend="# end conf-3.4.4\n")
+ with conf_file as conf:
+ conf.addEntry("key3", "val3")
+ conf.addEntry("key2", "val3")
+ with open(self.tname, 'r') as f:
+
+ self.assertEqual(f.read(), "key1=val1\n"
+ " key2 =val2\n"
+ "# start conf-3.4.4\n"
+ "key3=val3\n"
+ "# end conf-3.4.4\n")
+
+ def testPrefixAndPrepend(self):
+ self.writeConf("/var/log/libvirt/libvirtd.log {\n"
+ " weekly\n"
+ "}\n")
+ conf_file = ConfigFile(self.tname,
+ confstart='# start conf-3.4.4\n',
+ confend="# end conf-3.4.4\n")
+ with conf_file as conf:
+ conf.prefixLines("# comment ")
+ conf.prependSection("Some text to\n"
+ "add at the top\n")
+ with open(self.tname, 'r') as f:
+ self.assertEqual(f.read(),
+ "# start conf-3.4.4\n"
+ "Some text to\n"
+ "add at the top\n"
+ "# end conf-3.4.4\n"
+ "# comment /var/log/libvirt/libvirtd.log {\n"
+ "# comment weekly\n"
+ "# comment }\n")
+
+ def testRemoveConfSection(self):
+ self.writeConf("key=val\n"
+ "kay=val\n"
+ "# start conf-text-here don't matter\n"
+ "all you sections are belong to us\n"
+ "# end conf-text-here don't matter\n")
+ conf_file = ConfigFile(self.tname,
+ confstart="# start conf",
+ confend="# end conf")
+ with conf_file as conf:
+ conf.removeConf()
+ with open(self.tname, 'r') as f:
+ self.assertEqual(f.read(), "key=val\n"
+ "kay=val\n")
--
To view, visit http://gerrit.ovirt.org/27129
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: If8c7ae2b562650e403fc39024f3531d44b2b9c4f
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: mooli tayer <mtayer at redhat.com>
More information about the vdsm-patches
mailing list