text: from __future__ import absolute_import
  #
  # Copyright (c) 2018 Juniper Networks, Inc. All rights reserved.
  #
  
  from builtins import str
  import os
  import random
  import signal
  import socket
  import subprocess
  import sys
  
  from attrdict import AttrDict
  from cfgm_common import vnc_cgitb
  from cfgm_common.kombu_amqp import KombuAmqpClient
  from cfgm_common.vnc_object_db import VncObjectDBClient
  from cfgm_common.zkclient import ZookeeperClient
  import gevent
  from gevent import monkey
  import psutil
  
  from .device_job_manager import DeviceJobManager
  from .device_ztp_manager import DeviceZtpManager
  from .dm_amqp import DMAmqpHandle
  from .dm_server_args import parse_args
  from .logger import DeviceManagerLogger
  
  from .device_manager import DeviceManager # noqa
  monkey.patch_all() # noqa
  
  
  _amqp_client = None
  _zookeeper_client = None
  
  
  def initialize_amqp_client(logger, args):
      amqp_client = None
      try:
          # prepare rabbitMQ params
          rabbitmq_cfg = AttrDict(
              servers=args.rabbit_server,
              port=args.rabbit_port,
              user=args.rabbit_user,
              password=args.rabbit_password,
              vhost=args.rabbit_vhost,
              ha_mode=args.rabbit_ha_mode,
              use_ssl=args.rabbit_use_ssl,
              ssl_version=args.kombu_ssl_version,
              ssl_keyfile=args.kombu_ssl_keyfile,
              ssl_certfile=args.kombu_ssl_certfile,
              ssl_ca_certs=args.kombu_ssl_ca_certs
          )
          amqp_client = KombuAmqpClient(
              logger.log, rabbitmq_cfg,
              heartbeat=0)
          amqp_client.run()
      except Exception as e:
          logger.error("Error while initializing the AMQP"
                       " client %s" % repr(e))
          if amqp_client is not None:
              amqp_client.stop()
      return amqp_client
  # end initialize_amqp_client
  
  
  def initialize_db_connection(logger, args):
      credential = None
      if args.cassandra_user and args.cassandra_password:
          credential = {
              'username': args.cassandra_user,
              'password': args.cassandra_password
          }
  
      timeout = int(args.job_manager_db_conn_retry_timeout)
      max_retries = int(args.job_manager_db_conn_max_retries)
  
      retry_count = 1
      while True:
          try:
              return VncObjectDBClient(
                  args.cassandra_server_list, db_prefix=args.cluster_id,
                  logger=logger.log, credential=credential,
                  ssl_enabled=args.cassandra_use_ssl,
                  ca_certs=args.cassandra_ca_certs)
          except Exception as e:
              if retry_count >= max_retries:
                  raise e
              logger.error("Error while initializing db connection, "
                           "retrying: %s" % str(e))
              gevent.sleep(timeout)
          finally:
              retry_count = retry_count + 1
  # end initialize_db_connection
  
  
  def run_device_manager(dm_logger, args):
      global _amqp_client
  
      dm_logger.notice("Elected master Device Manager node. Initializing... ")
      dm_logger.introspect_init()
      DeviceZtpManager.get_instance().set_active()
      DeviceManager(dm_logger, args, None, _amqp_client)
      if _amqp_client._consumer_gl is not None:
          gevent.joinall([_amqp_client._consumer_gl])
  # end run_device_manager
  
  
  def run_full_dm(pid):
      # won master election, destroy any created process
      running_procs = [x for x in psutil.process_iter()]
      for proc in running_procs:
          # dm shouldn't destroy itself
          if proc.pid == pid:
              continue
          elif 'contrail-device-manager' in ' '.join(proc.cmdline()):
              proc.kill()
      script_to_run = sys.argv
      script_to_run.append('--dm_run_mode Full')
      proc = subprocess.Popen(script_to_run, close_fds=True)
      gevent.joinall([gevent.spawn(dummy_gl, proc)])
  # end run_full_dm
  
  
  def dummy_gl(proc):
      while True:
          gevent.sleep(10)
          if proc.poll() is None:
              # proc is still running
              pass
          elif proc.poll() == 0:
              # proc is terminated, kill self
              os._exit(2)
          else:
              # proc completed, this shouldnt happen
              os._exit(2)
  # end dummy_gl
  
  
  def run_partial_dm(pid):
      # if we are not master, start only DeviceJobManager
      is_master = False
      running_procs = [x for x in psutil.process_iter()]
      for proc in running_procs:
          if proc.pid == pid:
              continue
          elif 'contrail-device-manager' in ' '.join(proc.cmdline()):
              is_master = True
      if not is_master:
          # start dm with Partial flag
          script_to_run = sys.argv
          script_to_run.append('--dm_run_mode Partial')
          proc = subprocess.Popen(script_to_run, close_fds=True)
          for x in range(3):
              gevent.sleep(5)
              if proc.poll() is None:
                  # proc is still running
                  pass
              else:
                  # proc completed, this shouldnt happen
                  os._exit(2)
  # end master_watcher
  
  
  def sighup_handler():
      if DeviceManager.get_instance() is not None:
          DeviceManager.get_instance().sighup_handler()
  # end sighup_handler
  
  
  def sigterm_handler():
      global _amqp_client
  
      DeviceManager.destroy_instance()
      DeviceZtpManager.destroy_instance()
      DeviceJobManager.destroy_instance()
  
      if _amqp_client is not None:
          _amqp_client.stop()
  # end sigterm_handler
  
  
  def run_job_ztp_manager(dm_logger, args):
      # Initialize AMQP handler then close it to be sure remain queue of a
      # precedent run is cleaned
      vnc_amqp = DMAmqpHandle(dm_logger, {}, args)
      vnc_amqp.establish()
      vnc_amqp.close()
      dm_logger.debug("Removed remaining AMQP queue from previous run")
  
      global _amqp_client
      _amqp_client = initialize_amqp_client(dm_logger, args)
      _db_conn = initialize_db_connection(dm_logger, args)
  
      try:
          # Initialize the device job manager
          DeviceJobManager(_amqp_client, _db_conn, args,
                           dm_logger)
          # Allow kombu client to connect consumers
          gevent.sleep(0.5)
      except Exception as e:
          dm_logger.error("Error while initializing the device job "
                          "manager %s" % str(e))
          raise e
  
      try:
          # Initialize the device ztp manager
          DeviceZtpManager(_amqp_client, _db_conn, args, dm_logger)
          # Allow kombu client to connect consumers
          gevent.sleep(0.5)
      except Exception as e:
          dm_logger.error("Error while initializing the device ztp "
                          "manager %s" % str(e))
          raise e
  
      if args.dm_run_mode == 'Partial':
          dm_logger.notice("Process %s started in Partial mode..."
                           % os.getpid())
          if _amqp_client._consumer_gl is not None:
              gevent.joinall([_amqp_client._consumer_gl])
  # end run_job_ztp_manager
  
  
  def main(args_str=None):
      global _amqp_client
  
      if not args_str:
          args_str = ' '.join(sys.argv[1:])
      args = parse_args(args_str)
      if args.cluster_id:
          client_pfx = args.cluster_id + '-'
          zk_path_pfx = args.cluster_id + '/'
      else:
          client_pfx = ''
          zk_path_pfx = ''
  
      # randomize collector list
      args.random_collectors = args.collectors
      if args.collectors:
          args.random_collectors = random.sample(args.collectors,
                                                 len(args.collectors))
  
      args.log_level = str(args.log_level)
  
      if 'host_ip' not in args:
          args.host_ip = socket.gethostbyname(socket.getfqdn())
  
      gevent.signal(signal.SIGHUP, sighup_handler)
      gevent.signal(signal.SIGTERM, sigterm_handler)
      gevent.signal(signal.SIGINT, sigterm_handler)
  
      if args.dm_run_mode == 'Full':
          dm_logger = DeviceManagerLogger(args, http_server_port=-1)
          run_job_ztp_manager(dm_logger, args)
          dm_logger.notice("Process %s prepared to run in Full mode..."
                           % os.getpid())
          run_device_manager(dm_logger, args)
      elif args.dm_run_mode == 'Partial':
          dm_logger = DeviceManagerLogger(args, http_server_port=-1)
          dm_logger.notice("Process %s prepared to run in Partial mode..."
                           % os.getpid())
          run_job_ztp_manager(dm_logger, args)
      else:
          if args.zookeeper_ssl_enable:
              _zookeeper_client = ZookeeperClient(client_pfx + "device-manager",
                                                  args.zk_server_ip,
                                                  args.host_ip,
                                                  args.zookeeper_ssl_enable,
                                                  args.zookeeper_ssl_keyfile,
                                                  args.zookeeper_ssl_certificate,
                                                  args.zookeeper_ssl_ca_cert)
          else:
              _zookeeper_client = ZookeeperClient(client_pfx + "device-manager",
                                                  args.zk_server_ip,
                                                  args.host_ip)
          pid = os.getpid()
          run_partial_dm(pid)
          _zookeeper_client.master_election(zk_path_pfx + "/device-manager",
                                            os.getpid(), run_full_dm, pid)
  # end main
  
  
  def server_main():
      vnc_cgitb.enable(format='text')
      main()
  # end server_main
  
  
  if __name__ == '__main__':
      server_main()
  