From 899d2a818c6936a2f23cb262172afe7ce4f1461c Mon Sep 17 00:00:00 2001
From: Michael Hanselmann <hansmi@google.com>
Date: Fri, 9 Nov 2007 14:53:53 +0000
Subject: [PATCH] Add functions to modify /etc/hosts.

Reviewed-by: schreiberal
---
 lib/utils.py                  | 63 +++++++++++++++++++++++++
 test/ganeti.utils_unittest.py | 89 ++++++++++++++++++++++++++++++++++-
 2 files changed, 151 insertions(+), 1 deletion(-)

diff --git a/lib/utils.py b/lib/utils.py
index 0022569f9..dfdd059a3 100644
--- a/lib/utils.py
+++ b/lib/utils.py
@@ -20,6 +20,7 @@
 
 
 """Ganeti small utilities
+
 """
 
 
@@ -745,6 +746,68 @@ def RemoveAuthorizedKey(file_name, key):
     raise
 
 
+def AddEtcHostsEntry(file_name, hostname, ip):
+  """
+
+  """
+  f = open(file_name, 'a+')
+  try:
+    nl = True
+    for line in f:
+      fields = line.split()
+      if len(fields) < 2 or fields[0].startswith('#'):
+        continue
+      if fields[0] == ip and hostname in fields[1:]:
+        break
+      nl = line.endswith('\n')
+    else:
+      if not nl:
+        f.write("\n")
+      f.write(ip)
+      f.write(' ')
+      f.write(hostname)
+      f.write("\n")
+      f.flush()
+  finally:
+    f.close()
+
+
+def RemoveEtcHostsEntry(file_name, hostname):
+  """
+
+  """
+  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
+  try:
+    out = os.fdopen(fd, 'w')
+    try:
+      f = open(file_name, 'r')
+      try:
+        for line in f:
+          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(fields[0])
+                out.write(' ')
+                out.write(' '.join(names))
+              continue
+
+          out.write(line)
+
+        out.flush()
+        os.rename(tmpname, file_name)
+      finally:
+        f.close()
+    finally:
+      out.close()
+  except:
+    RemoveFile(tmpname)
+    raise
+
+
 def CreateBackup(file_name):
   """Creates a backup of a file.
 
diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py
index 22c0cc40b..ab9956a33 100755
--- a/test/ganeti.utils_unittest.py
+++ b/test/ganeti.utils_unittest.py
@@ -37,7 +37,8 @@ from ganeti import utils
 from ganeti.utils import IsProcessAlive, Lock, Unlock, RunCmd, \
      RemoveFile, CheckDict, MatchNameComponent, FormatUnit, \
      ParseUnit, AddAuthorizedKey, RemoveAuthorizedKey, \
-     ShellQuote, ShellQuoteArgs, TcpPing, ListVisibleFiles
+     ShellQuote, ShellQuoteArgs, TcpPing, ListVisibleFiles, \
+     AddEtcHostsEntry, RemoveEtcHostsEntry
 from ganeti.errors import LockError, UnitParseError
 
 
@@ -431,6 +432,92 @@ class TestSshKeys(unittest.TestCase):
       os.unlink(tmpname)
 
 
+class TestEtcHosts(unittest.TestCase):
+  """Test functions modifying /etc/hosts"""
+
+  def writeTestFile(self):
+    (fd, tmpname) = tempfile.mkstemp(prefix = 'ganeti-test')
+    f = os.fdopen(fd, 'w')
+    try:
+      f.write('# This is a test file for /etc/hosts\n')
+      f.write('127.0.0.1\tlocalhost\n')
+      f.write('192.168.1.1 router gw\n')
+    finally:
+      f.close()
+
+    return tmpname
+
+  def testAddingNewIp(self):
+    tmpname = self.writeTestFile()
+    try:
+      AddEtcHostsEntry(tmpname, 'myhost.domain.tld', '1.2.3.4')
+
+      f = open(tmpname, 'r')
+      try:
+        self.assertEqual(md5.new(f.read(8192)).hexdigest(),
+                         '00e0e88250482e7449743c89a49e9349')
+      finally:
+        f.close()
+    finally:
+      os.unlink(tmpname)
+
+  def testAddingExistingIp(self):
+    tmpname = self.writeTestFile()
+    try:
+      AddEtcHostsEntry(tmpname, 'myhost.domain.tld', '192.168.1.1')
+
+      f = open(tmpname, 'r')
+      try:
+        self.assertEqual(md5.new(f.read(8192)).hexdigest(),
+                         '4dc04c0acdd247175e0b980c6beea822')
+      finally:
+        f.close()
+    finally:
+      os.unlink(tmpname)
+
+  def testRemovingExistingHost(self):
+    tmpname = self.writeTestFile()
+    try:
+      RemoveEtcHostsEntry(tmpname, 'router')
+
+      f = open(tmpname, 'r')
+      try:
+        self.assertEqual(md5.new(f.read(8192)).hexdigest(),
+                         '7d1e7a559eedbc25e0dff67d33ccac84')
+      finally:
+        f.close()
+    finally:
+      os.unlink(tmpname)
+
+  def testRemovingSingleExistingHost(self):
+    tmpname = self.writeTestFile()
+    try:
+      RemoveEtcHostsEntry(tmpname, 'localhost')
+
+      f = open(tmpname, 'r')
+      try:
+        self.assertEqual(md5.new(f.read(8192)).hexdigest(),
+                         'ec4e4589b56f82fdb88db5675de011b1')
+      finally:
+        f.close()
+    finally:
+      os.unlink(tmpname)
+
+  def testRemovingNonExistingHost(self):
+    tmpname = self.writeTestFile()
+    try:
+      RemoveEtcHostsEntry(tmpname, 'myhost')
+
+      f = open(tmpname, 'r')
+      try:
+        self.assertEqual(md5.new(f.read(8192)).hexdigest(),
+                         'aa005bddc6d9ee399c296953f194929e')
+      finally:
+        f.close()
+    finally:
+      os.unlink(tmpname)
+
+
 class TestShellQuoting(unittest.TestCase):
   """Test case for shell quoting functions"""
 
-- 
GitLab