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): |