Revision 26288e68
b/lib/utils.py | ||
---|---|---|
615 | 615 |
"""Class implementing resolver and hostname functionality |
616 | 616 |
|
617 | 617 |
""" |
618 |
_VALID_NAME_RE = re.compile("^[a-z0-9._-]{1,255}$") |
|
619 |
|
|
618 | 620 |
def __init__(self, name=None): |
619 | 621 |
"""Initialize the host name object. |
620 | 622 |
|
... | ... | |
665 | 667 |
|
666 | 668 |
return result |
667 | 669 |
|
670 |
@classmethod |
|
671 |
def NormalizeName(cls, hostname): |
|
672 |
"""Validate and normalize the given hostname. |
|
673 |
|
|
674 |
@attention: the validation is a bit more relaxed than the standards |
|
675 |
require; most importantly, we allow underscores in names |
|
676 |
@raise errors.OpPrereqError: when the name is not valid |
|
677 |
|
|
678 |
""" |
|
679 |
hostname = hostname.lower() |
|
680 |
if (not cls._VALID_NAME_RE.match(hostname) or |
|
681 |
# double-dots, meaning empty label |
|
682 |
".." in hostname or |
|
683 |
# empty initial label |
|
684 |
hostname.startswith(".")): |
|
685 |
raise errors.OpPrereqError("Invalid hostname '%s'" % hostname, |
|
686 |
errors.ECODE_INVAL) |
|
687 |
if hostname.endswith("."): |
|
688 |
hostname = hostname.rstrip(".") |
|
689 |
return hostname |
|
690 |
|
|
668 | 691 |
|
669 | 692 |
def GetHostInfo(name=None): |
670 | 693 |
"""Lookup host name and raise an OpPrereqError for failures""" |
b/test/ganeti.utils_unittest.py | ||
---|---|---|
47 | 47 |
ShellQuote, ShellQuoteArgs, TcpPing, ListVisibleFiles, \ |
48 | 48 |
SetEtcHostsEntry, RemoveEtcHostsEntry, FirstFree, OwnIpAddress, \ |
49 | 49 |
TailFile, ForceDictType, SafeEncode, IsNormAbsPath, FormatTime, \ |
50 |
UnescapeAndSplit, RunParts, PathJoin |
|
50 |
UnescapeAndSplit, RunParts, PathJoin, HostInfo
|
|
51 | 51 |
|
52 | 52 |
from ganeti.errors import LockError, UnitParseError, GenericError, \ |
53 |
ProgrammerError |
|
53 |
ProgrammerError, OpPrereqError
|
|
54 | 54 |
|
55 | 55 |
|
56 | 56 |
class TestIsProcessAlive(unittest.TestCase): |
... | ... | |
1284 | 1284 |
self.failUnlessRaises(ValueError, PathJoin, "/a", "/b") |
1285 | 1285 |
|
1286 | 1286 |
|
1287 |
class TestHostInfo(unittest.TestCase): |
|
1288 |
"""Testing case for HostInfo""" |
|
1289 |
|
|
1290 |
def testUppercase(self): |
|
1291 |
data = "AbC.example.com" |
|
1292 |
self.failUnlessEqual(HostInfo.NormalizeName(data), data.lower()) |
|
1293 |
|
|
1294 |
def testTooLongName(self): |
|
1295 |
data = "a.b." + "c" * 255 |
|
1296 |
self.failUnlessRaises(OpPrereqError, HostInfo.NormalizeName, data) |
|
1297 |
|
|
1298 |
def testTrailingDot(self): |
|
1299 |
data = "a.b.c" |
|
1300 |
self.failUnlessEqual(HostInfo.NormalizeName(data + "."), data) |
|
1301 |
|
|
1302 |
def testInvalidName(self): |
|
1303 |
data = [ |
|
1304 |
"a b", |
|
1305 |
"a/b", |
|
1306 |
".a.b", |
|
1307 |
"a..b", |
|
1308 |
] |
|
1309 |
for value in data: |
|
1310 |
self.failUnlessRaises(OpPrereqError, HostInfo.NormalizeName, value) |
|
1311 |
|
|
1312 |
def testValidName(self): |
|
1313 |
data = [ |
|
1314 |
"a.b", |
|
1315 |
"a-b", |
|
1316 |
"a_b", |
|
1317 |
"a.b.c", |
|
1318 |
] |
|
1319 |
for value in data: |
|
1320 |
HostInfo.NormalizeName(value) |
|
1321 |
|
|
1322 |
|
|
1323 |
|
|
1287 | 1324 |
if __name__ == '__main__': |
1288 | 1325 |
testutils.GanetiTestProgram() |
Also available in: Unified diff