From 2c30e9d709c444390223f96d37304bdbedc080c2 Mon Sep 17 00:00:00 2001 From: Alexander Schreiber <als@google.com> Date: Mon, 17 Sep 2007 11:18:49 +0000 Subject: [PATCH] Added TcpPing to do ping-alike via TCP connect(2) with defined source address. To be used to replace the currently fping(8) based reachability test. Reviewed-by: imsnah --- lib/utils.py | 35 ++++++++++++++++++++- test/ganeti.utils_unittest.py | 57 ++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/lib/utils.py b/lib/utils.py index b43570f6b..3f2864658 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -32,7 +32,7 @@ import re import socket import tempfile import shutil -from errno import ENOENT, ENOTDIR, EISDIR, EEXIST +from errno import ENOENT, ENOTDIR, EISDIR, EEXIST, EADDRNOTAVAIL, ECONNREFUSED from ganeti import logger from ganeti import errors @@ -786,3 +786,36 @@ def GetLocalIPAddresses(): " output: %s" % (result.cmd, result.fail_reason, result.output)) return _ParseIpOutput(result.output) + + +def TcpPing(source, target, port, timeout=10, live_port_needed=True): + """Simple ping implementation using TCP connect(2). + + Try to do a TCP connect(2) from the specified source IP to the specified + target IP and the specified target port. If live_port_needed is set to true, + requires the remote end to accept the connection. The timeout is specified + in seconds and defaults to 10 seconds + + """ + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + sucess = False + + try: + sock.bind((source, 0)) + except socket.error, (errcode, errstring): + if errcode == EADDRNOTAVAIL: + success = False + + sock.settimeout(timeout) + + try: + sock.connect((target, port)) + sock.close() + success = True + except socket.timeout: + success = False + except socket.error, (errcode, errstring): + success = (not live_port_needed) and (errcode == ECONNREFUSED) + + return success diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py index 285c7fff5..388cb44bd 100755 --- a/test/ganeti.utils_unittest.py +++ b/test/ganeti.utils_unittest.py @@ -27,14 +27,17 @@ import time import tempfile import os.path import md5 +import socket +from errno import EADDRNOTAVAIL import ganeti from ganeti.utils import IsProcessAlive, Lock, Unlock, RunCmd, \ RemoveFile, CheckDict, MatchNameComponent, FormatUnit, \ ParseUnit, AddAuthorizedKey, RemoveAuthorizedKey, \ - ShellQuote, ShellQuoteArgs, _ParseIpOutput + ShellQuote, ShellQuoteArgs, _ParseIpOutput, TcpPing from ganeti.errors import LockError, UnitParseError + class TestIsProcessAlive(unittest.TestCase): """Testing case for IsProcessAlive""" def setUp(self): @@ -467,5 +470,57 @@ class TestIpAdressList(unittest.TestCase): self._test(output, ['127.0.0.1', '10.0.0.1', '1.2.3.4']) +class TestTcpPing(unittest.TestCase): + """Testcase for TCP version of ping - against listen(2)ing port""" + + def setUp(self): + self.listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.listener.bind(("127.0.0.1", 0)) + self.listenerport = self.listener.getsockname()[1] + self.listener.listen(1) + + def tearDown(self): + self.listener.shutdown(socket.SHUT_RDWR) + del self.listener + del self.listenerport + + def testTcpPingToLocalHostAccept(self): + self.assert_(TcpPing("127.0.0.1", + "127.0.0.1", + self.listenerport, + timeout=10, + live_port_needed=True), + "failed to connect to test listener") + + +class TestTcpPingDeaf(unittest.TestCase): + """Testcase for TCP version of ping - against non listen(2)ing port""" + + def setUp(self): + self.deaflistener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.deaflistener.bind(("127.0.0.1", 0)) + self.deaflistenerport = self.deaflistener.getsockname()[1] + + def tearDown(self): + del self.deaflistener + del self.deaflistenerport + + def testTcpPingToLocalHostAcceptDeaf(self): + self.failIf(TcpPing("127.0.0.1", + "127.0.0.1", + self.deaflistenerport, + timeout=10, # timeout for blocking operations + live_port_needed=True), # need successful connect(2) + "successfully connected to deaf listener") + + def testTcpPingToLocalHostNoAccept(self): + self.assert_(TcpPing("127.0.0.1", + "127.0.0.1", + self.deaflistenerport, + timeout=10, # timeout for blocking operations + live_port_needed=False), # ECONNREFUSED is OK + "failed to ping alive host on deaf port") + + if __name__ == '__main__': unittest.main() -- GitLab