Package Products :: Package ZenModel :: Module zendmd |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenModel.zendmd

      1  #!/usr/bin/env python
      2  ##############################################################################
      3  #
      4  # Copyright (C) Zenoss, Inc. 2007, all rights reserved.
      5  #
      6  # This content is made available according to terms specified in
      7  # License.zenoss under the directory where your Zenoss product is installed.
      8  #
      9  ##############################################################################
     10
     11
     12  import sys
     13  import os
     14  import os.path
     15  import code
     16  import atexit
     17  import logging
     18  import transaction
     19  from subprocess import Popen, PIPE
     20  from optparse import OptionParser
     21
     22 -def setup_loader():
     23      os.environ.setdefault("CELERY_LOADER", "Products.ZenUtils.celeryintegration.ZenossLoader")
     24
     25  setup_loader()
     26
     27  # Parse the command line for host and port; have to do it before Zope
     28  # configuration, because it hijacks option parsing.
     29
     30
     31  parser = OptionParser(usage='usage: %prog [options] -- [ipthon_options] [ipython_args]')
     32  parser.add_option('--host',
     33              dest="host", default=None,
     34              help="Hostname of ZEO server")
     35  parser.add_option('--port',
     36              dest="port", type="int", default=None,
     37              help="Port of ZEO server")
     38  parser.add_option('--script',
     39              dest="script", default=None,
     40              help="Name of file to execute.")
     41  parser.add_option('--commit',
     42              dest="commit", default=False, action="store_true",
     43              help="Run commit() at end of script?")
     44  parser.add_option('-n', '--no-ipython',
     45              dest="use_ipython", default=True, action="store_false",
     46              help="Do not embed IPython shell if IPython is found")
     47
     48  opts, args = parser.parse_args()
     49
     50  readline = rlcompleter = None
     51  Completer = object
     52  IPShellEmbed = None
     53
     54  if opts.use_ipython:
     55      try:
     56          import readline
     57
     58          try:
     59              from IPython.Shell import IPShellEmbed
     60          except ImportError:
     61              IPShellEmbed = None
     62          except AttributeError:
     63              # Looks like we have IPython but the wrong version of readline, likely on OSX 10.6
     64              IPShellEmbed = None
     65          from rlcompleter import Completer
     66      except ImportError:
     67          pass
     68
     69  # Zope magic ensues!
     70  import Zope2
     71  CONF_FILE = os.path.join(os.environ['ZENHOME'], 'etc', 'zope.conf')
     72
     73  # hide any positional arguments during Zope2 configure
     74  _argv = sys.argv
     75  sys.argv = [sys.argv[0], ] + [x for x in sys.argv[1:] if x.startswith("-")]
     76  Zope2.configure(CONF_FILE)
     77  sys.argv = _argv # restore normality
     78
     79  # Now we have the right paths, so we can do the rest of the imports
     80  from Products.CMFCore.utils import getToolByName
     81  from AccessControl.SecurityManagement import newSecurityManager
     82  from AccessControl.SecurityManagement import noSecurityManager
     83  from Products.ZenUtils.Utils import zenPath, set_context
     84  from Products.ZenModel.IpNetwork import IpNetworkPrinterFactory
     85  from Products.ZenMessaging import audit
     86
     87  _CUSTOMSTUFF = []
     88
     89
     90 -def set_db_config(host=None, port=None):
     91      # Modify the database configuration manually
     92      from App.config import getConfiguration
     93      serverconfig = getConfiguration().databases[1].config.storage.config
     94      xhost, xport = serverconfig.server[0].address
     95      if host: xhost = host
     96      if port: xport = port
     97      serverconfig.server[0].address = (xhost, xport)
     98
     99
    100 -def _customStuff():
    101      """
    102      Everything available in the console is defined here.
    103      """
    104
    105      import socket
    106      from transaction import commit
    107      from pprint import pprint
    108      from Products.ZenUtils.Utils import setLogLevel
    109      from Products.Zuul import getFacade, listFacades
    110
    111      # Connect to the database, set everything up
    112      app = Zope2.app()
    113      app = set_context(app)
    114
    115      def login(username='admin'):
    116          utool = getToolByName(app, 'acl_users')
    117          user = utool.getUserById(username)
    118          if user is None:
    119              user = app.zport.acl_users.getUserById(username)
    120          user = user.__of__(utool)
    121          newSecurityManager(None, user)
    122          from AccessControl.Implementation import setImplementation
    123          #Chip's pitched battle against segfault.
    124          #import pdb;pdb.set_trace()
    125          #setImplementation('PYTHON')
    126
    127      login('admin')
    128
    129      # Useful references
    130      zport = app.zport
    131      dmd   = zport.dmd
    132      sync  = zport._p_jar.sync
    133      find  = dmd.Devices.findDevice
    134      devices = dmd.Devices
    135      me = find(socket.getfqdn())
    136      auditComment = audit.auditComment
    137      shell_stdout = []
    138      shell_stderr = []
    139
    140      def reindex():
    141          sync()
    142          dmd.Devices.reIndex()
    143          dmd.Events.reIndex()
    144          dmd.Manufacturers.reIndex()
    145          dmd.Networks.reIndex()
    146          commit()
    147
    148      def logout():
    149          noSecurityManager()
    150
    151      def zhelp():
    152          cmds = sorted(filter(lambda x: not x.startswith("_"), _CUSTOMSTUFF))
    153          for cmd in cmds:
    154              print cmd
    155
    156      def grepdir(obj, regex=""):
    157          if regex:
    158              import re
    159              pattern = re.compile(regex)
    160              for key in dir(obj):
    161                  if pattern.search(key):
    162                      print key
    163
    164      def lookupGuid(guid):
    165          """
    166          Given a guid this returns the object that it identifies
    167          """
    168          from Products.ZenUtils.guid.interfaces import IGUIDManager
    169          manager = IGUIDManager(dmd)
    170          return manager.getObject(guid)
    171
    172      def version():
    173          for info in zport.About.getAllVersions():
    174              print "%10s: %s" % (info['header'], info['data'])
    175          print "%10s: %s" % ("DMD", dmd.version)
    176
    177      def printNets(net=dmd.Networks, format="text", out=sys.stdout):
    178          """
    179          Print out the IpNetwork and IpAddress hierarchy under net.  To print
    180          out everything call printNets(dmd.Networks).  format can be text,
    181          python, or xml.
    182          """
    183          factory = IpNetworkPrinterFactory()
    184          printer = factory.createIpNetworkPrinter(format, out)
    185          printer.printIpNetwork(net)
    186
    187
    188      def cleandir(obj):
    189          portaldir = set(dir(dmd))
    190          objdir = set(dir(obj))
    191          appdir = set(dir(app))
    192          result = sorted(objdir - portaldir - appdir)
    193          pprint(result)
    194
    195      def history(start=None, end=None, lines=30,
    196                     number=False):
    197          """
    198          Display the history starting from entry 'start' to
    199          entry 'end'. Only available on platforms where the
    200          readline module can be imported.
    201
    202          History starts from 0 and goes to a large number.
    203          The history file is $ZENHOME/.pyhistory by default.
    204
    205          @parameter start: Line number to start printing
    206          @type start: integer
    207          @parameter end: Line number to finish printing
    208          @type end: integer
    209          @parameter lines: number of lines to show if no end
    210          @type lines: integer
    211          @parameter number: show the line numbers?
    212          @type number: boolean
    213          """
    214          if readline is not None:
    215              maxHistLength = readline.get_current_history_length()
    216              if start is None:
    217                  start = maxHistLength
    218              if end is None:
    219                  end = maxHistLength - lines
    220              if start < end:
    221                  end, start = start, end
    222              for i in range(end, start):
    223                  if number:
    224                      print i, readline.get_history_item(i)
    225                  else:
    226                      print readline.get_history_item(i)
    227
    228      def sh(cmd, interactive=True):
    229          """
    230          Execute a shell command.  If interactive is False, then
    231          direct the contents of stdout into shell_stdout and the
    232          output of stderr into shell_stderr.
    233
    234          @parameter cmd: shell command to execute
    235          @type cmd: string
    236          @parameter interactive: show outut to the screen or not
    237          @type interactive: boolean
    238          """
    239          if interactive:
    240              proc = Popen(cmd, shell=True)
    241          else:
    242              proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
    243          output, errors = proc.communicate()
    244          proc.wait()
    245          if not interactive:
    246              output = output.split('\n')[:-1]
    247              errors = errors.split('\n')[:-1]
    248              _CUSTOMSTUFF['shell_stdout'] = output
    249              _CUSTOMSTUFF['shell_stderr'] = errors
    250          return output, errors
    251
    252      def edit(file=None, start=None, end=None, lines=30):
    253          """
    254          Use the value of the EDITOR environment variable to
    255          edit a file.  Defaults to the original Unix IDE -- vi.
    256
    257          @parameter file: name of file to edit -- defaults to a temp file
    258          @type file: string
    259          @parameter start: Line number to start printing
    260          @type start: integer
    261          @parameter end: Line number to finish printing
    262          @type end: integer
    263          @parameter lines: number of lines to show if no end
    264          @type lines: integer
    265          """
    266          editor = os.environ.get('EDITOR', 'vi')
    267          isNewFile = True
    268          isTmpName = False
    269          if file == None:
    270              isTmpName = True
    271              file = os.tempnam()
    272              fp = open(file, 'w')
    273          elif os.path.exists(file):
    274              isNewFile = False
    275          else:
    276              fp = open(file, 'w')
    277
    278          if isNewFile and readline is not None:
    279              maxHistLength = readline.get_current_history_length()
    280              if start is None:
    281                  start = maxHistLength
    282              if end is None:
    283                  end = maxHistLength - lines
    284              if start < end:
    285                  end, start = start, end
    286              for i in range(end, start):
    287                  fp.write(readline.get_history_item(i) + '\n')
    288              fp.close()
    289
    290          sh('%s %s' % (editor, file))
    291          execfile(file, globals(), _CUSTOMSTUFF)
    292          if isTmpName:
    293              os.unlink(file)
    294
    295      _CUSTOMSTUFF = locals()
    296      return _CUSTOMSTUFF
    297
    298
    299 -class ZenCompleter(Completer):
    300      """
    301      Provides the abiility to specify *just* the zendmd-specific
    302      stuff when you first enter and hit tab-tab, and also the
    303      ability to remove junk that we don't need to see.
    304      """
    305      ignored_names = [
    306          "COPY", "DELETE", "HEAD", "HistoricalRevisions",
    307          "LOCK", "MKCOL", "MOVE", "OPTIONS",
    308          "Open", "PROPFIND", "PROPPATCH",
    309          "PUT", "REQUEST", "SQLConnectionIDs",
    310          "SiteRootAdd", "TRACE", "UNLOCK",
    311          "ac_inherited_permissions",
    312          "access_debug_info",
    313          "bobobase_modification_time",
    314          "manage_historyCompare",
    315          "manage_historyCopy",
    316          "manage_addDTMLDocument",
    317          "manage_addDTMLMethod",
    318          "manage_clone",
    319          "manage_copyObjects",
    320          "manage_copyright",
    321          "manage_cutObjects",
    322          "manage_historicalComparison",
    323          "validClipData",
    324          "manage_CopyContainerAllItems",
    325          "manage_CopyContainerFirstItem",
    326          "manage_DAVget",
    327          "manage_FTPlist",
    328          "manage_UndoForm",
    329          "manage_access",
    330      ]
    331      ignored_prefixes = [
    332         '_', 'wl_', 'cb_', 'acl', 'http__', 'dav_',
    333         'manage_before', 'manage_after',
    334         'manage_acquired',
    335      ]
    336
    337      current_prompt = ''
    338 -    def complete(self, text, state):
    339          # Don't show all objects if we're typing in code
    340          if self.current_prompt == sys.ps2:
    341              if state == 0:
    342                  if text == '':
    343                      return '    '
    344              else:
    345                  return None
    346
    347          return Completer.complete(self, text, state)
    348
    349
    350 -    def global_matches(self, text):
    351          """
    352          Compute matches when text is a simple name.
    353          """
    354          matches = []
    355          for name in self.namespace:
    356              if name.startswith(text):
    357                  matches.append(name)
    358
    359          return matches
    360
    361 -    def attr_matches(self, text):
    362          """
    363          Compute matches when text contains a dot.
    364          """
    365          matches = []
    366          for name in Completer.attr_matches(self, text):
    367              if name.endswith("__roles__"):
    368                  continue
    369              component = name.split('.')[-1]
    370              if component in self.ignored_names:
    371                  continue
    372              ignore = False
    373              for prefix in self.ignored_prefixes:
    374                  if component.startswith(prefix):
    375                      ignore = True
    376                      break
    377
    378              if not ignore:
    379                  matches.append(name)
    380
    381          return matches
    382          #return filter(lambda x: not x.endswith("__roles__"),
    383                        #Completer.attr_matches(self, text))
    384
    385
    386
    387 -class HistoryConsole(code.InteractiveConsole):
    388      """
    389      Subclass the default InteractiveConsole to get readline history
    390      """
    391 -    def __init__(self, locals=None, filename="<console>",
    392                   histfile=zenPath('.pyhistory')):
    393          code.InteractiveConsole.__init__(self, locals, filename)
    394          self.completer = None
    395          if readline is not None:
    396              self.completer = ZenCompleter(locals)
    397              readline.set_completer(self.completer.complete)
    398              readline.parse_and_bind("tab: complete")
    399          self.init_history(histfile)
    400
    401
    402 -    def init_history(self, histfile):
    403          if hasattr(readline, "read_history_file"):
    404              try:
    405                  readline.read_history_file(histfile)
    406              except IOError:
    407                  pass
    408              atexit.register(self.save_history, histfile)
    409
    410 -    def save_history(self, histfile):
    411          readline.write_history_file(histfile)
    412
    413 -    def raw_input(self, prompt=""):
    414          if self.completer:
    415              self.completer.current_prompt = prompt
    416          return code.InteractiveConsole.raw_input(self, prompt)
    417
    418 -    def runsource(self, source, filename):
    419          if source and source[0] == '!':
    420              self.locals['sh'](source[1:])
    421              return False
    422          elif source and source[0] == '|':
    423              self.locals['sh'](source[1:], interactive=False)
    424              return False
    425          return code.InteractiveConsole.runsource(self, source, filename)
    426
    427
    428  if __name__=="__main__":
    429      # Do we want to connect to a database other than the one specified in
    430      # zope.conf?
    431      if opts.host or opts.port:
    432          set_db_config(opts.host, opts.port)
    433
    434      vars = _customStuff()
    435      # set the first positional argument as the --script arg
    436      for arg in sys.argv[1:]:
    437          if not arg.startswith("-") and os.path.exists(arg):
    438             opts.script = arg
    439             break
    440      if opts.script:
    441          if not os.path.exists(opts.script):
    442              print "Unable to open script file '%s' -- exiting" % opts.script
    443              sys.exit(1)
    444          execfile(opts.script, globals(), vars)
    445          if opts.commit:
    446              from transaction import commit
    447              commit()
    448          else:
    449              try:
    450                  transaction.abort()
    451              except:
    452                  pass
    453          sys.exit(0)
    454
    455      audit.audit('Shell.Script.Run')
    456      _banner = ("Welcome to the Zenoss dmd command shell!\n"
    457               "'dmd' is bound to the DataRoot. 'zhelp()' to get a list of "
    458               "commands.")
    459      try:
    460          if IPShellEmbed:
    461              sys.argv[1:] = args
    462              ipshell = IPShellEmbed(banner=_banner)
    463              ipshell(local_ns=vars)
    464          else:
    465              if readline is not None:
    466                  _banner = '\n'.join([_banner,
    467                                       "Use TAB-TAB to see a list of zendmd related commands.",
    468                                       "Tab completion also works for objects -- hit tab after"
    469                                       " an object name and '.'", " (eg dmd. + tab-key)."])
    470
    471
    472              # Start up the console
    473              myconsole = HistoryConsole(locals=vars)
    474              myconsole.interact(_banner)
    475      finally:
    476          # try to abort any open transactions for our two phase commit listeners
    477          try:
    478              transaction.abort()
    479          except:
    480              pass
    481