2009-10-20 10:52:23 +00:00
# -*- coding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
2010-12-30 09:17:34 +00:00
#
2009-06-11 11:27:56 +00:00
# OpenERP, Open Source Management Solution
2009-10-14 12:32:15 +00:00
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
2008-06-16 07:24:04 +00:00
#
2008-11-03 18:27:16 +00:00
# This program is free software: you can redistribute it and/or modify
2009-10-14 12:32:15 +00:00
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
2006-12-07 13:41:40 +00:00
#
2008-11-03 18:27:16 +00:00
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2009-10-14 12:32:15 +00:00
# GNU Affero General Public License for more details.
2006-12-07 13:41:40 +00:00
#
2009-10-14 12:32:15 +00:00
# You should have received a copy of the GNU Affero General Public License
2010-12-30 09:17:34 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2006-12-07 13:41:40 +00:00
#
2008-11-03 18:27:16 +00:00
##############################################################################
2012-09-12 11:46:51 +00:00
from __future__ import with_statement
import contextlib
2009-06-11 11:27:56 +00:00
import base64
2011-08-01 08:54:46 +00:00
import locale
import logging
2008-12-18 19:00:07 +00:00
import os
2011-08-01 08:54:46 +00:00
import platform
2008-12-18 19:00:07 +00:00
import security
2011-08-01 08:54:46 +00:00
import sys
2008-12-18 19:00:07 +00:00
import thread
import threading
2006-12-07 13:41:40 +00:00
import time
2011-08-01 08:54:46 +00:00
import traceback
from cStringIO import StringIO
2011-02-07 12:57:23 +00:00
from openerp . tools . translate import _
import openerp . netsvc as netsvc
import openerp . pooler as pooler
import openerp . release as release
import openerp . sql_db as sql_db
import openerp . tools as tools
2011-05-11 14:47:54 +00:00
import openerp . modules
2011-09-26 15:14:03 +00:00
import openerp . exceptions
2012-01-15 21:42:14 +00:00
from openerp . service import http_server
2012-08-31 13:53:09 +00:00
from openerp import SUPERUSER_ID
2010-01-20 16:39:13 +00:00
2011-06-23 09:04:57 +00:00
#.apidoc title: Exported Service methods
#.apidoc module-mods: member-order: bysource
""" This python module defines the RPC methods available to remote clients.
Each ' Export Service ' is a group of ' methods ' , which in turn are RPC
procedures to be called . Each method has its own arguments footprint .
"""
2012-01-24 15:07:50 +00:00
_logger = logging . getLogger ( __name__ )
2011-09-30 13:59:42 +00:00
RPC_VERSION_1 = { ' server_version ' : ' 6.1 ' , ' protocol_version ' : 1 }
2011-08-09 12:00:57 +00:00
# This should be moved to openerp.modules.db, along side initialize().
def _initialize_db ( serv , id , db_name , demo , lang , user_password ) :
cr = None
try :
serv . actions [ id ] [ ' progress ' ] = 0
cr = sql_db . db_connect ( db_name ) . cursor ( )
openerp . modules . db . initialize ( cr ) # TODO this should be removed as it is done by pooler.restart_pool.
tools . config [ ' lang ' ] = lang
cr . commit ( )
cr . close ( )
pool = pooler . restart_pool ( db_name , demo , serv . actions [ id ] ,
update_module = True ) [ 1 ]
cr = sql_db . db_connect ( db_name ) . cursor ( )
if lang :
modobj = pool . get ( ' ir.module.module ' )
2012-08-31 13:53:09 +00:00
mids = modobj . search ( cr , SUPERUSER_ID , [ ( ' state ' , ' = ' , ' installed ' ) ] )
modobj . update_translations ( cr , SUPERUSER_ID , mids , lang )
2011-08-09 12:00:57 +00:00
2012-08-10 08:18:36 +00:00
cr . execute ( ' UPDATE res_users SET password= %s , lang= %s , active=True WHERE login= %s ' , (
2011-08-09 12:00:57 +00:00
user_password , lang , ' admin ' ) )
2012-08-13 10:06:22 +00:00
cr . execute ( ' SELECT login, password ' \
2012-08-10 08:18:36 +00:00
' FROM res_users ' \
2011-08-09 12:00:57 +00:00
' ORDER BY login ' )
serv . actions [ id ] . update ( users = cr . dictfetchall ( ) , clean = True )
cr . commit ( )
cr . close ( )
except Exception , e :
serv . actions [ id ] . update ( clean = False , exception = e )
2012-01-24 15:07:50 +00:00
_logger . exception ( ' CREATE DATABASE failed: ' )
2011-08-09 12:00:57 +00:00
serv . actions [ id ] [ ' traceback ' ] = traceback . format_exc ( )
if cr :
cr . close ( )
2009-08-29 15:23:46 +00:00
class db ( netsvc . ExportService ) :
2008-07-22 14:24:36 +00:00
def __init__ ( self , name = " db " ) :
2009-08-29 15:23:46 +00:00
netsvc . ExportService . __init__ ( self , name )
2008-07-22 14:24:36 +00:00
self . actions = { }
self . id = 0
self . id_protect = threading . Semaphore ( )
2011-09-25 15:23:18 +00:00
def dispatch ( self , method , params ) :
2010-12-30 09:17:34 +00:00
if method in [ ' create ' , ' get_progress ' , ' drop ' , ' dump ' ,
' restore ' , ' rename ' ,
2011-09-01 13:04:50 +00:00
' change_admin_password ' , ' migrate_databases ' ,
2012-10-19 10:13:49 +00:00
' create_database ' , ' duplicate_database ' ] :
2009-11-24 14:44:05 +00:00
passwd = params [ 0 ]
params = params [ 1 : ]
security . check_super ( passwd )
elif method in [ ' db_exist ' , ' list ' , ' list_lang ' , ' server_version ' ] :
# params = params
# No security check for these methods
pass
else :
raise KeyError ( " Method not found: %s " % method )
fn = getattr ( self , ' exp_ ' + method )
return fn ( * params )
2010-12-30 09:17:34 +00:00
2010-01-20 16:39:13 +00:00
def _create_empty_database ( self , name ) :
2012-02-09 21:33:17 +00:00
db = sql_db . db_connect ( ' postgres ' )
2010-01-20 16:39:13 +00:00
cr = db . cursor ( )
2012-01-17 16:49:40 +00:00
chosen_template = tools . config [ ' db_template ' ]
2010-01-20 16:39:13 +00:00
try :
cr . autocommit ( True ) # avoid transaction block
2012-01-17 16:49:40 +00:00
cr . execute ( """ CREATE DATABASE " %s " ENCODING ' unicode ' TEMPLATE " %s " """ % ( name , chosen_template ) )
2010-01-20 16:39:13 +00:00
finally :
cr . close ( )
2009-08-29 15:23:46 +00:00
def exp_create ( self , db_name , demo , lang , user_password = ' admin ' ) :
2008-07-22 14:24:36 +00:00
self . id_protect . acquire ( )
self . id + = 1
id = self . id
self . id_protect . release ( )
self . actions [ id ] = { ' clean ' : False }
2010-01-20 16:39:13 +00:00
self . _create_empty_database ( db_name )
2009-11-23 17:07:34 +00:00
2012-01-24 15:07:50 +00:00
_logger . info ( ' CREATE DATABASE %s ' , db_name . lower ( ) )
2011-08-09 12:00:57 +00:00
create_thread = threading . Thread ( target = _initialize_db ,
2008-09-02 17:53:29 +00:00
args = ( self , id , db_name , demo , lang , user_password ) )
2008-07-22 14:24:36 +00:00
create_thread . start ( )
self . actions [ id ] [ ' thread ' ] = create_thread
return id
2011-09-01 13:04:50 +00:00
def exp_create_database ( self , db_name , demo , lang , user_password = ' admin ' ) :
""" Similar to exp_create but blocking. """
self . id_protect . acquire ( )
self . id + = 1
id = self . id
self . id_protect . release ( )
self . actions [ id ] = { ' clean ' : False }
2012-11-14 11:25:21 +00:00
_logger . info ( ' Create database ` %s `. ' , db_name )
2011-09-01 13:04:50 +00:00
self . _create_empty_database ( db_name )
_initialize_db ( self , id , db_name , demo , lang , user_password )
return True
2012-10-19 10:13:49 +00:00
def exp_duplicate_database ( self , db_original_name , db_name ) :
2012-11-14 11:25:21 +00:00
_logger . info ( ' Duplicate database ` %s ` to ` %s `. ' , db_original_name , db_name )
2012-12-09 03:03:48 +00:00
sql_db . close_db ( db_original_name )
2012-10-19 10:13:49 +00:00
db = sql_db . db_connect ( ' postgres ' )
cr = db . cursor ( )
try :
cr . autocommit ( True ) # avoid transaction block
cr . execute ( """ CREATE DATABASE " %s " ENCODING ' unicode ' TEMPLATE " %s " """ % ( db_name , db_original_name ) )
finally :
cr . close ( )
return True
2009-08-29 15:23:46 +00:00
def exp_get_progress ( self , id ) :
2008-07-22 14:24:36 +00:00
if self . actions [ id ] [ ' thread ' ] . isAlive ( ) :
2011-04-20 15:27:18 +00:00
# return openerp.modules.init_progress[db_name]
2008-07-22 14:24:36 +00:00
return ( min ( self . actions [ id ] . get ( ' progress ' , 0 ) , 0.95 ) , [ ] )
else :
clean = self . actions [ id ] [ ' clean ' ]
if clean :
users = self . actions [ id ] [ ' users ' ]
2010-01-20 16:39:13 +00:00
self . actions . pop ( id )
2008-07-22 14:24:36 +00:00
return ( 1.0 , users )
else :
2011-09-27 10:22:46 +00:00
e = self . actions [ id ] [ ' exception ' ] # TODO this seems wrong: actions[id]['traceback'] is set, but not 'exception'.
2010-01-20 16:39:13 +00:00
self . actions . pop ( id )
2008-07-22 14:24:36 +00:00
raise Exception , e
2009-08-29 15:23:46 +00:00
def exp_drop ( self , db_name ) :
2012-02-22 10:26:39 +00:00
if not self . exp_db_exist ( db_name ) :
return False
2011-07-13 15:35:21 +00:00
openerp . modules . registry . RegistryManager . delete ( db_name )
2008-12-09 13:31:32 +00:00
sql_db . close_db ( db_name )
2008-07-22 14:24:36 +00:00
2012-02-09 21:33:17 +00:00
db = sql_db . db_connect ( ' postgres ' )
2010-01-20 16:39:13 +00:00
cr = db . cursor ( )
cr . autocommit ( True ) # avoid transaction block
2008-07-22 14:24:36 +00:00
try :
2012-03-16 16:02:16 +00:00
# Try to terminate all other connections that might prevent
# dropping the database
2012-02-22 10:26:39 +00:00
try :
2012-11-28 15:34:23 +00:00
# PostgreSQL 9.2 renamed pg_stat_activity.procpid to pid:
# http://www.postgresql.org/docs/9.2/static/release-9-2.html#AEN110389
pid_col = ' pid ' if cr . _cnx . server_version > = 90200 else ' procpid '
cr . execute ( """ SELECT pg_terminate_backend( %(pid_col)s )
2012-03-16 16:02:16 +00:00
FROM pg_stat_activity
2012-11-28 15:34:23 +00:00
WHERE datname = % % s AND
% ( pid_col ) s != pg_backend_pid ( ) """ % { ' pid_col ' : pid_col},
2012-03-16 16:02:16 +00:00
( db_name , ) )
2012-02-22 10:26:39 +00:00
except Exception :
pass
2012-03-16 16:02:16 +00:00
2008-07-22 14:24:36 +00:00
try :
2010-01-20 16:39:13 +00:00
cr . execute ( ' DROP DATABASE " %s " ' % db_name )
except Exception , e :
2012-01-24 15:07:50 +00:00
_logger . error ( ' DROP DB: %s failed: \n %s ' , db_name , e )
2010-01-20 16:39:13 +00:00
raise Exception ( " Couldn ' t drop database %s : %s " % ( db_name , e ) )
else :
2012-01-24 15:07:50 +00:00
_logger . info ( ' DROP DB: %s ' , db_name )
2008-07-22 14:24:36 +00:00
finally :
2010-01-20 16:39:13 +00:00
cr . close ( )
2008-07-22 14:24:36 +00:00
return True
2012-09-12 11:46:51 +00:00
@contextlib.contextmanager
def _set_pg_password_in_environment ( self ) :
""" On Win32, pg_dump (and pg_restore) require that
: envvar : ` PGPASSWORD ` be set
This context management method handles setting
: envvar : ` PGPASSWORD ` iif win32 and the envvar is not already
set , and removing it afterwards .
"""
if os . name != ' nt ' or os . environ . get ( ' PGPASSWORD ' ) :
yield
else :
2009-07-09 08:38:04 +00:00
os . environ [ ' PGPASSWORD ' ] = tools . config [ ' db_password ' ]
2012-09-12 11:46:51 +00:00
try :
yield
finally :
del os . environ [ ' PGPASSWORD ' ]
2009-07-09 08:38:04 +00:00
2009-08-29 15:23:46 +00:00
def exp_dump ( self , db_name ) :
2012-09-12 11:46:51 +00:00
logger = logging . getLogger ( ' openerp.service.web_services.db.dump ' )
with self . _set_pg_password_in_environment ( ) :
2012-01-31 11:08:49 +00:00
cmd = [ ' pg_dump ' , ' --format=c ' , ' --no-owner ' ]
if tools . config [ ' db_user ' ] :
cmd . append ( ' --username= ' + tools . config [ ' db_user ' ] )
if tools . config [ ' db_host ' ] :
cmd . append ( ' --host= ' + tools . config [ ' db_host ' ] )
if tools . config [ ' db_port ' ] :
cmd . append ( ' --port= ' + str ( tools . config [ ' db_port ' ] ) )
cmd . append ( db_name )
stdin , stdout = tools . exec_pg_command_pipe ( * tuple ( cmd ) )
stdin . close ( )
data = stdout . read ( )
res = stdout . close ( )
if not data or res :
2012-09-12 11:46:51 +00:00
logger . error (
2012-02-08 14:22:48 +00:00
' DUMP DB: %s failed! Please verify the configuration of the database password on the server. '
' It should be provided as a -w <PASSWD> command-line option, or as `db_password` in the '
' server configuration file. \n %s ' , db_name , data )
2012-01-31 11:08:49 +00:00
raise Exception , " Couldn ' t dump database "
2012-09-12 11:46:51 +00:00
logger . info ( ' DUMP DB successful: %s ' , db_name )
2012-01-31 11:08:49 +00:00
return base64 . encodestring ( data )
2008-07-22 14:24:36 +00:00
2009-08-29 15:23:46 +00:00
def exp_restore ( self , db_name , data ) :
2012-09-12 11:46:51 +00:00
logger = logging . getLogger ( ' openerp.service.web_services.db.restore ' )
with self . _set_pg_password_in_environment ( ) :
2012-01-31 11:08:49 +00:00
if self . exp_db_exist ( db_name ) :
2012-09-12 11:46:51 +00:00
logger . warning ( ' RESTORE DB: %s already exists ' , db_name )
2012-01-31 11:08:49 +00:00
raise Exception , " Database already exists "
self . _create_empty_database ( db_name )
cmd = [ ' pg_restore ' , ' --no-owner ' ]
if tools . config [ ' db_user ' ] :
cmd . append ( ' --username= ' + tools . config [ ' db_user ' ] )
if tools . config [ ' db_host ' ] :
cmd . append ( ' --host= ' + tools . config [ ' db_host ' ] )
if tools . config [ ' db_port ' ] :
cmd . append ( ' --port= ' + str ( tools . config [ ' db_port ' ] ) )
cmd . append ( ' --dbname= ' + db_name )
args2 = tuple ( cmd )
buf = base64 . decodestring ( data )
if os . name == " nt " :
tmpfile = ( os . environ [ ' TMP ' ] or ' C: \\ ' ) + os . tmpnam ( )
file ( tmpfile , ' wb ' ) . write ( buf )
args2 = list ( args2 )
2012-02-14 19:30:30 +00:00
args2 . append ( tmpfile )
2012-01-31 11:08:49 +00:00
args2 = tuple ( args2 )
stdin , stdout = tools . exec_pg_command_pipe ( * args2 )
if not os . name == " nt " :
stdin . write ( base64 . decodestring ( data ) )
stdin . close ( )
res = stdout . close ( )
if res :
raise Exception , " Couldn ' t restore database "
2012-09-12 11:46:51 +00:00
logger . info ( ' RESTORE DB: %s ' , db_name )
2012-01-31 11:08:49 +00:00
return True
2008-07-22 14:24:36 +00:00
2009-08-29 15:23:46 +00:00
def exp_rename ( self , old_name , new_name ) :
2011-07-13 15:35:21 +00:00
openerp . modules . registry . RegistryManager . delete ( old_name )
2009-05-20 14:58:19 +00:00
sql_db . close_db ( old_name )
2012-02-09 21:33:17 +00:00
db = sql_db . db_connect ( ' postgres ' )
2010-01-20 16:39:13 +00:00
cr = db . cursor ( )
2010-05-27 14:13:47 +00:00
cr . autocommit ( True ) # avoid transaction block
2009-05-20 14:58:19 +00:00
try :
try :
2010-01-20 16:39:13 +00:00
cr . execute ( ' ALTER DATABASE " %s " RENAME TO " %s " ' % ( old_name , new_name ) )
except Exception , e :
2012-01-24 15:07:50 +00:00
_logger . error ( ' RENAME DB: %s -> %s failed: \n %s ' , old_name , new_name , e )
2010-01-20 16:39:13 +00:00
raise Exception ( " Couldn ' t rename database %s to %s : %s " % ( old_name , new_name , e ) )
else :
fs = os . path . join ( tools . config [ ' root_path ' ] , ' filestore ' )
if os . path . exists ( os . path . join ( fs , old_name ) ) :
os . rename ( os . path . join ( fs , old_name ) , os . path . join ( fs , new_name ) )
2012-01-24 15:07:50 +00:00
_logger . info ( ' RENAME DB: %s -> %s ' , old_name , new_name )
2009-05-20 14:58:19 +00:00
finally :
2010-01-20 16:39:13 +00:00
cr . close ( )
2009-05-20 14:58:19 +00:00
return True
2009-08-29 15:23:46 +00:00
def exp_db_exist ( self , db_name ) :
2009-12-01 13:32:14 +00:00
## Not True: in fact, check if connection to database is possible. The database may exists
return bool ( sql_db . db_connect ( db_name ) )
2008-07-22 14:24:36 +00:00
2010-05-12 13:07:56 +00:00
def exp_list ( self , document = False ) :
if not tools . config [ ' list_db ' ] and not document :
2011-09-26 15:14:03 +00:00
raise openerp . exceptions . AccessDenied ( )
2012-01-17 16:49:40 +00:00
chosen_template = tools . config [ ' db_template ' ]
templates_list = tuple ( set ( [ ' template0 ' , ' template1 ' , ' postgres ' , chosen_template ] ) )
2012-02-09 21:33:17 +00:00
db = sql_db . db_connect ( ' postgres ' )
2010-01-20 16:39:13 +00:00
cr = db . cursor ( )
2008-07-22 14:24:36 +00:00
try :
2009-01-12 09:40:20 +00:00
try :
2010-01-20 16:39:13 +00:00
db_user = tools . config [ " db_user " ]
if not db_user and os . name == ' posix ' :
import pwd
db_user = pwd . getpwuid ( os . getuid ( ) ) [ 0 ]
if not db_user :
2012-02-08 00:38:00 +00:00
cr . execute ( " select usename from pg_user where usesysid=(select datdba from pg_database where datname= %s ) " , ( tools . config [ " db_name " ] , ) )
2010-01-20 16:39:13 +00:00
res = cr . fetchone ( )
db_user = res and str ( res [ 0 ] )
if db_user :
2012-02-08 00:38:00 +00:00
cr . execute ( " select datname from pg_database where datdba=(select usesysid from pg_user where usename= %s ) and datname not in %s order by datname " , ( db_user , templates_list ) )
2010-01-20 16:39:13 +00:00
else :
2012-02-08 00:38:00 +00:00
cr . execute ( " select datname from pg_database where datname not in %s order by datname " , ( templates_list , ) )
2010-01-20 16:39:13 +00:00
res = [ str ( name ) for ( name , ) in cr . fetchall ( ) ]
2010-07-26 09:33:35 +00:00
except Exception :
2010-01-20 16:39:13 +00:00
res = [ ]
2009-01-12 09:40:20 +00:00
finally :
2010-01-20 16:39:13 +00:00
cr . close ( )
2008-09-08 22:52:36 +00:00
res . sort ( )
2008-07-22 14:24:36 +00:00
return res
2009-08-29 15:23:46 +00:00
def exp_change_admin_password ( self , new_password ) :
2008-07-22 14:24:36 +00:00
tools . config [ ' admin_passwd ' ] = new_password
tools . config . save ( )
return True
2008-09-11 07:29:45 +00:00
2009-08-29 15:23:46 +00:00
def exp_list_lang ( self ) :
2008-07-22 14:24:36 +00:00
return tools . scan_languages ( )
2008-08-20 08:20:19 +00:00
2009-08-29 15:23:46 +00:00
def exp_server_version ( self ) :
2008-08-20 08:20:19 +00:00
""" Return the version of the server
Used by the client to verify the compatibility with its own version
"""
2008-09-12 19:45:04 +00:00
return release . version
2009-01-02 22:34:23 +00:00
2009-08-29 15:23:46 +00:00
def exp_migrate_databases ( self , databases ) :
2009-01-07 15:53:45 +00:00
2011-02-07 12:57:23 +00:00
from openerp . osv . orm import except_orm
from openerp . osv . osv import except_osv
2009-01-07 15:53:45 +00:00
2009-01-02 22:34:23 +00:00
for db in databases :
try :
2012-01-24 17:30:17 +00:00
_logger . info ( ' migrate database %s ' , db )
2009-01-02 22:34:23 +00:00
tools . config [ ' update ' ] [ ' base ' ] = True
2009-06-11 11:27:56 +00:00
pooler . restart_pool ( db , force_demo = False , update_module = True )
2009-01-07 15:53:45 +00:00
except except_orm , inst :
2011-07-29 08:38:24 +00:00
netsvc . abort_response ( 1 , inst . name , ' warning ' , inst . value )
2009-01-07 15:53:45 +00:00
except except_osv , inst :
2011-09-26 15:14:03 +00:00
netsvc . abort_response ( 1 , inst . name , ' warning ' , inst . value )
2010-01-20 16:39:13 +00:00
except Exception :
2012-02-02 12:54:42 +00:00
_logger . exception ( ' Exception in migrate_databases: ' )
2009-01-02 22:34:23 +00:00
raise
2009-01-05 12:17:23 +00:00
return True
2006-12-07 13:41:40 +00:00
2011-07-28 12:02:04 +00:00
class common ( netsvc . ExportService ) :
2011-10-13 10:47:50 +00:00
2008-07-22 14:24:36 +00:00
def __init__ ( self , name = " common " ) :
2011-07-28 12:02:04 +00:00
netsvc . ExportService . __init__ ( self , name )
2009-08-29 15:23:46 +00:00
2011-09-25 15:23:18 +00:00
def dispatch ( self , method , params ) :
2011-10-13 10:47:50 +00:00
if method in [ ' login ' , ' about ' , ' timezone_get ' , ' get_server_environment ' ,
' login_message ' , ' get_stats ' , ' check_connectivity ' ,
' list_http_services ' , ' version ' , ' authenticate ' ] :
2009-11-24 14:44:05 +00:00
pass
2010-11-17 11:52:32 +00:00
elif method in [ ' get_available_updates ' , ' get_migration_scripts ' , ' set_loglevel ' , ' get_os_time ' , ' get_sqlcount ' ] :
2009-11-24 14:44:05 +00:00
passwd = params [ 0 ]
params = params [ 1 : ]
security . check_super ( passwd )
else :
raise Exception ( " Method not found: %s " % method )
2010-12-30 09:17:34 +00:00
2009-11-24 14:44:05 +00:00
fn = getattr ( self , ' exp_ ' + method )
return fn ( * params )
2009-08-29 15:23:46 +00:00
2011-10-13 10:47:50 +00:00
def exp_login ( self , db , login , password ) :
# TODO: legacy indirection through 'security', should use directly
# the res.users model
res = security . login ( db , login , password )
msg = res and ' successful login ' or ' bad login or password '
2012-01-24 15:07:50 +00:00
_logger . info ( " %s from ' %s ' using database ' %s ' " , msg , login , db . lower ( ) )
2011-10-13 10:47:50 +00:00
return res or False
def exp_authenticate ( self , db , login , password , user_agent_env ) :
res_users = pooler . get_pool ( db ) . get ( ' res.users ' )
return res_users . authenticate ( db , login , password , user_agent_env )
2011-09-30 13:59:42 +00:00
def exp_version ( self ) :
return RPC_VERSION_1
2009-08-29 15:23:46 +00:00
def exp_about ( self , extended = False ) :
2008-08-05 07:54:26 +00:00
""" Return information about the OpenERP Server.
@param extended : if True then return version info
@return string if extended is False else tuple
"""
info = _ ( '''
2006-12-07 13:41:40 +00:00
2008-04-09 11:33:09 +00:00
OpenERP is an ERP + CRM program for small and medium businesses .
2006-12-07 13:41:40 +00:00
The whole source code is distributed under the terms of the
GNU Public Licence .
2012-08-10 08:18:36 +00:00
( c ) 2003 - TODAY - OpenERP SA ''' )
2007-04-30 10:16:11 +00:00
2008-08-05 07:54:26 +00:00
if extended :
2008-09-12 19:45:04 +00:00
return info , release . version
2008-08-05 07:54:26 +00:00
return info
2009-08-29 15:23:46 +00:00
def exp_timezone_get ( self , db , login , password ) :
2010-07-27 15:22:11 +00:00
return tools . misc . get_server_timezone ( )
2009-06-11 11:27:56 +00:00
2009-08-29 15:23:46 +00:00
def exp_get_available_updates ( self , contract_id , contract_password ) :
2011-02-07 12:57:23 +00:00
import openerp . tools . maintenance as tm
2009-02-11 16:19:06 +00:00
try :
rc = tm . remote_contract ( contract_id , contract_password )
if not rc . id :
2009-06-11 11:27:56 +00:00
raise tm . RemoteContractException ( ' This contract does not exist or is not active ' )
2011-04-20 15:27:18 +00:00
return rc . get_available_updates ( rc . id , openerp . modules . get_modules_with_version ( ) )
2009-02-11 16:19:06 +00:00
except tm . RemoteContractException , e :
2011-07-29 08:38:24 +00:00
netsvc . abort_response ( 1 , ' Migration Error ' , ' warning ' , str ( e ) )
2009-06-11 11:27:56 +00:00
2009-01-02 14:43:25 +00:00
2009-08-29 15:23:46 +00:00
def exp_get_migration_scripts ( self , contract_id , contract_password ) :
2011-02-07 12:57:23 +00:00
import openerp . tools . maintenance as tm
2009-06-11 11:27:56 +00:00
try :
2009-01-09 09:15:55 +00:00
rc = tm . remote_contract ( contract_id , contract_password )
2009-01-02 22:34:23 +00:00
if not rc . id :
2009-06-11 11:27:56 +00:00
raise tm . RemoteContractException ( ' This contract does not exist or is not active ' )
2009-01-02 22:34:23 +00:00
if rc . status != ' full ' :
2009-01-09 09:15:55 +00:00
raise tm . RemoteContractException ( ' Can not get updates for a partial contract ' )
2009-01-02 22:34:23 +00:00
2012-01-24 17:30:17 +00:00
_logger . info ( ' starting migration with contract %s ' , rc . name )
2009-01-02 22:34:23 +00:00
2011-04-20 15:27:18 +00:00
zips = rc . retrieve_updates ( rc . id , openerp . modules . get_modules_with_version ( ) )
2009-06-11 11:27:56 +00:00
2009-01-22 13:23:38 +00:00
from shutil import rmtree , copytree , copy
backup_directory = os . path . join ( tools . config [ ' root_path ' ] , ' backup ' , time . strftime ( ' % Y- % m- %d - % H- % M ' ) )
if zips and not os . path . isdir ( backup_directory ) :
2012-02-08 14:22:48 +00:00
_logger . info ( ' create a new backup directory to store the old modules: %s ' , backup_directory )
2009-01-22 13:23:38 +00:00
os . makedirs ( backup_directory )
2009-01-02 22:34:23 +00:00
for module in zips :
2012-01-24 17:30:17 +00:00
_logger . info ( ' upgrade module %s ' , module )
2011-04-20 15:27:18 +00:00
mp = openerp . modules . get_module_path ( module )
2009-01-02 22:34:23 +00:00
if mp :
if os . path . isdir ( mp ) :
2009-01-22 13:23:38 +00:00
copytree ( mp , os . path . join ( backup_directory , module ) )
2009-01-09 13:59:21 +00:00
if os . path . islink ( mp ) :
os . unlink ( mp )
else :
rmtree ( mp )
2009-01-02 22:34:23 +00:00
else :
2009-01-22 13:23:38 +00:00
copy ( mp + ' zip ' , backup_directory )
2009-01-02 22:34:23 +00:00
os . unlink ( mp + ' .zip ' )
2009-01-22 13:23:38 +00:00
try :
try :
base64_decoded = base64 . decodestring ( zips [ module ] )
2010-07-26 09:33:35 +00:00
except Exception :
2012-01-24 17:30:17 +00:00
_logger . error ( ' unable to read the module %s ' , module )
2009-01-22 13:23:38 +00:00
raise
2010-01-20 16:39:13 +00:00
zip_contents = StringIO ( base64_decoded )
2009-01-22 13:23:38 +00:00
zip_contents . seek ( 0 )
try :
try :
tools . extract_zip_file ( zip_contents , tools . config [ ' addons_path ' ] )
2010-07-26 09:33:35 +00:00
except Exception :
2012-01-24 17:30:17 +00:00
_logger . error ( ' unable to extract the module %s ' , module )
2009-01-22 13:23:38 +00:00
rmtree ( module )
raise
finally :
zip_contents . close ( )
2010-07-26 09:33:35 +00:00
except Exception :
2012-01-24 17:30:17 +00:00
_logger . error ( ' restore the previous version of the module %s ' , module )
2009-01-22 13:23:38 +00:00
nmp = os . path . join ( backup_directory , module )
if os . path . isdir ( nmp ) :
copytree ( nmp , tools . config [ ' addons_path ' ] )
else :
copy ( nmp + ' .zip ' , tools . config [ ' addons_path ' ] )
raise
2009-01-05 12:17:23 +00:00
return True
2009-01-09 09:15:55 +00:00
except tm . RemoteContractException , e :
2011-07-29 08:38:24 +00:00
netsvc . abort_response ( 1 , ' Migration Error ' , ' warning ' , str ( e ) )
2009-01-02 22:34:23 +00:00
except Exception , e :
2012-02-02 12:54:42 +00:00
_logger . exception ( ' Exception in get_migration_script: ' )
2009-01-02 22:34:23 +00:00
raise
2009-06-11 11:27:56 +00:00
2009-08-29 15:23:46 +00:00
def exp_get_server_environment ( self ) :
2009-07-24 04:58:25 +00:00
os_lang = ' . ' . join ( [ x for x in locale . getdefaultlocale ( ) if x ] )
2009-07-30 07:36:45 +00:00
if not os_lang :
os_lang = ' NOT SET '
2009-07-14 05:31:17 +00:00
environment = ' \n Environment Information : \n ' \
2009-07-30 07:36:45 +00:00
' System : %s \n ' \
' OS Name : %s \n ' \
% ( platform . platform ( ) , platform . os . name )
if os . name == ' posix ' :
2012-01-19 19:17:56 +00:00
if platform . system ( ) == ' Linux ' :
lsbinfo = os . popen ( ' lsb_release -a ' ) . read ( )
environment + = ' %s ' % ( lsbinfo )
else :
environment + = ' Your System is not lsb compliant \n '
2009-07-30 07:36:45 +00:00
environment + = ' Operating System Release : %s \n ' \
' Operating System Version : %s \n ' \
' Operating System Architecture : %s \n ' \
' Operating System Locale : %s \n ' \
' Python Version : %s \n ' \
2009-08-28 14:20:11 +00:00
' OpenERP-Server Version : %s ' \
2009-07-30 07:36:45 +00:00
% ( platform . release ( ) , platform . version ( ) , platform . architecture ( ) [ 0 ] ,
2009-08-28 14:20:11 +00:00
os_lang , platform . python_version ( ) , release . version )
2009-06-11 11:27:56 +00:00
return environment
2009-08-03 10:08:43 +00:00
2009-08-29 15:23:46 +00:00
def exp_login_message ( self ) :
2009-08-03 10:08:43 +00:00
return tools . config . get ( ' login_message ' , False )
2010-06-22 11:15:49 +00:00
def exp_set_loglevel ( self , loglevel , logger = None ) :
2012-01-24 17:30:17 +00:00
# TODO Previously, the level was set on the now deprecated
# `openerp.netsvc.Logger` class.
2009-08-14 10:18:22 +00:00
return True
2009-10-28 00:30:33 +00:00
def exp_get_stats ( self ) :
res = " OpenERP server: %d threads \n " % threading . active_count ( )
2009-11-24 14:44:05 +00:00
res + = netsvc . Server . allStats ( )
2009-10-28 00:30:33 +00:00
return res
2010-03-01 17:19:21 +00:00
2010-07-26 09:33:34 +00:00
def exp_list_http_services ( self ) :
return http_server . list_http_services ( )
2010-03-01 17:19:21 +00:00
def exp_check_connectivity ( self ) :
2012-02-09 21:33:17 +00:00
return bool ( sql_db . db_connect ( ' postgres ' ) )
2010-12-30 09:17:34 +00:00
2010-11-16 16:20:25 +00:00
def exp_get_os_time ( self ) :
return os . times ( )
2009-10-28 00:30:33 +00:00
2010-11-17 11:52:32 +00:00
def exp_get_sqlcount ( self ) :
2012-02-01 23:56:04 +00:00
if not logging . getLogger ( ' openerp.sql_db ' ) . isEnabledFor ( logging . DEBUG ) :
_logger . warning ( " Counters of SQL will not be reliable unless logger openerp.sql_db is set to level DEBUG or higer. " )
2010-11-17 11:52:32 +00:00
return sql_db . sql_counter
2006-12-07 13:41:40 +00:00
2009-08-29 15:23:46 +00:00
class objects_proxy ( netsvc . ExportService ) :
2008-07-22 14:24:36 +00:00
def __init__ ( self , name = " object " ) :
2009-08-29 15:23:46 +00:00
netsvc . ExportService . __init__ ( self , name )
2008-09-11 07:29:45 +00:00
2011-09-25 15:23:18 +00:00
def dispatch ( self , method , params ) :
2009-11-24 14:44:05 +00:00
( db , uid , passwd ) = params [ 0 : 3 ]
2012-03-16 11:12:18 +00:00
threading . current_thread ( ) . uid = uid
2009-11-24 14:44:05 +00:00
params = params [ 3 : ]
2010-12-08 13:13:28 +00:00
if method == ' obj_list ' :
raise NameError ( " obj_list has been discontinued via RPC as of 6.0, please query ir.model directly! " )
2012-01-05 16:03:51 +00:00
if method not in [ ' execute ' , ' execute_kw ' , ' exec_workflow ' ] :
2010-12-08 13:13:28 +00:00
raise NameError ( " Method not available %s " % method )
2009-11-24 14:44:05 +00:00
security . check ( db , uid , passwd )
2011-07-29 08:38:24 +00:00
assert openerp . osv . osv . service , " The object_proxy class must be started with start_object_proxy. "
2012-12-08 18:11:51 +00:00
openerp . modules . registry . RegistryManager . check_registry_signaling ( db )
2011-07-29 08:38:24 +00:00
fn = getattr ( openerp . osv . osv . service , method )
2009-11-24 14:44:05 +00:00
res = fn ( db , uid , * params )
2012-12-08 18:11:51 +00:00
openerp . modules . registry . RegistryManager . signal_caches_change ( db )
2009-11-24 14:44:05 +00:00
return res
2010-12-30 09:17:34 +00:00
2006-12-07 13:41:40 +00:00
#
# Wizard ID: 1
# - None = end of wizard
#
# Wizard Type: 'form'
# - form
# - print
#
# Wizard datas: {}
# TODO: change local request to OSE request/reply pattern
#
2009-08-29 15:23:46 +00:00
class wizard ( netsvc . ExportService ) :
2008-07-22 14:24:36 +00:00
def __init__ ( self , name = ' wizard ' ) :
2009-08-29 15:23:46 +00:00
netsvc . ExportService . __init__ ( self , name )
2008-07-22 14:24:36 +00:00
self . id = 0
self . wiz_datas = { }
self . wiz_name = { }
self . wiz_uid = { }
2011-09-25 15:23:18 +00:00
def dispatch ( self , method , params ) :
2009-11-24 14:44:05 +00:00
( db , uid , passwd ) = params [ 0 : 3 ]
2012-03-16 11:12:18 +00:00
threading . current_thread ( ) . uid = uid
2009-11-24 14:44:05 +00:00
params = params [ 3 : ]
if method not in [ ' execute ' , ' create ' ] :
raise KeyError ( " Method not supported %s " % method )
security . check ( db , uid , passwd )
fn = getattr ( self , ' exp_ ' + method )
res = fn ( db , uid , * params )
return res
2010-12-30 09:17:34 +00:00
2008-07-22 14:24:36 +00:00
def _execute ( self , db , uid , wiz_id , datas , action , context ) :
self . wiz_datas [ wiz_id ] . update ( datas )
wiz = netsvc . LocalService ( ' wizard. ' + self . wiz_name [ wiz_id ] )
return wiz . execute ( db , uid , self . wiz_datas [ wiz_id ] , action , context )
2009-08-29 15:23:46 +00:00
def exp_create ( self , db , uid , wiz_name , datas = None ) :
2008-07-22 14:24:36 +00:00
if not datas :
datas = { }
2006-12-07 13:41:40 +00:00
#FIXME: this is not thread-safe
2008-07-22 14:24:36 +00:00
self . id + = 1
self . wiz_datas [ self . id ] = { }
self . wiz_name [ self . id ] = wiz_name
self . wiz_uid [ self . id ] = uid
return self . id
2009-08-29 15:23:46 +00:00
def exp_execute ( self , db , uid , wiz_id , datas , action = ' init ' , context = None ) :
2008-07-22 14:24:36 +00:00
if not context :
context = { }
if wiz_id in self . wiz_uid :
if self . wiz_uid [ wiz_id ] == uid :
return self . _execute ( db , uid , wiz_id , datas , action , context )
else :
2011-09-27 08:19:02 +00:00
raise openerp . exceptions . AccessDenied ( )
2008-07-22 14:24:36 +00:00
else :
2011-09-27 08:19:02 +00:00
raise openerp . exceptions . Warning ( ' Wizard not found. ' )
2006-12-07 13:41:40 +00:00
#
# TODO: set a maximum report number per user to avoid DOS attacks
#
# Report state:
# False -> True
#
2009-01-15 13:34:04 +00:00
2009-08-29 15:23:46 +00:00
class report_spool ( netsvc . ExportService ) :
2008-07-22 14:24:36 +00:00
def __init__ ( self , name = ' report ' ) :
2009-08-29 15:23:46 +00:00
netsvc . ExportService . __init__ ( self , name )
2008-07-22 14:24:36 +00:00
self . _reports = { }
self . id = 0
self . id_protect = threading . Semaphore ( )
2011-09-25 15:23:18 +00:00
def dispatch ( self , method , params ) :
2009-11-24 14:44:05 +00:00
( db , uid , passwd ) = params [ 0 : 3 ]
2012-03-16 11:12:18 +00:00
threading . current_thread ( ) . uid = uid
2009-11-24 14:44:05 +00:00
params = params [ 3 : ]
2011-09-01 13:04:50 +00:00
if method not in [ ' report ' , ' report_get ' , ' render_report ' ] :
2009-11-24 14:44:05 +00:00
raise KeyError ( " Method not supported %s " % method )
security . check ( db , uid , passwd )
2012-12-08 18:11:51 +00:00
openerp . modules . registry . RegistryManager . check_registry_signaling ( db )
2009-11-24 14:44:05 +00:00
fn = getattr ( self , ' exp_ ' + method )
res = fn ( db , uid , * params )
2012-12-08 18:11:51 +00:00
openerp . modules . registry . RegistryManager . signal_caches_change ( db )
2009-11-24 14:44:05 +00:00
return res
2011-09-01 13:04:50 +00:00
def exp_render_report ( self , db , uid , object , ids , datas = None , context = None ) :
if not datas :
datas = { }
if not context :
context = { }
self . id_protect . acquire ( )
self . id + = 1
id = self . id
self . id_protect . release ( )
self . _reports [ id ] = { ' uid ' : uid , ' result ' : False , ' state ' : False , ' exception ' : None }
cr = pooler . get_db ( db ) . cursor ( )
try :
obj = netsvc . LocalService ( ' report. ' + object )
( result , format ) = obj . create ( cr , uid , ids , datas , context )
if not result :
tb = sys . exc_info ( )
2011-09-27 10:22:46 +00:00
self . _reports [ id ] [ ' exception ' ] = openerp . exceptions . DeferredException ( ' RML is not available at specified location or not enough data to print! ' , tb )
2011-09-01 13:04:50 +00:00
self . _reports [ id ] [ ' result ' ] = result
self . _reports [ id ] [ ' format ' ] = format
self . _reports [ id ] [ ' state ' ] = True
except Exception , exception :
2012-02-08 14:22:48 +00:00
_logger . exception ( ' Exception: %s \n ' , exception )
2011-09-01 13:04:50 +00:00
if hasattr ( exception , ' name ' ) and hasattr ( exception , ' value ' ) :
2011-09-27 10:22:46 +00:00
self . _reports [ id ] [ ' exception ' ] = openerp . exceptions . DeferredException ( tools . ustr ( exception . name ) , tools . ustr ( exception . value ) )
2011-09-01 13:04:50 +00:00
else :
2012-02-02 12:54:42 +00:00
tb = sys . exc_info ( )
2011-09-27 10:22:46 +00:00
self . _reports [ id ] [ ' exception ' ] = openerp . exceptions . DeferredException ( tools . exception_to_unicode ( exception ) , tb )
2011-09-01 13:04:50 +00:00
self . _reports [ id ] [ ' state ' ] = True
cr . commit ( )
cr . close ( )
return self . _check_report ( id )
2009-08-29 15:23:46 +00:00
def exp_report ( self , db , uid , object , ids , datas = None , context = None ) :
2008-07-22 14:24:36 +00:00
if not datas :
datas = { }
if not context :
context = { }
2008-09-11 07:29:45 +00:00
2008-07-22 14:24:36 +00:00
self . id_protect . acquire ( )
self . id + = 1
id = self . id
self . id_protect . release ( )
self . _reports [ id ] = { ' uid ' : uid , ' result ' : False , ' state ' : False , ' exception ' : None }
def go ( id , uid , ids , datas , context ) :
2008-12-19 19:16:57 +00:00
cr = pooler . get_db ( db ) . cursor ( )
2008-07-22 14:24:36 +00:00
try :
obj = netsvc . LocalService ( ' report. ' + object )
( result , format ) = obj . create ( cr , uid , ids , datas , context )
2010-01-06 06:33:08 +00:00
if not result :
tb = sys . exc_info ( )
2011-09-27 10:22:46 +00:00
self . _reports [ id ] [ ' exception ' ] = openerp . exceptions . DeferredException ( ' RML is not available at specified location or not enough data to print! ' , tb )
2008-07-22 14:24:36 +00:00
self . _reports [ id ] [ ' result ' ] = result
self . _reports [ id ] [ ' format ' ] = format
self . _reports [ id ] [ ' state ' ] = True
except Exception , exception :
2012-02-08 14:22:48 +00:00
_logger . exception ( ' Exception: %s \n ' , exception )
2010-10-14 13:58:54 +00:00
if hasattr ( exception , ' name ' ) and hasattr ( exception , ' value ' ) :
2011-09-27 10:22:46 +00:00
self . _reports [ id ] [ ' exception ' ] = openerp . exceptions . DeferredException ( tools . ustr ( exception . name ) , tools . ustr ( exception . value ) )
2010-10-14 13:58:54 +00:00
else :
2012-02-02 12:54:42 +00:00
tb = sys . exc_info ( )
2011-09-27 10:22:46 +00:00
self . _reports [ id ] [ ' exception ' ] = openerp . exceptions . DeferredException ( tools . exception_to_unicode ( exception ) , tb )
2008-07-22 14:24:36 +00:00
self . _reports [ id ] [ ' state ' ] = True
2009-05-20 15:25:47 +00:00
cr . commit ( )
2008-12-19 19:16:57 +00:00
cr . close ( )
2008-07-22 14:24:36 +00:00
return True
thread . start_new_thread ( go , ( id , uid , ids , datas , context ) )
return id
def _check_report ( self , report_id ) :
result = self . _reports [ report_id ]
2010-10-14 13:58:54 +00:00
exc = result [ ' exception ' ]
if exc :
2011-07-29 08:38:24 +00:00
netsvc . abort_response ( exc , exc . message , ' warning ' , exc . traceback )
2008-07-22 14:24:36 +00:00
res = { ' state ' : result [ ' state ' ] }
if res [ ' state ' ] :
if tools . config [ ' reportgz ' ] :
import zlib
res2 = zlib . compress ( result [ ' result ' ] )
res [ ' code ' ] = ' zlib '
else :
#CHECKME: why is this needed???
if isinstance ( result [ ' result ' ] , unicode ) :
res2 = result [ ' result ' ] . encode ( ' latin1 ' , ' replace ' )
else :
res2 = result [ ' result ' ]
if res2 :
res [ ' result ' ] = base64 . encodestring ( res2 )
res [ ' format ' ] = result [ ' format ' ]
del self . _reports [ report_id ]
return res
2009-08-29 15:23:46 +00:00
def exp_report_get ( self , db , uid , report_id ) :
2008-07-22 14:24:36 +00:00
if report_id in self . _reports :
if self . _reports [ report_id ] [ ' uid ' ] == uid :
return self . _check_report ( report_id )
else :
raise Exception , ' AccessDenied '
else :
raise Exception , ' ReportNotFound '
2006-12-07 13:41:40 +00:00
2011-05-07 11:21:29 +00:00
def start_web_services ( ) :
db ( )
common ( )
objects_proxy ( )
wizard ( )
report_spool ( )
2006-12-07 13:41:40 +00:00
2008-07-23 15:01:27 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: