#!/usr/bin/env python3
# Copyright (c) 2009, 2010 Arista Networks, Inc.  All rights reserved.
# Arista Networks, Inc. Confidential and Proprietary.

# This script will run directly on the dut, using RibdDumpParser, or
# on a test driver, using ArosTest.  We assume that if we can't import
# ArosTest then we're running on the dut.
from __future__ import absolute_import, division, print_function
try:
   import importlib
   ArosTest = importlib.import_module( 'ArosTest' )
   onDut = False
except ImportError:
   onDut = True
import RibdDumpParser
import datetime, sys, optparse # pylint: disable=deprecated-module
import Tac, signal
import GiiTestLib

op = optparse.OptionParser( prog='RibdMemoryMonitor', \
                            usage='RibdMemoryMonitor [options] [eos dut]' )
op.add_option( '-a', '--all', action='store_true',
      help='Display all allocation types, not just those used' )
op.add_option( '-o', '--once', action='store_true',
      help='Display full memory usage once' )
op.add_option( '-c', '--cumulative', action='store_true',
      help='Display deltas from first run' )
op.add_option( '-f', '--file', action='store',
      help='Parse file and display full memory usage once' )
op.add_option( '-v', '--vrf', action='store',
      help='Monitor memory for a given vrf' )
opts, args = op.parse_args( sys.argv[ 1: ] )

cumulative = opts.cumulative
signal.signal( signal.SIGINT, lambda signal, frame : sys.exit(0) )

if opts.file:
   # Not really "on dut", but "not using ArosTest"
   onDut = True

class LocalEdut( object ): # pylint: disable=useless-object-inheritance
   def __init__( self ):
      self.giiModeCmdIs = GiiTestLib.giiModeCmdIs
   # pylint: disable-msg=R0201
   def ribdDump( self ):
      return RibdDumpParser.ribdDump()

if not( onDut ): # pylint: disable=superfluous-parens
   if not args:
      dutspec = ArosTest.defaultDutspec()
   else:
      dutspec = args[ 0 ]
   dut = ArosTest.getDutExact( dutspec )
   ArosTest.ownOrElse( dut )
   if dut.isPhysicalHardware():
      edut = ArosTest.edutForDut( dut )
   else:
      edut = LocalEdut()
else:
   dut = "local system"
   edut = LocalEdut()


if opts.vrf:
   vrfName = opts.vrf
   if isinstance( edut, LocalEdut ):
      print( "Run cmd under netns, specifying vrf on local system has no effect" )
      sys.exit( 0 )
else:
   vrfName = 'default'


now = datetime.datetime.now()
if not ( opts.once or opts.file ):
   print( now, "begin monitoring ribd memory usage on", dut )
if opts.file:
   # pylint: disable-next=consider-using-with
   dump = RibdDumpParser.RibdDump( open( opts.file ).read() )
   usage = dump.memUsage()
else:
   try:
      dump = edut.giiModeCmdIs( vrfName, "show memory" )
      usage = GiiTestLib.memUsage( dump )
   # pylint: disable-msg=W0703
   except Exception as e:
      print( e )
      sys.exit( 1 )
if opts.once or opts.file:
   RibdDumpParser.printMemUsageDelta( usage, printAll=opts.all )
   sys.exit( 0 )

spinner = "|/-\\"
spinidx = 0
while True:
   # pylint: disable-next=consider-using-f-string
   sys.stdout.write( "%s\b" % spinner[ spinidx % len( spinner ) ] )
   sys.stdout.flush()
   spinidx += 1
   now = datetime.datetime.now()
   prevUsage = usage
   try:
      dump = edut.giiModeCmdIs( vrfName, "show memory" )
   # pylint: disable-msg=W0703
   except Exception as e:
      print( e )
      sys.exit( 1 )
   if dump is None:
      sys.stdout.write( "!\b" )
      sys.stdout.flush()
      continue
   curUsage = GiiTestLib.memUsage( dump )
   diff = RibdDumpParser.memUsageDelta( prevUsage, curUsage )
   RibdDumpParser.printMemUsageDelta( diff, prefix=now, printAll=opts.all )
   if not cumulative:
      usage = curUsage
