[IMP] tests: added a simple test case to create a database via XML-RPC.
[odoo/odoo.git] / openerp-server
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 ##############################################################################
4 #
5 #    OpenERP, Open Source Management Solution
6 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU Affero General Public License as
10 #    published by the Free Software Foundation, either version 3 of the
11 #    License, or (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU Affero General Public License for more details.
17 #
18 #    You should have received a copy of the GNU Affero General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 """
24 OpenERP - Server
25 OpenERP is an ERP+CRM program for small and medium businesses.
26
27 The whole source code is distributed under the terms of the
28 GNU Public Licence.
29
30 (c) 2003-TODAY, Fabien Pinckaers - OpenERP SA
31 """
32
33 import logging
34 import os
35 import signal
36 import sys
37 import threading
38 import traceback
39 import time
40
41 import openerp
42 __author__ = openerp.release.author
43 __version__ = openerp.release.version
44
45 def check_root_user():
46     """ Exit if the process's user is 'root' (on POSIX system)."""
47     if os.name == 'posix':
48         import pwd
49         if pwd.getpwuid(os.getuid())[0] == 'root' :
50             sys.stderr.write("Running as user 'root' is a security risk, aborting.\n")
51             sys.exit(1)
52
53 def check_postgres_user():
54     """ Exit if the configured database user is 'postgres'.
55
56     This function assumes the configuration has been initialized.
57     """
58     config = openerp.tools.config
59     if config['db_user'] == 'postgres':
60         sys.stderr.write("Using the database user 'postgres' is a security risk, aborting.")
61         sys.exit(1)
62
63 def report_configuration():
64     """ Log the server version and some configuration values.
65
66     This function assumes the configuration has been initialized.
67     """
68     config = openerp.tools.config
69     logger = logging.getLogger('server')
70     logger.info("OpenERP version %s", __version__)
71     for name, value in [('addons paths', config['addons_path']),
72                         ('database hostname', config['db_host'] or 'localhost'),
73                         ('database port', config['db_port'] or '5432'),
74                         ('database user', config['db_user'])]:
75         logger.info("%s: %s", name, value)
76
77 def setup_pid_file():
78     """ Create a file with the process id written in it.
79
80     This function assumes the configuration has been initialized.
81     """
82     config = openerp.tools.config
83     if config['pidfile']:
84         fd = open(config['pidfile'], 'w')
85         pidtext = "%d" % (os.getpid())
86         fd.write(pidtext)
87         fd.close()
88
89 def preload_registry(dbname):
90     """ Preload a registry, and start the cron."""
91     db, pool = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False)
92     pool.get('ir.cron').restart(db.dbname)
93
94 def run_test_file(dbname, test_file):
95     """ Preload a registry, possibly run a test file, and start the cron."""
96     db, pool = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False)
97
98     cr = db.cursor()
99     logger = logging.getLogger('server')
100     logger.info('loading test file %s', test_file)
101     openerp.tools.convert_yaml_import(cr, 'base', file(test_file), {}, 'test', True)
102     cr.rollback()
103     cr.close()
104
105 def export_translation():
106     config = openerp.tools.config
107     dbname = config['db_name']
108     logger = logging.getLogger('server')
109
110     if config["language"]:
111         msg = "language %s" % (config["language"],)
112     else:
113         msg = "new language"
114     logger.info('writing translation file for %s to %s', msg,
115         config["translate_out"])
116
117     fileformat = os.path.splitext(config["translate_out"])[-1][1:].lower()
118     buf = file(config["translate_out"], "w")
119     cr = openerp.pooler.get_db(dbname).cursor()
120     openerp.tools.trans_export(config["language"],
121         config["translate_modules"] or ["all"], buf, fileformat, cr)
122     cr.close()
123     buf.close()
124
125     logger.info('translation file written successfully')
126
127 def import_translation():
128     config = openerp.tools.config
129     context = {'overwrite': config["overwrite_existing_translations"]}
130     dbname = config['db_name']
131
132     cr = openerp.pooler.get_db(dbname).cursor()
133     openerp.tools.trans_load( cr, config["translate_in"], config["language"],
134         context=context)
135     openerp.tools.trans_update_res_ids(cr)
136     cr.commit()
137     cr.close()
138
139 # Variable keeping track of the number of calls to the signal handler defined
140 # below. This variable is monitored by ``quit_on_signals()``.
141 quit_signals_received = 0
142
143 def signal_handler(sig, frame):
144     """ Signal handler: exit ungracefully on the second handled signal.
145
146     :param sig: the signal number
147     :param frame: the interrupted stack frame or None
148     """
149     global quit_signals_received
150     quit_signals_received += 1
151     if quit_signals_received > 1:
152         # logging.shutdown was already called at this point.
153         sys.stderr.write("Forced shutdown.\n")
154         os._exit(0)
155
156 def dumpstacks(sig, frame):
157     """ Signal handler: dump a stack trace for each existing thread."""
158     # code from http://stackoverflow.com/questions/132058/getting-stack-trace-from-a-running-python-application#answer-2569696
159     # modified for python 2.5 compatibility
160     thread_map = dict(threading._active, **threading._limbo)
161     id2name = dict([(threadId, thread.getName()) for threadId, thread in thread_map.items()])
162     code = []
163     for threadId, stack in sys._current_frames().items():
164         code.append("\n# Thread: %s(%d)" % (id2name[threadId], threadId))
165         for filename, lineno, name, line in traceback.extract_stack(stack):
166             code.append('File: "%s", line %d, in %s' % (filename, lineno, name))
167             if line:
168                 code.append("  %s" % (line.strip()))
169     logging.getLogger('dumpstacks').info("\n".join(code))
170
171 def setup_signal_handlers():
172     """ Register the signal handler defined above. """
173     SIGNALS = map(lambda x: getattr(signal, "SIG%s" % x), "INT TERM".split())
174     map(lambda sig: signal.signal(sig, signal_handler), SIGNALS)
175     if os.name == 'posix':
176         signal.signal(signal.SIGQUIT, dumpstacks)
177
178 def quit_on_signals():
179     """ Wait for one or two signals then shutdown the server.
180
181     The first SIGINT or SIGTERM signal will initiate a graceful shutdown while
182     a second one if any will force an immediate exit.
183
184     """
185     # Wait for a first signal to be handled. (time.sleep will be interrupted
186     # by the signal handler.)
187     while quit_signals_received == 0:
188         time.sleep(60)
189
190     if config['pidfile']:
191         os.unlink(config['pidfile'])
192
193     openerp.service.stop_services()
194     sys.exit(0)
195
196 if __name__ == "__main__":
197
198     os.environ["TZ"] = "UTC"
199
200     check_root_user()
201     openerp.tools.config.parse_config(sys.argv[1:])
202     check_postgres_user()
203     openerp.netsvc.init_logger()
204     report_configuration()
205
206     config = openerp.tools.config
207
208     setup_signal_handlers()
209
210     if config["test_file"]:
211         run_test_file(config['db_name'], config['test_file'])
212         sys.exit(0)
213
214     if config["translate_out"]:
215         export_translation()
216         sys.exit(0)
217
218     if config["translate_in"]:
219         import_translation()
220         sys.exit(0)
221
222     if not config["stop_after_init"]:
223         # Some module register themselves when they are loaded so we need the
224         # services to be running before loading any registry.
225         openerp.service.start_services()
226
227     if config['db_name']:
228         for dbname in config['db_name'].split(','):
229             preload_registry(dbname)
230
231     if config["stop_after_init"]:
232         sys.exit(0)
233
234     setup_pid_file()
235     logger = logging.getLogger('server')
236     logger.info('OpenERP server is running, waiting for connections...')
237     quit_on_signals()
238
239 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: