From 17b97ab3d27b766e64b8868019b7914c97d08fe1 Mon Sep 17 00:00:00 2001
From: Michael Hanselmann <hansmi@google.com>
Date: Tue, 11 Jan 2011 16:01:48 +0100
Subject: [PATCH] utils: Move code manipulating /etc/hosts to separate file

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 Makefile.am                             |   2 +
 lib/utils/__init__.py                   | 101 +-----------------
 lib/utils/nodesetup.py                  | 130 ++++++++++++++++++++++++
 test/ganeti.utils.nodesetup_unittest.py | 116 +++++++++++++++++++++
 test/ganeti.utils_unittest.py           |  84 +--------------
 5 files changed, 250 insertions(+), 183 deletions(-)
 create mode 100644 lib/utils/nodesetup.py
 create mode 100755 test/ganeti.utils.nodesetup_unittest.py

diff --git a/Makefile.am b/Makefile.am
index 9f261b434..35c0a20c0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -219,6 +219,7 @@ utils_PYTHON = \
 	lib/utils/io.py \
 	lib/utils/log.py \
 	lib/utils/mlock.py \
+	lib/utils/nodesetup.py \
 	lib/utils/retry.py \
 	lib/utils/text.py \
 	lib/utils/wrapper.py \
@@ -493,6 +494,7 @@ python_tests = \
 	test/ganeti.utils.hash_unittest.py \
 	test/ganeti.utils.io_unittest.py \
 	test/ganeti.utils.mlock_unittest.py \
+	test/ganeti.utils.nodesetup_unittest.py \
 	test/ganeti.utils.retry_unittest.py \
 	test/ganeti.utils.text_unittest.py \
 	test/ganeti.utils.wrapper_unittest.py \
diff --git a/lib/utils/__init__.py b/lib/utils/__init__.py
index 582b4ef49..23d8a25be 100644
--- a/lib/utils/__init__.py
+++ b/lib/utils/__init__.py
@@ -62,6 +62,7 @@ from ganeti.utils.wrapper import * # pylint: disable-msg=W0401
 from ganeti.utils.filelock import * # pylint: disable-msg=W0401
 from ganeti.utils.io import * # pylint: disable-msg=W0401
 from ganeti.utils.x509 import * # pylint: disable-msg=W0401
+from ganeti.utils.nodesetup import * # pylint: disable-msg=W0401
 
 
 #: when set to True, L{RunCmd} is disabled
@@ -1076,106 +1077,6 @@ def ParseCpuMask(cpu_mask):
   return cpu_list
 
 
-def SetEtcHostsEntry(file_name, ip, hostname, aliases):
-  """Sets the name of an IP address and hostname in /etc/hosts.
-
-  @type file_name: str
-  @param file_name: path to the file to modify (usually C{/etc/hosts})
-  @type ip: str
-  @param ip: the IP address
-  @type hostname: str
-  @param hostname: the hostname to be added
-  @type aliases: list
-  @param aliases: the list of aliases to add for the hostname
-
-  """
-  # Ensure aliases are unique
-  aliases = UniqueSequence([hostname] + aliases)[1:]
-
-  def _WriteEtcHosts(fd):
-    # Duplicating file descriptor because os.fdopen's result will automatically
-    # close the descriptor, but we would still like to have its functionality.
-    out = os.fdopen(os.dup(fd), "w")
-    try:
-      for line in ReadFile(file_name).splitlines(True):
-        fields = line.split()
-        if fields and not fields[0].startswith("#") and ip == fields[0]:
-          continue
-        out.write(line)
-
-      out.write("%s\t%s" % (ip, hostname))
-      if aliases:
-        out.write(" %s" % " ".join(aliases))
-      out.write("\n")
-      out.flush()
-    finally:
-      out.close()
-
-  WriteFile(file_name, fn=_WriteEtcHosts, mode=0644)
-
-
-def AddHostToEtcHosts(hostname, ip):
-  """Wrapper around SetEtcHostsEntry.
-
-  @type hostname: str
-  @param hostname: a hostname that will be resolved and added to
-      L{constants.ETC_HOSTS}
-  @type ip: str
-  @param ip: The ip address of the host
-
-  """
-  SetEtcHostsEntry(constants.ETC_HOSTS, ip, hostname, [hostname.split(".")[0]])
-
-
-def RemoveEtcHostsEntry(file_name, hostname):
-  """Removes a hostname from /etc/hosts.
-
-  IP addresses without names are removed from the file.
-
-  @type file_name: str
-  @param file_name: path to the file to modify (usually C{/etc/hosts})
-  @type hostname: str
-  @param hostname: the hostname to be removed
-
-  """
-  def _WriteEtcHosts(fd):
-    # Duplicating file descriptor because os.fdopen's result will automatically
-    # close the descriptor, but we would still like to have its functionality.
-    out = os.fdopen(os.dup(fd), "w")
-    try:
-      for line in ReadFile(file_name).splitlines(True):
-        fields = line.split()
-        if len(fields) > 1 and not fields[0].startswith("#"):
-          names = fields[1:]
-          if hostname in names:
-            while hostname in names:
-              names.remove(hostname)
-            if names:
-              out.write("%s %s\n" % (fields[0], " ".join(names)))
-            continue
-
-        out.write(line)
-
-      out.flush()
-    finally:
-      out.close()
-
-  WriteFile(file_name, fn=_WriteEtcHosts, mode=0644)
-
-
-def RemoveHostFromEtcHosts(hostname):
-  """Wrapper around RemoveEtcHostsEntry.
-
-  @type hostname: str
-  @param hostname: hostname that will be resolved and its
-      full and shot name will be removed from
-      L{constants.ETC_HOSTS}
-
-  """
-  RemoveEtcHostsEntry(constants.ETC_HOSTS, hostname)
-  RemoveEtcHostsEntry(constants.ETC_HOSTS, hostname.split(".")[0])
-
-
 def GetHomeDir(user, default=None):
   """Try to get the homedir of the given user.
 
diff --git a/lib/utils/nodesetup.py b/lib/utils/nodesetup.py
new file mode 100644
index 000000000..80e2b9807
--- /dev/null
+++ b/lib/utils/nodesetup.py
@@ -0,0 +1,130 @@
+#
+#
+
+# Copyright (C) 2006, 2007, 2010, 2011 Google 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.
+
+"""Utility functions for manipulating /etc/hosts.
+
+"""
+
+import os
+
+from ganeti import constants
+
+from ganeti.utils import algo
+from ganeti.utils import io
+
+
+def SetEtcHostsEntry(file_name, ip, hostname, aliases):
+  """Sets the name of an IP address and hostname in /etc/hosts.
+
+  @type file_name: str
+  @param file_name: path to the file to modify (usually C{/etc/hosts})
+  @type ip: str
+  @param ip: the IP address
+  @type hostname: str
+  @param hostname: the hostname to be added
+  @type aliases: list
+  @param aliases: the list of aliases to add for the hostname
+
+  """
+  # Ensure aliases are unique
+  aliases = algo.UniqueSequence([hostname] + aliases)[1:]
+
+  def _WriteEtcHosts(fd):
+    # Duplicating file descriptor because os.fdopen's result will automatically
+    # close the descriptor, but we would still like to have its functionality.
+    out = os.fdopen(os.dup(fd), "w")
+    try:
+      for line in io.ReadFile(file_name).splitlines(True):
+        fields = line.split()
+        if fields and not fields[0].startswith("#") and ip == fields[0]:
+          continue
+        out.write(line)
+
+      out.write("%s\t%s" % (ip, hostname))
+      if aliases:
+        out.write(" %s" % " ".join(aliases))
+      out.write("\n")
+      out.flush()
+    finally:
+      out.close()
+
+  io.WriteFile(file_name, fn=_WriteEtcHosts, mode=0644)
+
+
+def AddHostToEtcHosts(hostname, ip):
+  """Wrapper around SetEtcHostsEntry.
+
+  @type hostname: str
+  @param hostname: a hostname that will be resolved and added to
+      L{constants.ETC_HOSTS}
+  @type ip: str
+  @param ip: The ip address of the host
+
+  """
+  SetEtcHostsEntry(constants.ETC_HOSTS, ip, hostname, [hostname.split(".")[0]])
+
+
+def RemoveEtcHostsEntry(file_name, hostname):
+  """Removes a hostname from /etc/hosts.
+
+  IP addresses without names are removed from the file.
+
+  @type file_name: str
+  @param file_name: path to the file to modify (usually C{/etc/hosts})
+  @type hostname: str
+  @param hostname: the hostname to be removed
+
+  """
+  def _WriteEtcHosts(fd):
+    # Duplicating file descriptor because os.fdopen's result will automatically
+    # close the descriptor, but we would still like to have its functionality.
+    out = os.fdopen(os.dup(fd), "w")
+    try:
+      for line in io.ReadFile(file_name).splitlines(True):
+        fields = line.split()
+        if len(fields) > 1 and not fields[0].startswith("#"):
+          names = fields[1:]
+          if hostname in names:
+            while hostname in names:
+              names.remove(hostname)
+            if names:
+              out.write("%s %s\n" % (fields[0], " ".join(names)))
+            continue
+
+        out.write(line)
+
+      out.flush()
+    finally:
+      out.close()
+
+  io.WriteFile(file_name, fn=_WriteEtcHosts, mode=0644)
+
+
+def RemoveHostFromEtcHosts(hostname):
+  """Wrapper around RemoveEtcHostsEntry.
+
+  @type hostname: str
+  @param hostname: hostname that will be resolved and its
+      full and shot name will be removed from
+      L{constants.ETC_HOSTS}
+
+  """
+  RemoveEtcHostsEntry(constants.ETC_HOSTS, hostname)
+  RemoveEtcHostsEntry(constants.ETC_HOSTS, hostname.split(".")[0])
diff --git a/test/ganeti.utils.nodesetup_unittest.py b/test/ganeti.utils.nodesetup_unittest.py
new file mode 100755
index 000000000..3d386a465
--- /dev/null
+++ b/test/ganeti.utils.nodesetup_unittest.py
@@ -0,0 +1,116 @@
+#!/usr/bin/python
+#
+
+# Copyright (C) 2006, 2007, 2010 Google 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.
+
+
+"""Script for testing ganeti.utils.nodesetup"""
+
+import os
+import tempfile
+import unittest
+
+from ganeti import constants
+from ganeti import utils
+
+import testutils
+
+
+class TestEtcHosts(testutils.GanetiTestCase):
+  """Test functions modifying /etc/hosts"""
+
+  def setUp(self):
+    testutils.GanetiTestCase.setUp(self)
+    self.tmpname = self._CreateTempFile()
+    handle = open(self.tmpname, "w")
+    try:
+      handle.write("# This is a test file for /etc/hosts\n")
+      handle.write("127.0.0.1\tlocalhost\n")
+      handle.write("192.0.2.1 router gw\n")
+    finally:
+      handle.close()
+
+  def testSettingNewIp(self):
+    utils.SetEtcHostsEntry(self.tmpname, "198.51.100.4", "myhost.example.com",
+                           ["myhost"])
+
+    self.assertFileContent(self.tmpname,
+      "# This is a test file for /etc/hosts\n"
+      "127.0.0.1\tlocalhost\n"
+      "192.0.2.1 router gw\n"
+      "198.51.100.4\tmyhost.example.com myhost\n")
+    self.assertFileMode(self.tmpname, 0644)
+
+  def testSettingExistingIp(self):
+    utils.SetEtcHostsEntry(self.tmpname, "192.0.2.1", "myhost.example.com",
+                           ["myhost"])
+
+    self.assertFileContent(self.tmpname,
+      "# This is a test file for /etc/hosts\n"
+      "127.0.0.1\tlocalhost\n"
+      "192.0.2.1\tmyhost.example.com myhost\n")
+    self.assertFileMode(self.tmpname, 0644)
+
+  def testSettingDuplicateName(self):
+    utils.SetEtcHostsEntry(self.tmpname, "198.51.100.4", "myhost", ["myhost"])
+
+    self.assertFileContent(self.tmpname,
+      "# This is a test file for /etc/hosts\n"
+      "127.0.0.1\tlocalhost\n"
+      "192.0.2.1 router gw\n"
+      "198.51.100.4\tmyhost\n")
+    self.assertFileMode(self.tmpname, 0644)
+
+  def testRemovingExistingHost(self):
+    utils.RemoveEtcHostsEntry(self.tmpname, "router")
+
+    self.assertFileContent(self.tmpname,
+      "# This is a test file for /etc/hosts\n"
+      "127.0.0.1\tlocalhost\n"
+      "192.0.2.1 gw\n")
+    self.assertFileMode(self.tmpname, 0644)
+
+  def testRemovingSingleExistingHost(self):
+    utils.RemoveEtcHostsEntry(self.tmpname, "localhost")
+
+    self.assertFileContent(self.tmpname,
+      "# This is a test file for /etc/hosts\n"
+      "192.0.2.1 router gw\n")
+    self.assertFileMode(self.tmpname, 0644)
+
+  def testRemovingNonExistingHost(self):
+    utils.RemoveEtcHostsEntry(self.tmpname, "myhost")
+
+    self.assertFileContent(self.tmpname,
+      "# This is a test file for /etc/hosts\n"
+      "127.0.0.1\tlocalhost\n"
+      "192.0.2.1 router gw\n")
+    self.assertFileMode(self.tmpname, 0644)
+
+  def testRemovingAlias(self):
+    utils.RemoveEtcHostsEntry(self.tmpname, "gw")
+
+    self.assertFileContent(self.tmpname,
+      "# This is a test file for /etc/hosts\n"
+      "127.0.0.1\tlocalhost\n"
+      "192.0.2.1 router\n")
+    self.assertFileMode(self.tmpname, 0644)
+
+
+if __name__ == "__main__":
+  testutils.GanetiTestProgram()
diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py
index 1d5805767..ea136f3b5 100755
--- a/test/ganeti.utils_unittest.py
+++ b/test/ganeti.utils_unittest.py
@@ -45,8 +45,7 @@ from ganeti import utils
 from ganeti import errors
 from ganeti.utils import RunCmd, \
      FirstFree, \
-     RunParts, \
-     SetEtcHostsEntry, RemoveEtcHostsEntry
+     RunParts
 
 
 class TestIsProcessAlive(unittest.TestCase):
@@ -575,87 +574,6 @@ class TestParseCpuMask(unittest.TestCase):
       self.assertRaises(errors.ParseError, utils.ParseCpuMask, data)
 
 
-class TestEtcHosts(testutils.GanetiTestCase):
-  """Test functions modifying /etc/hosts"""
-
-  def setUp(self):
-    testutils.GanetiTestCase.setUp(self)
-    self.tmpname = self._CreateTempFile()
-    handle = open(self.tmpname, 'w')
-    try:
-      handle.write('# This is a test file for /etc/hosts\n')
-      handle.write('127.0.0.1\tlocalhost\n')
-      handle.write('192.0.2.1 router gw\n')
-    finally:
-      handle.close()
-
-  def testSettingNewIp(self):
-    SetEtcHostsEntry(self.tmpname, '198.51.100.4', 'myhost.example.com',
-                     ['myhost'])
-
-    self.assertFileContent(self.tmpname,
-      "# This is a test file for /etc/hosts\n"
-      "127.0.0.1\tlocalhost\n"
-      "192.0.2.1 router gw\n"
-      "198.51.100.4\tmyhost.example.com myhost\n")
-    self.assertFileMode(self.tmpname, 0644)
-
-  def testSettingExistingIp(self):
-    SetEtcHostsEntry(self.tmpname, '192.0.2.1', 'myhost.example.com',
-                     ['myhost'])
-
-    self.assertFileContent(self.tmpname,
-      "# This is a test file for /etc/hosts\n"
-      "127.0.0.1\tlocalhost\n"
-      "192.0.2.1\tmyhost.example.com myhost\n")
-    self.assertFileMode(self.tmpname, 0644)
-
-  def testSettingDuplicateName(self):
-    SetEtcHostsEntry(self.tmpname, '198.51.100.4', 'myhost', ['myhost'])
-
-    self.assertFileContent(self.tmpname,
-      "# This is a test file for /etc/hosts\n"
-      "127.0.0.1\tlocalhost\n"
-      "192.0.2.1 router gw\n"
-      "198.51.100.4\tmyhost\n")
-    self.assertFileMode(self.tmpname, 0644)
-
-  def testRemovingExistingHost(self):
-    RemoveEtcHostsEntry(self.tmpname, 'router')
-
-    self.assertFileContent(self.tmpname,
-      "# This is a test file for /etc/hosts\n"
-      "127.0.0.1\tlocalhost\n"
-      "192.0.2.1 gw\n")
-    self.assertFileMode(self.tmpname, 0644)
-
-  def testRemovingSingleExistingHost(self):
-    RemoveEtcHostsEntry(self.tmpname, 'localhost')
-
-    self.assertFileContent(self.tmpname,
-      "# This is a test file for /etc/hosts\n"
-      "192.0.2.1 router gw\n")
-    self.assertFileMode(self.tmpname, 0644)
-
-  def testRemovingNonExistingHost(self):
-    RemoveEtcHostsEntry(self.tmpname, 'myhost')
-
-    self.assertFileContent(self.tmpname,
-      "# This is a test file for /etc/hosts\n"
-      "127.0.0.1\tlocalhost\n"
-      "192.0.2.1 router gw\n")
-    self.assertFileMode(self.tmpname, 0644)
-
-  def testRemovingAlias(self):
-    RemoveEtcHostsEntry(self.tmpname, 'gw')
-
-    self.assertFileContent(self.tmpname,
-      "# This is a test file for /etc/hosts\n"
-      "127.0.0.1\tlocalhost\n"
-      "192.0.2.1 router\n")
-    self.assertFileMode(self.tmpname, 0644)
-
-
 class TestGetMounts(unittest.TestCase):
   """Test case for GetMounts()."""
 
-- 
GitLab