Package Products :: Package ZenUtils :: Module RunCommand |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenUtils.RunCommand

      1  #!/usr/bin/env python
      2  ##############################################################################
      3  #
      4  # Copyright (C) Zenoss, Inc. 2010, 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  __doc__ = """RunCommand
     13  Run an event command on the local device or on the remote collector.
     14  Assumes that SSH keys have been set up to all remote collectors.
     15
     16    Example usage:
     17
     18  dcsh -collector=xxx 'zencommand run'
     19
     20    The actual command to run *MUST* be in quotes!
     21  """
     22
     23  import logging
     24  log = logging.getLogger('zen.runCommand')
     25
     26  import os
     27  from subprocess import Popen, PIPE
     28  import StringIO
     29  import signal
     30
     31  import Globals
     32  from Products.ZenUtils.ZenScriptBase import ZenScriptBase
     33  from Products.ZenUtils.Utils import zenPath
     34
     35
     36 -class collectorStats:
     37 -    def __init__(self, id, hostname):
     38          self.id = id
     39          self.hostname = hostname
     40          self.succeeded = False
     41          self.stdout = ''
     42          self.stderr = ''
     43
     44
     45 -class RunCommand(ZenScriptBase):
     46 -    def __init__(self):
     47          ZenScriptBase.__init__(self, connect=True)
     48
     49 -    def buildOptions(self):
     50          ZenScriptBase.buildOptions(self)
     51          self.parser.add_option('--collector', dest='collector',
     52              help="Name of specific collector on which to run the command")
     53          self.parser.add_option('--timeout', dest='timeout',
     54                             default=60, type="int",
     55                             help="Kill the process after this many seconds.")
     56          self.parser.add_option('-n', '--useprefix', action='store_false',
     57                                 dest='useprefix', default=True,
     58                             help="Prefix the collector name for remote servers")
     59
     60 -    def run(self):
     61          collectors = self._getCollectors()
     62          if collectors is None:
     63              return
     64          for collector in collectors:
     65              self._runCommandOnCollector(collector)
     66          self.report(collectors)
     67
     68 -    def _getCollectors(self):
     69          if self.options.collector:
     70              try:
     71                  collectors = [self.dmd.Monitors.Performance._getOb(
     72                      self.options.collector)]
     73              except AttributeError:
     74                  log.critical("No collector named %s could be found. Exiting",
     75                      self.options.collector)
     76                  return
     77          else:
     78              collectors = self.dmd.Monitors.Performance.objectValues(
     79                  spec="PerformanceConf")
     80
     81          return [collectorStats(x.id, getattr(x, 'hostname', x.id)) \
     82                          for x in collectors]
     83
     84 -    def report(self, collectors):
     85          header = """
     86  Collector       StdOut/Stderr"""
     87          delimLen = 65
     88          print header
     89          print '-' * delimLen
     90
     91          collectorNames = dict(zip(map(lambda x: x.id, collectors), collectors))
     92          for name in sorted(collectorNames.keys()):
     93              collector = collectorNames[name]
     94              print "%s     %s %s" % (name, collector.stdout, collector.stderr)
     95              print '-' * delimLen
     96
     97 -    def _runCommandOnCollector(self, collector):
     98          def killTimedOutProc(signum, frame):
     99              log.error("Killing process id %s ...", proc.pid)
    100              try:
    101                  os.kill(proc.pid, signal.SIGKILL)
    102              except OSError:
    103                  pass
    104
    105          if collector.id == 'localhost' or not self.options.useprefix:
    106              remote_command = self.args[0]
    107          else:
    108              remote_command = '%s_%s' % (collector.id, self.args[0])
    109
    110          if collector.hostname == 'localhost':
    111              collectorCommand = [remote_command]
    112          else:
    113              collectorCommand = ['ssh', collector.hostname, remote_command]
    114
    115          collectorCommand = ' '.join(collectorCommand)
    116          log.debug("Runing command '%s' on collector %s (%s)",
    117                    collectorCommand, collector.id, collector.hostname)
    118          proc = Popen(collectorCommand, stdout=PIPE, stderr=PIPE, shell=True)
    119          signal.signal(signal.SIGALRM, killTimedOutProc)
    120          signal.alarm(self.options.timeout)
    121          collector.stdout, collector.stderr = proc.communicate()
    122          proc.wait()
    123          signal.alarm(0) # Disable the alarm
    124
    125
    126  if __name__ == '__main__':
    127      zrc = RunCommand()
    128      zrc.run()
    129