2009-10-20 10:52:23 +00:00
# -*- coding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
2010-03-11 08:49:41 +00:00
#
2009-01-15 10:12:10 +00:00
# OpenERP, Open Source Management Solution
2009-10-14 12:32:15 +00:00
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
2012-02-01 10:28:38 +00:00
# Copyright (C) 2010-2012 OpenERP s.a. (<http://openerp.com>).
2006-12-07 13:41:40 +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-03-11 08:49:41 +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
##############################################################################
2006-12-07 13:41:40 +00:00
2008-12-16 18:10:07 +00:00
import ConfigParser
import optparse
import os
import sys
2011-02-07 12:57:23 +00:00
import openerp
2011-08-08 13:54:53 +00:00
import openerp . conf
2011-02-07 12:57:23 +00:00
import openerp . loglevels as loglevels
2008-12-16 18:10:07 +00:00
import logging
2011-02-07 12:57:23 +00:00
import openerp . release as release
2006-12-07 13:41:40 +00:00
2011-05-31 12:53:22 +00:00
class MyOption ( optparse . Option , object ) :
""" optparse Option with two additional attributes.
The list of command line options ( getopt . Option ) is used to create the
list of the configuration file options . When reading the file , and then
reading the command line arguments , we don ' t want optparse.parse results
to override the configuration file values . But if we provide default
values to optparse , optparse will return them and we can ' t know if they
were really provided by the user or not . A solution is to not use
optparse ' s default attribute, but use a custom one (that will be copied
to create the default values of the configuration file ) .
"""
def __init__ ( self , * opts , * * attrs ) :
self . my_default = attrs . pop ( ' my_default ' , None )
super ( MyOption , self ) . __init__ ( * opts , * * attrs )
2011-06-23 09:03:57 +00:00
2008-12-19 00:00:49 +00:00
def check_ssl ( ) :
try :
from OpenSSL import SSL
import socket
2011-05-09 09:44:48 +00:00
2010-11-17 17:17:54 +00:00
return hasattr ( socket , ' ssl ' ) and hasattr ( SSL , " Connection " )
2008-12-19 00:00:49 +00:00
except :
return False
2012-04-23 12:24:07 +00:00
DEFAULT_LOG_HANDLER = [ ' :INFO ' ]
2006-12-07 13:41:40 +00:00
class configmanager ( object ) :
2008-07-22 14:24:36 +00:00
def __init__ ( self , fname = None ) :
2011-04-19 13:40:16 +00:00
# Options not exposed on the command line. Command line options will be added
# from optparse's parser.
2008-07-22 14:24:36 +00:00
self . options = {
' admin_passwd ' : ' admin ' ,
2009-01-15 10:12:10 +00:00
' csv_internal_sep ' : ' , ' ,
2009-08-03 10:08:43 +00:00
' login_message ' : False ,
2010-12-20 10:19:58 +00:00
' publisher_warranty_url ' : ' http://services.openerp.com/publisher-warranty/ ' ,
2011-04-19 13:40:16 +00:00
' reportgz ' : False ,
' root_path ' : None ,
2008-07-22 14:24:36 +00:00
}
2011-02-07 17:03:17 +00:00
2011-04-19 13:40:16 +00:00
# Not exposed in the configuration file.
self . blacklist_for_save = set (
[ ' publisher_warranty_url ' , ' load_language ' , ' root_path ' ,
2011-12-20 16:45:54 +00:00
' init ' , ' save ' , ' config ' , ' update ' , ' stop_after_init ' ] )
2010-03-11 08:49:41 +00:00
2011-06-01 07:44:00 +00:00
# dictionary mapping option destination (keys in self.options) to MyOptions.
self . casts = { }
2009-11-24 14:44:05 +00:00
self . misc = { }
2010-04-19 11:00:51 +00:00
self . config_file = fname
self . has_ssl = check_ssl ( )
2008-12-19 00:00:49 +00:00
2012-02-01 00:30:15 +00:00
self . _LOGLEVELS = dict ( [ ( getattr ( loglevels , ' LOG_ %s ' % x ) , getattr ( logging , x ) ) for x in ( ' CRITICAL ' , ' ERROR ' , ' WARNING ' , ' INFO ' , ' TEST ' , ' DEBUG ' , ' NOTSET ' ) ] )
2008-07-22 14:24:36 +00:00
2008-09-12 19:45:04 +00:00
version = " %s %s " % ( release . description , release . version )
2011-05-31 12:53:22 +00:00
self . parser = parser = optparse . OptionParser ( version = version , option_class = MyOption )
2009-01-15 10:12:10 +00:00
2011-02-07 17:03:17 +00:00
# Server startup config
group = optparse . OptionGroup ( parser , " Common options " )
group . add_option ( " -c " , " --config " , dest = " config " , help = " specify alternate config file " )
group . add_option ( " -s " , " --save " , action = " store_true " , dest = " save " , default = False ,
2008-12-24 00:57:34 +00:00
help = " save configuration to ~/.openerp_serverrc " )
2011-02-07 17:03:17 +00:00
group . add_option ( " -i " , " --init " , dest = " init " , help = " install one or more modules (comma-separated list, use \" all \" for all modules), requires -d " )
group . add_option ( " -u " , " --update " , dest = " update " ,
help = " update one or more modules (comma-separated list, use \" all \" for all modules). Requires -d. " )
group . add_option ( " --without-demo " , dest = " without_demo " ,
help = " disable loading demo data for modules to be installed (comma-separated, use \" all \" for all modules). Requires -d and -i. Default is %d efault " ,
2011-05-31 12:53:22 +00:00
my_default = False )
group . add_option ( " -P " , " --import-partial " , dest = " import_partial " , my_default = ' ' ,
2011-04-19 13:40:16 +00:00
help = " Use this for big data importation, if it crashes you will be able to continue at the current state. Provide a filename to store intermediate importation states. " )
2011-02-07 17:03:17 +00:00
group . add_option ( " --pidfile " , dest = " pidfile " , help = " file where the server pid will be stored " )
2011-10-14 09:36:26 +00:00
group . add_option ( " --addons-path " , dest = " addons_path " ,
help = " specify additional addons paths (separated by commas). " ,
action = " callback " , callback = self . _check_addons_path , nargs = 1 , type = " string " )
2011-10-01 13:16:19 +00:00
group . add_option ( " --load " , dest = " server_wide_modules " , help = " Comma-separated list of server-wide modules default=web " )
2011-02-07 17:03:17 +00:00
parser . add_option_group ( group )
2009-01-15 10:12:10 +00:00
2011-09-02 13:31:36 +00:00
# XML-RPC / HTTP
2010-05-31 12:26:50 +00:00
group = optparse . OptionGroup ( parser , " XML-RPC Configuration " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --xmlrpc-interface " , dest = " xmlrpc_interface " , my_default = ' ' ,
2011-04-19 13:40:16 +00:00
help = " Specify the TCP IP address for the XML-RPC protocol. The empty string binds to all interfaces. " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --xmlrpc-port " , dest = " xmlrpc_port " , my_default = 8069 ,
2011-04-19 13:40:16 +00:00
help = " specify the TCP port for the XML-RPC protocol " , type = " int " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --no-xmlrpc " , dest = " xmlrpc " , action = " store_false " , my_default = True ,
2011-04-19 13:40:16 +00:00
help = " disable the XML-RPC protocol " )
2012-09-24 10:56:22 +00:00
group . add_option ( " --proxy-mode " , dest = " proxy_mode " , action = " store_true " , my_default = False ,
help = " Enable correct behavior when behind a reverse proxy " )
2010-05-31 12:26:50 +00:00
parser . add_option_group ( group )
2011-09-02 13:31:36 +00:00
# XML-RPC / HTTPS
2010-06-07 12:30:25 +00:00
title = " XML-RPC Secure Configuration "
if not self . has_ssl :
title + = " (disabled as ssl is unavailable) "
group = optparse . OptionGroup ( parser , title )
2011-05-31 12:53:22 +00:00
group . add_option ( " --xmlrpcs-interface " , dest = " xmlrpcs_interface " , my_default = ' ' ,
2011-04-19 13:40:16 +00:00
help = " Specify the TCP IP address for the XML-RPC Secure protocol. The empty string binds to all interfaces. " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --xmlrpcs-port " , dest = " xmlrpcs_port " , my_default = 8071 ,
2011-04-19 13:40:16 +00:00
help = " specify the TCP port for the XML-RPC Secure protocol " , type = " int " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --no-xmlrpcs " , dest = " xmlrpcs " , action = " store_false " , my_default = True ,
2011-04-19 13:40:16 +00:00
help = " disable the XML-RPC Secure protocol " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --cert-file " , dest = " secure_cert_file " , my_default = ' server.cert ' ,
2011-04-19 13:40:16 +00:00
help = " specify the certificate file for the SSL connection " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --pkey-file " , dest = " secure_pkey_file " , my_default = ' server.pkey ' ,
2011-04-19 13:40:16 +00:00
help = " specify the private key file for the SSL connection " )
2010-06-07 12:30:25 +00:00
parser . add_option_group ( group )
2010-05-31 14:17:39 +00:00
2010-08-10 13:12:00 +00:00
# NET-RPC
2010-05-31 12:26:50 +00:00
group = optparse . OptionGroup ( parser , " NET-RPC Configuration " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --netrpc-interface " , dest = " netrpc_interface " , my_default = ' ' ,
2011-04-19 13:40:16 +00:00
help = " specify the TCP IP address for the NETRPC protocol " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --netrpc-port " , dest = " netrpc_port " , my_default = 8070 ,
2011-04-19 13:40:16 +00:00
help = " specify the TCP port for the NETRPC protocol " , type = " int " )
2012-12-09 18:56:51 +00:00
# Needed a few day for runbot and saas
group . add_option ( " --no-netrpc " , dest = " netrpc " , action = " store_false " , my_default = False , help = " disable the NETRPC protocol " )
group . add_option ( " --netrpc " , dest = " netrpc " , action = " store_true " , my_default = False , help = " enable the NETRPC protocol " )
2010-05-31 12:26:50 +00:00
parser . add_option_group ( group )
2010-09-08 13:08:10 +00:00
2011-09-25 00:54:37 +00:00
# WEB
# TODO move to web addons after MetaOption merge
group = optparse . OptionGroup ( parser , " Web interface Configuration " )
group . add_option ( " --db-filter " , dest = " dbfilter " , default = ' .* ' ,
help = " Filter listed database " , metavar = " REGEXP " )
parser . add_option_group ( group )
2010-08-10 13:12:00 +00:00
# Static HTTP
group = optparse . OptionGroup ( parser , " Static HTTP service " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --static-http-enable " , dest = " static_http_enable " , action = " store_true " , my_default = False , help = " enable static HTTP service for serving plain HTML files " )
2010-08-10 13:12:00 +00:00
group . add_option ( " --static-http-document-root " , dest = " static_http_document_root " , help = " specify the directory containing your static HTML files (e.g ' /var/www/ ' ) " )
group . add_option ( " --static-http-url-prefix " , dest = " static_http_url_prefix " , help = " specify the URL root prefix where you want web browsers to access your static HTML files (e.g ' / ' ) " )
parser . add_option_group ( group )
2010-09-08 13:08:10 +00:00
2010-04-30 14:22:50 +00:00
# Testing Group
group = optparse . OptionGroup ( parser , " Testing Configuration " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --test-file " , dest = " test_file " , my_default = False ,
2011-04-19 13:40:16 +00:00
help = " Launch a YML test file. " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --test-report-directory " , dest = " test_report_directory " , my_default = False ,
2011-04-19 13:40:16 +00:00
help = " If set, will save sample of all reports in this directory. " )
2012-03-01 13:46:08 +00:00
group . add_option ( " --test-enable " , action = " store_true " , dest = " test_enable " ,
my_default = False , help = " Enable YAML and unit tests. " )
2010-08-10 13:17:55 +00:00
group . add_option ( " --test-commit " , action = " store_true " , dest = " test_commit " ,
2012-03-02 11:28:34 +00:00
my_default = False , help = " Commit database changes performed by YAML or XML tests. " )
2010-04-30 14:22:50 +00:00
parser . add_option_group ( group )
2010-05-13 07:07:00 +00:00
2008-12-22 23:04:18 +00:00
# Logging Group
group = optparse . OptionGroup ( parser , " Logging Configuration " )
group . add_option ( " --logfile " , dest = " logfile " , help = " file where the server log will be stored " )
2012-02-01 00:10:19 +00:00
group . add_option ( " --no-logrotate " , dest = " logrotate " , action = " store_false " , my_default = True , help = " do not rotate the logfile " )
group . add_option ( " --syslog " , action = " store_true " , dest = " syslog " , my_default = False , help = " Send the log to the syslog server " )
2012-04-23 12:24:07 +00:00
group . add_option ( ' --log-handler ' , action = " append " , default = DEFAULT_LOG_HANDLER , my_default = DEFAULT_LOG_HANDLER , metavar = " PREFIX:LEVEL " , help = ' setup a handler at LEVEL for a given PREFIX. An empty PREFIX indicates the root logger. This option can be repeated. Example: " openerp.orm:DEBUG " or " werkzeug:CRITICAL " (default: " :INFO " ) ' )
2012-02-06 22:14:20 +00:00
group . add_option ( ' --log-request ' , action = " append_const " , dest = " log_handler " , const = " openerp.netsvc.rpc.request:DEBUG " , help = ' shortcut for --log-handler=openerp.netsvc.rpc.request:DEBUG ' )
group . add_option ( ' --log-response ' , action = " append_const " , dest = " log_handler " , const = " openerp.netsvc.rpc.response:DEBUG " , help = ' shortcut for --log-handler=openerp.netsvc.rpc.response:DEBUG ' )
2012-10-10 20:48:29 +00:00
group . add_option ( ' --log-web ' , action = " append_const " , dest = " log_handler " , const = " openerp.addons.web.http:DEBUG " , help = ' shortcut for --log-handler=openerp.addons.web.http:DEBUG ' )
2012-02-01 00:10:19 +00:00
group . add_option ( ' --log-sql ' , action = " append_const " , dest = " log_handler " , const = " openerp.sql_db:DEBUG " , help = ' shortcut for --log-handler=openerp.sql_db:DEBUG ' )
2012-02-06 23:02:15 +00:00
# For backward-compatibility, map the old log levels to something
# quite close.
levels = [ ' info ' , ' debug_rpc ' , ' warn ' , ' test ' , ' critical ' ,
' debug_sql ' , ' error ' , ' debug ' , ' debug_rpc_answer ' , ' notset ' ]
group . add_option ( ' --log-level ' , dest = ' log_level ' , type = ' choice ' , choices = levels ,
my_default = ' info ' , help = ' specify the level of the logging. Accepted values: ' + str ( levels ) + ' (deprecated option). ' )
2012-02-01 00:10:19 +00:00
2008-12-22 23:04:18 +00:00
parser . add_option_group ( group )
# SMTP Group
2008-12-19 00:37:50 +00:00
group = optparse . OptionGroup ( parser , " SMTP Configuration " )
2011-05-31 12:53:22 +00:00
group . add_option ( ' --email-from ' , dest = ' email_from ' , my_default = False ,
2011-04-19 13:40:16 +00:00
help = ' specify the SMTP email address for sending email ' )
2011-05-31 12:53:22 +00:00
group . add_option ( ' --smtp ' , dest = ' smtp_server ' , my_default = ' localhost ' ,
2011-04-19 13:40:16 +00:00
help = ' specify the SMTP server for sending email ' )
2011-05-31 12:53:22 +00:00
group . add_option ( ' --smtp-port ' , dest = ' smtp_port ' , my_default = 25 ,
2011-04-19 13:40:16 +00:00
help = ' specify the SMTP port ' , type = " int " )
2011-05-31 12:53:22 +00:00
group . add_option ( ' --smtp-ssl ' , dest = ' smtp_ssl ' , action = ' store_true ' , my_default = False ,
2013-01-15 12:40:58 +00:00
help = ' if passed, SMTP connections will be encrypted with SSL (STARTTLS) ' )
2011-05-31 12:53:22 +00:00
group . add_option ( ' --smtp-user ' , dest = ' smtp_user ' , my_default = False ,
2011-04-19 13:40:16 +00:00
help = ' specify the SMTP username for sending email ' )
2011-05-31 12:53:22 +00:00
group . add_option ( ' --smtp-password ' , dest = ' smtp_password ' , my_default = False ,
2011-04-19 13:40:16 +00:00
help = ' specify the SMTP password for sending email ' )
2008-12-19 00:37:50 +00:00
parser . add_option_group ( group )
2009-01-15 10:12:10 +00:00
2008-07-22 14:24:36 +00:00
group = optparse . OptionGroup ( parser , " Database related options " )
2011-05-31 12:53:22 +00:00
group . add_option ( " -d " , " --database " , dest = " db_name " , my_default = False ,
2011-04-19 13:40:16 +00:00
help = " specify the database name " )
2011-05-31 12:53:22 +00:00
group . add_option ( " -r " , " --db_user " , dest = " db_user " , my_default = False ,
2011-04-19 13:40:16 +00:00
help = " specify the database user name " )
2011-05-31 12:53:22 +00:00
group . add_option ( " -w " , " --db_password " , dest = " db_password " , my_default = False ,
2011-04-19 13:40:16 +00:00
help = " specify the database password " )
2009-01-15 10:12:10 +00:00
group . add_option ( " --pg_path " , dest = " pg_path " , help = " specify the pg executable path " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --db_host " , dest = " db_host " , my_default = False ,
2011-04-19 13:40:16 +00:00
help = " specify the database host " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --db_port " , dest = " db_port " , my_default = False ,
2011-04-19 13:40:16 +00:00
help = " specify the database port " , type = " int " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --db_maxconn " , dest = " db_maxconn " , type = ' int ' , my_default = 64 ,
2008-12-24 00:57:34 +00:00
help = " specify the the maximum number of physical connections to posgresql " )
2012-02-09 21:33:17 +00:00
group . add_option ( " --db-template " , dest = " db_template " , my_default = " template1 " ,
2012-01-18 14:53:34 +00:00
help = " specify a custom database template to create a new database " )
2008-07-22 14:24:36 +00:00
parser . add_option_group ( group )
group = optparse . OptionGroup ( parser , " Internationalisation options " ,
2008-09-10 08:46:40 +00:00
" Use these options to translate OpenERP to another language. "
2008-08-19 13:10:16 +00:00
" See i18n section of the user manual. Option ' -d ' is mandatory. "
" Option ' -l ' is mandatory in case of importation "
)
2010-10-20 14:42:48 +00:00
group . add_option ( ' --load-language ' , dest = " load_language " ,
help = " specifies the languages for the translations you want to be loaded " )
2009-01-15 10:12:10 +00:00
group . add_option ( ' -l ' , " --language " , dest = " language " ,
2008-12-24 00:57:34 +00:00
help = " specify the language of the translation file. Use it with --i18n-export or --i18n-import " )
2009-01-15 10:12:10 +00:00
group . add_option ( " --i18n-export " , dest = " translate_out " ,
2008-12-24 00:57:34 +00:00
help = " export all sentences to be translated to a CSV file, a PO file or a TGZ archive and exit " )
2009-01-15 10:12:10 +00:00
group . add_option ( " --i18n-import " , dest = " translate_in " ,
2008-12-24 00:57:34 +00:00
help = " import a CSV or a PO file with translations and exit. The ' -l ' option is required. " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --i18n-overwrite " , dest = " overwrite_existing_translations " , action = " store_true " , my_default = False ,
2011-02-09 10:08:45 +00:00
help = " overwrites existing translation terms on updating a module or importing a CSV or a PO file. " )
2009-01-15 10:12:10 +00:00
group . add_option ( " --modules " , dest = " translate_modules " ,
2008-12-24 00:57:34 +00:00
help = " specify modules to export. Use in combination with --i18n-export " )
2008-07-22 14:24:36 +00:00
parser . add_option_group ( group )
2010-05-12 12:56:50 +00:00
security = optparse . OptionGroup ( parser , ' Security-related options ' )
2011-05-31 12:53:22 +00:00
security . add_option ( ' --no-database-list ' , action = " store_false " , dest = ' list_db ' , my_default = True ,
2011-04-19 13:40:16 +00:00
help = " disable the ability to return the list of databases " )
2010-05-12 12:56:50 +00:00
parser . add_option_group ( security )
2010-05-13 07:07:00 +00:00
2011-02-07 17:03:17 +00:00
# Advanced options
group = optparse . OptionGroup ( parser , " Advanced options " )
2011-05-31 12:53:22 +00:00
group . add_option ( ' --debug ' , dest = ' debug_mode ' , action = ' store_true ' , my_default = False , help = ' enable debug mode ' )
group . add_option ( " --stop-after-init " , action = " store_true " , dest = " stop_after_init " , my_default = False ,
2011-04-19 13:40:16 +00:00
help = " stop the server after its initialization " )
2011-05-31 12:53:22 +00:00
group . add_option ( " -t " , " --timezone " , dest = " timezone " , my_default = False ,
2011-04-19 13:40:16 +00:00
help = " specify reference timezone for the server (e.g. Europe/Brussels " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --osv-memory-count-limit " , dest = " osv_memory_count_limit " , my_default = False ,
2011-02-08 14:09:24 +00:00
help = " Force a limit on the maximum number of records kept in the virtual "
" osv_memory tables. The default is False, which means no count-based limit. " ,
type = " int " )
2011-05-31 12:53:22 +00:00
group . add_option ( " --osv-memory-age-limit " , dest = " osv_memory_age_limit " , my_default = 1.0 ,
2011-02-08 14:09:24 +00:00
help = " Force a limit on the maximum age of records kept in the virtual "
" osv_memory tables. This is a decimal value expressed in hours, "
" and the default is 1 hour. " ,
type = " float " )
2012-12-09 17:04:47 +00:00
group . add_option ( " --max-cron-threads " , dest = " max_cron_threads " , my_default = 2 ,
2012-12-09 22:53:49 +00:00
help = " Maximum number of threads processing concurrently cron jobs (default 2). " ,
2011-08-08 13:54:53 +00:00
type = " int " )
2012-09-22 10:51:07 +00:00
group . add_option ( " --unaccent " , dest = " unaccent " , my_default = False , action = " store_true " ,
help = " Use the unaccent function provided by the database when available. " )
parser . add_option_group ( group )
group = optparse . OptionGroup ( parser , " Multiprocessing options " )
2012-01-20 15:00:50 +00:00
# TODO sensible default for the three following limits.
2012-09-22 10:51:07 +00:00
group . add_option ( " --workers " , dest = " workers " , my_default = 0 ,
help = " Specify the number of workers, 0 disable prefork mode. " ,
2012-01-20 15:00:50 +00:00
type = " int " )
2012-09-22 10:51:07 +00:00
group . add_option ( " --limit-memory-soft " , dest = " limit_memory_soft " , my_default = 640 * 1024 * 1024 ,
2012-12-29 13:22:16 +00:00
help = " Maximum allowed virtual memory per worker, when reached the worker be reset after the current request (default 671088640 aka 640MB). " ,
2012-01-20 15:00:50 +00:00
type = " int " )
2012-09-22 10:51:07 +00:00
group . add_option ( " --limit-memory-hard " , dest = " limit_memory_hard " , my_default = 768 * 1024 * 1024 ,
2012-12-29 13:22:16 +00:00
help = " Maximum allowed virtual memory per worker, when reached, any memory allocation will fail (default 805306368 aka 768MB). " ,
2012-09-22 10:51:07 +00:00
type = " int " )
group . add_option ( " --limit-time-cpu " , dest = " limit_time_cpu " , my_default = 60 ,
2012-12-09 22:53:49 +00:00
help = " Maximum allowed CPU time per request (default 60). " ,
2012-09-22 10:51:07 +00:00
type = " int " )
2012-12-09 22:53:49 +00:00
group . add_option ( " --limit-time-real " , dest = " limit_time_real " , my_default = 120 ,
help = " Maximum allowed Real time per request (default 120). " ,
2012-09-22 10:51:07 +00:00
type = " int " )
group . add_option ( " --limit-request " , dest = " limit_request " , my_default = 8192 ,
2012-12-09 22:53:49 +00:00
help = " Maximum number of request to be processed per worker (default 8192). " ,
2012-01-20 15:00:50 +00:00
type = " int " )
2011-02-07 17:03:17 +00:00
parser . add_option_group ( group )
2011-05-31 12:53:22 +00:00
# Copy all optparse options (i.e. MyOption) into self.options.
2011-04-19 13:40:16 +00:00
for group in parser . option_groups :
for option in group . option_list :
2012-04-23 12:24:07 +00:00
if option . dest not in self . options :
self . options [ option . dest ] = option . my_default
self . casts [ option . dest ] = option
2011-04-19 13:40:16 +00:00
2011-09-02 13:31:36 +00:00
self . parse_config ( None , False )
2011-02-08 09:29:23 +00:00
2011-09-02 13:31:36 +00:00
def parse_config ( self , args = None , complete = True ) :
""" Parse the configuration file (if any) and the command-line
arguments .
This method initializes openerp . tools . config and openerp . conf ( the
former should be removed in the furture ) with library - wide
configuration values .
This method must be called before proper usage of this library can be
made .
2011-02-08 09:29:23 +00:00
2011-09-02 13:31:36 +00:00
Typical usage of this method :
openerp . tools . config . parse_config ( sys . argv [ 1 : ] )
: param complete : this is a hack used in __init__ ( ) , leave it to True .
"""
2011-06-01 11:50:55 +00:00
if args is None :
args = [ ]
opt , args = self . parser . parse_args ( args )
2008-07-22 14:24:36 +00:00
2009-01-29 16:52:06 +00:00
def die ( cond , msg ) :
if cond :
2011-02-09 10:07:35 +00:00
self . parser . error ( msg )
# Ensures no illegitimate argument is silently discarded (avoids insidious "hyphen to dash" problem)
2011-04-18 13:10:23 +00:00
die ( args , " unrecognized parameters: ' %s ' " % " " . join ( args ) )
2009-01-29 16:52:06 +00:00
die ( bool ( opt . syslog ) and bool ( opt . logfile ) ,
" the syslog and logfile options are exclusive " )
die ( opt . translate_in and ( not opt . language or not opt . db_name ) ,
" the i18n-import option cannot be used without the language (-l) and the database (-d) options " )
2011-02-09 10:08:45 +00:00
die ( opt . overwrite_existing_translations and not ( opt . translate_in or opt . update ) ,
" the i18n-overwrite option cannot be used without the i18n-import option or without the update option " )
2010-11-19 16:13:39 +00:00
2009-01-29 16:52:06 +00:00
die ( opt . translate_out and ( not opt . db_name ) ,
" the i18n-export option cannot be used without the database (-d) option " )
2008-07-22 14:24:36 +00:00
2010-02-02 07:44:15 +00:00
# Check if the config file exists (-c used, but not -s)
2009-12-07 10:56:45 +00:00
die ( not opt . save and opt . config and not os . path . exists ( opt . config ) ,
2010-02-02 07:44:15 +00:00
" The config file ' %s ' selected with -c/--config doesn ' t exist, " \
2012-12-14 12:38:03 +00:00
" use -s/--save if you want to generate it " % opt . config )
2009-12-07 10:56:45 +00:00
2008-07-22 14:24:36 +00:00
# place/search the config file on Win32 near the server installation
# (../etc from the server)
# if the server is run by an unprivileged user, he has to specify location of a config file where he has the rights to write,
# else he won't be able to save the configurations, or even to start the server...
if os . name == ' nt ' :
2008-09-10 08:46:40 +00:00
rcfilepath = os . path . join ( os . path . abspath ( os . path . dirname ( sys . argv [ 0 ] ) ) , ' openerp-server.conf ' )
2008-07-22 14:24:36 +00:00
else :
2008-09-10 08:46:40 +00:00
rcfilepath = os . path . expanduser ( ' ~/.openerp_serverrc ' )
2008-07-22 14:24:36 +00:00
2009-11-27 11:07:12 +00:00
self . rcfile = os . path . abspath (
2010-04-19 11:00:51 +00:00
self . config_file or opt . config \
or os . environ . get ( ' OPENERP_SERVER ' ) or rcfilepath )
2008-07-22 14:24:36 +00:00
self . load ( )
2009-01-15 10:12:10 +00:00
2008-07-22 14:24:36 +00:00
# Verify that we want to log or not, if not the output will go to stdout
if self . options [ ' logfile ' ] in ( ' None ' , ' False ' ) :
self . options [ ' logfile ' ] = False
# the same for the pidfile
if self . options [ ' pidfile ' ] in ( ' None ' , ' False ' ) :
self . options [ ' pidfile ' ] = False
2008-12-19 00:06:50 +00:00
2012-02-01 00:10:19 +00:00
# if defined dont take the configfile value even if the defined value is None
2010-05-31 12:26:50 +00:00
keys = [ ' xmlrpc_interface ' , ' xmlrpc_port ' , ' db_name ' , ' db_user ' , ' db_password ' , ' db_host ' ,
2012-09-22 10:51:07 +00:00
' db_port ' , ' db_template ' , ' logfile ' , ' pidfile ' , ' smtp_port ' ,
2010-09-08 13:08:10 +00:00
' email_from ' , ' smtp_server ' , ' smtp_user ' , ' smtp_password ' ,
2010-05-31 12:26:50 +00:00
' netrpc_interface ' , ' netrpc_port ' , ' db_maxconn ' , ' import_partial ' , ' addons_path ' ,
2010-06-07 12:56:17 +00:00
' netrpc ' , ' xmlrpc ' , ' syslog ' , ' without_demo ' , ' timezone ' ,
' xmlrpcs_interface ' , ' xmlrpcs_port ' , ' xmlrpcs ' ,
2011-09-25 01:20:39 +00:00
' static_http_enable ' , ' static_http_document_root ' , ' static_http_url_prefix ' ,
2012-02-06 23:02:15 +00:00
' secure_cert_file ' , ' secure_pkey_file ' , ' dbfilter ' , ' log_handler ' , ' log_level '
2010-06-07 12:56:17 +00:00
]
2008-12-19 00:06:50 +00:00
for arg in keys :
2012-04-23 12:24:07 +00:00
# Copy the command-line argument (except the special case for log_handler, due to
# action=append requiring a real default, so we cannot use the my_default workaround)
if getattr ( opt , arg ) and getattr ( opt , arg ) != DEFAULT_LOG_HANDLER :
2008-07-22 14:24:36 +00:00
self . options [ arg ] = getattr ( opt , arg )
2011-06-01 07:44:00 +00:00
# ... or keep, but cast, the config file value.
elif isinstance ( self . options [ arg ] , basestring ) and self . casts [ arg ] . type in optparse . Option . TYPE_CHECKER :
self . options [ arg ] = optparse . Option . TYPE_CHECKER [ self . casts [ arg ] . type ] ( self . casts [ arg ] , arg , self . options [ arg ] )
2008-07-22 14:24:36 +00:00
2012-04-23 12:24:07 +00:00
if isinstance ( self . options [ ' log_handler ' ] , basestring ) :
self . options [ ' log_handler ' ] = self . options [ ' log_handler ' ] . split ( ' , ' )
2012-02-01 00:10:19 +00:00
# if defined but None take the configfile value
2010-09-12 12:07:43 +00:00
keys = [
2010-12-29 18:58:33 +00:00
' language ' , ' translate_out ' , ' translate_in ' , ' overwrite_existing_translations ' ,
' debug_mode ' , ' smtp_ssl ' , ' load_language ' ,
2010-09-12 12:07:43 +00:00
' stop_after_init ' , ' logrotate ' , ' without_demo ' , ' netrpc ' , ' xmlrpc ' , ' syslog ' ,
2012-09-24 10:56:22 +00:00
' list_db ' , ' xmlrpcs ' , ' proxy_mode ' ,
2012-03-01 13:46:08 +00:00
' test_file ' , ' test_enable ' , ' test_commit ' , ' test_report_directory ' ,
2012-09-22 10:51:07 +00:00
' osv_memory_count_limit ' , ' osv_memory_age_limit ' , ' max_cron_threads ' , ' unaccent ' ,
' workers ' , ' limit_memory_hard ' , ' limit_memory_soft ' , ' limit_time_cpu ' , ' limit_time_real ' , ' limit_request '
2010-09-12 12:07:43 +00:00
]
2008-12-22 23:35:28 +00:00
for arg in keys :
2011-06-01 07:44:00 +00:00
# Copy the command-line argument...
2009-03-15 16:19:13 +00:00
if getattr ( opt , arg ) is not None :
self . options [ arg ] = getattr ( opt , arg )
2011-06-01 07:44:00 +00:00
# ... or keep, but cast, the config file value.
elif isinstance ( self . options [ arg ] , basestring ) and self . casts [ arg ] . type in optparse . Option . TYPE_CHECKER :
self . options [ arg ] = optparse . Option . TYPE_CHECKER [ self . casts [ arg ] . type ] ( self . casts [ arg ] , arg , self . options [ arg ] )
2008-12-22 23:35:28 +00:00
2011-02-08 17:09:27 +00:00
self . options [ ' root_path ' ] = os . path . abspath ( os . path . expanduser ( os . path . expandvars ( os . path . dirname ( openerp . __file__ ) ) ) )
2008-07-22 14:24:36 +00:00
if not self . options [ ' addons_path ' ] or self . options [ ' addons_path ' ] == ' None ' :
self . options [ ' addons_path ' ] = os . path . join ( self . options [ ' root_path ' ] , ' addons ' )
2011-02-08 17:09:27 +00:00
else :
2011-02-14 10:29:14 +00:00
self . options [ ' addons_path ' ] = " , " . join (
os . path . abspath ( os . path . expanduser ( os . path . expandvars ( x ) ) )
for x in self . options [ ' addons_path ' ] . split ( ' , ' ) )
2008-07-22 14:24:36 +00:00
2008-12-24 00:57:34 +00:00
self . options [ ' init ' ] = opt . init and dict . fromkeys ( opt . init . split ( ' , ' ) , 1 ) or { }
2008-07-22 14:24:36 +00:00
self . options [ " demo " ] = not opt . without_demo and self . options [ ' init ' ] or { }
2008-12-24 00:57:34 +00:00
self . options [ ' update ' ] = opt . update and dict . fromkeys ( opt . update . split ( ' , ' ) , 1 ) or { }
2008-07-22 14:24:36 +00:00
self . options [ ' translate_modules ' ] = opt . translate_modules and map ( lambda m : m . strip ( ) , opt . translate_modules . split ( ' , ' ) ) or [ ' all ' ]
self . options [ ' translate_modules ' ] . sort ( )
2009-01-15 10:12:10 +00:00
2011-05-09 12:19:10 +00:00
# TODO checking the type of the parameters should be done for every
# parameters, not just the timezone.
# The call to get_server_timezone() sets the timezone; this should
# probably done here.
2010-01-05 15:23:12 +00:00
if self . options [ ' timezone ' ] :
2011-05-09 12:19:10 +00:00
# Prevent the timezone to be True. (The config file parsing changes
# the string 'True' to the boolean value True. It would be probably
# be better to remove that conversion.)
die ( not isinstance ( self . options [ ' timezone ' ] , basestring ) ,
" Invalid timezone value in configuration or environment: %r . \n "
" Please fix this in your configuration. " % ( self . options [ ' timezone ' ] ) )
2010-03-11 08:49:41 +00:00
# If an explicit TZ was provided in the config, make sure it is known
2010-01-05 15:23:12 +00:00
try :
import pytz
2010-11-17 17:17:54 +00:00
pytz . timezone ( self . options [ ' timezone ' ] )
2010-01-05 15:23:12 +00:00
except pytz . UnknownTimeZoneError :
die ( True , " The specified timezone ( %s ) is invalid " % self . options [ ' timezone ' ] )
except :
# If pytz is missing, don't check the provided TZ, it will be ignored anyway.
pass
2008-07-22 14:24:36 +00:00
if opt . pg_path :
self . options [ ' pg_path ' ] = opt . pg_path
if self . options . get ( ' language ' , False ) :
2009-04-07 21:22:46 +00:00
if len ( self . options [ ' language ' ] ) > 5 :
2009-01-29 14:21:45 +00:00
raise Exception ( ' ERROR: The Lang name must take max 5 chars, Eg: -lfr_BE ' )
2009-01-29 16:52:06 +00:00
if not self . options [ ' db_user ' ] :
try :
import getpass
self . options [ ' db_user ' ] = getpass . getuser ( )
except :
self . options [ ' db_user ' ] = None
die ( not self . options [ ' db_user ' ] , ' ERROR: No user specified for the connection to the database ' )
if self . options [ ' db_password ' ] :
if sys . platform == ' win32 ' and not self . options [ ' db_host ' ] :
self . options [ ' db_host ' ] = ' localhost '
2009-02-06 18:06:14 +00:00
#if self.options['db_host']:
# self._generate_pgpassfile()
2009-01-29 16:52:06 +00:00
2008-07-22 14:24:36 +00:00
if opt . save :
self . save ( )
2011-09-02 13:31:36 +00:00
openerp . conf . addons_paths = self . options [ ' addons_path ' ] . split ( ' , ' )
2011-10-01 13:16:19 +00:00
if opt . server_wide_modules :
openerp . conf . server_wide_modules = map ( lambda m : m . strip ( ) , opt . server_wide_modules . split ( ' , ' ) )
else :
2012-12-20 10:15:11 +00:00
openerp . conf . server_wide_modules = [ ' web ' , ' web_kanban ' ]
2011-09-02 13:31:36 +00:00
if complete :
openerp . modules . module . initialize_sys_path ( )
2009-01-29 16:52:06 +00:00
def _generate_pgpassfile ( self ) :
"""
Generate the pgpass file with the parameters from the command line ( db_host , db_user ,
db_password )
Used because pg_dump and pg_restore can not accept the password on the command line .
"""
is_win32 = sys . platform == ' win32 '
if is_win32 :
filename = os . path . join ( os . environ [ ' APPDATA ' ] , ' pgpass.conf ' )
else :
filename = os . path . join ( os . environ [ ' HOME ' ] , ' .pgpass ' )
text_to_add = " %(db_host)s :*:*: %(db_user)s : %(db_password)s " % self . options
if os . path . exists ( filename ) :
content = [ x . strip ( ) for x in file ( filename , ' r ' ) . readlines ( ) ]
if text_to_add in content :
return
fp = file ( filename , ' a+ ' )
fp . write ( text_to_add + " \n " )
fp . close ( )
if is_win32 :
2010-11-17 17:17:54 +00:00
try :
import _winreg
except ImportError :
_winreg = None
2009-01-29 16:52:06 +00:00
x = _winreg . ConnectRegistry ( None , _winreg . HKEY_LOCAL_MACHINE )
y = _winreg . OpenKey ( x , r " SYSTEM \ CurrentControlSet \ Control \ Session Manager \ Environment " , 0 , _winreg . KEY_ALL_ACCESS )
_winreg . SetValueEx ( y , " PGPASSFILE " , 0 , _winreg . REG_EXPAND_SZ , filename )
_winreg . CloseKey ( y )
_winreg . CloseKey ( x )
else :
import stat
os . chmod ( filename , stat . S_IRUSR + stat . S_IWUSR )
2011-04-30 15:25:05 +00:00
def _is_addons_path ( self , path ) :
for f in os . listdir ( path ) :
modpath = os . path . join ( path , f )
if os . path . isdir ( modpath ) :
def hasfile ( filename ) :
return os . path . isfile ( os . path . join ( modpath , filename ) )
if hasfile ( ' __init__.py ' ) and ( hasfile ( ' __openerp__.py ' ) or hasfile ( ' __terp__.py ' ) ) :
return True
return False
2010-03-11 08:49:41 +00:00
2011-04-30 15:25:05 +00:00
def _check_addons_path ( self , option , opt , value , parser ) :
ad_paths = [ ]
for path in value . split ( ' , ' ) :
path = path . strip ( )
res = os . path . abspath ( os . path . expanduser ( path ) )
if not os . path . isdir ( res ) :
raise optparse . OptionValueError ( " option %s : no such directory: %r " % ( opt , path ) )
if not self . _is_addons_path ( res ) :
raise optparse . OptionValueError ( " option %s : The addons-path %r does not seem to a be a valid Addons Directory! " % ( opt , path ) )
ad_paths . append ( res )
setattr ( parser . values , option . dest , " , " . join ( ad_paths ) )
2008-10-21 07:08:13 +00:00
2008-07-22 14:24:36 +00:00
def load ( self ) :
p = ConfigParser . ConfigParser ( )
try :
p . read ( [ self . rcfile ] )
for ( name , value ) in p . items ( ' options ' ) :
if value == ' True ' or value == ' true ' :
value = True
if value == ' False ' or value == ' false ' :
value = False
self . options [ name ] = value
2009-11-24 14:44:05 +00:00
#parse the other sections, as well
for sec in p . sections ( ) :
if sec == ' options ' :
continue
if not self . misc . has_key ( sec ) :
self . misc [ sec ] = { }
for ( name , value ) in p . items ( sec ) :
if value == ' True ' or value == ' true ' :
value = True
if value == ' False ' or value == ' false ' :
value = False
self . misc [ sec ] [ name ] = value
2008-07-22 14:24:36 +00:00
except IOError :
pass
except ConfigParser . NoSectionError :
pass
def save ( self ) :
p = ConfigParser . ConfigParser ( )
2009-03-11 14:26:50 +00:00
loglevelnames = dict ( zip ( self . _LOGLEVELS . values ( ) , self . _LOGLEVELS . keys ( ) ) )
2008-07-22 14:24:36 +00:00
p . add_section ( ' options ' )
2010-11-17 17:17:54 +00:00
for opt in sorted ( self . options . keys ( ) ) :
2010-11-19 16:13:39 +00:00
if opt in ( ' version ' , ' language ' , ' translate_out ' , ' translate_in ' , ' overwrite_existing_translations ' , ' init ' , ' update ' ) :
2009-03-11 14:26:50 +00:00
continue
2010-11-18 13:42:56 +00:00
if opt in self . blacklist_for_save :
continue
2012-03-02 11:28:34 +00:00
if opt in ( ' log_level ' , ) :
2009-03-11 14:26:50 +00:00
p . set ( ' options ' , opt , loglevelnames . get ( self . options [ opt ] , self . options [ opt ] ) )
else :
p . set ( ' options ' , opt , self . options [ opt ] )
2010-03-11 08:49:41 +00:00
2010-11-17 17:17:54 +00:00
for sec in sorted ( self . misc . keys ( ) ) :
2011-11-28 11:14:30 +00:00
p . add_section ( sec )
2010-11-17 17:17:54 +00:00
for opt in sorted ( self . misc [ sec ] . keys ( ) ) :
2009-11-24 14:44:05 +00:00
p . set ( sec , opt , self . misc [ sec ] [ opt ] )
2008-07-22 14:24:36 +00:00
# try to create the directories and write the file
try :
2010-11-09 22:09:07 +00:00
rc_exists = os . path . exists ( self . rcfile )
if not rc_exists and not os . path . exists ( os . path . dirname ( self . rcfile ) ) :
2008-07-22 14:24:36 +00:00
os . makedirs ( os . path . dirname ( self . rcfile ) )
try :
p . write ( file ( self . rcfile , ' w ' ) )
2010-11-09 22:09:07 +00:00
if not rc_exists :
os . chmod ( self . rcfile , 0600 )
2008-07-22 14:24:36 +00:00
except IOError :
sys . stderr . write ( " ERROR: couldn ' t write the config file \n " )
except OSError :
# what to do if impossible?
sys . stderr . write ( " ERROR: couldn ' t create the config directory \n " )
def get ( self , key , default = None ) :
return self . options . get ( key , default )
2009-08-14 09:21:06 +00:00
def get_misc ( self , sect , key , default = None ) :
return self . misc . get ( sect , { } ) . get ( key , default )
2008-07-22 14:24:36 +00:00
def __setitem__ ( self , key , value ) :
self . options [ key ] = value
2012-05-30 06:42:37 +00:00
if key in self . options and isinstance ( self . options [ key ] , basestring ) and \
key in self . casts and self . casts [ key ] . type in optparse . Option . TYPE_CHECKER :
2012-05-23 12:53:54 +00:00
self . options [ key ] = optparse . Option . TYPE_CHECKER [ self . casts [ key ] . type ] ( self . casts [ key ] , key , self . options [ key ] )
2008-07-22 14:24:36 +00:00
def __getitem__ ( self , key ) :
return self . options [ key ]
2006-12-07 13:41:40 +00:00
config = configmanager ( )
2011-11-22 08:58:48 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: