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

# Source Code for Module Products.ZenModel.ZenPackManager

      1  ##############################################################################
      2  #
      3  # Copyright (C) Zenoss, Inc. 2008, all rights reserved.
      4  #
      5  # This content is made available according to terms specified in
      6  # License.zenoss under the directory where your Zenoss product is installed.
      7  #
      8  ##############################################################################
      9
     10
     11  __doc__="""ZenPackManager
     12  ZenPackManager is a Zope Product that helps manage ZenPacks
     13  """
     14
     15  from Globals import InitializeClass
     16  from ZenModelRM import ZenModelRM
     17  from Products.ZenRelations.RelSchema import *
     18  from AccessControl import ClassSecurityInfo
     19  from ZenossSecurity import ZEN_MANAGE_DMD
     20  from Products.ZenMessaging.audit import audit
     21  from Products.ZenUtils.Utils import binPath
     22  from Products.ZenWidgets import messaging
     23  import os
     24  import tempfile
     25  import logging
     26
     27  log = logging.getLogger('zen.ZenPackManager')
     28
     29 -def manage_addZenPackManager(context, newId='', REQUEST=None):
     30      """
     31      Create a ZenPackManager instance
     32      """
     33      if not newId:
     34          newId = 'ZenPackManager'
     35      zpm = ZenPackManager(newId)
     36      context._setObject(newId, zpm)
     37      zpm = context._getOb(newId)
     38      if REQUEST is not None:
     39          REQUEST.RESPONSE.redirect(context.absolute_url() + '/manage_main')
     40
     41
     42 -class ZenPackManager(ZenModelRM):
     43      """
     44      ZenPackManager is responsibe for managing ZenPacks
     45      """
     46
     47      portal_type = meta_type = 'ZenPackManager'
     48
     49      default_catalog = 'zenPackNameSearch'
     50
     51      _relations = ZenModelRM._relations + (
     52          ('packs', ToManyCont(ToOne, 'Products.ZenModel.ZenPack', 'manager')),
     53          )
     54
     55      factory_type_information = (
     56          {
     57              'immediate_view' : 'viewZenPacks',
     58              'actions'        :
     59              (
     60                  { 'id'            : 'settings'
     61                  , 'name'          : 'Settings'
     62                  , 'action'        : '../editSettings'
     63                  , 'permissions'   : ( "Manage DMD", )
     64                  },
     65                  { 'id'            : 'manage'
     66                  , 'name'          : 'Commands'
     67                  , 'action'        : '../dataRootManage'
     68                  , 'permissions'   : ('Manage DMD',)
     69                  },
     70                  { 'id'            : 'users'
     71                  , 'name'          : 'Users'
     72                  , 'action'        : '../ZenUsers/manageUserFolder'
     73                  , 'permissions'   : ( 'Manage DMD', )
     74                  },
     75                  { 'id'            : 'packs'
     76                  , 'name'          : 'ZenPacks'
     77                  , 'action'        : 'viewZenPacks'
     78                  , 'permissions'   : ( "Manage DMD", )
     79                  },
     80                  { 'id'            : 'portlets'
     81                  , 'name'          : 'Portlets'
     82                  , 'action'        : '../editPortletPerms'
     83                  , 'permissions'   : ( "Manage DMD", )
     84                  },
     85                  { 'id'            : 'daemons'
     86                  , 'name'          : 'Daemons'
     87                  , 'action'        : '../About/zenossInfo'
     88                  , 'permissions'   : ( "Manage DMD", )
     89                  },
     90                  { 'id'            : 'versions'
     91                  , 'name'          : 'Versions'
     92                  , 'action'        : '../About/zenossVersions'
     93                  , 'permissions'   : ( "Manage DMD", )
     94                  },
     95                  { 'id'            : 'backups'
     96                  , 'name'          : 'Backups'
     97                  , 'action'        : '../backupInfo'
     98                  , 'permissions'   : ( "Manage DMD", )
     99                  },
    100                  { 'id'            : 'eventConfig'
    101                  , 'name'          : 'Events'
    102                  , 'action'        : 'eventConfig'
    103                  , 'permissions'   : ( "Manage DMD", )
    104                  },
    105                  { 'id'            : 'userInterfaceConfig'
    106                  , 'name'          : 'User Interface'
    107                  , 'action'        : '../userInterfaceConfig'
    108                  , 'permissions'   : ( "Manage DMD", )
    109                  },
    110              )
    111           },
    112          )
    113
    114      security = ClassSecurityInfo()
    115
    116
    117      security.declareProtected(ZEN_MANAGE_DMD, 'manage_addZenPack')
    118 -    def manage_addZenPack(self, packId, REQUEST=None):
    119          """
    120          Create a new zenpack on the filesystem with the given info.
    121          Install the pack.  If REQUEST then render the REQUEST otherwise
    122          return the new zenpack.
    123          """
    124          import Products.ZenUtils.ZenPackCmd as ZenPackCmd
    125
    126          if not getattr(self.dmd, 'ZenPackManager'):
    127              msg = 'Your Zenoss database appears to be out of date. Try ' \
    128                      'running zenmigrate to update.'
    129              if REQUEST:
    130                  messaging.IMessageSender(self).sendToBrowser(
    131                      'Error', msg, priority=messaging.WARNING)
    132                  return self.callZenScreen(REQUEST)
    133              from ZenPack import ZenPackNeedMigrateException
    134              raise ZenPackNeedMigrateException(msg)
    135
    136          # Make sure a zenpack can be created with given info
    137          canCreate, msgOrId = ZenPackCmd.CanCreateZenPack(self, packId)
    138          if canCreate:
    139              packId = msgOrId
    140          else:
    141              if REQUEST:
    142                  messaging.IMessageSender(self).sendToBrowser(
    143                      'Add ZenPack', msgOrId)
    144                  return self.callZenScreen(REQUEST, redirect=False)
    145              from ZenPack import ZenPackException
    146              raise ZenPackException(msgOrId)
    147
    148          # Create it
    149          zpDir = ZenPackCmd.CreateZenPack(packId)
    150
    151          # Install it
    152          zenPacks = ZenPackCmd.InstallEggAndZenPack(self.dmd, zpDir, link=True,
    153                                                     forceRunExternal=True)
    154          zenPack = self.packs._getOb(packId, None)
    155          audit('UI.ZenPack.Create', packId)
    156          if REQUEST:
    157              if zenPack:
    158                  return REQUEST['RESPONSE'].redirect(zenPack.getPrimaryUrlPath())
    159              messaging.IMessageSender(self).sendToBrowser(
    160                  'Error', 'There was an error creating the ZenPack.',
    161                  priority=messaging.WARNING)
    162              return self.callZenScreen(REQUEST)
    163          return zenPack
    164
    165
    166      security.declareProtected(ZEN_MANAGE_DMD, 'manage_removeZenPacks')
    167 -    def manage_removeZenPacks(self, ids=(), REQUEST=None):
    168          """
    169          Uninstall the given zenpacks.  Uninstall the zenpack egg.  If not in
    170          development mode then also delete the egg from the filesystem.
    171          """
    172          import Products.ZenUtils.ZenPackCmd as ZenPackCmd
    173          # avoid circular imports
    174          from Products.ZenMessaging.queuemessaging.schema import removeZenPackQueuesExchanges
    175
    176          if not getattr(self.dmd, 'ZenPackManager'):
    177              msg = 'Your Zenoss database appears to be out of date. Try ' \
    178                      'running zenmigrate to update.'
    179              if REQUEST:
    180                  messaging.IMessageSender(self).sendToBrowser(
    181                      'Error', msg, priority=messaging.WARNING)
    182                  return self.callZenScreen(REQUEST)
    183              from ZenPack import ZenPackNeedMigrateException
    184              raise ZenPackNeedMigrateException(msg)
    185
    186          canRemove, dependents = ZenPackCmd.CanRemoveZenPacks(self.dmd, ids)
    187          if not canRemove:
    188              msg = 'The following ZenPacks depend on one or more of the ' + \
    189                  ' ZenPacks you are trying to remove: %s' % ','.join(dependents)
    190              if REQUEST:
    191                  messaging.IMessageSender(self).sendToBrowser(
    192                      'Error', msg, priority=messaging.WARNING)
    193                  return self.callZenScreen(REQUEST)
    194              from ZenPack import ZenPackDependentsException
    195              raise ZenPackDependentsException(msg)
    196          for zpId in ids:
    197              zp = self.packs._getOb(zpId, None)
    198              if zp:
    199                  if zp.isEggPack():
    200                      ZenPackCmd.RemoveZenPack(self.dmd, zpId, skipDepsCheck=True)
    201                      audit('UI.ZenPack.Remove', zpId)
    202                  else:
    203                      os.system('%s --remove %s' % (
    204                                              binPath('zenpack'), zpId))
    205                      self._p_jar.sync()
    206
    207                  removeZenPackQueuesExchanges(zp.path())
    208          if REQUEST:
    209              return self.callZenScreen(REQUEST)
    210
    211
    212      security.declareProtected(ZEN_MANAGE_DMD, 'fetchZenPack')
    213 -    def fetchZenPack(self, packName, packVersion=''):
    214          """
    215          Retrieve the given zenpack from Zenoss.net and install.
    216          """
    217          import Products.ZenUtils.ZenPackCmd as ZenPackCmd
    218          zp = ZenPackCmd.FetchAndInstallZenPack(self.dmd, packName, packVersion)
    219          if REQUEST:
    220              return REQUEST['RESPONSE'].redirect(zp.getPrimaryUrlPath())
    221          return zp
    222
    223
    224
    225      security.declareProtected(ZEN_MANAGE_DMD, 'manage_installZenPack')
    226 -    def manage_installZenPack(self, zenpack=None, REQUEST=None):
    227          """
    228          Installs the given zenpack.  Zenpack is a file upload from the browser.
    229          """
    230          import re
    231          import time
    232          from subprocess import Popen, PIPE, STDOUT
    233
    234          from Products.ZenUtils.Utils import get_temp_dir
    235
    236          ZENPACK_INSTALL_TIMEOUT = 10 * 60 # 10 minutes
    237
    238          if not getattr(self.dmd, 'ZenPackManager'):
    239              msg = 'Your Zenoss database appears to be out of date. Try ' \
    240                      'running zenmigrate to update.'
    241              if REQUEST:
    242                  messaging.IMessageSender(self).sendToBrowser(
    243                      'Error', msg, priority=messaging.WARNING)
    244                  return self.callZenScreen(REQUEST)
    245              from ZenPack import ZenPackNeedMigrateException
    246              raise ZenPackNeedMigrateException(msg)
    247
    248          msg = ''
    249          with get_temp_dir() as tempDir:
    250              # zenpack.filename gives us filename of the zenpack with the
    251              # path as it exists on the client. We need just the filename.
    252              base_filename = re.split(r"\\|/", zenpack.filename)[-1]
    253              # Macs (and other broswers/OSs) always append a .zip to files they
    254              # believe to be zip files. Remedy that:
    255              if base_filename.endswith('.egg.zip'):
    256                  base_filename = base_filename[:-7] + 'egg'
    257
    258              # Write the zenpack to the filesystem
    259              tFile = open(os.path.join(tempDir, base_filename), 'wb')
    260              tFile.write(zenpack.read())
    261              tFile.close()
    262
    263              p = None # zenpack install process
    264              # ZEN-1781: Redirect to a temporary file so the stdout buffer
    265              # doesn't fill up and block till you read from it.
    266              outFile = None
    267              try:
    268                  outFile = tempfile.SpooledTemporaryFile()
    269                  # Run zenpack install
    270                  cmd = 'zenpack --install %s --fromui' % tFile.name
    271                  p = Popen(cmd, shell=True, stdout=outFile, stderr=STDOUT)
    272
    273                  endWait = time.time() + ZENPACK_INSTALL_TIMEOUT
    274                  # Wait for install to complete, fail, or time out
    275                  while p.poll() is None and time.time() < endWait:
    276                      time.sleep(1)
    277
    278                  if p.poll() is not None:
    279                      outFile.seek(0)
    280                      msg = outFile.read()
    281              finally:
    282                  if outFile:
    283                      outFile.close()
    284                  if p and p.poll() is None:
    285                      p.kill()
    286                      msg += 'Zenpack install killed due to timeout'
    287
    288          if REQUEST:
    289              # TODO: show the output in a scrollable window.
    290              # format command result for HTML
    291              #msg = '<br>'.join(line.strip() for line in msg.split('\n') if line.strip())
    292              log.info("Output from installing ZenPack %s:\n%s" % (zenpack.filename, msg))
    293              success = 'ERROR' not in msg
    294              msg = "Successfully installed ZenPack %s" % zenpack.filename if success \
    295                      else "Failed to install ZenPack %s. " \
    296                           "See event.log for details." % zenpack.filename
    297              messaging.IMessageSender(self).sendToBrowser('Zenpack', msg,
    298                  priority = messaging.INFO if success else messaging.CRITICAL)
    299              return self.callZenScreen(REQUEST)
    300
    301
    302 -    def getZnetProjectOptions(self):
    303          """
    304          Return a list of 2-tuples of (option value, option name) for the
    305          user to select a Zenoss.net project from.
    306          """
    307          projects = self.getZnetProjectsList()
    308          return [(p, p.split('/')[-1]) for p in projects]
    309
    310
    311 -    def getZnetProjectsList(self):
    312          """
    313          Return a list of the zenoss.net projects.
    314          """
    315          import json
    316          import Products.ZenUtils.DotNetCommunication as DotNetCommunication
    317          userSettings = self.dmd.ZenUsers.getUserSettings()
    318          session = DotNetCommunication.getDotNetSession(
    319                      userSettings.zenossNetUser,
    320                      userSettings.zenossNetPassword)
    321          projects = session.retrieve('projectList')
    322          projects = json.loads(projects)
    323          return projects
    324
    325
    326 -    def getBrokenPackName(self, ob):
    327          ''' Extract the zenpack name from the broken module
    328          '''
    329          return ob.id if ob.id and ob.id != 'broken' else ob.__class__.__module__
    330
    331
    332  InitializeClass(ZenPackManager)
    333