Skip to content

Commit

Permalink
[Portstat]: Add -p option to support portstat timer (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
sihuihan88 authored and jleveque committed Mar 20, 2017
1 parent 22b3d7a commit 4da9efe
Showing 1 changed file with 92 additions and 73 deletions.
165 changes: 92 additions & 73 deletions scripts/portstat
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import os.path
import re
import subprocess
import sys
import time

from collections import namedtuple, OrderedDict
from tabulate import tabulate
Expand Down Expand Up @@ -204,6 +205,68 @@ def parse_bcmcmd_ps(bcmcmd_output):
bcmcmd_lines = bcmcmd_output.split("\n")


def get_cnstat():
"""
Get the cnstat from netstat.
"""
try:
bcmcmd_output = subprocess.Popen(([BCMCMD_PATH,
'show counters changed same nz']),
stdout=subprocess.PIPE,
shell=False).communicate()[0]
except EnvironmentError as e:
print e, e.errno
sys.exit(e.errno)

bcm_dict = parse_bcmcmd_output(bcmcmd_output)

try:
netstat_out = subprocess.Popen(([NETSTAT_PATH, '-i']),
stdout=subprocess.PIPE,
shell=False).communicate()[0]
except EnvironmentError as e:
print e, e.errno
sys.exit(e.errno)

netstat_lines = netstat_out.split("\n")

# Since netstat -i returns some stats as 32-bits, get full 64-bit
# stats from /prov/net/dev and display only the 64-bit stats.
try:
proc_out = subprocess.Popen(([CAT_PATH, '/proc/net/dev']),
stdout=subprocess.PIPE,
shell=False).communicate()[0]
except EnvironmentError as e:
print e, e.errno
sys.exit(e.errno)

proc = {}
for line in proc_out.split("\n"):
parsed = re.findall("\s*([^ ]+):(.*)", line)
if not parsed:
continue
iface, stats = parsed[0]
proc[iface] = stats.split()

# Build a dictionary of the stats
cnstat_dict = OrderedDict()

cnstat_dict['time'] = datetime.datetime.now()

# We skip the first 2 lines since they contain no interface information
for i in range(2, len(netstat_lines) - 1):
netstats = netstat_lines[i].split()
if ":" in netstats[0]:
continue # Skip aliased interfaces
if ("eth" in netstats[0] or "lo" in netstats[0] or "docker" in netstats[0] or
"Vlan" in netstats[0] or "PortChannel" in netstats[0]):
continue # Skip these types of interfaces
else:
cnstat_dict.update(cnstat_create_bcm_element(i, netstats, bcm_dict[netstats[0]]))


return cnstat_dict

def cnstat_diff_print(cnstat_new_dict, cnstat_old_dict, use_json):
table = []

Expand Down Expand Up @@ -261,13 +324,15 @@ Examples:
portstat -d -t test
portstat
portstat -r
portstat -p 20
""")
parser.add_argument('-c', '--clear', action='store_true', help='Copy & clear stats')
parser.add_argument('-d', '--delete', action='store_true', help='Delete saved stats, either the uid or the specified tag')
parser.add_argument('-D', '--delete-all', action='store_true', help='Delete all saved stats')
parser.add_argument('-j', '--json', action='store_true', help='Display in JSON format')
parser.add_argument('-r', '--raw', action='store_true', help='Raw stats (unmodified output of netstat)')
parser.add_argument('-t', '--tag', type=str, help='Save stats with name TAG', default=None)
parser.add_argument('-p', '--period', type=int, help='Display stats over a specified period (in seconds).', default=0)
args = parser.parse_args()

save_fresh_stats = args.clear
Expand All @@ -277,6 +342,7 @@ Examples:
raw_stats = args.raw
tag_name = args.tag
uid = str(os.getuid())
wait_time_in_seconds = args.period

if not os.geteuid() == 0:
raise RuntimeError("must be root to run")
Expand Down Expand Up @@ -311,45 +377,13 @@ Examples:
if os.listdir(cnstat_dir) == []:
os.rmdir(cnstat_dir)
sys.exit(0)

cnstat_dict = get_cnstat()

try:
bcmcmd_output = subprocess.Popen(([BCMCMD_PATH,
'show counters changed same nz']),
stdout=subprocess.PIPE,
shell=False).communicate()[0]
except EnvironmentError as e:
print e, e.errno
sys.exit(e.errno)

bcm_dict = parse_bcmcmd_output(bcmcmd_output)

try:
netstat_out = subprocess.Popen(([NETSTAT_PATH, '-i']),
stdout=subprocess.PIPE,
shell=False).communicate()[0]
except EnvironmentError as e:
print e, e.errno
sys.exit(e.errno)

netstat_lines = netstat_out.split("\n")

# Since netstat -i returns some stats as 32-bits, get full 64-bit
# stats from /prov/net/dev and display only the 64-bit stats.
try:
proc_out = subprocess.Popen(([CAT_PATH, '/proc/net/dev']),
stdout=subprocess.PIPE,
shell=False).communicate()[0]
except EnvironmentError as e:
print e, e.errno
sys.exit(e.errno)

proc = {}
for line in proc_out.split("\n"):
parsed = re.findall("\s*([^ ]+):(.*)", line)
if not parsed:
continue
iface, stats = parsed[0]
proc[iface] = stats.split()
# Now decide what information to display
if raw_stats:
cnstat_print(cnstat_dict, use_json)
sys.exit(0)

# At this point, either we'll create a file or open an existing one.
if not os.path.exists(cnstat_dir):
Expand All @@ -359,26 +393,6 @@ Examples:
print e.errno, e
sys.exit(1)

# Build a dictionary of the stats
cnstat_dict = OrderedDict()

cnstat_dict['time'] = datetime.datetime.now()

# We skip the first 2 lines since they contain no interface information
for i in range(2, len(netstat_lines) - 1):
netstats = netstat_lines[i].split()
if ":" in netstats[0]:
continue # Skip aliased interfaces
if ("eth" in netstats[0] or "lo" in netstats[0] or "docker" in netstats[0] or
"Vlan" in netstats[0] or "PortChannel" in netstats[0]):
continue # Skip these types of interfaces
else:
cnstat_dict.update(cnstat_create_bcm_element(i, netstats, bcm_dict[netstats[0]]))

# Now decide what information to display
if raw_stats:
cnstat_print(cnstat_dict, use_json)
sys.exit(0)

if save_fresh_stats:
try:
Expand All @@ -388,20 +402,25 @@ Examples:
else:
print "Cleared counters"
sys.exit(0)

cnstat_cached_dict = OrderedDict()

if os.path.isfile(cnstat_fqn_file):
try:
cnstat_cached_dict = pickle.load(open(cnstat_fqn_file, 'r'))
print "Last cached time was " + str(cnstat_cached_dict.get('time'))
cnstat_diff_print(cnstat_dict, cnstat_cached_dict, use_json)
except IOError as e:
print e.errno, e
else:
if tag_name:
print "\nFile '%s' does not exist" % cnstat_fqn_file
print "Did you run 'portstat -c -t %s' to record the counters via tag %s?\n" % (tag_name, tag_name)

if wait_time_in_seconds == 0:
cnstat_cached_dict = OrderedDict()
if os.path.isfile(cnstat_fqn_file):
try:
cnstat_cached_dict = pickle.load(open(cnstat_fqn_file, 'r'))
print "Last cached time was " + str(cnstat_cached_dict.get('time'))
cnstat_diff_print(cnstat_dict, cnstat_cached_dict, use_json)
except IOError as e:
print e.errno, e
else:
cnstat_print(cnstat_dict, use_json)
if tag_name:
print "\nFile '%s' does not exist" % cnstat_fqn_file
print "Did you run 'portstat -c -t %s' to record the counters via tag %s?\n" % (tag_name, tag_name)
else:
cnstat_print(cnstat_dict, use_json)
else:
#wait for the specified time and then gather the new stats and output the difference.
time.sleep(wait_time_in_seconds)
cnstat_new_dict = get_cnstat()
cnstat_diff_print(cnstat_new_dict, cnstat_dict, use_json)

0 comments on commit 4da9efe

Please sign in to comment.