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

import argparse
import os
import socket
import sys

import AgentDirectory
import CliCommon
import Tac

def parseArgs():
   parser = argparse.ArgumentParser()
   parser.add_argument( '-s', '--sysname', action='store',
                        default=os.environ.get( 'SYSNAME','ar' ),
                        # pylint: disable-next=consider-using-f-string
                        help='system name (default: %s)' %
                             os.environ.get( 'SYSNAME', 'ar' ) )
   parser.add_argument( '-p', '--print-state', action='store_true', default=False,
                        help='Print the state of the CliServer' )
   parser.add_argument( '-c', '--print-child-state', action='store_true',
                        default=False,
                        help='Print the stack of child processes' )
   return parser.parse_args()

def isChildProcess( pid, ppid ):
   # check if it's a child of our main pid
   ppid = str( ppid )
   try:
      with open( f"/proc/{pid}/status" ) as f:
         for line in f:
            fields = line.split()
            if len( fields ) == 2 and fields[ 0 ] == 'PPid:':
               return fields[ 1 ] == ppid
   except OSError:
      pass
   return False

def printChildProcesses( agentPid ):
   # print stack info on child processes spawned by ConfigAgent
   print()
   pids = ( pid for pid in os.listdir( '/proc' )
            if pid.isdigit() and isChildProcess( pid, agentPid ) )
   for pid in pids:
      try:
         with open( f"/proc/{pid}/cmdline" ) as f:
            commStr = f.read().replace( '\x00', ' ' ).strip()
      except OSError:
         commStr = ""
      print( f"Child PID {pid} ({commStr})" )
      Tac.run( [ 'arstack', pid ], asRoot=True )
      print()

def main():
   options = parseArgs()
   if not options.print_state and not options.print_child_state:
      print( 'Only CliCtrl -p|--print-state or -c|--print-child-state '
             'is presently supported' )
      sys.exit( 1 )

   # connect to the server
   if options.print_state:
      sock = socket.socket( socket.AF_UNIX, socket.SOCK_STREAM, 0 )
      sock.connect( CliCommon.CLI_CTRL_ADDRESS_FMT % options.sysname )

      # we continue to receive output until the server disconnects
      while True:
         output = sock.recv( 1024 )
         if not output:
            break
         print( output.decode(), end='' )
      sock.close()

   if options.print_child_state:
      agent = AgentDirectory.agent( options.sysname, "ConfigAgent" )
      if agent:
         printChildProcesses( agent[ 'pid' ] )

if __name__ == '__main__':
   main()
