Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Portstat]: Add -p option to support portstat timer #16

Merged
merged 4 commits into from
Mar 20, 2017
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 96 additions & 78 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,76 @@ def parse_bcmcmd_ps(bcmcmd_output):
bcmcmd_lines = bcmcmd_output.split("\n")


def get_cnstat(cnstat_dir):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it does not look the cnstat_dir is really used in this function, can you remove this argument?

"""
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()

# At this point, either we'll create a file or open an existing one.
if not os.path.exists(cnstat_dir):
try:
os.makedirs(cnstat_dir)
except IOError as e:
print e.errno, e
sys.exit(1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here you only create a folder, but you do not use it anyway in the function. what's the purpose here? should we move it to some where else?


# 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 +332,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='Get the portstat within Period seconds', default=0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the help message clearer. Something like, "Display stats over a specified period (in seconds)."

args = parser.parse_args()

save_fresh_stats = args.clear
Expand All @@ -277,6 +350,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,69 +385,8 @@ Examples:
if os.listdir(cnstat_dir) == []:
os.rmdir(cnstat_dir)
sys.exit(0)

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()

# At this point, either we'll create a file or open an existing one.
if not os.path.exists(cnstat_dir):
try:
os.makedirs(cnstat_dir)
except IOError as e:
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]]))

cnstat_dict = get_cnstat(cnstat_dir)

# Now decide what information to display
if raw_stats:
Expand All @@ -388,20 +401,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 sometime and output the result
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"# Wait for the specified duration then gather new stats and output the difference"

time.sleep(wait_time_in_seconds)
cnstat_new_dict = get_cnstat(cnstat_dir)
cnstat_diff_print(cnstat_new_dict, cnstat_dict, use_json)