server/serverctl.py
changeset 2144 51c84d585456
parent 2107 6c4a4c514ac2
child 2394 92bba46b853f
child 2417 18a14c23413c
equal deleted inserted replaced
2141:0072247db207 2144:51c84d585456
     8 __docformat__ = "restructuredtext en"
     8 __docformat__ = "restructuredtext en"
     9 
     9 
    10 import sys
    10 import sys
    11 import os
    11 import os
    12 
    12 
    13 from logilab.common.configuration import REQUIRED, Configuration, ini_format_section
    13 from logilab.common.configuration import Configuration
    14 from logilab.common.clcommands import register_commands, cmd_run, pop_arg
    14 from logilab.common.clcommands import register_commands, cmd_run, pop_arg
    15 
    15 
    16 from cubicweb import AuthenticationError, ExecutionError, ConfigurationError
    16 from cubicweb import AuthenticationError, ExecutionError, ConfigurationError
    17 from cubicweb.toolsutils import (Command, CommandHandler, confirm,
    17 from cubicweb.toolsutils import Command, CommandHandler, confirm
    18                                  restrict_perms_to_user)
    18 from cubicweb.server import SOURCE_TYPES
    19 from cubicweb.server.serverconfig import ServerConfiguration
    19 from cubicweb.server.utils import ask_source_config
       
    20 from cubicweb.server.serverconfig import USER_OPTIONS, ServerConfiguration
    20 
    21 
    21 
    22 
    22 # utility functions ###########################################################
    23 # utility functions ###########################################################
    23 
    24 
    24 def source_cnx(source, dbname=None, special_privs=False, verbose=True):
    25 def source_cnx(source, dbname=None, special_privs=False, verbose=True):
    90     except AttributeError:
    91     except AttributeError:
    91         # set_isolation_level() is psycopg specific
    92         # set_isolation_level() is psycopg specific
    92         pass
    93         pass
    93     return cnx
    94     return cnx
    94 
    95 
    95 def generate_sources_file(sourcesfile, sourcescfg, keys=None):
       
    96     """serialize repository'sources configuration into a INI like file
       
    97 
       
    98     the `keys` parameter may be used to sort sections
       
    99     """
       
   100     from cubicweb.server.sources import SOURCE_TYPES
       
   101     if keys is None:
       
   102         keys = sourcescfg.keys()
       
   103     else:
       
   104         for key in sourcescfg:
       
   105             if not key in keys:
       
   106                 keys.append(key)
       
   107     stream = open(sourcesfile, 'w')
       
   108     for uri in keys:
       
   109         sconfig = sourcescfg[uri]
       
   110         if isinstance(sconfig, dict):
       
   111             # get a Configuration object
       
   112             _sconfig = Configuration(options=SOURCE_TYPES[sconfig['adapter']].options)
       
   113             for attr, val in sconfig.items():
       
   114                 if attr == 'uri':
       
   115                     continue
       
   116                 if attr == 'adapter':
       
   117                     _sconfig.adapter = val
       
   118                 else:
       
   119                     _sconfig.set_option(attr, val)
       
   120             sconfig = _sconfig
       
   121         optsbysect = list(sconfig.options_by_section())
       
   122         assert len(optsbysect) == 1, 'all options for a source should be in the same group'
       
   123         ini_format_section(stream, uri, optsbysect[0][1])
       
   124         if hasattr(sconfig, 'adapter'):
       
   125             print >> stream
       
   126             print >> stream, '# adapter for this source (YOU SHOULD NOT CHANGE THIS)'
       
   127             print >> stream, 'adapter=%s' % sconfig.adapter
       
   128         print >> stream
       
   129 
       
   130 def repo_cnx(config):
    96 def repo_cnx(config):
   131     """return a in-memory repository and a db api connection it"""
    97     """return a in-memory repository and a db api connection it"""
   132     from cubicweb.dbapi import in_memory_cnx
    98     from cubicweb.dbapi import in_memory_cnx
   133     from cubicweb.server.utils import manager_userpasswd
    99     from cubicweb.server.utils import manager_userpasswd
   134     try:
   100     try:
   153 
   119 
   154     def bootstrap(self, cubes, inputlevel=0):
   120     def bootstrap(self, cubes, inputlevel=0):
   155         """create an application by copying files from the given cube and by
   121         """create an application by copying files from the given cube and by
   156         asking information necessary to build required configuration files
   122         asking information necessary to build required configuration files
   157         """
   123         """
   158         from cubicweb.server.sources import SOURCE_TYPES
       
   159         config = self.config
   124         config = self.config
   160         print 'application\'s repository configuration'
   125         print 'application\'s repository configuration'
   161         print '-' * 72
   126         print '-' * 72
   162         config.input_config('email', inputlevel)
   127         config.input_config('email', inputlevel)
   163         if config.pyro_enabled():
   128         if config.pyro_enabled():
   168         sourcesfile = config.sources_file()
   133         sourcesfile = config.sources_file()
   169         sconfig = Configuration(options=SOURCE_TYPES['native'].options)
   134         sconfig = Configuration(options=SOURCE_TYPES['native'].options)
   170         sconfig.adapter = 'native'
   135         sconfig.adapter = 'native'
   171         sconfig.input_config(inputlevel=inputlevel)
   136         sconfig.input_config(inputlevel=inputlevel)
   172         sourcescfg = {'system': sconfig}
   137         sourcescfg = {'system': sconfig}
       
   138         for cube in cubes:
       
   139             # if a source is named as the cube containing it, we need the
       
   140             # source to use the cube, so add it.
       
   141             if cube in SOURCE_TYPES:
       
   142                 sourcescfg[cube] = ask_source_config(cube, inputlevel)
   173         while raw_input('enter another source [y/N]: ').strip().lower() == 'y':
   143         while raw_input('enter another source [y/N]: ').strip().lower() == 'y':
   174             sourcetype = raw_input('source type (%s): ' % ', '.join(SOURCE_TYPES.keys()))
   144             available = sorted(stype for stype in SOURCE_TYPES
   175             sconfig = Configuration(options=SOURCE_TYPES[sourcetype].options)
   145                                if not stype in cubes)
   176             sconfig.adapter = sourcetype
   146             while True:
   177             sourceuri = raw_input('source uri: ').strip()
   147                 sourcetype = raw_input('source type (%s): ' % ', '.join(available))
   178             assert not sourceuri in sourcescfg
   148                 if sourcetype in available:
   179             sconfig.input_config(inputlevel=inputlevel)
   149                     break
   180             sourcescfg[sourceuri] = sconfig
   150                 print 'unknown source type, use one of the available type'
   181             # module names look like cubes.mycube.themodule
   151             while True:
   182             sourcecube = SOURCE_TYPES[sourcetype].module.split('.', 2)[1]
   152                 sourceuri = raw_input('source uri: ').strip()
   183             # if the source adapter is coming from an external component, ensure
   153                 if sourceuri != 'admin' and sourceuri not in sourcescfg:
   184             # it's specified in used cubes
   154                     break
   185             if sourcecube != 'cubicweb' and not sourcecube in cubes:
   155                 print 'uri already used, choose another one'
   186                 cubes.append(sourcecube)
   156             sourcescfg[sourceuri] = ask_source_config(sourcetype)
       
   157             sourcemodule = SOURCE_TYPES[sourcetype].module
       
   158             if not sourcemodule.startswith('cubicweb.'):
       
   159                 # module names look like cubes.mycube.themodule
       
   160                 sourcecube = SOURCE_TYPES[sourcetype].module.split('.', 2)[1]
       
   161                 # if the source adapter is coming from an external component,
       
   162                 # ensure it's specified in used cubes
       
   163                 if not sourcecube in cubes:
       
   164                     cubes.append(sourcecube)
   187         sconfig = Configuration(options=USER_OPTIONS)
   165         sconfig = Configuration(options=USER_OPTIONS)
   188         sconfig.input_config(inputlevel=inputlevel)
   166         sconfig.input_config(inputlevel=inputlevel)
   189         sourcescfg['admin'] = sconfig
   167         sourcescfg['admin'] = sconfig
   190         generate_sources_file(sourcesfile, sourcescfg, ['admin', 'system'])
   168         config.write_sources_file(sourcescfg)
   191         restrict_perms_to_user(sourcesfile)
       
   192         # remember selected cubes for later initialization of the database
   169         # remember selected cubes for later initialization of the database
   193         config.write_bootstrap_cubes_file(cubes)
   170         config.write_bootstrap_cubes_file(cubes)
   194 
   171 
   195     def postcreate(self):
   172     def postcreate(self):
   196         if confirm('do you want to create repository\'s system database?'):
   173         if confirm('do you want to create repository\'s system database?'):
   197             verbosity = (self.config.mode == 'installed') and 'y' or 'n'
   174             verbosity = (self.config.mode == 'installed') and 'y' or 'n'
   198             cmd_run('db-create', self.config.appid, '--verbose=%s' % verbosity)
   175             cmd_run('db-create', self.config.appid, '--verbose=%s' % verbosity)
   199         else:
   176         else:
   200             print 'nevermind, you can do it later using the db-create command'
   177             print 'nevermind, you can do it later using the db-create command'
   201 
       
   202 USER_OPTIONS =  (
       
   203     ('login', {'type' : 'string',
       
   204                'default': REQUIRED,
       
   205                'help': "cubicweb manager account's login "
       
   206                '(this user will be created)',
       
   207                'inputlevel': 0,
       
   208                }),
       
   209     ('password', {'type' : 'password',
       
   210                   'help': "cubicweb manager account's password",
       
   211                   'inputlevel': 0,
       
   212                   }),
       
   213     )
       
   214 
   178 
   215 
   179 
   216 class RepositoryDeleteHandler(CommandHandler):
   180 class RepositoryDeleteHandler(CommandHandler):
   217     cmdname = 'delete'
   181     cmdname = 'delete'
   218     cfgname = 'repository'
   182     cfgname = 'repository'
   433         """run the command with its specific arguments"""
   397         """run the command with its specific arguments"""
   434         from cubicweb.server.sqlutils import sqlexec, SQL_PREFIX
   398         from cubicweb.server.sqlutils import sqlexec, SQL_PREFIX
   435         from cubicweb.server.utils import crypt_password, manager_userpasswd
   399         from cubicweb.server.utils import crypt_password, manager_userpasswd
   436         appid = pop_arg(args, 1, msg="No application specified !")
   400         appid = pop_arg(args, 1, msg="No application specified !")
   437         config = ServerConfiguration.config_for(appid)
   401         config = ServerConfiguration.config_for(appid)
   438         sourcescfg = config.sources()
   402         sourcescfg = config.read_sources_file()
   439         try:
   403         try:
   440             adminlogin = sourcescfg['admin']['login']
   404             adminlogin = sourcescfg['admin']['login']
   441         except KeyError:
   405         except KeyError:
   442             print 'could not get cubicweb administrator login'
   406             print 'could not get cubicweb administrator login'
   443             sys.exit(1)
   407             sys.exit(1)
   452                     cursor, withpb=False)
   416                     cursor, withpb=False)
   453             sconfig = Configuration(options=USER_OPTIONS)
   417             sconfig = Configuration(options=USER_OPTIONS)
   454             sconfig['login'] = adminlogin
   418             sconfig['login'] = adminlogin
   455             sconfig['password'] = passwd
   419             sconfig['password'] = passwd
   456             sourcescfg['admin'] = sconfig
   420             sourcescfg['admin'] = sconfig
   457             sourcesfile = config.sources_file()
   421             config.write_sources_file(sourcescfg)
   458             generate_sources_file(sourcesfile, sourcescfg)
       
   459             restrict_perms_to_user(sourcesfile)
       
   460         except Exception, ex:
   422         except Exception, ex:
   461             cnx.rollback()
   423             cnx.rollback()
   462             import traceback
   424             import traceback
   463             traceback.print_exc()
   425             traceback.print_exc()
   464             print 'An error occured:', ex
   426             print 'An error occured:', ex