Merge lp:~donkirkby/openobject-server/config-defaults into lp:openobject-server/5.0

Proposed by Don Kirkby
Status: Rejected
Rejected by: Olivier Dony (Odoo)
Proposed branch: lp:~donkirkby/openobject-server/config-defaults
Merge into: lp:openobject-server/5.0
Diff against target: 289 lines (+96/-64)
1 file modified
bin/tools/config.py (+96/-64)
To merge this branch: bzr merge lp:~donkirkby/openobject-server/config-defaults
Reviewer Review Type Date Requested Status
Olivier Dony (Odoo) Needs Resubmitting
Mantavya Gajjar (Open ERP) Pending
Xavier (Open ERP) Pending
Stephane Wirtel (OpenERP) Pending
Jay Vora (Serpent Consulting Services) Pending
Review via email: mp+19066@code.launchpad.net

Commit message

Make all configuration options available on command line and in configuration file as discussed in bug lp:392114

To post a comment you must log in.
Revision history for this message
Don Kirkby (donkirkby) wrote :

This is the work that I proposed in the bug discussion. I have tested it with all the options described in the code, and compared the in-memory values to those generated by

the old code. I also compared the configuration files saved by my new code and the old code.

In addition to adding support for all options in the configuration file and the command line, the following behaviours have changed:

- The reference to the soap option had been commented out from openerp-server.py and it wasn't allowed on the command line, so I removed it from the defaults.
- translate_modules now reads and writes to the configuration file in the same format that it uses on the command line. If it sees the old format, it continues to ignore it

during load, just like the old code did.
- netport and port used to be strings when loaded from a configuration file, and integers when loaded from the command line. They are now always integers.
- demo is no longer saved to the configuration file. (It was ignored during load, so this should be irrelevant.)

I did not get around to adding new names for the command line options that don't match their names in the configuration file.

I tried to break up the changes into smaller revisions to make the review easier. If there's something I can do to make my next proposal easier to review, please let me know.

1954. By Don Kirkby

merge 5.0.9 from 5.0 branch

Revision history for this message
Don Kirkby (donkirkby) wrote :

When I was merging release 5.0.9, I noticed that three people have touched the tools/config.py file recently, so I requested reviews from them for my fix to bug lp:392114 about configurations options not always working in both the config file and the command line.

1955. By Don Kirkby

[MERGE] release 5.0.15 from branch 5.0

Revision history for this message
Olivier Dony (Odoo) (odo-openerp) wrote :

Hello,

This is interesting, but please resubmit your changes for trunk, as we cannot merge any improvement on 5.0.
Also I'm not sure it makes sense to expose _all_ options as command-line args, because some could be harmful, like the super-admin password or the root_path...

Thanks!

review: Needs Resubmitting

Unmerged revisions

1955. By Don Kirkby

[MERGE] release 5.0.15 from branch 5.0

1954. By Don Kirkby

merge 5.0.9 from 5.0 branch

1953. By Don <don@don-desktop-openerp>

Remove debug code that I added in revision 1949.

1952. By Don <don@don-desktop-openerp>

Remove default values of None. Add some options to the command line that were only available in config files. Convert some parameters to strings for backward compatibility. Save translate_modules as comma separated list without brackets or quotes.

1951. By Don <don@don-desktop-openerp>

copy all options from OptionParser to config.options

1950. By Don <don@don-desktop-openerp>

move all default values from the option definitions to a dictionary called defaults.

1949. By Don <don@don-desktop-openerp>

some debug code to dump the contents of tools.config.options (I'll remove it before making a merge proposal)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/tools/config.py'
2--- bin/tools/config.py 2010-09-08 12:55:30 +0000
3+++ bin/tools/config.py 2010-11-05 21:37:16 +0000
4@@ -40,7 +40,7 @@
5 class configmanager(object):
6 def __init__(self, fname=None):
7 hasSSL = check_ssl()
8- self.options = {
9+ defaults = {
10 'email_from':False,
11 'interface': '', # this will bind the server to all interfaces
12 'port': 8069,
13@@ -55,19 +55,11 @@
14 'reportgz': False,
15 'netrpc': True,
16 'xmlrpc': True,
17- 'soap': False,
18- 'translate_in': None,
19- 'translate_out': None,
20- 'language': None,
21- 'pg_path': None,
22+# 'soap': False, #reference is commented out in bin/openerp-server.py
23 'admin_passwd': 'admin',
24 'csv_internal_sep': ',',
25- 'addons_path': None,
26- 'root_path': None,
27 'debug_mode': False,
28 'import_partial': "",
29- 'pidfile': None,
30- 'logfile': None,
31 'smtp_server': 'localhost',
32 'smtp_user': False,
33 'smtp_port':25,
34@@ -76,14 +68,17 @@
35 'price_accuracy': 2,
36 'secure' : False,
37 'syslog' : False,
38- 'log_level': logging.INFO,
39- 'assert_exit_level': logging.WARNING, # level above which a failed assert will be raise
40+ 'log_level': 'info',
41+ 'assert_exit_level': 'warn', # level above which a failed assert will be raise
42 'cache_timeout': 100000,
43 'login_message': False,
44 'list_db': True,
45+ 'server_actions_allow_code': False,
46+ 'translate_modules': 'all',
47+ 'without_demo': False
48 }
49 if hasSSL:
50- self.options.update({
51+ defaults.update({
52 'secure_cert_file': 'server.cert',
53 'secure_pkey_file': 'server.pkey',
54 'smtp_ssl': False,
55@@ -97,7 +92,7 @@
56 parser = optparse.OptionParser(version=version)
57
58 parser.add_option("-c", "--config", dest="config", help="specify alternate config file")
59- parser.add_option("-s", "--save", action="store_true", dest="save", default=False,
60+ parser.add_option("-s", "--save", action="store_true", dest="save",
61 help="save configuration to ~/.openerp_serverrc")
62 parser.add_option("--pidfile", dest="pidfile", help="file where the server pid will be stored")
63
64@@ -109,16 +104,16 @@
65 parser.add_option("--no-xmlrpc", dest="xmlrpc", action="store_false", help="disable xmlrpc")
66 parser.add_option("-i", "--init", dest="init", help="init a module (use \"all\" for all modules)")
67 parser.add_option("--without-demo", dest="without_demo",
68- help="load demo data for a module (use \"all\" for all modules)", default=False)
69+ help="load demo data for a module (use \"all\" for all modules)")
70 parser.add_option("-u", "--update", dest="update",
71 help="update a module (use \"all\" for all modules)")
72 parser.add_option("--cache-timeout", dest="cache_timeout",
73 help="set the timeout for the cache system", type="int")
74
75 # stops the server from launching after initialization
76- parser.add_option("--stop-after-init", action="store_true", dest="stop_after_init", default=False,
77+ parser.add_option("--stop-after-init", action="store_true", dest="stop_after_init",
78 help="stop the server after it initializes")
79- parser.add_option('--debug', dest='debug_mode', action='store_true', default=False, help='enable debug mode')
80+ parser.add_option('--debug', dest='debug_mode', action='store_true', help='enable debug mode')
81 parser.add_option("--assert-exit-level", dest='assert_exit_level', type="choice", choices=self._LOGLEVELS.keys(),
82 help="specify the level at which a failed assertion will stop the server. Accepted values: %s" % (self._LOGLEVELS.keys(),))
83 parser.add_option('--price_accuracy', dest='price_accuracy', type='int', help='specify the price accuracy')
84@@ -133,11 +128,24 @@
85 help="specify the private key file for the SSL connection")
86 parser.add_option_group(group)
87
88+ parser.add_option("--admin-passwd",
89+ help="set the super administrator password " +
90+ "(Warning: it is much better to set this in a " +
91+ "configuration file because command line arguments " +
92+ "are visible to other users.)")
93+ parser.add_option("--csv-internal-sep",
94+ help="set the separator character to use in import files")
95+ parser.add_option("--login-message",
96+ help="set the message displayed to users at log in")
97+ parser.add_option("--reportgz",
98+ action="store_true",
99+ help="return reports in a compressed format")
100+
101 # Logging Group
102 group = optparse.OptionGroup(parser, "Logging Configuration")
103 group.add_option("--logfile", dest="logfile", help="file where the server log will be stored")
104 group.add_option("--syslog", action="store_true", dest="syslog",
105- default=False, help="Send the log to the syslog server")
106+ help="Send the log to the syslog server")
107 group.add_option('--log-level', dest='log_level', type='choice', choices=self._LOGLEVELS.keys(),
108 help='specify the level of the logging. Accepted values: ' + str(self._LOGLEVELS.keys()))
109 parser.add_option_group(group)
110@@ -163,7 +171,7 @@
111 group.add_option("--db_maxconn", dest="db_maxconn", type='int',
112 help="specify the the maximum number of physical connections to posgresql")
113 group.add_option("-P", "--import-partial", dest="import_partial",
114- 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.", default=False)
115+ 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.")
116 parser.add_option_group(group)
117
118 group = optparse.OptionGroup(parser, "Internationalisation options",
119@@ -183,12 +191,16 @@
120 group.add_option("--addons-path", dest="addons_path",
121 help="specify an alternative addons path.",
122 action="callback", callback=self._check_addons_path, nargs=1, type="string")
123+ group.add_option("--root-path",
124+ help="path to the core server code (defaults to the location of this script)",
125+ action="callback", callback=self._check_addons_path, nargs=1, type="string")
126 parser.add_option_group(group)
127+ parser.set_defaults(**defaults)
128
129 security = optparse.OptionGroup(parser, 'Security-related options')
130 security.add_option('--no-database-list', action="store_false", dest='list_db', help="disable the ability to return the list of databases")
131 security.add_option('--enable-code-actions', action='store_true',
132- dest='server_actions_allow_code', default=False,
133+ dest='server_actions_allow_code',
134 help='Enables server actions of state "code". Warning, this is a security risk.')
135 parser.add_option_group(security)
136
137@@ -199,15 +211,6 @@
138 print msg
139 sys.exit(1)
140
141- die(bool(opt.syslog) and bool(opt.logfile),
142- "the syslog and logfile options are exclusive")
143-
144- die(opt.translate_in and (not opt.language or not opt.db_name),
145- "the i18n-import option cannot be used without the language (-l) and the database (-d) options")
146-
147- die(opt.translate_out and (not opt.db_name),
148- "the i18n-export option cannot be used without the database (-d) option")
149-
150 # place/search the config file on Win32 near the server installation
151 # (../etc from the server)
152 # 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,
153@@ -219,8 +222,34 @@
154
155 self.rcfile = os.path.abspath(
156 fname or opt.config or os.environ.get('OPENERP_SERVER') or rcfilepath)
157- self.load()
158-
159+ if self.__load_defaults(defaults):
160+ parser.set_defaults(**defaults)
161+ (opt, args) = parser.parse_args()
162+
163+ die(bool(opt.syslog) and bool(opt.logfile),
164+ "the syslog and logfile options are exclusive")
165+
166+ die(opt.translate_in and (not opt.language or not opt.db_name),
167+ "the i18n-import option cannot be used without the language (-l) and the database (-d) options")
168+
169+ die(opt.translate_out and (not opt.db_name),
170+ "the i18n-export option cannot be used without the database (-d) option")
171+
172+ self.options = {}
173+ for (arg, value) in opt.__dict__.iteritems():
174+ if arg in ('config', 'save'):
175+ continue #options are only used during parse process
176+ elif arg in ('db_maxconn', 'db_port', 'price_accuracy'):
177+ #convert some numeric parameters back to strings just
178+ #for backward compatibility
179+ #netport and port used to be strings from a config file
180+ #and ints from the command line, so now we leave them as ints
181+ value = str(value)
182+ if value == 'False':
183+ value = False
184+ elif arg == 'smtp_ssl' and value is None:
185+ continue #backward compatibility
186+ self.options[arg] = value
187
188 # Verify that we want to log or not, if not the output will go to stdout
189 if self.options['logfile'] in ('None', 'False'):
190@@ -229,29 +258,6 @@
191 if self.options['pidfile'] in ('None', 'False'):
192 self.options['pidfile'] = False
193
194- keys = ['interface', 'port', 'db_name', 'db_user', 'db_password', 'db_host',
195- 'db_port', 'logfile', 'pidfile', 'smtp_port', 'cache_timeout',
196- 'email_from', 'smtp_server', 'smtp_user', 'smtp_password', 'price_accuracy',
197- 'netinterface', 'netport', 'db_maxconn', 'import_partial', 'addons_path']
198-
199- if hasSSL:
200- keys.extend(['secure_cert_file', 'secure_pkey_file'])
201-
202- for arg in keys:
203- if getattr(opt, arg):
204- self.options[arg] = getattr(opt, arg)
205-
206- keys = ['language', 'translate_out', 'translate_in', 'debug_mode',
207- 'stop_after_init', 'without_demo', 'netrpc', 'xmlrpc', 'syslog',
208- 'list_db', 'server_actions_allow_code']
209-
210- if hasSSL and not self.options['secure']:
211- keys.extend(['secure', 'smtp_ssl'])
212-
213- for arg in keys:
214- if getattr(opt, arg) is not None:
215- self.options[arg] = getattr(opt, arg)
216-
217 if opt.assert_exit_level:
218 self.options['assert_exit_level'] = self._LOGLEVELS[opt.assert_exit_level]
219 else:
220@@ -352,33 +358,59 @@
221
222
223 setattr(parser.values, option.dest, res)
224-
225+
226 def load(self):
227+ """ Load values from a configuration file specified by self.rcfile
228+ into the dictionary self.options.
229+
230+ Not used in the main code, just here for backward compatibility.
231+ """
232+ self.__load_defaults(self.options)
233+
234+ def __load_defaults(self, defaults):
235+ """ Load values from a configuration specified by self.rcfile.
236+
237+ Returns true if the values were successfully loaded. Any reading
238+ errors are swallowed and the method returns false.
239+ """
240 p = ConfigParser.ConfigParser()
241+ isLoaded = False
242 try:
243 p.read([self.rcfile])
244 for (name,value) in p.items('options'):
245- if value=='True' or value=='true':
246+ if name == 'demo':
247+ continue
248+ elif name in ('init', 'update', 'translate_modules') and value.startswith(('[', '{')):
249+ continue #old config file with invalid format so ignore
250+ elif value=='True' or value=='true':
251 value = True
252- if value=='False' or value=='false':
253+ elif value=='False' or value=='false':
254 value = False
255- self.options[name] = value
256+ defaults[name] = value
257+ isLoaded = True
258 except IOError:
259 pass
260 except ConfigParser.NoSectionError:
261 pass
262+ return isLoaded
263
264 def save(self):
265 p = ConfigParser.ConfigParser()
266 loglevelnames = dict(zip(self._LOGLEVELS.values(), self._LOGLEVELS.keys()))
267 p.add_section('options')
268- for opt in self.options.keys():
269- if opt in ('version', 'language', 'translate_out', 'translate_in', 'init', 'update'):
270+ for (opt, value) in self.options.iteritems():
271+ if opt in ('version', 'language', 'translate_out', 'translate_in', 'init', 'update', 'demo'):
272 continue
273- if opt in ('log_level', 'assert_exit_level'):
274- p.set('options', opt, loglevelnames.get(self.options[opt], self.options[opt]))
275- else:
276- p.set('options', opt, self.options[opt])
277+ if opt == 'translate_modules':
278+ if not isinstance(value, list) or len(value) == 0:
279+ continue
280+ value.sort()
281+ value = ','.join(value)
282+ elif opt in ('log_level', 'assert_exit_level'):
283+ default = value
284+ value = loglevelnames.get(value, default)
285+
286+ p.set('options', opt, value)
287
288 # try to create the directories and write the file
289 try: