diff --git a/lib/cmdlib.py b/lib/cmdlib.py index f338da5f9c31b775fc05d0dad3aa027a0a99a2b8..ae9a30288c06e37a61773de99435f9d45c702af9 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -163,8 +163,16 @@ class NoHooksLU(LogicalUnit): return {}, [], [] +def _AddHostToEtcHosts(hostname): + """Wrapper around utils.SetEtcHostsEntry. + + """ + hi = utils.HostInfo(name=hostname) + utils.SetEtcHostsEntry(constants.ETC_HOSTS, hi.ip, hi.name, [hi.ShortName()]) + + def _RemoveHostFromEtcHosts(hostname): - """Wrapper around utils.RemoteEtcHostsEntry. + """Wrapper around utils.RemoveEtcHostsEntry. """ hi = utils.HostInfo(name=hostname) @@ -574,10 +582,7 @@ class LUInitCluster(LogicalUnit): f.close() sshkey = sshline.split(" ")[1] - 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 + _AddHostToEtcHosts(hostname.name) _UpdateKnownHosts(hostname.name, hostname.ip, sshkey) @@ -1484,10 +1489,7 @@ 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 - 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 + _AddHostToEtcHosts(new_node.name) _UpdateKnownHosts(new_node.name, new_node.primary_ip, self.cfg.GetHostKey()) diff --git a/lib/utils.py b/lib/utils.py index a71cd1f92b8db241437d797df6034bfb8c24b692..193fde8123ad4d24a5d3d167025417936575e4be 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -752,36 +752,43 @@ def RemoveAuthorizedKey(file_name, key): raise -def AddEtcHostsEntry(file_name, hostname, ip): - """Adds an IP address and hostname to /etc/hosts. +def SetEtcHostsEntry(file_name, ip, hostname, aliases): + """Sets the name of an IP address and hostname in /etc/hosts. """ - f = open(file_name, 'a+') + fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name)) 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() + out = os.fdopen(fd, 'w') + try: + f = open(file_name, 'r') + try: + written = False + for line in f: + fields = line.split() + if not fields[0].startswith('#') and ip == fields[0]: + continue + out.write(line) + + out.write("%s %s" % (ip, hostname)) + if aliases: + out.write(" %s" % ' '.join(aliases)) + out.write('\n') + + out.flush() + os.rename(tmpname, file_name) + finally: + f.close() + finally: + out.close() + except: + RemoveFile(tmpname) + raise def RemoveEtcHostsEntry(file_name, hostname): """Removes a hostname from /etc/hosts. - IP addresses without hostnames are removed from the file. + IP addresses without names are removed from the file. """ fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name)) try: @@ -797,9 +804,7 @@ def RemoveEtcHostsEntry(file_name, hostname): while hostname in names: names.remove(hostname) if names: - out.write(fields[0]) - out.write(' ') - out.write(' '.join(names)) + out.write("%s %s\n" % (fields[0], ' '.join(names))) continue out.write(line) diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py index ab9956a330887a6432fdd2e2e3dd256375e80820..99b57dd6dfaa53d718b1e98bedd65c4ba4033f80 100755 --- a/test/ganeti.utils_unittest.py +++ b/test/ganeti.utils_unittest.py @@ -38,7 +38,7 @@ from ganeti.utils import IsProcessAlive, Lock, Unlock, RunCmd, \ RemoveFile, CheckDict, MatchNameComponent, FormatUnit, \ ParseUnit, AddAuthorizedKey, RemoveAuthorizedKey, \ ShellQuote, ShellQuoteArgs, TcpPing, ListVisibleFiles, \ - AddEtcHostsEntry, RemoveEtcHostsEntry + SetEtcHostsEntry, RemoveEtcHostsEntry from ganeti.errors import LockError, UnitParseError @@ -447,29 +447,29 @@ class TestEtcHosts(unittest.TestCase): return tmpname - def testAddingNewIp(self): + def testSettingNewIp(self): tmpname = self.writeTestFile() try: - AddEtcHostsEntry(tmpname, 'myhost.domain.tld', '1.2.3.4') + SetEtcHostsEntry(tmpname, '1.2.3.4', 'myhost.domain.tld', ['myhost']) f = open(tmpname, 'r') try: self.assertEqual(md5.new(f.read(8192)).hexdigest(), - '00e0e88250482e7449743c89a49e9349') + '410c141dcafffd505f662a41713d2eab') finally: f.close() finally: os.unlink(tmpname) - def testAddingExistingIp(self): + def testSettingExistingIp(self): tmpname = self.writeTestFile() try: - AddEtcHostsEntry(tmpname, 'myhost.domain.tld', '192.168.1.1') + SetEtcHostsEntry(tmpname, '192.168.1.1', 'myhost.domain.tld', ['myhost']) f = open(tmpname, 'r') try: self.assertEqual(md5.new(f.read(8192)).hexdigest(), - '4dc04c0acdd247175e0b980c6beea822') + 'bbf60c542dec949f3968b59522ec0d7b') finally: f.close() finally: @@ -483,7 +483,7 @@ class TestEtcHosts(unittest.TestCase): f = open(tmpname, 'r') try: self.assertEqual(md5.new(f.read(8192)).hexdigest(), - '7d1e7a559eedbc25e0dff67d33ccac84') + '8b09207a23709d60240674601a3548b2') finally: f.close() finally: @@ -517,6 +517,20 @@ class TestEtcHosts(unittest.TestCase): finally: os.unlink(tmpname) + def testRemovingAlias(self): + tmpname = self.writeTestFile() + try: + RemoveEtcHostsEntry(tmpname, 'gw') + + f = open(tmpname, 'r') + try: + self.assertEqual(md5.new(f.read(8192)).hexdigest(), + '156dd3980a17b2ef934e2d0bf670aca2') + finally: + f.close() + finally: + os.unlink(tmpname) + class TestShellQuoting(unittest.TestCase): """Test case for shell quoting functions"""