server/serverconfig.py
changeset 0 b97547f5f1fa
child 136 ff51a18c66a3
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """server.serverconfig definition
       
     2 
       
     3 :organization: Logilab
       
     4 :copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     6 """
       
     7 __docformat__ = "restructuredtext en"
       
     8 
       
     9 import os
       
    10 from os.path import join, exists
       
    11 
       
    12 from logilab.common.configuration import Method
       
    13 from logilab.common.decorators import wproperty, cached, clear_cache
       
    14 
       
    15 from cubicweb import CW_SOFTWARE_ROOT, RegistryNotFound
       
    16 from cubicweb.toolsutils import env_path, read_config
       
    17 from cubicweb.cwconfig import CubicWebConfiguration, merge_options
       
    18 
       
    19 
       
    20 class ServerConfiguration(CubicWebConfiguration):
       
    21     """standalone RQL server"""
       
    22     name = 'repository'
       
    23     if os.environ.get('APYCOT_ROOT'):
       
    24         root = os.environ['APYCOT_ROOT']
       
    25         SCHEMAS_LIB_DIR = '%s/local/share/cubicweb/schemas/' % root
       
    26     elif CubicWebConfiguration.mode == 'dev':
       
    27         SCHEMAS_LIB_DIR = join(CW_SOFTWARE_ROOT, 'schemas')
       
    28         BACKUP_DIR = CubicWebConfiguration.RUNTIME_DIR
       
    29     else:
       
    30         SCHEMAS_LIB_DIR = '/usr/share/cubicweb/schemas/'
       
    31         BACKUP_DIR = '/var/lib/cubicweb/backup/'
       
    32 
       
    33     cubicweb_vobject_path = CubicWebConfiguration.cubicweb_vobject_path | set(['sobjects'])
       
    34     cube_vobject_path = CubicWebConfiguration.cube_vobject_path | set(['sobjects', 'hooks'])
       
    35 
       
    36     options = merge_options((
       
    37         # ctl configuration
       
    38         ('host',
       
    39          {'type' : 'string',
       
    40           'default': None,
       
    41           'help': 'host name if not correctly detectable through gethostname',
       
    42           'group': 'main', 'inputlevel': 1,
       
    43           }),
       
    44         ('pid-file',
       
    45          {'type' : 'string',
       
    46           'default': Method('default_pid_file'),
       
    47           'help': 'repository\'s pid file',
       
    48           'group': 'main', 'inputlevel': 2,
       
    49           }),
       
    50         ('uid',
       
    51          {'type' : 'string',
       
    52           'default': None,
       
    53           'help': 'if this option is set, use the specified user to start \
       
    54 the repository rather than the user running the command',
       
    55           'group': 'main', 'inputlevel': 0,
       
    56           }),
       
    57         ('session-time',
       
    58          {'type' : 'int',
       
    59           'default': 30*60,
       
    60           'help': 'session expiration time, default to 30 minutes',
       
    61           'group': 'main', 'inputlevel': 1,
       
    62           }),
       
    63         ('connections-pool-size',
       
    64          {'type' : 'int',
       
    65           'default': 4,
       
    66           'help': 'size of the connections pools. Each source supporting multiple \
       
    67 connections will have this number of opened connections.',
       
    68           'group': 'main', 'inputlevel': 1,
       
    69           }),
       
    70         ('rql-cache-size',
       
    71          {'type' : 'int',
       
    72           'default': 300,
       
    73           'help': 'size of the parsed rql cache size.',
       
    74           'group': 'main', 'inputlevel': 1,
       
    75           }),
       
    76         # email configuration
       
    77         ('default-recipients-mode',
       
    78          {'type' : 'choice',
       
    79           'choices' : ('default-dest-addrs', 'users', 'none'),
       
    80           'default': 'default-dest-addrs',
       
    81           'help': 'when a notification should be sent with no specific rules \
       
    82 to find recipients, recipients will be found according to this mode. Available \
       
    83 modes are "default-dest-addrs" (emails specified in the configuration \
       
    84 variable with the same name), "users" (every users which has activated \
       
    85 account with an email set), "none" (no notification).',
       
    86           'group': 'email', 'inputlevel': 1,
       
    87           }),
       
    88         ('default-dest-addrs',
       
    89          {'type' : 'csv',
       
    90           'default': (),
       
    91           'help': 'comma separated list of email addresses that will be used \
       
    92 as default recipient when an email is sent and the notification has no \
       
    93 specific recipient rules.',
       
    94           'group': 'email', 'inputlevel': 1,
       
    95           }),
       
    96         ('supervising-addrs',
       
    97          {'type' : 'csv',
       
    98           'default': (),
       
    99           'help': 'comma separated list of email addresses that will be \
       
   100 notified of every changes.',
       
   101           'group': 'email', 'inputlevel': 2,
       
   102           }),
       
   103         # pyro server.serverconfig
       
   104         ('pyro-port',
       
   105          {'type' : 'int',
       
   106           'default': None,
       
   107           'help': 'Pyro server port. If not set, it will be choosen randomly',
       
   108           'group': 'pyro-server', 'inputlevel': 2,
       
   109           }),
       
   110         ('pyro-id', # XXX reuse pyro-application-id
       
   111          {'type' : 'string',
       
   112           'default': None,
       
   113           'help': 'identifier of the repository in the pyro name server',
       
   114           'group': 'pyro-server', 'inputlevel': 2,
       
   115           }),
       
   116         ) + CubicWebConfiguration.options)
       
   117         
       
   118     # read the schema from the database
       
   119     read_application_schema = True
       
   120     bootstrap_schema = True
       
   121     
       
   122     # check user's state at login time
       
   123     consider_user_state = True
       
   124     
       
   125     # hooks registration configuration
       
   126     # all hooks should be activated during normal execution
       
   127     core_hooks = True
       
   128     usergroup_hooks = True
       
   129     schema_hooks = True
       
   130     notification_hooks = True
       
   131     security_hooks = True
       
   132     application_hooks = True
       
   133 
       
   134     # should some hooks be deactivated during [pre|post]create script execution
       
   135     free_wheel = False
       
   136     
       
   137     # list of enables sources when sources restriction is necessary
       
   138     # (eg repository initialization at least)
       
   139     _enabled_sources = None
       
   140     @wproperty
       
   141     def enabled_sources(self, sourceuris=None):
       
   142         self._enabled_sources = sourceuris
       
   143         clear_cache(self, 'sources')
       
   144         
       
   145     @classmethod
       
   146     def schemas_lib_dir(cls):
       
   147         """application schema directory"""
       
   148         return env_path('CW_SCHEMA_LIB', cls.SCHEMAS_LIB_DIR, 'schemas')
       
   149 
       
   150     @classmethod
       
   151     def backup_dir(cls):
       
   152         """backup directory where a stored db backups before migration"""
       
   153         return env_path('CW_BACKUP', cls.BACKUP_DIR, 'run time')
       
   154 
       
   155     def bootstrap_cubes(self):
       
   156         from logilab.common.textutils import get_csv
       
   157         for line in file(join(self.apphome, 'bootstrap_cubes')):
       
   158             line = line.strip()
       
   159             if not line or line.startswith('#'):
       
   160                 continue
       
   161             self.init_cubes(self.expand_cubes(get_csv(line)))
       
   162             break
       
   163         else:
       
   164             # no cubes
       
   165             self.init_cubes(())
       
   166         
       
   167     def write_bootstrap_cubes_file(self, cubes):
       
   168         stream = file(join(self.apphome, 'bootstrap_cubes'), 'w')
       
   169         stream.write('# this is a generated file only used for bootstraping\n')
       
   170         stream.write('# you should not have to edit this\n')
       
   171         stream.write('%s\n' % ','.join(cubes))
       
   172         stream.close()
       
   173         
       
   174     def sources_file(self):
       
   175         return join(self.apphome, 'sources')
       
   176     
       
   177     # this method has to be cached since when the server is running using a
       
   178     # restricted user, this user usually don't have access to the sources
       
   179     # configuration file (#16102)
       
   180     @cached
       
   181     def sources(self):
       
   182         """return a dictionnaries containing sources definitions indexed by
       
   183         sources'uri
       
   184         """
       
   185         allsources = read_config(self.sources_file())
       
   186         if self._enabled_sources is None:
       
   187             return allsources
       
   188         return dict((uri, config) for uri, config in allsources.items()
       
   189                     if uri in self._enabled_sources or uri == 'admin')
       
   190     
       
   191     def pyro_enabled(self):
       
   192         """pyro is always enabled in standalone repository configuration"""
       
   193         return True
       
   194         
       
   195     def load_hooks(self, vreg):
       
   196         hooks = {}
       
   197         for path in reversed([self.apphome] + self.cubes_path()):
       
   198             hooksfile = join(path, 'application_hooks.py')
       
   199             if exists(hooksfile):
       
   200                 self.warning('application_hooks.py is deprecated, use dynamic '
       
   201                              'objects to register hooks (%s)', hooksfile)
       
   202                 context = {}
       
   203                 # Use execfile rather than `load_module_from_name` because 
       
   204                 # the latter gets fooled by the `sys.modules` cache when 
       
   205                 # loading different configurations one after the other
       
   206                 # (another fix would have been to do :
       
   207                 #    sys.modules.pop('applications_hooks')
       
   208                 #  or to modify load_module_from_name so that it provides
       
   209                 #  a use_cache optional parameter
       
   210                 execfile(hooksfile, context, context)
       
   211                 for event, hooksdef in context['HOOKS'].items():
       
   212                     for ertype, hookcbs in hooksdef.items():
       
   213                         hooks.setdefault(event, {}).setdefault(ertype, []).extend(hookcbs)
       
   214         try:
       
   215             apphookdefs = vreg.registry_objects('hooks')
       
   216         except RegistryNotFound:
       
   217             return hooks
       
   218         for hookdef in apphookdefs:
       
   219             for event, ertype in hookdef.register_to():
       
   220                 if ertype == 'Any':
       
   221                     ertype = ''
       
   222                 cb = hookdef.make_callback(event)
       
   223                 hooks.setdefault(event, {}).setdefault(ertype, []).append(cb)
       
   224         return hooks
       
   225     
       
   226     def load_schema(self, expand_cubes=False):
       
   227         from cubicweb.schema import CubicWebSchemaLoader
       
   228         if expand_cubes:
       
   229             # in case some new dependencies have been introduced, we have to
       
   230             # reinitialize cubes so the full filesystem schema is read
       
   231             origcubes = self.cubes()
       
   232             self._cubes = None
       
   233             self.init_cubes(self.expand_cubes(origcubes))
       
   234         schema = CubicWebSchemaLoader().load(self)
       
   235         if expand_cubes:
       
   236             # restaure original value
       
   237             self._cubes = origcubes
       
   238         return schema
       
   239     
       
   240     def load_bootstrap_schema(self):
       
   241         from cubicweb.schema import BootstrapSchemaLoader
       
   242         schema = BootstrapSchemaLoader().load(self)
       
   243         schema.name = 'bootstrap'
       
   244         return schema
       
   245     
       
   246     def set_sources_mode(self, sources):
       
   247         if 'migration' in sources:
       
   248             from cubicweb.server.sources import source_adapter
       
   249             assert len(sources) == 1
       
   250             enabled_sources = []
       
   251             for uri, config in self.sources().iteritems():
       
   252                 if uri == 'admin':
       
   253                     continue
       
   254                 if source_adapter(config).connect_for_migration:
       
   255                     enabled_sources.append(uri)
       
   256                 else:
       
   257                     print 'not connecting to source', uri, 'during migration'
       
   258         elif 'all' in sources:
       
   259             assert len(sources) == 1
       
   260             enabled_sources= None
       
   261         else:
       
   262             known_sources = self.sources()
       
   263             for uri in sources:
       
   264                 assert uri in known_sources, uri
       
   265             enabled_sources = sources
       
   266         self._enabled_sources = enabled_sources
       
   267         clear_cache(self, 'sources')
       
   268         
       
   269     def migration_handler(self, schema=None, interactive=True,
       
   270                           cnx=None, repo=None, connect=True):
       
   271         """return a migration handler instance"""
       
   272         from cubicweb.server.migractions import ServerMigrationHelper
       
   273         return ServerMigrationHelper(self, schema, interactive=interactive,
       
   274                                      cnx=cnx, repo=repo, connect=connect,
       
   275                                      verbosity=getattr(self, 'verbosity', 0))