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

import sys, os

procMgrBaseDir = "/etc/ProcMgr.d/"
installedAgentsDir = procMgrBaseDir + "inst"
runnableAgentsDir = procMgrBaseDir + "run"

def quit( str=None ): # pylint: disable=redefined-builtin
   print( str )
   os._exit( 1 ) # pylint: disable=protected-access

def showAgentConfig():
   installedAgents = os.listdir( installedAgentsDir )
   runnableAgents = os.listdir( runnableAgentsDir )
   for a in installedAgents:
      runnableStr = "off"
      if a in runnableAgents:
         runnableStr = " on"
      # pylint: disable-next=consider-using-f-string
      print( "%-20s %3s" % ( a, runnableStr ) )

   firstWeirdAgent = True

   for weirdAgent in runnableAgents:
      if not weirdAgent in installedAgents:
         if firstWeirdAgent:
            print( "\n" )
            firstWeirdAgent = False
         # pylint: disable-next=consider-using-f-string
         print( "WARNING: %s appears to be runnable, but not installed!" %
                weirdAgent )

def deleteIfExists( f ):
   if os.access( f, os.F_OK ):
      os.unlink( f )

def main():
   import optparse # pylint: disable=import-outside-toplevel,deprecated-module
   parser = optparse.OptionParser()
   parser.add_option( "--add", dest="addAgent",
                      help="Make an agent visible to ProcMgr "
                      "(does not start the agent!)" )
   parser.add_option( "--del", dest="delAgent",
                      help="Make an agent invisible to ProcMgr "
                      "(does not stop the agent!)" )

   # Avoid things like '--add bobo --del bobo'
   if len( sys.argv ) > 3:
      parser.error( "Only a single '--add' or '--del' is supported at one time!" )

   ( options, args ) = parser.parse_args()
   if args:
      parser.error( "unexpected arguments" )

   agentName = options.addAgent or options.delAgent

   if agentName:
      agentConfigFile = installedAgentsDir + "/" + agentName
      agentSymlink = runnableAgentsDir + "/" + agentName

      if not os.access( agentConfigFile, os.F_OK | os.R_OK ):
         # pylint: disable-next=consider-using-f-string,consider-using-sys-exit
         quit( "%s does not exist, or is not accessible" % agentConfigFile )

   if options.addAgent:
      # NOTE: by deleting and re-creating the symlink, we change the
      #       ctime of the link's inode. This causes ProcMgr to
      #       restart the agent!
      #
      #       This is done on purpose: in general, looking at the
      #       process config file's contents does not give ProcMgr
      #       enough information to know whether to restart an agent.
      #
      #       Suppose that an agent's binary (or some shared library
      #       that the agent links against) is upgraded, but the
      #       heartbeat period or argv of the agent is not. ProcMgr
      #       has no way of knowing that it needs to restart the
      #       agent.
      #
      #       In this case, it is expected that "someone" calls
      #       "chkagent --add" to signal to ProcMgr that the agent
      #       needs to be restarted. We still need to solve the
      #       question of who that "someone" is -- probably not the
      #       package's .spec file! (We've recently moved away from
      #       putting 'service ProcMgr restart' into .spec file %post
      #       rules.)
      deleteIfExists( agentSymlink )
      os.symlink( agentConfigFile, agentSymlink)
   elif options.delAgent:
      deleteIfExists( agentSymlink )
   else:
      showAgentConfig()

if __name__ == "__main__":
   main()
