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
=== modified file 'anybox/recipe/openerp/base.py'
--- anybox/recipe/openerp/base.py 2014-11-30 17:44:41 +0000
+++ anybox/recipe/openerp/base.py 2015-05-21 14:27:54 +0000
@@ -45,6 +45,24 @@
45 """Parse RFC 2822-formatted http header and return a time int."""45 """Parse RFC 2822-formatted http header and return a time int."""
46 rfc822.mktime_tz(rfc822.parsedate_tz(h))46 rfc822.mktime_tz(rfc822.parsedate_tz(h))
4747
48def _common_path(*path):
49 """Return the longest path prefix that is a prefix of all paths"""
50 return os.path.dirname(os.path.commonprefix(path))
51
52def _relative_path(common, path):
53 """Copied from easy_install"""
54 r = []
55 while 1:
56 dirname, basename = os.path.split(path)
57 r.append(basename)
58 if dirname == common:
59 break
60 if dirname == path:
61 raise AssertionError("dirname of %s is the same" % dirname)
62 path = dirname
63 r.reverse()
64 return os.path.join(*r)
65
4866
49class MainSoftware(object):67class MainSoftware(object):
50 """Placeholder to represent the main software instead of an addon location.68 """Placeholder to represent the main software instead of an addon location.
@@ -152,8 +170,23 @@
152 self.vcs_clear_locks = clear_locks == 'true'170 self.vcs_clear_locks = clear_locks == 'true'
153 clear_retry = options.get('vcs-clear-retry', '').lower()171 clear_retry = options.get('vcs-clear-retry', '').lower()
154 self.clear_retry = clear_retry == 'true'172 self.clear_retry = clear_retry == 'true'
173 self.jailroot_dir = options.get('jailroot-dir')
174 self.python_scripts_executable = options.get(
175 'python-scripts-executable')
176
177 if self.jailroot_dir:
178 options['relative-paths'] = 'true'
155179
156 # same as in zc.recipe.eggs180 # same as in zc.recipe.eggs
181 relative_paths = options.get(
182 'relative-paths',
183 buildout['buildout'].get('relative-paths', 'false')
184 )
185 if relative_paths == 'true':
186 self._relative_paths = self.buildout_dir
187 else:
188 self._relative_paths = ''
189 assert relative_paths == 'false'
157 self.extra_paths = [190 self.extra_paths = [
158 join(self.buildout_dir, p.strip())191 join(self.buildout_dir, p.strip())
159 for p in option_splitlines(self.options.get('extra-paths'))192 for p in option_splitlines(self.options.get('extra-paths'))
@@ -429,6 +462,21 @@
429 return path462 return path
430 return join(self.buildout_dir, path)463 return join(self.buildout_dir, path)
431464
465 def make_jailroot_absolute(self, path):
466 """Make a path absolute to the jailroot."""
467 if self.jailroot_dir:
468 return join('/', self.make_relative(path))
469 return path
470
471 def make_relative(self, path):
472 """Make a path relative to the jailroot or buildout dir"""
473 if self._relative_paths:
474 root = self.jailroot_dir or self.buildout_dir
475 common = _common_path(path, root+'/')
476 relative = _relative_path(common, path)
477 return relative
478 return path
479
432 def sandboxed_tar_extract(self, sandbox, tarfile, first=None):480 def sandboxed_tar_extract(self, sandbox, tarfile, first=None):
433 """Extract those members that are below the tarfile path 'sandbox'.481 """Extract those members that are below the tarfile path 'sandbox'.
434482
@@ -1340,7 +1388,7 @@
1340 else:1388 else:
1341 base_addons = join(self.openerp_dir, 'openerp', 'addons')1389 base_addons = join(self.openerp_dir, 'openerp', 'addons')
1342 if os.path.exists(base_addons):1390 if os.path.exists(base_addons):
1343 self.addons_paths.insert(0, base_addons)1391 self.addons_paths.append(base_addons)
13441392
1345 self.insert_odoo_git_addons(base_addons)1393 self.insert_odoo_git_addons(base_addons)
13461394
@@ -1349,6 +1397,11 @@
1349 assert os.path.isdir(path), (1397 assert os.path.isdir(path), (
1350 "Not a directory: %r (aborting)" % path)1398 "Not a directory: %r (aborting)" % path)
13511399
1400 addons_paths = list(self.addons_paths)
1401 self.addons_paths = [
1402 self.make_jailroot_absolute(addons_path)
1403 for addons_path in addons_paths
1404 ]
1352 self.options['options.addons_path'] = ','.join(self.addons_paths)1405 self.options['options.addons_path'] = ','.join(self.addons_paths)
1353 if self.major_version <= (6, 0):1406 if self.major_version <= (6, 0):
1354 self._60_fix_root_path()1407 self._60_fix_root_path()
13551408
=== modified file 'anybox/recipe/openerp/server.py'
--- anybox/recipe/openerp/server.py 2014-11-29 18:05:24 +0000
+++ anybox/recipe/openerp/server.py 2015-05-21 14:27:54 +0000
@@ -8,8 +8,12 @@
8import zc.buildout8import zc.buildout
9from zc.buildout import UserError9from zc.buildout import UserError
10from anybox.recipe.openerp import devtools10from anybox.recipe.openerp import devtools
11<<<<<<< TREE
11from .base import BaseRecipe12from .base import BaseRecipe
12from .utils import option_splitlines, option_strip13from .utils import option_splitlines, option_strip
14=======
15from anybox.recipe.openerp.base import BaseRecipe, _relative_path
16>>>>>>> MERGE-SOURCE
1317
14logger = logging.getLogger(__name__)18logger = logging.getLogger(__name__)
1519
@@ -64,6 +68,17 @@
64 sw_modules = ('web', ) + sw_modules68 sw_modules = ('web', ) + sw_modules
65 self.server_wide_modules = sw_modules69 self.server_wide_modules = sw_modules
6670
71 if self.python_scripts_executable:
72 # Monkeypatch the script headers to replace the python
73 # executable by the one configured by the user
74 new_header = '#!%s' % self.python_scripts_executable
75 zc.buildout.easy_install.script_template = (
76 zc.buildout.easy_install.script_template.replace(
77 zc.buildout.easy_install.script_header, new_header))
78 zc.buildout.easy_install.py_script_template = (
79 zc.buildout.easy_install.py_script_template.replace(
80 zc.buildout.easy_install.script_header, new_header))
81
67 def apply_version_dependent_decisions(self):82 def apply_version_dependent_decisions(self):
68 """Store some booleans depending on detected version.83 """Store some booleans depending on detected version.
6984
@@ -294,17 +309,25 @@
294 desc = self.openerp_scripts[name] = dict(entry=entry)309 desc = self.openerp_scripts[name] = dict(entry=entry)
295 return name, desc310 return name, desc
296311
312 def _relativitize(self, path):
313 """Inspired from easy_install"""
314 if self._relative_paths:
315 return "join(base, %r)" % self.make_relative(path)
316 return path
317
297 def _register_main_startup_script(self, qualified_name):318 def _register_main_startup_script(self, qualified_name):
298 """Register main startup script, usually ``start_openerp`` for install.319 """Register main startup script, usually ``start_openerp`` for install.
299 """320 """
300 desc = self._get_or_create_script('openerp_starter',321 desc = self._get_or_create_script('openerp_starter',
301 name=qualified_name)[1]322 name=qualified_name)[1]
302323
303 arguments = '%r, %r, version=%r' % (self._get_server_command(),324 arguments = '%s, %s, version=%r' % (
304 self.config_path,325 self._relativitize(self._get_server_command()),
305 self.major_version)326 self._relativitize(self.config_path),
327 self.major_version)
306 if self.major_version >= (7, 3):328 if self.major_version >= (7, 3):
307 arguments += ', gevent_script_path=%r' % self.gevent_script_path329 arguments += ', gevent_script_path=%s' % (
330 self._relativitize(self.gevent_script_path))
308331
309 if self.server_wide_modules:332 if self.server_wide_modules:
310 arguments += ', server_wide_modules=%r' % (333 arguments += ', server_wide_modules=%r' % (
@@ -334,9 +357,9 @@
334 """357 """
335 desc = self._get_or_create_script('openerp_tester',358 desc = self._get_or_create_script('openerp_tester',
336 name=qualified_name)[1]359 name=qualified_name)[1]
337 arguments = '%r, %r, version=%r, just_test=True' % (360 arguments = '%s, %s, version=%r, just_test=True' % (
338 self._get_server_command(),361 self._relativitize(self._get_server_command()),
339 self.config_path,362 self._relativitize(self.config_path),
340 self.major_version)363 self.major_version)
341 if self.major_version >= (7, 3):364 if self.major_version >= (7, 3):
342 arguments += ', gevent_script_path=%r' % self.gevent_script_path365 arguments += ', gevent_script_path=%r' % self.gevent_script_path
@@ -364,9 +387,10 @@
364 script_source_path = self.make_absolute(script[0])387 script_source_path = self.make_absolute(script[0])
365 desc.update(388 desc.update(
366 entry='openerp_upgrader',389 entry='openerp_upgrader',
367 arguments='%r, %r, %r, %r' % (390 arguments='%s, %r, %s, %r' % (
368 script_source_path, script[1],391 self._relativitize(script_source_path), script[1],
369 self.config_path, self.buildout_dir),392 self._relativitize(self.config_path),
393 self.jailroot_dir and '/' or self.buildout_dir),
370 )394 )
371395
372 if not os.path.exists(script_source_path):396 if not os.path.exists(script_source_path):
@@ -403,7 +427,8 @@
403 # to resort on hacking sys.argv427 # to resort on hacking sys.argv
404 desc['initialization'] = (428 desc['initialization'] = (
405 "from sys import argv; argv[1:] = ['%s', '-c', '%s.conf.py']" % (429 "from sys import argv; argv[1:] = ['%s', '-c', '%s.conf.py']" % (
406 gunicorn_entry_point, join(self.etc, qualified_name)))430 gunicorn_entry_point,
431 self._relativitize(join(self.etc, qualified_name))))
407432
408 def _register_openerp_command(self, qualified_name):433 def _register_openerp_command(self, qualified_name):
409 """Register https://launchpad.net/openerp-command for install.434 """Register https://launchpad.net/openerp-command for install.
@@ -487,7 +512,9 @@
487 desc = self._get_or_create_script('openerp_cron_worker',512 desc = self._get_or_create_script('openerp_cron_worker',
488 name=qualified_name)[1]513 name=qualified_name)[1]
489 desc.update(entry='openerp_cron_worker',514 desc.update(entry='openerp_cron_worker',
490 arguments='%r, %r' % (script_src, self.config_path),515 arguments='%s, %s' % (
516 self._relativitize(script_src),
517 self._relativitize(self.config_path)),
491 initialization='',518 initialization='',
492 )519 )
493520
@@ -502,8 +529,9 @@
502 initialization = os.linesep.join((529 initialization = os.linesep.join((
503 "",530 "",
504 "from anybox.recipe.openerp.runtime.session import Session",531 "from anybox.recipe.openerp.runtime.session import Session",
505 "session = Session(%r, %r)" % (self.config_path,532 "session = Session(%s, %r)" % (
506 self.buildout_dir),533 self._relativitize(self.config_path),
534 self.jailroot_dir and '/' or self.buildout_dir),
507 "if len(sys.argv) <= 1:",535 "if len(sys.argv) <= 1:",
508 " print('To start the OpenERP working session, just do:')",536 " print('To start the OpenERP working session, just do:')",
509 " print(' session.open(db=DATABASE_NAME)')",537 " print(' session.open(db=DATABASE_NAME)')",
@@ -526,8 +554,7 @@
526 initialization=initialization,554 initialization=initialization,
527 arguments=self.options.get('arguments', ''),555 arguments=self.options.get('arguments', ''),
528 extra_paths=self.extra_paths,556 extra_paths=self.extra_paths,
529 # TODO investigate these options:557 relative_paths=self._relative_paths,
530 # relative_paths=self._relative_paths,
531 )558 )
532559
533 def _install_openerp_scripts(self):560 def _install_openerp_scripts(self):
@@ -544,8 +571,9 @@
544 common_init = os.linesep.join((571 common_init = os.linesep.join((
545 "",572 "",
546 "from anybox.recipe.openerp.runtime.session import Session",573 "from anybox.recipe.openerp.runtime.session import Session",
547 "session = Session(%r, %r)" % (self.config_path,574 "session = Session(%s, %r)" % (
548 self.buildout_dir),575 self._relativitize(self.config_path),
576 self.jailroot_dir and '/' or self.buildout_dir),
549 ))577 ))
550578
551 for script_name, desc in self.openerp_scripts.items():579 for script_name, desc in self.openerp_scripts.items():
@@ -569,9 +597,8 @@
569 interpreter='',597 interpreter='',
570 initialization=initialization,598 initialization=initialization,
571 arguments=desc.get('arguments', ''),599 arguments=desc.get('arguments', ''),
572 # TODO investigate these options:
573 extra_paths=self.extra_paths,600 extra_paths=self.extra_paths,
574 # relative_paths=self._relative_paths,601 relative_paths=self._relative_paths,
575 )602 )
576 self.openerp_installed.append(join(self.bin_dir, script_name))603 self.openerp_installed.append(join(self.bin_dir, script_name))
577604
578605
=== modified file 'doc/configuration.rst'
--- doc/configuration.rst 2014-11-12 03:33:02 +0000
+++ doc/configuration.rst 2015-05-21 14:27:54 +0000
@@ -408,6 +408,7 @@
408408
409Note that tarball downloads get re-extracted afresh in any case.409Note that tarball downloads get re-extracted afresh in any case.
410410
411<<<<<<< TREE
411vcs-revert412vcs-revert
412----------413----------
413414
@@ -440,6 +441,45 @@
440441
441.. note:: new in version 1.9.0442.. note:: new in version 1.9.0
442443
444=======
445:: _relocation_options:
446
447Options for buildout relocation and jail root
448~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
449
450.. _relative-paths:
451
452relative-paths
453--------------
454
455If set to true, this option will set up a movable buildout. Paths in scripts
456will be made relative to the buildout directory so that it can be relocated
457on the file system.
458
459.. _jailroot-dir:
460
461jailroot-dir
462---------------------
463
464If you build a jail root environment, specify the absolute path of the jail.
465Note that it must be a sub-directory of the buildout dir as easy install cannot
466build outside of the buildout dir. The addons-paths in the OpenERP configuration
467file will be adapted to this path. This option implies :ref:`relative-paths`.
468For instance, if you deploy OpenERP under a ``myjail`` sub-directory::
469
470 jailroot-dir = /root/mybuildout-dir/myjail
471
472.. _python-scripts-executable:
473
474python-scripts-executable
475-------------------------
476
477Specify an alternative Python executable to be used in the she-bang of
478generated scripts. For use in a jail root, ``/usr/bin/env python`` should
479be a sane value, or you could hardcode the path to the Python executable
480in your jail root.
481
482>>>>>>> MERGE-SOURCE
443.. _openerp_options:483.. _openerp_options:
444484
445OpenERP options485OpenERP options

Subscribers

People subscribed via source and target branches