Merge lp:~jbaudoux/anybox.recipe.openerp/1.8.5_relative_paths_jailroot into lp:anybox.recipe.openerp

Proposed by Jacques-Etienne Baudoux
Status: Needs review
Proposed branch: lp:~jbaudoux/anybox.recipe.openerp/1.8.5_relative_paths_jailroot
Merge into: lp:anybox.recipe.openerp
Diff against target: 311 lines (+141/-21) (has conflicts)
3 files modified
anybox/recipe/openerp/base.py (+54/-1)
anybox/recipe/openerp/server.py (+47/-20)
doc/configuration.rst (+40/-0)
Text conflict in anybox/recipe/openerp/server.py
Text conflict in doc/configuration.rst
To merge this branch: bzr merge lp:~jbaudoux/anybox.recipe.openerp/1.8.5_relative_paths_jailroot
Reviewer Review Type Date Requested Status
Anybox Pending
Review via email: mp+237238@code.launchpad.net

Description of the change

Improvement to be compliant with buildout option "relative_paths = true"
It allows the creation of a buildout that can be moved to a jail root and run OpenERP in that jail root without any modifications to any of the files in the buildout.

This replace my first MP here:
https://code.launchpad.net/~jbaudoux/anybox.recipe.openerp/20130908_relative_paths/+merge/184473

and includes improvements from this MP
https://code.launchpad.net/~therp-nl/anybox.recipe.openerp/jbaudoux-relative_paths_explicit_jailroot_support/+merge/205099

as well as some rework of that latest MP to let it work on my current setup.

See the 2 previous MP for review history.

To post a comment you must log in.
Revision history for this message
Georges Racinet (gracinet) wrote :

Hi, I'm at last in shape (well me and the recipe) to look at this request seriously. Sorry for being so slow.
First, could you please clarify some generalities for me ?

- I'm a bit confused by the jailroot terminology. Do you have something specific and hard in mind (such as a chroot or lxc container), or is this just about promising not to leave some directory, and therefore be admissible for a chroot ?

- I'm not sure to understand the use-case for the she-bang change. I'm used to control the she-bang by bootstrapping with the intended python. What's the difference here ? I got the "no modification of files" and find it a great perspective, but how does it play with the custom shebang (maybe a concrete example making the difference between building and running would help).

For the record, I've been playing with debian repackaging of buildouts lately, and I wonder if it would not precisely been served well by such features. Could it allow, e.g, to build on a CI worker in a certain directory and then run transparently in another ?

This could also be exactly what SlapOS (a distributed cloud system based on zc.buildout) would need

Revision history for this message
Jacques-Etienne Baudoux (jbaudoux) wrote :

Hello Georges,

In my case, odoo is build under a jailroot_dir directory:
/buildout.cfg
/jailroot_dir/odoo
/jailroot_dir/bin
/jailroot_dir/etc
/jailroot_dir/var
/jailroot_dir/dev

odoo is run inside jailroot_dir chroot. So paths in generated bin must be relative as well as path for etc/openerp.cfg

Regarding the python-scripts-executable for specify an alternative Python executable to be used in the she-bang of generated scripts, it is an addition of Terp that I'm not using. I only use the jailroot-dir option that implies relative-paths. This is enough for building the chroot environment.

435. By Jacques-Etienne Baudoux

[MOD] put base addons at the end of the addons path

Unmerged revisions

435. By Jacques-Etienne Baudoux

[MOD] put base addons at the end of the addons path

434. By Jacques-Etienne Baudoux

[RFR] Rewrite paths for running OpenERP in a jailroot: make jailroot-dir explicit in buildout.cfg, do not guess based on eggs directory; include addons path rewrite; rewrite calls to runtime.session

433. By Jacques-Etienne Baudoux

[MRG] lp:~anybox/anybox.recipe.openerp/1.8, revno 570

432. By Jacques-Etienne Baudoux

[FIX] Error in start_openerp script in calling _relativitiez

431. By Stefan Rijnhart (Opener)

[MRG] lp:~anybox/anybox.recipe.openerp/1.8, revno 534

430. By Stefan Rijnhart (Opener)

[FIX] Remove call to debugger

429. By Stefan Rijnhart (Opener)

[FIX] Terminology

428. By Stefan Rijnhart (Opener)

[IMP] Comment

427. By Stefan Rijnhart (Opener)

[FIX] Typo

426. By Stefan Rijnhart (Opener)

[RFR] Terminology

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'anybox/recipe/openerp/base.py'
2--- anybox/recipe/openerp/base.py 2014-11-30 17:44:41 +0000
3+++ anybox/recipe/openerp/base.py 2015-05-21 14:27:54 +0000
4@@ -45,6 +45,24 @@
5 """Parse RFC 2822-formatted http header and return a time int."""
6 rfc822.mktime_tz(rfc822.parsedate_tz(h))
7
8+def _common_path(*path):
9+ """Return the longest path prefix that is a prefix of all paths"""
10+ return os.path.dirname(os.path.commonprefix(path))
11+
12+def _relative_path(common, path):
13+ """Copied from easy_install"""
14+ r = []
15+ while 1:
16+ dirname, basename = os.path.split(path)
17+ r.append(basename)
18+ if dirname == common:
19+ break
20+ if dirname == path:
21+ raise AssertionError("dirname of %s is the same" % dirname)
22+ path = dirname
23+ r.reverse()
24+ return os.path.join(*r)
25+
26
27 class MainSoftware(object):
28 """Placeholder to represent the main software instead of an addon location.
29@@ -152,8 +170,23 @@
30 self.vcs_clear_locks = clear_locks == 'true'
31 clear_retry = options.get('vcs-clear-retry', '').lower()
32 self.clear_retry = clear_retry == 'true'
33+ self.jailroot_dir = options.get('jailroot-dir')
34+ self.python_scripts_executable = options.get(
35+ 'python-scripts-executable')
36+
37+ if self.jailroot_dir:
38+ options['relative-paths'] = 'true'
39
40 # same as in zc.recipe.eggs
41+ relative_paths = options.get(
42+ 'relative-paths',
43+ buildout['buildout'].get('relative-paths', 'false')
44+ )
45+ if relative_paths == 'true':
46+ self._relative_paths = self.buildout_dir
47+ else:
48+ self._relative_paths = ''
49+ assert relative_paths == 'false'
50 self.extra_paths = [
51 join(self.buildout_dir, p.strip())
52 for p in option_splitlines(self.options.get('extra-paths'))
53@@ -429,6 +462,21 @@
54 return path
55 return join(self.buildout_dir, path)
56
57+ def make_jailroot_absolute(self, path):
58+ """Make a path absolute to the jailroot."""
59+ if self.jailroot_dir:
60+ return join('/', self.make_relative(path))
61+ return path
62+
63+ def make_relative(self, path):
64+ """Make a path relative to the jailroot or buildout dir"""
65+ if self._relative_paths:
66+ root = self.jailroot_dir or self.buildout_dir
67+ common = _common_path(path, root+'/')
68+ relative = _relative_path(common, path)
69+ return relative
70+ return path
71+
72 def sandboxed_tar_extract(self, sandbox, tarfile, first=None):
73 """Extract those members that are below the tarfile path 'sandbox'.
74
75@@ -1340,7 +1388,7 @@
76 else:
77 base_addons = join(self.openerp_dir, 'openerp', 'addons')
78 if os.path.exists(base_addons):
79- self.addons_paths.insert(0, base_addons)
80+ self.addons_paths.append(base_addons)
81
82 self.insert_odoo_git_addons(base_addons)
83
84@@ -1349,6 +1397,11 @@
85 assert os.path.isdir(path), (
86 "Not a directory: %r (aborting)" % path)
87
88+ addons_paths = list(self.addons_paths)
89+ self.addons_paths = [
90+ self.make_jailroot_absolute(addons_path)
91+ for addons_path in addons_paths
92+ ]
93 self.options['options.addons_path'] = ','.join(self.addons_paths)
94 if self.major_version <= (6, 0):
95 self._60_fix_root_path()
96
97=== modified file 'anybox/recipe/openerp/server.py'
98--- anybox/recipe/openerp/server.py 2014-11-29 18:05:24 +0000
99+++ anybox/recipe/openerp/server.py 2015-05-21 14:27:54 +0000
100@@ -8,8 +8,12 @@
101 import zc.buildout
102 from zc.buildout import UserError
103 from anybox.recipe.openerp import devtools
104+<<<<<<< TREE
105 from .base import BaseRecipe
106 from .utils import option_splitlines, option_strip
107+=======
108+from anybox.recipe.openerp.base import BaseRecipe, _relative_path
109+>>>>>>> MERGE-SOURCE
110
111 logger = logging.getLogger(__name__)
112
113@@ -64,6 +68,17 @@
114 sw_modules = ('web', ) + sw_modules
115 self.server_wide_modules = sw_modules
116
117+ if self.python_scripts_executable:
118+ # Monkeypatch the script headers to replace the python
119+ # executable by the one configured by the user
120+ new_header = '#!%s' % self.python_scripts_executable
121+ zc.buildout.easy_install.script_template = (
122+ zc.buildout.easy_install.script_template.replace(
123+ zc.buildout.easy_install.script_header, new_header))
124+ zc.buildout.easy_install.py_script_template = (
125+ zc.buildout.easy_install.py_script_template.replace(
126+ zc.buildout.easy_install.script_header, new_header))
127+
128 def apply_version_dependent_decisions(self):
129 """Store some booleans depending on detected version.
130
131@@ -294,17 +309,25 @@
132 desc = self.openerp_scripts[name] = dict(entry=entry)
133 return name, desc
134
135+ def _relativitize(self, path):
136+ """Inspired from easy_install"""
137+ if self._relative_paths:
138+ return "join(base, %r)" % self.make_relative(path)
139+ return path
140+
141 def _register_main_startup_script(self, qualified_name):
142 """Register main startup script, usually ``start_openerp`` for install.
143 """
144 desc = self._get_or_create_script('openerp_starter',
145 name=qualified_name)[1]
146
147- arguments = '%r, %r, version=%r' % (self._get_server_command(),
148- self.config_path,
149- self.major_version)
150+ arguments = '%s, %s, version=%r' % (
151+ self._relativitize(self._get_server_command()),
152+ self._relativitize(self.config_path),
153+ self.major_version)
154 if self.major_version >= (7, 3):
155- arguments += ', gevent_script_path=%r' % self.gevent_script_path
156+ arguments += ', gevent_script_path=%s' % (
157+ self._relativitize(self.gevent_script_path))
158
159 if self.server_wide_modules:
160 arguments += ', server_wide_modules=%r' % (
161@@ -334,9 +357,9 @@
162 """
163 desc = self._get_or_create_script('openerp_tester',
164 name=qualified_name)[1]
165- arguments = '%r, %r, version=%r, just_test=True' % (
166- self._get_server_command(),
167- self.config_path,
168+ arguments = '%s, %s, version=%r, just_test=True' % (
169+ self._relativitize(self._get_server_command()),
170+ self._relativitize(self.config_path),
171 self.major_version)
172 if self.major_version >= (7, 3):
173 arguments += ', gevent_script_path=%r' % self.gevent_script_path
174@@ -364,9 +387,10 @@
175 script_source_path = self.make_absolute(script[0])
176 desc.update(
177 entry='openerp_upgrader',
178- arguments='%r, %r, %r, %r' % (
179- script_source_path, script[1],
180- self.config_path, self.buildout_dir),
181+ arguments='%s, %r, %s, %r' % (
182+ self._relativitize(script_source_path), script[1],
183+ self._relativitize(self.config_path),
184+ self.jailroot_dir and '/' or self.buildout_dir),
185 )
186
187 if not os.path.exists(script_source_path):
188@@ -403,7 +427,8 @@
189 # to resort on hacking sys.argv
190 desc['initialization'] = (
191 "from sys import argv; argv[1:] = ['%s', '-c', '%s.conf.py']" % (
192- gunicorn_entry_point, join(self.etc, qualified_name)))
193+ gunicorn_entry_point,
194+ self._relativitize(join(self.etc, qualified_name))))
195
196 def _register_openerp_command(self, qualified_name):
197 """Register https://launchpad.net/openerp-command for install.
198@@ -487,7 +512,9 @@
199 desc = self._get_or_create_script('openerp_cron_worker',
200 name=qualified_name)[1]
201 desc.update(entry='openerp_cron_worker',
202- arguments='%r, %r' % (script_src, self.config_path),
203+ arguments='%s, %s' % (
204+ self._relativitize(script_src),
205+ self._relativitize(self.config_path)),
206 initialization='',
207 )
208
209@@ -502,8 +529,9 @@
210 initialization = os.linesep.join((
211 "",
212 "from anybox.recipe.openerp.runtime.session import Session",
213- "session = Session(%r, %r)" % (self.config_path,
214- self.buildout_dir),
215+ "session = Session(%s, %r)" % (
216+ self._relativitize(self.config_path),
217+ self.jailroot_dir and '/' or self.buildout_dir),
218 "if len(sys.argv) <= 1:",
219 " print('To start the OpenERP working session, just do:')",
220 " print(' session.open(db=DATABASE_NAME)')",
221@@ -526,8 +554,7 @@
222 initialization=initialization,
223 arguments=self.options.get('arguments', ''),
224 extra_paths=self.extra_paths,
225- # TODO investigate these options:
226- # relative_paths=self._relative_paths,
227+ relative_paths=self._relative_paths,
228 )
229
230 def _install_openerp_scripts(self):
231@@ -544,8 +571,9 @@
232 common_init = os.linesep.join((
233 "",
234 "from anybox.recipe.openerp.runtime.session import Session",
235- "session = Session(%r, %r)" % (self.config_path,
236- self.buildout_dir),
237+ "session = Session(%s, %r)" % (
238+ self._relativitize(self.config_path),
239+ self.jailroot_dir and '/' or self.buildout_dir),
240 ))
241
242 for script_name, desc in self.openerp_scripts.items():
243@@ -569,9 +597,8 @@
244 interpreter='',
245 initialization=initialization,
246 arguments=desc.get('arguments', ''),
247- # TODO investigate these options:
248 extra_paths=self.extra_paths,
249- # relative_paths=self._relative_paths,
250+ relative_paths=self._relative_paths,
251 )
252 self.openerp_installed.append(join(self.bin_dir, script_name))
253
254
255=== modified file 'doc/configuration.rst'
256--- doc/configuration.rst 2014-11-12 03:33:02 +0000
257+++ doc/configuration.rst 2015-05-21 14:27:54 +0000
258@@ -408,6 +408,7 @@
259
260 Note that tarball downloads get re-extracted afresh in any case.
261
262+<<<<<<< TREE
263 vcs-revert
264 ----------
265
266@@ -440,6 +441,45 @@
267
268 .. note:: new in version 1.9.0
269
270+=======
271+:: _relocation_options:
272+
273+Options for buildout relocation and jail root
274+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
275+
276+.. _relative-paths:
277+
278+relative-paths
279+--------------
280+
281+If set to true, this option will set up a movable buildout. Paths in scripts
282+will be made relative to the buildout directory so that it can be relocated
283+on the file system.
284+
285+.. _jailroot-dir:
286+
287+jailroot-dir
288+---------------------
289+
290+If you build a jail root environment, specify the absolute path of the jail.
291+Note that it must be a sub-directory of the buildout dir as easy install cannot
292+build outside of the buildout dir. The addons-paths in the OpenERP configuration
293+file will be adapted to this path. This option implies :ref:`relative-paths`.
294+For instance, if you deploy OpenERP under a ``myjail`` sub-directory::
295+
296+ jailroot-dir = /root/mybuildout-dir/myjail
297+
298+.. _python-scripts-executable:
299+
300+python-scripts-executable
301+-------------------------
302+
303+Specify an alternative Python executable to be used in the she-bang of
304+generated scripts. For use in a jail root, ``/usr/bin/env python`` should
305+be a sane value, or you could hardcode the path to the Python executable
306+in your jail root.
307+
308+>>>>>>> MERGE-SOURCE
309 .. _openerp_options:
310
311 OpenERP options

Subscribers

People subscribed via source and target branches