text: # -*- coding: utf-8 -*-
  '''
  Read tops data from a mongodb collection
  
  This module will load tops data from a mongo collection. It uses the node's id
  for lookups.
  
  Salt Master Mongo Configuration
  ===============================
  
  The module shares the same base mongo connection variables as
  :py:mod:`salt.returners.mongo_return`. These variables go in your master
  config file.
  
     * ``mongo.db`` - The mongo database to connect to. Defaults to ``'salt'``.
     * ``mongo.host`` - The mongo host to connect to. Supports replica sets by
       specifying all hosts in the set, comma-delimited. Defaults to ``'salt'``.
     * ``mongo.port`` - The port that the mongo database is running on. Defaults
       to ``27017``.
     * ``mongo.user`` - The username for connecting to mongo. Only required if
       you are using mongo authentication. Defaults to ``''``.
     * ``mongo.password`` - The password for connecting to mongo. Only required
       if you are using mongo authentication. Defaults to ``''``.
  
  
  Configuring the Mongo Tops Subsystem
  ====================================
  
  .. code-block:: yaml
  
    master_tops:
      mongo:
        collection: tops
        id_field: _id
        re_replace: ""
        re_pattern: \\.example\\.com
        states_field: states
        environment_field: environment
  
  
  Module Documentation
  ====================
  '''
  
  # Import python libs
  import logging
  import re
  
  # Import third party libs
  try:
      import pymongo
      HAS_PYMONGO = True
  except ImportError:
      HAS_PYMONGO = False
  
  
  __opts__ = {'mongo.db': 'salt',
              'mongo.host': 'salt',
              'mongo.password': '',
              'mongo.port': 27017,
              'mongo.user': ''}
  
  
  def __virtual__():
      if not HAS_PYMONGO:
          return False
      return 'mongo'
  
  # Set up logging
  log = logging.getLogger(__name__)
  
  
  def top(**kwargs):
      '''
      Connect to a mongo database and read per-node tops data.
  
      Parameters:
          * `collection`: The mongodb collection to read data from. Defaults to
            ``'tops'``.
          * `id_field`: The field in the collection that represents an individual
            minion id. Defaults to ``'_id'``.
          * `re_pattern`: If your naming convention in the collection is shorter
            than the minion id, you can use this to trim the name.
            `re_pattern` will be used to match the name, and `re_replace` will
            be used to replace it. Backrefs are supported as they are in the
            Python standard library. If ``None``, no mangling of the name will
            be performed - the collection will be searched with the entire
            minion id. Defaults to ``None``.
          * `re_replace`: Use as the replacement value in node ids matched with
            `re_pattern`. Defaults to ''. Feel free to use backreferences here.
          * `states_field`: The name of the field providing a list of states.
          * `environment_field`: The name of the field providing the environment.
            Defaults to ``environment``.
      '''
      host = __opts__['mongo.host']
      port = __opts__['mongo.port']
      collection = __opts__['master_tops']['mongo'].get('collection', 'tops')
      id_field = __opts__['master_tops']['mongo'].get('id_field', '_id')
      re_pattern = __opts__['master_tops']['mongo'].get('re_pattern', '')
      re_replace = __opts__['master_tops']['mongo'].get('re_replace', '')
      states_field = __opts__['master_tops']['mongo'].get('states_field', 'states')
      environment_field = __opts__['master_tops']['mongo'].get('environment_field', 'environment')
  
      log.info('connecting to {0}:{1} for mongo ext_tops'.format(host, port))
      conn = pymongo.Connection(host, port)
  
      log.debug('using database \'{0}\''.format(__opts__['mongo.db']))
      mdb = conn[__opts__['mongo.db']]
  
      user = __opts__.get('mongo.user')
      password = __opts__.get('mongo.password')
  
      if user and password:
          log.debug('authenticating as \'{0}\''.format(user))
          mdb.authenticate(user, password)
  
      # Do the regex string replacement on the minion id
      minion_id = kwargs['opts']['id']
      if re_pattern:
          minion_id = re.sub(re_pattern, re_replace, minion_id)
  
      log.info(
          'ext_tops.mongo: looking up tops def for {{\'{0}\': \'{1}\'}} '
          'in mongo'.format(
              id_field, minion_id
          )
      )
  
      result = mdb[collection].find_one({id_field: minion_id}, fields=[states_field, environment_field])
      if result and states_field in result:
          if environment_field in result:
              environment = result[environment_field]
          else:
              environment = 'base'
          log.debug('ext_tops.mongo: found document, returning states')
          return {environment: result[states_field]}
      else:
          # If we can't find the minion the database it's not necessarily an
          # error.
          log.debug(
              'ext_tops.mongo: no document found in collection {0}'.format(
                  collection
              )
          )
          return {}
  