Revision 17b97ab3

b/Makefile.am
219 219
	lib/utils/io.py \
220 220
	lib/utils/log.py \
221 221
	lib/utils/mlock.py \
222
	lib/utils/nodesetup.py \
222 223
	lib/utils/retry.py \
223 224
	lib/utils/text.py \
224 225
	lib/utils/wrapper.py \
......
493 494
	test/ganeti.utils.hash_unittest.py \
494 495
	test/ganeti.utils.io_unittest.py \
495 496
	test/ganeti.utils.mlock_unittest.py \
497
	test/ganeti.utils.nodesetup_unittest.py \
496 498
	test/ganeti.utils.retry_unittest.py \
497 499
	test/ganeti.utils.text_unittest.py \
498 500
	test/ganeti.utils.wrapper_unittest.py \
b/lib/utils/__init__.py
62 62
from ganeti.utils.filelock import * # pylint: disable-msg=W0401
63 63
from ganeti.utils.io import * # pylint: disable-msg=W0401
64 64
from ganeti.utils.x509 import * # pylint: disable-msg=W0401
65
from ganeti.utils.nodesetup import * # pylint: disable-msg=W0401
65 66

  
66 67

  
67 68
#: when set to True, L{RunCmd} is disabled
......
1076 1077
  return cpu_list
1077 1078

  
1078 1079

  
1079
def SetEtcHostsEntry(file_name, ip, hostname, aliases):
1080
  """Sets the name of an IP address and hostname in /etc/hosts.
1081

  
1082
  @type file_name: str
1083
  @param file_name: path to the file to modify (usually C{/etc/hosts})
1084
  @type ip: str
1085
  @param ip: the IP address
1086
  @type hostname: str
1087
  @param hostname: the hostname to be added
1088
  @type aliases: list
1089
  @param aliases: the list of aliases to add for the hostname
1090

  
1091
  """
1092
  # Ensure aliases are unique
1093
  aliases = UniqueSequence([hostname] + aliases)[1:]
1094

  
1095
  def _WriteEtcHosts(fd):
1096
    # Duplicating file descriptor because os.fdopen's result will automatically
1097
    # close the descriptor, but we would still like to have its functionality.
1098
    out = os.fdopen(os.dup(fd), "w")
1099
    try:
1100
      for line in ReadFile(file_name).splitlines(True):
1101
        fields = line.split()
1102
        if fields and not fields[0].startswith("#") and ip == fields[0]:
1103
          continue
1104
        out.write(line)
1105

  
1106
      out.write("%s\t%s" % (ip, hostname))
1107
      if aliases:
1108
        out.write(" %s" % " ".join(aliases))
1109
      out.write("\n")
1110
      out.flush()
1111
    finally:
1112
      out.close()
1113

  
1114
  WriteFile(file_name, fn=_WriteEtcHosts, mode=0644)
1115

  
1116

  
1117
def AddHostToEtcHosts(hostname, ip):
1118
  """Wrapper around SetEtcHostsEntry.
1119

  
1120
  @type hostname: str
1121
  @param hostname: a hostname that will be resolved and added to
1122
      L{constants.ETC_HOSTS}
1123
  @type ip: str
1124
  @param ip: The ip address of the host
1125

  
1126
  """
1127
  SetEtcHostsEntry(constants.ETC_HOSTS, ip, hostname, [hostname.split(".")[0]])
1128

  
1129

  
1130
def RemoveEtcHostsEntry(file_name, hostname):
1131
  """Removes a hostname from /etc/hosts.
1132

  
1133
  IP addresses without names are removed from the file.
1134

  
1135
  @type file_name: str
1136
  @param file_name: path to the file to modify (usually C{/etc/hosts})
1137
  @type hostname: str
1138
  @param hostname: the hostname to be removed
1139

  
1140
  """
1141
  def _WriteEtcHosts(fd):
1142
    # Duplicating file descriptor because os.fdopen's result will automatically
1143
    # close the descriptor, but we would still like to have its functionality.
1144
    out = os.fdopen(os.dup(fd), "w")
1145
    try:
1146
      for line in ReadFile(file_name).splitlines(True):
1147
        fields = line.split()
1148
        if len(fields) > 1 and not fields[0].startswith("#"):
1149
          names = fields[1:]
1150
          if hostname in names:
1151
            while hostname in names:
1152
              names.remove(hostname)
1153
            if names:
1154
              out.write("%s %s\n" % (fields[0], " ".join(names)))
1155
            continue
1156

  
1157
        out.write(line)
1158

  
1159
      out.flush()
1160
    finally:
1161
      out.close()
1162

  
1163
  WriteFile(file_name, fn=_WriteEtcHosts, mode=0644)
1164

  
1165

  
1166
def RemoveHostFromEtcHosts(hostname):
1167
  """Wrapper around RemoveEtcHostsEntry.
1168

  
1169
  @type hostname: str
1170
  @param hostname: hostname that will be resolved and its
1171
      full and shot name will be removed from
1172
      L{constants.ETC_HOSTS}
1173

  
1174
  """
1175
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hostname)
1176
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hostname.split(".")[0])
1177

  
1178

  
1179 1080
def GetHomeDir(user, default=None):
1180 1081
  """Try to get the homedir of the given user.
1181 1082

  
b/lib/utils/nodesetup.py
1
#
2
#
3

  
4
# Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21
"""Utility functions for manipulating /etc/hosts.
22

  
23
"""
24

  
25
import os
26

  
27
from ganeti import constants
28

  
29
from ganeti.utils import algo
30
from ganeti.utils import io
31

  
32

  
33
def SetEtcHostsEntry(file_name, ip, hostname, aliases):
34
  """Sets the name of an IP address and hostname in /etc/hosts.
35

  
36
  @type file_name: str
37
  @param file_name: path to the file to modify (usually C{/etc/hosts})
38
  @type ip: str
39
  @param ip: the IP address
40
  @type hostname: str
41
  @param hostname: the hostname to be added
42
  @type aliases: list
43
  @param aliases: the list of aliases to add for the hostname
44

  
45
  """
46
  # Ensure aliases are unique
47
  aliases = algo.UniqueSequence([hostname] + aliases)[1:]
48

  
49
  def _WriteEtcHosts(fd):
50
    # Duplicating file descriptor because os.fdopen's result will automatically
51
    # close the descriptor, but we would still like to have its functionality.
52
    out = os.fdopen(os.dup(fd), "w")
53
    try:
54
      for line in io.ReadFile(file_name).splitlines(True):
55
        fields = line.split()
56
        if fields and not fields[0].startswith("#") and ip == fields[0]:
57
          continue
58
        out.write(line)
59

  
60
      out.write("%s\t%s" % (ip, hostname))
61
      if aliases:
62
        out.write(" %s" % " ".join(aliases))
63
      out.write("\n")
64
      out.flush()
65
    finally:
66
      out.close()
67

  
68
  io.WriteFile(file_name, fn=_WriteEtcHosts, mode=0644)
69

  
70

  
71
def AddHostToEtcHosts(hostname, ip):
72
  """Wrapper around SetEtcHostsEntry.
73

  
74
  @type hostname: str
75
  @param hostname: a hostname that will be resolved and added to
76
      L{constants.ETC_HOSTS}
77
  @type ip: str
78
  @param ip: The ip address of the host
79

  
80
  """
81
  SetEtcHostsEntry(constants.ETC_HOSTS, ip, hostname, [hostname.split(".")[0]])
82

  
83

  
84
def RemoveEtcHostsEntry(file_name, hostname):
85
  """Removes a hostname from /etc/hosts.
86

  
87
  IP addresses without names are removed from the file.
88

  
89
  @type file_name: str
90
  @param file_name: path to the file to modify (usually C{/etc/hosts})
91
  @type hostname: str
92
  @param hostname: the hostname to be removed
93

  
94
  """
95
  def _WriteEtcHosts(fd):
96
    # Duplicating file descriptor because os.fdopen's result will automatically
97
    # close the descriptor, but we would still like to have its functionality.
98
    out = os.fdopen(os.dup(fd), "w")
99
    try:
100
      for line in io.ReadFile(file_name).splitlines(True):
101
        fields = line.split()
102
        if len(fields) > 1 and not fields[0].startswith("#"):
103
          names = fields[1:]
104
          if hostname in names:
105
            while hostname in names:
106
              names.remove(hostname)
107
            if names:
108
              out.write("%s %s\n" % (fields[0], " ".join(names)))
109
            continue
110

  
111
        out.write(line)
112

  
113
      out.flush()
114
    finally:
115
      out.close()
116

  
117
  io.WriteFile(file_name, fn=_WriteEtcHosts, mode=0644)
118

  
119

  
120
def RemoveHostFromEtcHosts(hostname):
121
  """Wrapper around RemoveEtcHostsEntry.
122

  
123
  @type hostname: str
124
  @param hostname: hostname that will be resolved and its
125
      full and shot name will be removed from
126
      L{constants.ETC_HOSTS}
127

  
128
  """
129
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hostname)
130
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hostname.split(".")[0])
b/test/ganeti.utils.nodesetup_unittest.py
1
#!/usr/bin/python
2
#
3

  
4
# Copyright (C) 2006, 2007, 2010 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21

  
22
"""Script for testing ganeti.utils.nodesetup"""
23

  
24
import os
25
import tempfile
26
import unittest
27

  
28
from ganeti import constants
29
from ganeti import utils
30

  
31
import testutils
32

  
33

  
34
class TestEtcHosts(testutils.GanetiTestCase):
35
  """Test functions modifying /etc/hosts"""
36

  
37
  def setUp(self):
38
    testutils.GanetiTestCase.setUp(self)
39
    self.tmpname = self._CreateTempFile()
40
    handle = open(self.tmpname, "w")
41
    try:
42
      handle.write("# This is a test file for /etc/hosts\n")
43
      handle.write("127.0.0.1\tlocalhost\n")
44
      handle.write("192.0.2.1 router gw\n")
45
    finally:
46
      handle.close()
47

  
48
  def testSettingNewIp(self):
49
    utils.SetEtcHostsEntry(self.tmpname, "198.51.100.4", "myhost.example.com",
50
                           ["myhost"])
51

  
52
    self.assertFileContent(self.tmpname,
53
      "# This is a test file for /etc/hosts\n"
54
      "127.0.0.1\tlocalhost\n"
55
      "192.0.2.1 router gw\n"
56
      "198.51.100.4\tmyhost.example.com myhost\n")
57
    self.assertFileMode(self.tmpname, 0644)
58

  
59
  def testSettingExistingIp(self):
60
    utils.SetEtcHostsEntry(self.tmpname, "192.0.2.1", "myhost.example.com",
61
                           ["myhost"])
62

  
63
    self.assertFileContent(self.tmpname,
64
      "# This is a test file for /etc/hosts\n"
65
      "127.0.0.1\tlocalhost\n"
66
      "192.0.2.1\tmyhost.example.com myhost\n")
67
    self.assertFileMode(self.tmpname, 0644)
68

  
69
  def testSettingDuplicateName(self):
70
    utils.SetEtcHostsEntry(self.tmpname, "198.51.100.4", "myhost", ["myhost"])
71

  
72
    self.assertFileContent(self.tmpname,
73
      "# This is a test file for /etc/hosts\n"
74
      "127.0.0.1\tlocalhost\n"
75
      "192.0.2.1 router gw\n"
76
      "198.51.100.4\tmyhost\n")
77
    self.assertFileMode(self.tmpname, 0644)
78

  
79
  def testRemovingExistingHost(self):
80
    utils.RemoveEtcHostsEntry(self.tmpname, "router")
81

  
82
    self.assertFileContent(self.tmpname,
83
      "# This is a test file for /etc/hosts\n"
84
      "127.0.0.1\tlocalhost\n"
85
      "192.0.2.1 gw\n")
86
    self.assertFileMode(self.tmpname, 0644)
87

  
88
  def testRemovingSingleExistingHost(self):
89
    utils.RemoveEtcHostsEntry(self.tmpname, "localhost")
90

  
91
    self.assertFileContent(self.tmpname,
92
      "# This is a test file for /etc/hosts\n"
93
      "192.0.2.1 router gw\n")
94
    self.assertFileMode(self.tmpname, 0644)
95

  
96
  def testRemovingNonExistingHost(self):
97
    utils.RemoveEtcHostsEntry(self.tmpname, "myhost")
98

  
99
    self.assertFileContent(self.tmpname,
100
      "# This is a test file for /etc/hosts\n"
101
      "127.0.0.1\tlocalhost\n"
102
      "192.0.2.1 router gw\n")
103
    self.assertFileMode(self.tmpname, 0644)
104

  
105
  def testRemovingAlias(self):
106
    utils.RemoveEtcHostsEntry(self.tmpname, "gw")
107

  
108
    self.assertFileContent(self.tmpname,
109
      "# This is a test file for /etc/hosts\n"
110
      "127.0.0.1\tlocalhost\n"
111
      "192.0.2.1 router\n")
112
    self.assertFileMode(self.tmpname, 0644)
113

  
114

  
115
if __name__ == "__main__":
116
  testutils.GanetiTestProgram()
b/test/ganeti.utils_unittest.py
45 45
from ganeti import errors
46 46
from ganeti.utils import RunCmd, \
47 47
     FirstFree, \
48
     RunParts, \
49
     SetEtcHostsEntry, RemoveEtcHostsEntry
48
     RunParts
50 49

  
51 50

  
52 51
class TestIsProcessAlive(unittest.TestCase):
......
575 574
      self.assertRaises(errors.ParseError, utils.ParseCpuMask, data)
576 575

  
577 576

  
578
class TestEtcHosts(testutils.GanetiTestCase):
579
  """Test functions modifying /etc/hosts"""
580

  
581
  def setUp(self):
582
    testutils.GanetiTestCase.setUp(self)
583
    self.tmpname = self._CreateTempFile()
584
    handle = open(self.tmpname, 'w')
585
    try:
586
      handle.write('# This is a test file for /etc/hosts\n')
587
      handle.write('127.0.0.1\tlocalhost\n')
588
      handle.write('192.0.2.1 router gw\n')
589
    finally:
590
      handle.close()
591

  
592
  def testSettingNewIp(self):
593
    SetEtcHostsEntry(self.tmpname, '198.51.100.4', 'myhost.example.com',
594
                     ['myhost'])
595

  
596
    self.assertFileContent(self.tmpname,
597
      "# This is a test file for /etc/hosts\n"
598
      "127.0.0.1\tlocalhost\n"
599
      "192.0.2.1 router gw\n"
600
      "198.51.100.4\tmyhost.example.com myhost\n")
601
    self.assertFileMode(self.tmpname, 0644)
602

  
603
  def testSettingExistingIp(self):
604
    SetEtcHostsEntry(self.tmpname, '192.0.2.1', 'myhost.example.com',
605
                     ['myhost'])
606

  
607
    self.assertFileContent(self.tmpname,
608
      "# This is a test file for /etc/hosts\n"
609
      "127.0.0.1\tlocalhost\n"
610
      "192.0.2.1\tmyhost.example.com myhost\n")
611
    self.assertFileMode(self.tmpname, 0644)
612

  
613
  def testSettingDuplicateName(self):
614
    SetEtcHostsEntry(self.tmpname, '198.51.100.4', 'myhost', ['myhost'])
615

  
616
    self.assertFileContent(self.tmpname,
617
      "# This is a test file for /etc/hosts\n"
618
      "127.0.0.1\tlocalhost\n"
619
      "192.0.2.1 router gw\n"
620
      "198.51.100.4\tmyhost\n")
621
    self.assertFileMode(self.tmpname, 0644)
622

  
623
  def testRemovingExistingHost(self):
624
    RemoveEtcHostsEntry(self.tmpname, 'router')
625

  
626
    self.assertFileContent(self.tmpname,
627
      "# This is a test file for /etc/hosts\n"
628
      "127.0.0.1\tlocalhost\n"
629
      "192.0.2.1 gw\n")
630
    self.assertFileMode(self.tmpname, 0644)
631

  
632
  def testRemovingSingleExistingHost(self):
633
    RemoveEtcHostsEntry(self.tmpname, 'localhost')
634

  
635
    self.assertFileContent(self.tmpname,
636
      "# This is a test file for /etc/hosts\n"
637
      "192.0.2.1 router gw\n")
638
    self.assertFileMode(self.tmpname, 0644)
639

  
640
  def testRemovingNonExistingHost(self):
641
    RemoveEtcHostsEntry(self.tmpname, 'myhost')
642

  
643
    self.assertFileContent(self.tmpname,
644
      "# This is a test file for /etc/hosts\n"
645
      "127.0.0.1\tlocalhost\n"
646
      "192.0.2.1 router gw\n")
647
    self.assertFileMode(self.tmpname, 0644)
648

  
649
  def testRemovingAlias(self):
650
    RemoveEtcHostsEntry(self.tmpname, 'gw')
651

  
652
    self.assertFileContent(self.tmpname,
653
      "# This is a test file for /etc/hosts\n"
654
      "127.0.0.1\tlocalhost\n"
655
      "192.0.2.1 router\n")
656
    self.assertFileMode(self.tmpname, 0644)
657

  
658

  
659 577
class TestGetMounts(unittest.TestCase):
660 578
  """Test case for GetMounts()."""
661 579

  

Also available in: Unified diff