server/serverctl.py
changeset 6882 b5e34836f84e
parent 6782 b5d6f5391695
parent 6867 f691757792f9
child 6948 013f81b729de
equal deleted inserted replaced
6856:ac092197c099 6882:b5e34836f84e
    23 # possible (for cubicweb-ctl reactivity, necessary for instance for usable bash
    23 # possible (for cubicweb-ctl reactivity, necessary for instance for usable bash
    24 # completion). So import locally in command helpers.
    24 # completion). So import locally in command helpers.
    25 import sys
    25 import sys
    26 import os
    26 import os
    27 
    27 
       
    28 from logilab.common import nullobject
    28 from logilab.common.configuration import Configuration
    29 from logilab.common.configuration import Configuration
    29 from logilab.common.shellutils import ASK
    30 from logilab.common.shellutils import ASK
    30 
    31 
    31 from cubicweb import AuthenticationError, ExecutionError, ConfigurationError
    32 from cubicweb import AuthenticationError, ExecutionError, ConfigurationError
    32 from cubicweb.toolsutils import Command, CommandHandler, underline_title
    33 from cubicweb.toolsutils import Command, CommandHandler, underline_title
    54         if dbhost:
    55         if dbhost:
    55             print '%s@%s' % (dbname, dbhost),
    56             print '%s@%s' % (dbname, dbhost),
    56         else:
    57         else:
    57             print dbname,
    58             print dbname,
    58     if dbhelper.users_support:
    59     if dbhelper.users_support:
    59         if not verbose or (not special_privs and source.get('db-user')):
    60         if not special_privs and source.get('db-user'):
    60             user = source['db-user']
    61             user = source['db-user']
    61             if verbose:
    62             if verbose:
    62                 print 'as', user
    63                 print 'as', user
    63             if source.get('db-password'):
    64             password = source.get('db-password')
    64                 password = source['db-password']
       
    65             else:
       
    66                 password = getpass('password: ')
       
    67         else:
    65         else:
    68             print
    66             if verbose:
       
    67                 print
    69             if special_privs:
    68             if special_privs:
    70                 print 'WARNING'
    69                 print 'WARNING'
    71                 print ('the user will need the following special access rights '
    70                 print ('the user will need the following special access rights '
    72                        'on the database:')
    71                        'on the database:')
    73                 print special_privs
    72                 print special_privs
    74                 print
    73                 print
    75             default_user = source.get('db-user', os.environ.get('USER', ''))
    74             default_user = source.get('db-user', os.environ.get('USER', ''))
    76             user = raw_input('Connect as user ? [%r]: ' % default_user)
    75             user = raw_input('Connect as user ? [%r]: ' % default_user)
    77             user = user or default_user
    76             user = user.strip() or default_user
    78             if user == source.get('db-user') and source.get('db-password'):
    77             if user == source.get('db-user'):
    79                 password = source['db-password']
    78                 password = source['db-password']
    80             else:
    79             else:
    81                 password = getpass('password: ')
    80                 password = getpass('password: ')
    82     else:
    81     else:
    83         user = password = None
    82         user = password = None
   106         from logilab.database import get_db_helper
   105         from logilab.database import get_db_helper
   107         system_db = get_db_helper(source['db-driver']).system_database()
   106         system_db = get_db_helper(source['db-driver']).system_database()
   108         return source_cnx(source, system_db, special_privs=special_privs, verbose=verbose)
   107         return source_cnx(source, system_db, special_privs=special_privs, verbose=verbose)
   109     return source_cnx(source, special_privs=special_privs, verbose=verbose)
   108     return source_cnx(source, special_privs=special_privs, verbose=verbose)
   110 
   109 
   111 def _db_sys_cnx(source, what, db=None, user=None, verbose=True):
   110 def _db_sys_cnx(source, special_privs, verbose=True):
   112     """return a connection on the RDMS system table (to create/drop a user
   111     """return a connection on the RDMS system table (to create/drop a user or a
   113     or a database
   112     database)
   114     """
   113     """
   115     import logilab.common as lgp
   114     import logilab.common as lgp
   116     from logilab.database import get_db_helper
   115     from logilab.database import get_db_helper
   117     lgp.USE_MX_DATETIME = False
   116     lgp.USE_MX_DATETIME = False
   118     special_privs = ''
       
   119     driver = source['db-driver']
   117     driver = source['db-driver']
   120     helper = get_db_helper(driver)
   118     helper = get_db_helper(driver)
   121     if user is not None and helper.users_support:
       
   122         special_privs += '%s USER' % what
       
   123     if db is not None:
       
   124         special_privs += ' %s DATABASE' % what
       
   125     # connect on the dbms system base to create our base
   119     # connect on the dbms system base to create our base
   126     cnx = system_source_cnx(source, True, special_privs=special_privs, verbose=verbose)
   120     cnx = system_source_cnx(source, True, special_privs=special_privs,
       
   121                             verbose=verbose)
   127     # disable autocommit (isolation_level(1)) because DROP and
   122     # disable autocommit (isolation_level(1)) because DROP and
   128     # CREATE DATABASE can't be executed in a transaction
   123     # CREATE DATABASE can't be executed in a transaction
   129     try:
   124     try:
   130         cnx.set_isolation_level(0)
   125         cnx.set_isolation_level(0)
   131     except AttributeError:
   126     except AttributeError:
   192             CWCTL.run(['db-create', self.config.appid, '--verbose=%s' % verbosity])
   187             CWCTL.run(['db-create', self.config.appid, '--verbose=%s' % verbosity])
   193         else:
   188         else:
   194             print ('-> nevermind, you can do it later with '
   189             print ('-> nevermind, you can do it later with '
   195                    '"cubicweb-ctl db-create %s".' % self.config.appid)
   190                    '"cubicweb-ctl db-create %s".' % self.config.appid)
   196 
   191 
       
   192 ERROR = nullobject()
       
   193 
       
   194 def confirm_on_error_or_die(msg, func, *args, **kwargs):
       
   195     try:
       
   196         return func(*args, **kwargs)
       
   197     except Exception, ex:
       
   198         print 'ERROR', ex
       
   199         if not ASK.confirm('An error occurred while %s. Continue anyway?' % msg):
       
   200             raise ExecutionError(str(ex))
       
   201     return ERROR
   197 
   202 
   198 class RepositoryDeleteHandler(CommandHandler):
   203 class RepositoryDeleteHandler(CommandHandler):
   199     cmdname = 'delete'
   204     cmdname = 'delete'
   200     cfgname = 'repository'
   205     cfgname = 'repository'
   201 
   206 
   205         source = self.config.sources()['system']
   210         source = self.config.sources()['system']
   206         dbname = source['db-name']
   211         dbname = source['db-name']
   207         helper = get_db_helper(source['db-driver'])
   212         helper = get_db_helper(source['db-driver'])
   208         if ASK.confirm('Delete database %s ?' % dbname):
   213         if ASK.confirm('Delete database %s ?' % dbname):
   209             if source['db-driver'] == 'sqlite':
   214             if source['db-driver'] == 'sqlite':
   210                 os.unlink(source['db-name'])
   215                 if confirm_on_error_or_die(
       
   216                     'deleting database file %s' % dbname,
       
   217                     os.unlink, source['db-name']) is not ERROR:
       
   218                     print '-> database %s dropped.' % dbname
   211                 return
   219                 return
   212             user = source['db-user'] or None
   220             user = source['db-user'] or None
   213             cnx = _db_sys_cnx(source, 'DROP DATABASE', user=user)
   221             cnx = confirm_on_error_or_die('connecting to database %s' % dbname,
       
   222                                           _db_sys_cnx, source, 'DROP DATABASE', user=user)
       
   223             if cnx is ERROR:
       
   224                 return
   214             cursor = cnx.cursor()
   225             cursor = cnx.cursor()
   215             try:
   226             try:
   216                 cursor.execute('DROP DATABASE %s' % dbname)
   227                 if confirm_on_error_or_die(
   217                 print '-> database %s dropped.' % dbname
   228                     'dropping database %s' % dbname,
       
   229                     cursor.execute, 'DROP DATABASE "%s"' % dbname) is not ERROR:
       
   230                     print '-> database %s dropped.' % dbname
   218                 # XXX should check we are not connected as user
   231                 # XXX should check we are not connected as user
   219                 if user and helper.users_support and \
   232                 if user and helper.users_support and \
   220                        ASK.confirm('Delete user %s ?' % user, default_is_yes=False):
   233                        ASK.confirm('Delete user %s ?' % user, default_is_yes=False):
   221                     cursor.execute('DROP USER %s' % user)
   234                     if confirm_on_error_or_die(
   222                     print '-> user %s dropped.' % user
   235                         'dropping user %s' % user,
       
   236                         cursor.execute, 'DROP USER %s' % user) is not ERROR:
       
   237                         print '-> user %s dropped.' % user
   223                 cnx.commit()
   238                 cnx.commit()
   224             except:
   239             except:
   225                 cnx.rollback()
   240                 cnx.rollback()
   226                 raise
   241                 raise
   227 
   242 
   311                 ASK.confirm('Database %s already exists. Drop it?' % dbname)):
   326                 ASK.confirm('Database %s already exists. Drop it?' % dbname)):
   312                 os.unlink(dbname)
   327                 os.unlink(dbname)
   313         elif self.config.create_db:
   328         elif self.config.create_db:
   314             print '\n'+underline_title('Creating the system database')
   329             print '\n'+underline_title('Creating the system database')
   315             # connect on the dbms system base to create our base
   330             # connect on the dbms system base to create our base
   316             dbcnx = _db_sys_cnx(source, 'CREATE DATABASE and / or USER', verbose=verbose)
   331             dbcnx = _db_sys_cnx(source, 'CREATE/DROP DATABASE and / or USER', verbose=verbose)
   317             cursor = dbcnx.cursor()
   332             cursor = dbcnx.cursor()
   318             try:
   333             try:
   319                 if helper.users_support:
   334                 if helper.users_support:
   320                     user = source['db-user']
   335                     user = source['db-user']
   321                     if not helper.user_exists(cursor, user) and (automatic or \
   336                     if not helper.user_exists(cursor, user) and (automatic or \
   331                 dbcnx.commit()
   346                 dbcnx.commit()
   332                 print '-> database %s created.' % dbname
   347                 print '-> database %s created.' % dbname
   333             except:
   348             except:
   334                 dbcnx.rollback()
   349                 dbcnx.rollback()
   335                 raise
   350                 raise
   336         cnx = system_source_cnx(source, special_privs='LANGUAGE C', verbose=verbose)
   351         cnx = system_source_cnx(source, special_privs='CREATE LANGUAGE',
       
   352                                 verbose=verbose)
   337         cursor = cnx.cursor()
   353         cursor = cnx.cursor()
   338         helper.init_fti_extensions(cursor)
   354         helper.init_fti_extensions(cursor)
   339         # postgres specific stuff
   355         # postgres specific stuff
   340         if driver == 'postgres':
   356         if driver == 'postgres':
   341             # install plpythonu/plpgsql language if not installed by the cube
   357             # install plpythonu/plpgsql language if not installed by the cube