Files
opencafe/cafe/engine/clients/ping.py
Christopher Hunt 333812211a 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
2016-02-23 15:35:20 -06:00

126 lines
4.7 KiB
Python

# Copyright 2015 Rackspace
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import platform
import re
import subprocess
class PingClient(object):
"""
@summary: Client to ping windows or linux servers
"""
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, num_pings=DEFAULT_NUM_PINGS):
"""
@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 windows in os_type
else cls.PING_IPV4_COMMAND_LINUX)
ping_ipv6 = (cls.PING_IPV6_COMMAND_WINDOWS if windows in os_type
else cls.PING_IPV6_COMMAND_LINUX)
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:
# 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