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