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