Basic Ping Client Rework

* Added ability to specify number of pings to be transmitted
* Abstracted ping logic to return "percent of pings requests not responded". The logic was not reworked,
  and stayed the same for now... (could be reworked, but currently out of scope for current need).
* Added wrapper functions to return different information:
   ping() - returns True/False --> Same as original ping() command (for backwards compatability)
   ping_percent_loss() --> Returns percent of (missing replies)/requests
   ping_percent_success() --> Returns percent of (received replies)/requests

Change-Id: If242fd02dde3642372c6c5e1f3e117a38e51c1d7
This commit is contained in:
Christopher Hunt 2016-02-23 15:06:26 -06:00
parent af6c42498b
commit 333812211a
1 changed files with 83 additions and 16 deletions

View File

@ -21,38 +21,105 @@ class PingClient(object):
@summary: Client to ping windows or linux servers
"""
PING_IPV4_COMMAND_LINUX = 'ping -c 3'
PING_IPV6_COMMAND_LINUX = 'ping6 -c 3'
PING_IPV4_COMMAND_WINDOWS = 'ping'
PING_IPV6_COMMAND_WINDOWS = 'ping -6'
DEFAULT_NUM_PINGS = 3
PING_IPV4_COMMAND_LINUX = 'ping -c {num_pings}'
PING_IPV6_COMMAND_LINUX = 'ping6 -c {num_pings}'
PING_IPV4_COMMAND_WINDOWS = 'ping -c {num_pings}'
PING_IPV6_COMMAND_WINDOWS = 'ping -6 -c {num_pings}'
PING_PACKET_LOSS_REGEX = '(\d{1,3})\.?\d*\%.*loss'
@classmethod
def ping(cls, ip, ip_address_version):
def ping(cls, ip, ip_address_version, num_pings=DEFAULT_NUM_PINGS):
"""
@summary: Ping a server with a IP
@summary: Ping an IP address, return if replies were received or not.
@param ip: IP address to ping
@type ip: string
@param ip_address_version: IP Address version (4 or 6)
@type ip_address_version: int
@param num_pings: Number of pings to attempt
@type num_pings: int
@return: True if the server was reachable, False otherwise
@rtype: bool
"""
packet_loss_percent = cls._ping(
ip=ip, ip_address_version=ip_address_version, num_pings=num_pings)
return packet_loss_percent != '100'
@classmethod
def ping_percent_success(cls, ip, ip_address_version,
num_pings=DEFAULT_NUM_PINGS):
"""
@summary: Ping an IP address, return the percent of replies received
@param ip: IP address to ping
@type ip: string
@param ip_address_version: IP Address version (4 or 6)
@type ip_address_version: int
@param num_pings: Number of pings to attempt
@type num_pings: int
@return: Percent of responses received, based on number of requests
@rtype: int
"""
packet_loss_percent = cls._ping(
ip=ip, ip_address_version=ip_address_version, num_pings=num_pings)
return 100 - int(packet_loss_percent)
@classmethod
def ping_percent_loss(cls, ip, ip_address_version,
num_pings=DEFAULT_NUM_PINGS):
"""
@summary: Ping an IP address, return the percent of replies not
returned
@param ip: IP address to ping
@type ip: string
@param ip_address_version: IP Address version (4 or 6)
@type ip_address_version: int
@param num_pings: Number of pings to attempt
@type num_pings: int
@return: Percent of responses not received, based on number of requests
@rtype: int
"""
return int(cls._ping(
ip=ip, ip_address_version=ip_address_version, num_pings=num_pings))
@classmethod
def _ping(cls, ip, ip_address_version, num_pings):
"""
@summary: Ping an IP address
@param ip: IP address to ping
@type ip: string
@param ip_address_version: IP Address version (4 or 6)
@type ip_address_version: int
@param num_pings: Number of pings to attempt
@type num_pings: int
@return: Percent of ping replies received
@rtype: int
"""
windows = 'windows'
os_type = platform.system().lower()
ping_ipv4 = (cls.PING_IPV4_COMMAND_WINDOWS if os_type == 'windows'
ping_ipv4 = (cls.PING_IPV4_COMMAND_WINDOWS if windows in os_type
else cls.PING_IPV4_COMMAND_LINUX)
ping_ipv6 = (cls.PING_IPV6_COMMAND_WINDOWS if os_type == 'windows'
ping_ipv6 = (cls.PING_IPV6_COMMAND_WINDOWS if windows in os_type
else cls.PING_IPV6_COMMAND_LINUX)
ping_command = ping_ipv6 if ip_address_version == 6 else ping_ipv4
command = '{command} {address}'.format(
command=ping_command, address=ip)
process = subprocess.Popen(command, shell=True,
stdout=subprocess.PIPE)
ping_cmd = ping_ipv6 if ip_address_version == 6 else ping_ipv4
ping_cmd = ping_cmd.format(num_pings=num_pings)
cmd = '{command} {address}'.format(command=ping_cmd, address=ip)
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
process.wait()
try:
packet_loss_percent = re.search(
cls.PING_PACKET_LOSS_REGEX,
process.stdout.read()).group(1)
except Exception:
# If there is no match, fail
return False
return packet_loss_percent != '100'
# When there is no match, 100% ping loss is the best response
# (for now). There has to be a better way, since the regex not
# matching does not guarantee that the target IP is not online.
# e.g. - The ping utility was not available/located in the path or
# the expected ping output changed.
packet_loss_percent = 100
return packet_loss_percent