commit c8a0948f2e864c310a6e2a52c03fd8df4033237a
Author: Michael Hanselmann <hansmi@google.com>
Date:   Fri Nov 9 14:54:29 2007 +0000

    Use new functions to modify /etc/hosts.
    
    Reviewed-by: schreiberal

diff --git a/lib/backend.py b/lib/backend.py
index ac84801..5e1d70e 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -122,7 +122,6 @@ def LeaveCluster():
       if os.path.isfile(full_name) and not os.path.islink(full_name):
         utils.RemoveFile(full_name)
 
-
   try:
     priv_key, pub_key, auth_keys = ssh.GetUserFiles(constants.GANETI_RUNAS)
   except errors.OpExecError, err:
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 117fd92..3cb1156 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -163,6 +163,15 @@ class NoHooksLU(LogicalUnit):
     return {}, [], []
 
 
+def _RemoveHostFromEtcHosts(hostname):
+  """Wrapper around utils.RemoteEtcHostsEntry.
+
+  """
+  hi = utils.HostInfo(name=hostname)
+  utils.RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.name)
+  utils.RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.ShortName())
+
+
 def _GetWantedNodes(lu, nodes):
   """Returns list of checked and expanded node names.
 
@@ -285,86 +294,6 @@ def _BuildInstanceHookEnvByObject(instance, override=None):
   return _BuildInstanceHookEnv(**args)
 
 
-def _UpdateEtcHosts(fullnode, ip):
-  """Ensure a node has a correct entry in /etc/hosts.
-
-  Args:
-    fullnode - Fully qualified domain name of host. (str)
-    ip       - IPv4 address of host (str)
-
-  """
-  node = fullnode.split(".", 1)[0]
-
-  f = open('/etc/hosts', 'r+')
-
-  inthere = False
-
-  save_lines = []
-  add_lines = []
-  removed = False
-
-  while True:
-    rawline = f.readline()
-
-    if not rawline:
-      # End of file
-      break
-
-    line = rawline.split('\n')[0]
-
-    # Strip off comments
-    line = line.split('#')[0]
-
-    if not line:
-      # Entire line was comment, skip
-      save_lines.append(rawline)
-      continue
-
-    fields = line.split()
-
-    haveall = True
-    havesome = False
-    for spec in [ ip, fullnode, node ]:
-      if spec not in fields:
-        haveall = False
-      if spec in fields:
-        havesome = True
-
-    if haveall:
-      inthere = True
-      save_lines.append(rawline)
-      continue
-
-    if havesome and not haveall:
-      # Line (old, or manual?) which is missing some.  Remove.
-      removed = True
-      continue
-
-    save_lines.append(rawline)
-
-  if not inthere:
-    add_lines.append('%s\t%s %s\n' % (ip, fullnode, node))
-
-  if removed:
-    if add_lines:
-      save_lines = save_lines + add_lines
-
-    # We removed a line, write a new file and replace old.
-    fd, tmpname = tempfile.mkstemp('tmp', 'hosts_', '/etc')
-    newfile = os.fdopen(fd, 'w')
-    newfile.write(''.join(save_lines))
-    newfile.close()
-    os.rename(tmpname, '/etc/hosts')
-
-  elif add_lines:
-    # Simply appending a new line will do the trick.
-    f.seek(0, 2)
-    for add in add_lines:
-      f.write(add)
-
-  f.close()
-
-
 def _UpdateKnownHosts(fullnode, ip, pubkey):
   """Ensure a node has a correct known_hosts entry.
 
@@ -645,7 +574,10 @@ class LUInitCluster(LogicalUnit):
       f.close()
     sshkey = sshline.split(" ")[1]
 
-    _UpdateEtcHosts(hostname.name, hostname.ip)
+    hi = utils.HostInfo(name=hostname.name)
+    utils.AddEtcHostsEntry(constants.ETC_HOSTS, hostname.name, hi.ip)
+    utils.AddEtcHostsEntry(constants.ETC_HOSTS, hi.ShortName(), hi.ip)
+    del hi
 
     _UpdateKnownHosts(hostname.name, hostname.ip, sshkey)
 
@@ -687,10 +619,12 @@ class LUDestroyCluster(NoHooksLU):
     """Destroys the cluster.
 
     """
+    master = self.sstore.GetMasterNode()
     priv_key, pub_key, _ = ssh.GetUserFiles(constants.GANETI_RUNAS)
     utils.CreateBackup(priv_key)
     utils.CreateBackup(pub_key)
-    rpc.call_node_leave_cluster(self.sstore.GetMasterNode())
+    rpc.call_node_leave_cluster(master)
+    _RemoveHostFromEtcHosts(master)
 
 
 class LUVerifyCluster(NoHooksLU):
@@ -1205,6 +1139,8 @@ class LURemoveNode(LogicalUnit):
 
     self.cfg.RemoveNode(node.name)
 
+    _RemoveHostFromEtcHosts(node.name)
+
 
 class LUQueryNodes(NoHooksLU):
   """Logical unit for querying nodes.
@@ -1548,7 +1484,11 @@ class LUAddNode(LogicalUnit):
       raise errors.OpExecError("Cannot transfer ssh keys to the new node")
 
     # Add node to our /etc/hosts, and add key to known_hosts
-    _UpdateEtcHosts(new_node.name, new_node.primary_ip)
+    hi = utils.HostInfo(name=new_node.name)
+    utils.AddEtcHostsEntry(constants.ETC_HOSTS, new_node.name, hi.ip)
+    utils.AddEtcHostsEntry(constants.ETC_HOSTS, hi.ShortName(), hi.ip)
+    del hi
+
     _UpdateKnownHosts(new_node.name, new_node.primary_ip,
                       self.cfg.GetHostKey())
 
diff --git a/lib/constants.py b/lib/constants.py
index 7de4890..b09c2ad 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -38,6 +38,7 @@ CLUSTER_CONF_FILE = DATA_DIR + "/config.data"
 SSL_CERT_FILE = DATA_DIR + "/server.pem"
 WATCHER_STATEFILE = DATA_DIR + "/watcher.data"
 SSH_KNOWN_HOSTS_FILE = DATA_DIR + "/known_hosts"
+ETC_HOSTS = "/etc/hosts"
 
 NODE_INITD_SCRIPT = _autoconf.SYSCONFDIR + "/init.d/ganeti"
 DEFAULT_NODED_PORT = 1811
diff --git a/lib/utils.py b/lib/utils.py
index dfdd059..2d1b208 100644
--- a/lib/utils.py
+++ b/lib/utils.py
@@ -418,6 +418,12 @@ class HostInfo:
     self.name, self.aliases, self.ipaddrs = self.LookupHostname(name)
     self.ip = self.ipaddrs[0]
 
+  def ShortName(self):
+    """Returns the hostname without domain.
+
+    """
+    return self.name.split('.')[0]
+
   @staticmethod
   def SysName():
     """Return the current system's name.
