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

# Source Code for Module Products.ZenModel.zenbuild

      1  ###########################################################################
      2  #
      3  # This program is part of Zenoss Core, an open source monitoring platform.
      4  # Copyright (C) 2007, Zenoss Inc.
      5  #
      6  # This program is free software; you can redistribute it and/or modify it
      7  # under the terms of the GNU General Public License version 2 or (at your
      8  # option) any later version as published by the Free Software Foundation.
      9  #
     10  # For complete information please visit: http://www.zenoss.com/oss/
     11  #
     12  ###########################################################################
     13
     14  __doc__="""zenbuild
     15
     16  Build the zentinel portal object and the dmd database
     17
     18  $Id: DmdBuilder.py,v 1.11 2004/04/06 22:33:07 edahl Exp $"""
     19
     20  __version__ = "$Revision: 1.11 $"[11:-2]
     21
     22  import os
     23  import Globals
     24  import transaction
     25  import subprocess
     26
     27  from Products.ZenUtils.Utils import zenPath
     28
     29  from Products.ZenUtils import Security
     30  from Products.ZenUtils.CmdBase import CmdBase
     31  from Products.PluggableAuthService import plugins
     32  from MySQLdb import OperationalError
     33
     34 -class zenbuild(CmdBase):
     35
     36      sitename = "zport"
     37
     38 -    def connect(self):
     39          zopeconf = zenPath("etc/zope.conf")
     40          import Zope2
     41          Zope2.configure(zopeconf)
     42          self.app = Zope2.app()
     43
     44 -    def buildOptions(self):
     45          CmdBase.buildOptions(self)
     46          self.parser.add_option('--xml', dest="fromXml",
     47                  action='store_true', default=False,
     48                  help="Load data from XML files instead of SQL")
     49          self.parser.add_option('-s','--evthost', dest="evthost",
     50                  default="127.0.0.1", help="events database hostname")
     51          self.parser.add_option('-u','--evtuser', dest="evtuser", default="root",
     52                  help="username used to connect to the events database")
     53          self.parser.add_option('-p','--evtpass', dest="evtpass", default="",
     54                  help="password used to connect to the events database")
     55          self.parser.add_option('-d','--evtdb', dest="evtdb", default="events",
     56                  help="name of events database")
     57          self.parser.add_option('-t','--evtport', dest="evtport",
     58                  type='int', default=3306,
     59                  help="port used to connect to the events database")
     60          self.parser.add_option('--smtphost', dest="smtphost", default="localhost",
     61                  help="smtp host")
     62          self.parser.add_option('--smtpport', dest="smtpport", default=25,
     63                  help="smtp port")
     64          self.parser.add_option('--cachesize',
     65                      dest="cachesize",default=1000, type='int',
     66                      help="in memory cachesize default: 1000")
     67          self.parser.add_option('--host',
     68                      dest="host",default="localhost",
     69                      help="hostname of MySQL object store")
     70          self.parser.add_option('--port',
     71                      dest="port", type="int", default=3306,
     72                      help="port of MySQL object store")
     73          self.parser.add_option('--mysqluser', dest='mysqluser', default='zenoss',
     74                      help='username for MySQL object store')
     75          self.parser.add_option('--mysqlpasswd', dest='mysqlpasswd', default='zenoss',
     76                      help='passwd for MySQL object store')
     77          self.parser.add_option('--mysqldb', dest='mysqldb', default='zodb',
     78                      help='Name of database for MySQL object store')
     79          self.parser.add_option('--mysqlsocket', dest='mysqlsocket', default=None,
     80                      help='Name of socket file for MySQL server connection')
     81          self.parser.add_option('--cacheservers', dest='cacheservers',
     82                      default="127.0.0.1:11211",
     83                      help='memcached servers to use for object cache (eg. 127.0.0.1:11211)')
     84          self.parser.add_option('--pagecommand', dest="pagecommand", default="$ZENHOME/bin/zensnpp localhost 444 $RECIPIENT",
     85                  help="page command")
     86          # amqp stuff
     87          self.parser.add_option('--amqphost', dest="amqphost", default="localhost",
     88                                 help="AMQP Host Location")
     89          self.parser.add_option('--amqpport', dest="amqpport", default=5672,
     90                                 help="AMQP Server Port")
     91          self.parser.add_option('--amqpvhost', dest="amqpvhost", default="/zenoss",
     92                                 help="Default Virtual Host")
     93          self.parser.add_option('--amqpuser', dest="amqpuser", default="zenoss",
     94                                 help="AMQP User Name")
     95          self.parser.add_option('--amqppassword', dest="amqppassword", default="zenoss",
     96                                 help="AMQP Password")
     97
     98 -    def zodbConnect(self):
     99          """
    100          Used to connect to ZODB (without going through the entire ZOPE
    101          initialization process. This allows us to get a lightweight
    102          connection to the database to test to see if the database is already
    103          initialized.
    104          """
    105          self.options.port = self.options.port or 3306
    106          from relstorage.storage import RelStorage
    107          from relstorage.adapters.mysql import MySQLAdapter
    108          connectionParams = {
    109              'host' : self.options.host,
    110              'port' : self.options.port,
    111              'user' : self.options.mysqluser,
    112              'passwd' : self.options.mysqlpasswd,
    113              'db' : self.options.mysqldb,
    114          }
    115          if getattr(self.options, 'mysqlsocket', None) and self.options.mysqlsocket != 'None':
    116              connectionParams['unix_socket'] = self.options.mysqlsocket
    117
    118          kwargs = {
    119              'keep_history': False,
    120          }
    121          from relstorage.options import Options
    122          adapter = MySQLAdapter(options=Options(**kwargs),**connectionParams)
    123          self.storage = RelStorage(adapter, **kwargs)
    124          from ZODB import DB
    125          self.db = DB(self.storage, cache_size=self.options.cachesize)
    126
    127 -    def build(self):
    128          mysqlcmd = ['mysql', '-u', self.options.mysqluser]
    129          if self.options.mysqlpasswd:
    130              mysqlcmd.append('-p%s' % self.options.mysqlpasswd)
    131          mysqlcmd.extend([
    132              '-h', self.options.host,
    133              '--port', str(self.options.port)
    134          ])
    135
    136          mysqlcmd = subprocess.list2cmdline(mysqlcmd)
    137
    138          conn = None
    139          try:
    140              self.zodbConnect()
    141              conn = self.db.open()
    142              root = conn.root()
    143              app = root.get('Application')
    144              if app and getattr(app, self.sitename, None) is not None:
    145                  print "zport portal object exists; exiting."
    146                  return
    147          except OperationalError, e:
    148              if 'Unknown database' in e[1]:
    149                  queries = (
    150                      'CREATE DATABASE %s;' % self.options.mysqldb,
    151                      "GRANT ALL ON %s.* TO %s@'%s' IDENTIFIED BY '%s';" % (
    152                          self.options.mysqldb, self.options.mysqluser,
    153                          self.options.host, self.options.mysqlpasswd),
    154                      "GRANT ALL ON %s.* TO %s@'%%' IDENTIFIED BY '%s';" % (
    155                          self.options.mysqldb, self.options.mysqluser,
    156                          self.options.mysqlpasswd),
    157                      "FLUSH PRIVILEGES;"
    158                  )
    159
    160                  for query in queries:
    161                      cmd = mysqlcmd + ' -e "%s"' % query
    162                      os.system(cmd)
    163              else:
    164                  raise
    165          finally:
    166              if conn:
    167                  conn.close()
    168              if self.db:
    169                  self.db.close()
    170                  self.db = None
    171              if self.storage:
    172                  self.storage.close()
    173                  self.storage = None
    174
    175          if self.options.fromXml:
    176              self.connect()
    177              from Products.ZenModel.ZentinelPortal import manage_addZentinelPortal
    178              manage_addZentinelPortal(self.app, self.sitename)
    179              site = self.app._getOb(self.sitename)
    180
    181              # build index_html
    182              if self.app.hasObject('index_html'):
    183                  self.app._delObject('index_html')
    184              from Products.PythonScripts.PythonScript import manage_addPythonScript
    185              manage_addPythonScript(self.app, 'index_html')
    186              newIndexHtml = self.app._getOb('index_html')
    187              text = 'container.REQUEST.RESPONSE.redirect("/zport/dmd/")\n'
    188              newIndexHtml.ZPythonScript_edit('', text)
    189
    190              # build standard_error_message
    191              if self.app.hasObject('standard_error_message'):
    192                  self.app._delObject('standard_error_message')
    193              file = open(zenPath('Products/ZenModel/dtml/standard_error_message.dtml'))
    194              try:
    195                  text = file.read()
    196              finally:
    197                  file.close()
    198              import OFS.DTMLMethod
    199              OFS.DTMLMethod.addDTMLMethod(self.app, id='standard_error_message',
    200                                              file=text)
    201
    202              # Convert the acl_users folder at the root to a PAS folder and update
    203              # the login form to use the Zenoss login form
    204              Security.replaceACLWithPAS(self.app, deleteBackup=True)
    205
    206              # Add groupManager to zport.acl
    207              acl = site.acl_users
    208              if not hasattr(acl, 'groupManager'):
    209                  plugins.ZODBGroupManager.addZODBGroupManager(acl, 'groupManager')
    210              acl.groupManager.manage_activateInterfaces(['IGroupsPlugin',])
    211
    212              trans = transaction.get()
    213              trans.note("Initial ZentinelPortal load by zenbuild.py")
    214              trans.commit()
    215              print "ZentinelPortal loaded at %s" % self.sitename
    216
    217              # build dmd
    218              from Products.ZenModel.DmdBuilder import DmdBuilder
    219              dmdBuilder = DmdBuilder(site,
    220                                      self.options.evthost,
    221                                      self.options.evtuser,
    222                                      self.options.evtpass,
    223                                      self.options.evtdb,
    224                                      self.options.evtport,
    225                                      self.options.smtphost,
    226                                      self.options.smtpport,
    227                                      self.options.pagecommand)
    228              dmdBuilder.build()
    229              transaction.commit()
    230
    231              # Load XML Data
    232              from Products.ZenModel.XmlDataLoader import XmlDataLoader
    233              dl = XmlDataLoader(noopts=True, app=self.app)
    234              dl.loadDatabase()
    235
    236          else:
    237
    238              mysqlcmd += ' %s' % self.options.mysqldb
    239
    240              cmd = 'cat $ZENHOME/Products/ZenModel/data/zodb.sql.gz | gzip -c -d | %s' % mysqlcmd
    241              os.system(cmd)
    242
    243              # Relstorage may have already loaded items into the cache in the
    244              # initial connection to the database. We have to expire everything
    245              # in the cache in order to prevent errors with overlapping
    246              # transactions from the model which was just imported above.
    247              if self.options.cacheservers:
    248                  self.flush_memcached(self.options.cacheservers.split())
    249
    250              self.connect()
    251
    252              # Set all the attributes
    253              site = getattr(self.app, self.sitename, None)
    254              site.dmd.smtpHost = self.options.smtphost
    255              site.dmd.smtpPort = self.options.smtpport
    256              site.dmd.pageCommand = self.options.pagecommand
    257              site.dmd.uuid = None
    258              site.dmd._rq = False
    259              for evmgr in (site.dmd.ZenEventManager, site.dmd.ZenEventHistory):
    260                  evmgr.username = self.options.evtuser
    261                  evmgr.password = self.options.evtpass
    262                  evmgr.database = self.options.evtdb
    263                  evmgr.host = self.options.evthost
    264                  evmgr.port = self.options.evtport
    265              transaction.commit()
    266
    267          # Update the global conf
    268          print "Updating global.conf"
    269          zenglobalconf = zenPath('bin', 'zenglobalconf')
    270          cmd = [zenglobalconf, '-u']
    271          for opt in ('host', 'port', 'mysqldb', 'mysqluser', 'mysqlpasswd',
    272                      'amqphost', 'amqpport', 'amqpvhost', 'amqpuser',
    273                      'amqppassword', 'cacheservers'):
    274              cmd.append('%s=%s' % (opt, getattr(self.options, opt)))
    275          subprocess.call(cmd)
    276
    277          # Load reports
    278          from Products.ZenReports.ReportLoader import ReportLoader
    279          rl = ReportLoader(noopts=True, app=self.app)
    280          rl.loadDatabase()
    281
    282 -    def flush_memcached(self, cacheservers):
    283          import memcache
    284          mc = memcache.Client(cacheservers, debug=0)
    285          mc.flush_all()
    286          mc.disconnect_all()
    287
    288  if __name__ == "__main__":
    289      zb = zenbuild()
    290      zb.build()
    291