server/serverctl.py
branchstable
changeset 7140 ba51dac1115d
parent 7121 c2badb6de3fe
child 7155 4bab50b02927
equal deleted inserted replaced
7139:20807d3d7cf6 7140:ba51dac1115d
    25 import sys
    25 import sys
    26 import os
    26 import os
    27 
    27 
    28 from logilab.common import nullobject
    28 from logilab.common import nullobject
    29 from logilab.common.configuration import Configuration
    29 from logilab.common.configuration import Configuration
    30 from logilab.common.shellutils import ASK
    30 from logilab.common.shellutils import ASK, generate_password
    31 
    31 
    32 from cubicweb import AuthenticationError, ExecutionError, ConfigurationError
    32 from cubicweb import AuthenticationError, ExecutionError, ConfigurationError
    33 from cubicweb.toolsutils import Command, CommandHandler, underline_title
    33 from cubicweb.toolsutils import Command, CommandHandler, underline_title
    34 from cubicweb.cwctl import CWCTL
    34 from cubicweb.cwctl import CWCTL, check_options_consistency
    35 from cubicweb.server import SOURCE_TYPES
    35 from cubicweb.server import SOURCE_TYPES
    36 from cubicweb.server.serverconfig import (
    36 from cubicweb.server.serverconfig import (
    37     USER_OPTIONS, ServerConfiguration, SourceConfiguration,
    37     USER_OPTIONS, ServerConfiguration, SourceConfiguration,
    38     ask_source_config, generate_source_config)
    38     ask_source_config, generate_source_config)
    39 
    39 
   152 
   152 
   153 class RepositoryCreateHandler(CommandHandler):
   153 class RepositoryCreateHandler(CommandHandler):
   154     cmdname = 'create'
   154     cmdname = 'create'
   155     cfgname = 'repository'
   155     cfgname = 'repository'
   156 
   156 
   157     def bootstrap(self, cubes, inputlevel=0):
   157     def bootstrap(self, cubes, automatic=False, inputlevel=0):
   158         """create an instance by copying files from the given cube and by asking
   158         """create an instance by copying files from the given cube and by asking
   159         information necessary to build required configuration files
   159         information necessary to build required configuration files
   160         """
   160         """
   161         config = self.config
   161         config = self.config
   162         print underline_title('Configuring the repository')
   162         if not automatic:
   163         config.input_config('email', inputlevel)
   163             print underline_title('Configuring the repository')
   164         # ask for pyro configuration if pyro is activated and we're not using a
   164             config.input_config('email', inputlevel)
   165         # all-in-one config, in which case this is done by the web side command
   165             # ask for pyro configuration if pyro is activated and we're not
   166         # handler
   166             # using a all-in-one config, in which case this is done by the web
   167         if config.pyro_enabled() and config.name != 'all-in-one':
   167             # side command handler
   168             config.input_config('pyro', inputlevel)
   168             if config.pyro_enabled() and config.name != 'all-in-one':
   169         print '\n'+underline_title('Configuring the sources')
   169                 config.input_config('pyro', inputlevel)
       
   170             print '\n'+underline_title('Configuring the sources')
   170         sourcesfile = config.sources_file()
   171         sourcesfile = config.sources_file()
   171         # XXX hack to make Method('default_instance_id') usable in db option
   172         # hack to make Method('default_instance_id') usable in db option defs
   172         # defs (in native.py)
   173         # (in native.py)
   173         sconfig = SourceConfiguration(config,
   174         sconfig = SourceConfiguration(config,
   174                                       options=SOURCE_TYPES['native'].options)
   175                                       options=SOURCE_TYPES['native'].options)
   175         sconfig.input_config(inputlevel=inputlevel)
   176         if not automatic:
       
   177             sconfig.input_config(inputlevel=inputlevel)
       
   178             print
   176         sourcescfg = {'system': sconfig}
   179         sourcescfg = {'system': sconfig}
   177         print
   180         if automatic:
   178         sconfig = Configuration(options=USER_OPTIONS)
   181             # XXX modify a copy
   179         sconfig.input_config(inputlevel=inputlevel)
   182             password = generate_password()
       
   183             print 'Administration account is admin / %s' % password
       
   184             USER_OPTIONS[1][1]['default'] = password
       
   185             sconfig = Configuration(options=USER_OPTIONS)
       
   186         else:
       
   187             sconfig = Configuration(options=USER_OPTIONS)
       
   188             sconfig.input_config(inputlevel=inputlevel)
   180         sourcescfg['admin'] = sconfig
   189         sourcescfg['admin'] = sconfig
   181         config.write_sources_file(sourcescfg)
   190         config.write_sources_file(sourcescfg)
   182         # remember selected cubes for later initialization of the database
   191         # remember selected cubes for later initialization of the database
   183         config.write_bootstrap_cubes_file(cubes)
   192         config.write_bootstrap_cubes_file(cubes)
   184 
   193 
   185     def postcreate(self):
   194     def postcreate(self, automatic=False, inputlevel=0):
   186         if ASK.confirm('Run db-create to create the system database ?'):
   195         if automatic:
   187             verbosity = (self.config.mode == 'installed') and 'y' or 'n'
   196             CWCTL.run(['db-create', '--automatic', self.config.appid])
   188             CWCTL.run(['db-create', self.config.appid])
   197         elif ASK.confirm('Run db-create to create the system database ?'):
       
   198             CWCTL.run(['db-create', '--config-level', str(inputlevel),
       
   199                        self.config.appid])
   189         else:
   200         else:
   190             print ('-> nevermind, you can do it later with '
   201             print ('-> nevermind, you can do it later with '
   191                    '"cubicweb-ctl db-create %s".' % self.config.appid)
   202                    '"cubicweb-ctl db-create %s".' % self.config.appid)
   192 
   203 
   193 ERROR = nullobject()
   204 ERROR = nullobject()
   291     """
   302     """
   292     name = 'db-create'
   303     name = 'db-create'
   293     arguments = '<instance>'
   304     arguments = '<instance>'
   294     min_args = max_args = 1
   305     min_args = max_args = 1
   295     options = (
   306     options = (
       
   307         ('automatic',
       
   308          {'short': 'a', 'action' : 'store_true',
       
   309           'default': False,
       
   310           'help': 'automatic mode: never ask and use default answer to every '
       
   311           'question. this may require that your login match a database super '
       
   312           'user (allowed to create database & all).',
       
   313           }),
       
   314         ('config-level',
       
   315          {'short': 'l', 'type' : 'int', 'metavar': '<level>',
       
   316           'default': 0,
       
   317           'help': 'configuration level (0..2): 0 will ask for essential '
       
   318           'configuration parameters only while 2 will ask for all parameters',
       
   319           }),
   296         ('create-db',
   320         ('create-db',
   297          {'short': 'c', 'type': 'yn', 'metavar': '<y or n>',
   321          {'short': 'c', 'type': 'yn', 'metavar': '<y or n>',
   298           'default': True,
   322           'default': True,
   299           'help': 'create the database (yes by default)'}),
   323           'help': 'create the database (yes by default)'
   300         ('quiet',
       
   301          {'short': 'q', 'action' : 'store_true',
       
   302           'default': False,
       
   303           'help': 'be quiet. Suppose database user in the sources file is a '
       
   304           'super user and don\'t ask for alternate login.',
       
   305           }),
   324           }),
   306         ('automatic',
       
   307          {'short': 'a', 'type' : 'yn', 'metavar': '<auto>',
       
   308           'default': 'n',
       
   309           'help': 'automatic mode: never ask and use default answer to every question',
       
   310           }
       
   311          ),
       
   312         )
   325         )
       
   326 
   313     def run(self, args):
   327     def run(self, args):
   314         """run the command with its specific arguments"""
   328         """run the command with its specific arguments"""
   315         from logilab.database import get_db_helper
   329         from logilab.database import get_db_helper
   316         quiet = self.get('quiet')
   330         check_options_consistency(self.config)
   317         automatic = self.get('automatic')
   331         automatic = self.get('automatic')
   318         appid = args.pop()
   332         appid = args.pop()
   319         config = ServerConfiguration.config_for(appid)
   333         config = ServerConfiguration.config_for(appid)
   320         source = config.sources()['system']
   334         source = config.sources()['system']
   321         dbname = source['db-name']
   335         dbname = source['db-name']
   328                 os.unlink(dbname)
   342                 os.unlink(dbname)
   329         elif self.config.create_db:
   343         elif self.config.create_db:
   330             print '\n'+underline_title('Creating the system database')
   344             print '\n'+underline_title('Creating the system database')
   331             # connect on the dbms system base to create our base
   345             # connect on the dbms system base to create our base
   332             dbcnx = _db_sys_cnx(source, 'CREATE/DROP DATABASE and / or USER',
   346             dbcnx = _db_sys_cnx(source, 'CREATE/DROP DATABASE and / or USER',
   333                                 interactive=not quiet)
   347                                 interactive=not automatic)
   334             cursor = dbcnx.cursor()
   348             cursor = dbcnx.cursor()
   335             try:
   349             try:
   336                 if helper.users_support:
   350                 if helper.users_support:
   337                     user = source['db-user']
   351                     user = source['db-user']
   338                     if not helper.user_exists(cursor, user) and (automatic or \
   352                     if not helper.user_exists(cursor, user) and (automatic or \
   341                         print '-> user %s created.' % user
   355                         print '-> user %s created.' % user
   342                 if dbname in helper.list_databases(cursor):
   356                 if dbname in helper.list_databases(cursor):
   343                     if automatic or ASK.confirm('Database %s already exists -- do you want to drop it ?' % dbname):
   357                     if automatic or ASK.confirm('Database %s already exists -- do you want to drop it ?' % dbname):
   344                         cursor.execute('DROP DATABASE %s' % dbname)
   358                         cursor.execute('DROP DATABASE %s' % dbname)
   345                     else:
   359                     else:
       
   360                         print ('you may want to run "cubicweb-ctl db-init '
       
   361                                '--drop %s" manually to continue.' % config.appid)
   346                         return
   362                         return
   347                 createdb(helper, source, dbcnx, cursor)
   363                 createdb(helper, source, dbcnx, cursor)
   348                 dbcnx.commit()
   364                 dbcnx.commit()
   349                 print '-> database %s created.' % dbname
   365                 print '-> database %s created.' % dbname
   350             except:
   366             except:
   351                 dbcnx.rollback()
   367                 dbcnx.rollback()
   352                 raise
   368                 raise
   353         cnx = system_source_cnx(source, special_privs='CREATE LANGUAGE',
   369         cnx = system_source_cnx(source, special_privs='CREATE LANGUAGE',
   354                                 interactive=not quiet)
   370                                 interactive=not automatic)
   355         cursor = cnx.cursor()
   371         cursor = cnx.cursor()
   356         helper.init_fti_extensions(cursor)
   372         helper.init_fti_extensions(cursor)
   357         # postgres specific stuff
   373         # postgres specific stuff
   358         if driver == 'postgres':
   374         if driver == 'postgres':
   359             # install plpythonu/plpgsql language if not installed by the cube
   375             # install plpythonu/plpgsql language if not installed by the cube
   362                 helper.create_language(cursor, extlang)
   378                 helper.create_language(cursor, extlang)
   363         cursor.close()
   379         cursor.close()
   364         cnx.commit()
   380         cnx.commit()
   365         print '-> database for instance %s created and necessary extensions installed.' % appid
   381         print '-> database for instance %s created and necessary extensions installed.' % appid
   366         print
   382         print
   367         if automatic or ASK.confirm('Run db-init to initialize the system database ?'):
   383         if automatic:
   368             CWCTL.run(['db-init', config.appid])
   384             CWCTL.run(['db-init', '--automatic', '--config-level', '0',
       
   385                        config.appid])
       
   386         elif ASK.confirm('Run db-init to initialize the system database ?'):
       
   387             CWCTL.run(['db-init', '--config-level',
       
   388                        str(self.config.config_level), config.appid])
   369         else:
   389         else:
   370             print ('-> nevermind, you can do it later with '
   390             print ('-> nevermind, you can do it later with '
   371                    '"cubicweb-ctl db-init %s".' % config.appid)
   391                    '"cubicweb-ctl db-init %s".' % config.appid)
   372 
   392 
   373 
   393 
   382     """
   402     """
   383     name = 'db-init'
   403     name = 'db-init'
   384     arguments = '<instance>'
   404     arguments = '<instance>'
   385     min_args = max_args = 1
   405     min_args = max_args = 1
   386     options = (
   406     options = (
       
   407         ('automatic',
       
   408          {'short': 'a', 'action' : 'store_true',
       
   409           'default': False,
       
   410           'help': 'automatic mode: never ask and use default answer to every '
       
   411           'question.',
       
   412           }),
       
   413         ('config-level',
       
   414          {'short': 'l', 'type': 'int', 'default': 1,
       
   415           'help': 'level threshold for questions asked when configuring '
       
   416           'another source'
       
   417           }),
   387         ('drop',
   418         ('drop',
   388          {'short': 'd', 'action': 'store_true',
   419          {'short': 'd', 'action': 'store_true',
   389           'default': False,
   420           'default': False,
   390           'help': 'insert drop statements to remove previously existant \
   421           'help': 'insert drop statements to remove previously existant '
   391 tables, indexes... (no by default)'}),
   422           'tables, indexes... (no by default)'
   392         ('config-level',
       
   393          {'short': 'l', 'type': 'int', 'default': 1,
       
   394           'help': 'level threshold for questions asked when configuring another source'
       
   395           }),
   423           }),
   396         )
   424         )
   397 
   425 
   398     def run(self, args):
   426     def run(self, args):
       
   427         check_options_consistency(self.config)
   399         print '\n'+underline_title('Initializing the system database')
   428         print '\n'+underline_title('Initializing the system database')
   400         from cubicweb.server import init_repository
   429         from cubicweb.server import init_repository
   401         from logilab.database import get_connection
   430         from logilab.database import get_connection
   402         appid = args[0]
   431         appid = args[0]
   403         config = ServerConfiguration.config_for(appid)
   432         config = ServerConfiguration.config_for(appid)
   414             raise ConfigurationError(
   443             raise ConfigurationError(
   415                 'You seem to have provided wrong connection information in '\
   444                 'You seem to have provided wrong connection information in '\
   416                 'the %s file. Resolve this first (error: %s).'
   445                 'the %s file. Resolve this first (error: %s).'
   417                 % (config.sources_file(), str(ex).strip()))
   446                 % (config.sources_file(), str(ex).strip()))
   418         init_repository(config, drop=self.config.drop)
   447         init_repository(config, drop=self.config.drop)
   419         while ASK.confirm('Enter another source ?', default_is_yes=False):
   448         if not self.config.automatic:
   420             CWCTL.run(['add-source', '--config-level', self.config.config_level, config.appid])
   449             while ASK.confirm('Enter another source ?', default_is_yes=False):
       
   450                 CWCTL.run(['add-source', '--config-level',
       
   451                            str(self.config.config_level), config.appid])
   421 
   452 
   422 
   453 
   423 class AddSourceCommand(Command):
   454 class AddSourceCommand(Command):
   424     """Add a data source to an instance.
   455     """Add a data source to an instance.
   425 
   456