server/serverctl.py
branchstable
changeset 2394 92bba46b853f
parent 2107 6c4a4c514ac2
child 2395 e3093fc12a00
equal deleted inserted replaced
2393:6190852af97f 2394:92bba46b853f
    17 from cubicweb.toolsutils import Command, CommandHandler, confirm
    17 from cubicweb.toolsutils import Command, CommandHandler, confirm
    18 from cubicweb.server import SOURCE_TYPES
    18 from cubicweb.server import SOURCE_TYPES
    19 from cubicweb.server.utils import ask_source_config
    19 from cubicweb.server.utils import ask_source_config
    20 from cubicweb.server.serverconfig import USER_OPTIONS, ServerConfiguration
    20 from cubicweb.server.serverconfig import USER_OPTIONS, ServerConfiguration
    21 
    21 
    22 
       
    23 # utility functions ###########################################################
    22 # utility functions ###########################################################
    24 
    23 
    25 def source_cnx(source, dbname=None, special_privs=False, verbose=True):
    24 def source_cnx(source, dbname=None, special_privs=False, verbose=True):
    26     """open and return a connection to the system database defined in the
    25     """open and return a connection to the system database defined in the
    27     given server.serverconfig
    26     given server.serverconfig
    30     from logilab.common.db import get_connection
    29     from logilab.common.db import get_connection
    31     dbhost = source['db-host']
    30     dbhost = source['db-host']
    32     if dbname is None:
    31     if dbname is None:
    33         dbname = source['db-name']
    32         dbname = source['db-name']
    34     driver = source['db-driver']
    33     driver = source['db-driver']
    35     print '**** connecting to %s database %s@%s' % (driver, dbname, dbhost),
    34     print '-> connecting to %s database %s@%s' % (driver, dbname, dbhost or 'localhost'),
    36     if not verbose or (not special_privs and source.get('db-user')):
    35     if not verbose or (not special_privs and source.get('db-user')):
    37         user = source['db-user']
    36         user = source['db-user']
    38         print 'as', user
    37         print 'as', user
    39         if source.get('db-password'):
    38         if source.get('db-password'):
    40             password = source['db-password']
    39             password = source['db-password']
   104         login, pwd = manager_userpasswd()
   103         login, pwd = manager_userpasswd()
   105     while True:
   104     while True:
   106         try:
   105         try:
   107             return in_memory_cnx(config, login, pwd)
   106             return in_memory_cnx(config, login, pwd)
   108         except AuthenticationError:
   107         except AuthenticationError:
   109             print 'wrong user/password'
   108             print '-> Error: wrong user/password.'
   110             # reset cubes else we'll have an assertion error on next retry
   109             # reset cubes else we'll have an assertion error on next retry
   111             config._cubes = None
   110             config._cubes = None
   112         login, pwd = manager_userpasswd()
   111         login, pwd = manager_userpasswd()
   113 
   112 
   114 # repository specific command handlers ########################################
   113 # repository specific command handlers ########################################
   145                                if not stype in cubes)
   144                                if not stype in cubes)
   146             while True:
   145             while True:
   147                 sourcetype = raw_input('source type (%s): ' % ', '.join(available))
   146                 sourcetype = raw_input('source type (%s): ' % ', '.join(available))
   148                 if sourcetype in available:
   147                 if sourcetype in available:
   149                     break
   148                     break
   150                 print 'unknown source type, use one of the available type'
   149                 print '-> unknown source type, use one of the available types.'
   151             while True:
   150             while True:
   152                 sourceuri = raw_input('source uri: ').strip()
   151                 sourceuri = raw_input('source uri: ').strip()
   153                 if sourceuri != 'admin' and sourceuri not in sourcescfg:
   152                 if sourceuri != 'admin' and sourceuri not in sourcescfg:
   154                     break
   153                     break
   155                 print 'uri already used, choose another one'
   154                 print '-> uri already used, choose another one.'
   156             sourcescfg[sourceuri] = ask_source_config(sourcetype)
   155             sourcescfg[sourceuri] = ask_source_config(sourcetype)
   157             sourcemodule = SOURCE_TYPES[sourcetype].module
   156             sourcemodule = SOURCE_TYPES[sourcetype].module
   158             if not sourcemodule.startswith('cubicweb.'):
   157             if not sourcemodule.startswith('cubicweb.'):
   159                 # module names look like cubes.mycube.themodule
   158                 # module names look like cubes.mycube.themodule
   160                 sourcecube = SOURCE_TYPES[sourcetype].module.split('.', 2)[1]
   159                 sourcecube = SOURCE_TYPES[sourcetype].module.split('.', 2)[1]
   168         config.write_sources_file(sourcescfg)
   167         config.write_sources_file(sourcescfg)
   169         # remember selected cubes for later initialization of the database
   168         # remember selected cubes for later initialization of the database
   170         config.write_bootstrap_cubes_file(cubes)
   169         config.write_bootstrap_cubes_file(cubes)
   171 
   170 
   172     def postcreate(self):
   171     def postcreate(self):
   173         if confirm('do you want to create repository\'s system database?'):
   172         if confirm('Do you want to run db-create to create repository\'s system database?'):
   174             verbosity = (self.config.mode == 'installed') and 'y' or 'n'
   173             verbosity = (self.config.mode == 'installed') and 'y' or 'n'
   175             cmd_run('db-create', self.config.appid, '--verbose=%s' % verbosity)
   174             cmd_run('db-create', self.config.appid, '--verbose=%s' % verbosity)
   176         else:
   175         else:
   177             print 'nevermind, you can do it later using the db-create command'
   176             print '-> nevermind, you can do it later using the db-create command.'
   178 
   177 
   179 
   178 
   180 class RepositoryDeleteHandler(CommandHandler):
   179 class RepositoryDeleteHandler(CommandHandler):
   181     cmdname = 'delete'
   180     cmdname = 'delete'
   182     cfgname = 'repository'
   181     cfgname = 'repository'
   185         """remove application's configuration and database"""
   184         """remove application's configuration and database"""
   186         from logilab.common.adbh import get_adv_func_helper
   185         from logilab.common.adbh import get_adv_func_helper
   187         source = self.config.sources()['system']
   186         source = self.config.sources()['system']
   188         dbname = source['db-name']
   187         dbname = source['db-name']
   189         helper = get_adv_func_helper(source['db-driver'])
   188         helper = get_adv_func_helper(source['db-driver'])
   190         if confirm('delete database %s ?' % dbname):
   189         if confirm('Delete database %s ?' % dbname):
   191             user = source['db-user'] or None
   190             user = source['db-user'] or None
   192             cnx = _db_sys_cnx(source, 'DROP DATABASE', user=user)
   191             cnx = _db_sys_cnx(source, 'DROP DATABASE', user=user)
   193             cursor = cnx.cursor()
   192             cursor = cnx.cursor()
   194             try:
   193             try:
   195                 cursor.execute('DROP DATABASE %s' % dbname)
   194                 cursor.execute('DROP DATABASE %s' % dbname)
   196                 print 'database %s dropped' % dbname
   195                 print '-> database %s dropped.' % dbname
   197                 # XXX should check we are not connected as user
   196                 # XXX should check we are not connected as user
   198                 if user and helper.users_support and \
   197                 if user and helper.users_support and \
   199                        confirm('delete user %s ?' % user, default_is_yes=False):
   198                        confirm('Delete user %s ?' % user, default_is_yes=False):
   200                     cursor.execute('DROP USER %s' % user)
   199                     cursor.execute('DROP USER %s' % user)
   201                     print 'user %s dropped' % user
   200                     print '-> user %s dropped.' % user
   202                 cnx.commit()
   201                 cnx.commit()
   203             except:
   202             except:
   204                 cnx.rollback()
   203                 cnx.rollback()
   205                 raise
   204                 raise
   206 
   205 
   274             cursor = dbcnx.cursor()
   273             cursor = dbcnx.cursor()
   275             try:
   274             try:
   276                 if helper.users_support:
   275                 if helper.users_support:
   277                     user = source['db-user']
   276                     user = source['db-user']
   278                     if not helper.user_exists(cursor, user) and \
   277                     if not helper.user_exists(cursor, user) and \
   279                            confirm('create db user %s ?' % user, default_is_yes=False):
   278                            confirm('Create db user %s ?' % user, default_is_yes=False):
   280                         helper.create_user(source['db-user'], source['db-password'])
   279                         helper.create_user(source['db-user'], source['db-password'])
   281                         print 'user %s created' % user
   280                         print '-> user %s created.' % user
   282                 dbname = source['db-name']
   281                 dbname = source['db-name']
   283                 if dbname in helper.list_databases(cursor):
   282                 if dbname in helper.list_databases(cursor):
   284                     if confirm('DB %s already exists -- do you want to drop it ?' % dbname):
   283                     if confirm('Database %s already exists -- do you want to drop it ?' % dbname):
   285                         cursor.execute('DROP DATABASE %s' % dbname)
   284                         cursor.execute('DROP DATABASE %s' % dbname)
   286                     else:
   285                     else:
   287                         return
   286                         return
   288                 if dbcnx.logged_user != source['db-user']:
   287                 if dbcnx.logged_user != source['db-user']:
   289                     helper.create_database(cursor, dbname, source['db-user'],
   288                     helper.create_database(cursor, dbname, source['db-user'],
   290                                            source['db-encoding'])
   289                                            source['db-encoding'])
   291                 else:
   290                 else:
   292                     helper.create_database(cursor, dbname,
   291                     helper.create_database(cursor, dbname,
   293                                            encoding=source['db-encoding'])
   292                                            encoding=source['db-encoding'])
   294                 dbcnx.commit()
   293                 dbcnx.commit()
   295                 print 'database %s created' % source['db-name']
   294                 print '-> database %s created.' % source['db-name']
   296             except:
   295             except:
   297                 dbcnx.rollback()
   296                 dbcnx.rollback()
   298                 raise
   297                 raise
   299         cnx = system_source_cnx(source, special_privs='LANGUAGE C', verbose=verbose)
   298         cnx = system_source_cnx(source, special_privs='LANGUAGE C', verbose=verbose)
   300         cursor = cnx.cursor()
   299         cursor = cnx.cursor()
   305             # install plpythonu/plpgsql language if not installed by the cube
   304             # install plpythonu/plpgsql language if not installed by the cube
   306             for extlang in ('plpythonu', 'plpgsql'):
   305             for extlang in ('plpythonu', 'plpgsql'):
   307                 helper.create_language(cursor, extlang)
   306                 helper.create_language(cursor, extlang)
   308         cursor.close()
   307         cursor.close()
   309         cnx.commit()
   308         cnx.commit()
   310         print 'database for application %s created and necessary extensions installed' % appid
   309         print '-> database for application %s created and necessary extensions installed.' % appid
   311         print
   310         print
   312         if confirm('do you want to initialize the system database?'):
   311         if confirm('Do you want to run db-init to initialize the system database?'):
   313             cmd_run('db-init', config.appid)
   312             cmd_run('db-init', config.appid)
   314         else:
   313         else:
   315             print 'nevermind, you can do it later using the db-init command'
   314             print '-> nevermind, you can do it later using the db-init command.'
   316 
   315 
   317 
   316 
   318 class InitApplicationCommand(Command):
   317 class InitApplicationCommand(Command):
   319     """Initialize the system database of an application (run after 'db-create').
   318     """Initialize the system database of an application (run after 'db-create').
   320 
   319 
   377                               set_owner=set_owner), cursor)
   376                               set_owner=set_owner), cursor)
   378         except Exception, ex:
   377         except Exception, ex:
   379             cnx.rollback()
   378             cnx.rollback()
   380             import traceback
   379             import traceback
   381             traceback.print_exc()
   380             traceback.print_exc()
   382             print 'An error occured:', ex
   381             print '-> an error occured:', ex
   383         else:
   382         else:
   384             cnx.commit()
   383             cnx.commit()
   385             print 'grants given to %s on application %s' % (appid, user)
   384             print '-> rights granted to %s on application %s.' % (appid, user)
   386 
   385 
   387 class ResetAdminPasswordCommand(Command):
   386 class ResetAdminPasswordCommand(Command):
   388     """Reset the administrator password.
   387     """Reset the administrator password.
   389 
   388 
   390     <application>
   389     <application>
   401         config = ServerConfiguration.config_for(appid)
   400         config = ServerConfiguration.config_for(appid)
   402         sourcescfg = config.read_sources_file()
   401         sourcescfg = config.read_sources_file()
   403         try:
   402         try:
   404             adminlogin = sourcescfg['admin']['login']
   403             adminlogin = sourcescfg['admin']['login']
   405         except KeyError:
   404         except KeyError:
   406             print 'could not get cubicweb administrator login'
   405             print '-> Error: could not get cubicweb administrator login.'
   407             sys.exit(1)
   406             sys.exit(1)
   408         cnx = source_cnx(sourcescfg['system'])
   407         cnx = source_cnx(sourcescfg['system'])
   409         cursor = cnx.cursor()
   408         cursor = cnx.cursor()
   410         _, passwd = manager_userpasswd(adminlogin, confirm=True,
   409         _, passwd = manager_userpasswd(adminlogin, confirm=True,
   411                                        passwdmsg='new password for %s' % adminlogin)
   410                                        passwdmsg='new password for %s' % adminlogin)
   421             config.write_sources_file(sourcescfg)
   420             config.write_sources_file(sourcescfg)
   422         except Exception, ex:
   421         except Exception, ex:
   423             cnx.rollback()
   422             cnx.rollback()
   424             import traceback
   423             import traceback
   425             traceback.print_exc()
   424             traceback.print_exc()
   426             print 'An error occured:', ex
   425             print '-> an error occured:', ex
   427         else:
   426         else:
   428             cnx.commit()
   427             cnx.commit()
   429             print 'password reset, sources file regenerated'
   428             print '-> password reset, sources file regenerated.'
   430 
   429 
   431 
   430 
   432 class StartRepositoryCommand(Command):
   431 class StartRepositoryCommand(Command):
   433     """Start an CubicWeb RQL server for a given application.
   432     """Start an CubicWeb RQL server for a given application.
   434 
   433 
   486     if os.system(cmd):
   485     if os.system(cmd):
   487         raise ExecutionError('Error while retrieving the dump')
   486         raise ExecutionError('Error while retrieving the dump')
   488     rmcmd = 'ssh -t %s "rm -f /tmp/%s.dump"' % (host, appid)
   487     rmcmd = 'ssh -t %s "rm -f /tmp/%s.dump"' % (host, appid)
   489     print rmcmd
   488     print rmcmd
   490     if os.system(rmcmd) and not confirm(
   489     if os.system(rmcmd) and not confirm(
   491         'an error occured while deleting remote dump. Continue anyway?'):
   490         'An error occured while deleting remote dump. Continue anyway?'):
   492         raise ExecutionError('Error while deleting remote dump')
   491         raise ExecutionError('Error while deleting remote dump')
   493 
   492 
   494 def _local_dump(appid, output):
   493 def _local_dump(appid, output):
   495     config = ServerConfiguration.config_for(appid)
   494     config = ServerConfiguration.config_for(appid)
   496     # schema=1 to avoid unnecessary schema loading
   495     # schema=1 to avoid unnecessary schema loading
   537         return 'needapplupgrade'
   536         return 'needapplupgrade'
   538     for cube in config.cubes():
   537     for cube in config.cubes():
   539         try:
   538         try:
   540             softversion = config.cube_version(cube)
   539             softversion = config.cube_version(cube)
   541         except ConfigurationError:
   540         except ConfigurationError:
   542             print "no cube version information for %s, is the cube installed?" % cube
   541             print "-> Error: no cube version information for %s, please check that the cube is installed." % cube
   543             continue
   542             continue
   544         try:
   543         try:
   545             applversion = vcconf[cube]
   544             applversion = vcconf[cube]
   546         except KeyError:
   545         except KeyError:
   547             print "no cube version information for %s in version configuration" % cube
   546             print "-> Error: no cube version information for %s in version configuration." % cube
   548             continue
   547             continue
   549         if softversion == applversion:
   548         if softversion == applversion:
   550             continue
   549             continue
   551         if softversion > applversion:
   550         if softversion > applversion:
   552             return 'needsoftupgrade'
   551             return 'needsoftupgrade'
   653             _remote_dump(host, srcappid, output, self.config.sudo)
   652             _remote_dump(host, srcappid, output, self.config.sudo)
   654         else:
   653         else:
   655             _local_dump(srcappid, output)
   654             _local_dump(srcappid, output)
   656         _local_restore(destappid, output, not self.config.no_drop)
   655         _local_restore(destappid, output, not self.config.no_drop)
   657         if self.config.keep_dump:
   656         if self.config.keep_dump:
   658             print 'you can get the dump file at', output
   657             print '-> you can get the dump file at', output
   659         else:
   658         else:
   660             os.remove(output)
   659             os.remove(output)
   661 
   660 
   662 
   661 
   663 class CheckRepositoryCommand(Command):
   662 class CheckRepositoryCommand(Command):