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

# Source Code for Module Products.ZenModel.zendmd

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