Merge lp:~jbaudoux/anybox.recipe.openerp/20130908_relative_paths into lp:anybox.recipe.openerp

Proposed by Jacques-Etienne Baudoux
Status: Needs review
Proposed branch: lp:~jbaudoux/anybox.recipe.openerp/20130908_relative_paths
Merge into: lp:anybox.recipe.openerp
Diff against target: 140 lines (+51/-13)
2 files modified
anybox/recipe/openerp/base.py (+9/-0)
anybox/recipe/openerp/server.py (+42/-13)
To merge this branch: bzr merge lp:~jbaudoux/anybox.recipe.openerp/20130908_relative_paths
Reviewer Review Type Date Requested Status
Anybox Pending
Review via email: mp+184473@code.launchpad.net

Description of the change

Improvement to be compliant with buildout option "relative_paths = true"

To post a comment you must log in.
423. By Jacques-Etienne Baudoux

Fix format string

Revision history for this message
Georges Racinet (gracinet) wrote :

Really interesting if I understand it correctly, this the forever delayed "TODO investigate these options" ! Thank you for the contribution.

I'd need to read the details of _relativitize(), and especially understand why the one from zc.buildout.easy_install is not enough, but one thing is for sure : this will need dedicated unit tests and documentation : if OpenERP buildouts can be made relocatable, then the doc must state it explicitely, along with limitations (simply pointing out that it behaves exactly as zc.recipe.egg in that respect, it that is the case).

Not yet decided whether this can go to 1.7 or trunk. There's nothing that seems to be so dangerous (a breakage would not stay unnoticed for long).

Revision history for this message
Georges Racinet (gracinet) wrote :

inclusion in trunk could be done faster, if that matters to you.
Also, with the new Sphinx documentation, that seems to be the most sensible choice for a new feature (even if we should have supported this from the beginning). Mention of relocability can be done in the non-specific parts of doc/configuration.rst, I guess.

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

It allows me to deploy in a chroot subdirectory.
It's now compliant with the relative_paths option of buildout for the python scripts.
For your information, it's, however, still missing some hack to take care the the addons path in the openerp.cfg. I didn't found a nice way to solve that. For now, I'm solving it by creating a symling this: mybuildoutdirfullpath/chroot/mybuildoutdirfullpath -> /

Revision history for this message
Georges Racinet (gracinet) wrote :

OpenERP has a tendency to interpret paths relative to what if feels to be its home directory, namely the parent dir of the 'openerp' package.

In our case that's self.openerp_dir, so maybe you could work out something with os.path.relpath based on it ?

I don't know if that's true for addons, but it is for log files : bin/start_openerp --log-file=my.log will put the log file at <buildout_dir>/parts/<server part location>/my.log

One of the many reasons we wanted to normalize stuff in upgrade scripts (easy to forget to write down in maintainance procedures).

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

As the openerp.cfg is generated by importing openerp.tools.config from buildout, and the path is generated by openerp with os.path.abspath(os.path.expanduser(os.path.expandvars(os.path.dirname(openerp.__file__))))
I don't see anyway to have relative path here.
And as having full path in openerp.cfg is not blocking, so I'm gonna leave it like this.

Nevertheless, for python, relative path is required for the python module loader if you deploy in chroot jail. So, I suggest you merge this MP.

Revision history for this message
Georges Racinet (gracinet) wrote :

> As the openerp.cfg is generated by importing openerp.tools.config from
> buildout, and the path is generated by openerp with os.path.abspath(os.path.ex
> panduser(os.path.expandvars(os.path.dirname(openerp.__file__))))
> I don't see anyway to have relative path here.

This I don't really understand: that'd be the initial generation, but the recipe overwrites openerp.cfg afterwards by writing directly to it with a ConfigParser instance, IIRC

> And as having full path in openerp.cfg is not blocking, so I'm gonna leave it
> like this.
>
> Nevertheless, for python, relative path is required for the python module
> loader if you deploy in chroot jail. So, I suggest you merge this MP.

I see, for the chroot use case, you *need* paths to be relative.
But for simple relocability without rerunning buildout, it'd be neat to have a full relative setup.
I'll take a look at the merge this afternoon. Meanwhile, if you have opportunity to add tests in anybox/recipe/openerp/test_server.py or test_base.py, that'd be great (tests are needed anyway).

Revision history for this message
Georges Racinet (gracinet) wrote :

Took a look at the merge today (sorry, I'm late) and a few more question arise:

 - the invocation of Session in the generated interpreter now uses the buildout dir (to read the expected VERSION file)
 - is there a specific reason not to pass a relative path in the scripts generation, too ?

That makes too much questionning for merging before 1.8.0, I'll take a look at these again rigth after the release of 1.8.0 (should be first thing tomorrow morning CEST).

Revision history for this message
Georges Racinet (gracinet) wrote :

But I'm confident that it can make it before 1.8.1

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

> This I don't really understand: that'd be the initial generation, but the recipe overwrites openerp.cfg afterwards by writing directly to it with a ConfigParser instance, IIRC
ok, I see what you mean. This has to be investigated a bit more.

> - is there a specific reason not to pass a relative path in the scripts generation, too ?
Of what scripts are you talking? All the python scripts in bin seems to be with relative path

Anyway, thanks for the time you spend reviewing this. I need to look at your latest developments

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

Hi Georges,

I'm coming back on this MP as I just found some time to investigate that openerp.cfg addons_path that is not relative to the root of the chroot jail.

So, it's coming from server.py:
|- def _create_default_config(self):
|| """Have OpenERP generate its default config file.
|| """
|| self.options.setdefault('options.admin_passwd', '')
|| if self.major_version <= (6, 0):
|| # root-path not available as command-line option
|| os.chdir(join(self.openerp_dir, 'bin'))
|| subprocess.check_call([self.script_path, '--stop-after-init', '-s',
|| ])
|| else:
|| sys.path.extend([self.openerp_dir])
|| sys.path.extend([egg.location for egg in self.ws])
|| from openerp.tools.config import configmanager
|| configmanager(self.config_path).save()

I see 2 options:

1/ no improvement to this MP. Only python scripts are relative. However, each item in the addons path is prefixed by the path of the jail.
addons_path = /home/jbaudoux/chroot/opt/server/openerp/addons,....
and, inside the jail, workaround by creating a symlink /home/jbaudoux/chroot -> /

2/ don't use
|| from openerp.tools.config import configmanager
|| configmanager(self.config_path).save()
but run the jail start script like it was previously
|| subprocess.check_call([self.script_path, '--stop-after-init', '-s',
|| ])
where self.script_path has to be replaced by a new buildout variable specifying the script to run
This also has the advantage that if buildout is not run by the user that will run openerp, the openerp.cfg file gets the right ownership which is currently not the case.

What do you prefer? Option 1 is working fine (so I keep this MP as it is) but if you'd like to have option 2 implemented, I can make a MP to this MP.

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Hi Jacques Etienne,

thank you for your work! I'm suggesting some changes to streamline the preparation of running the buildout in a jail root here: https://code.launchpad.net/~therp-nl/anybox.recipe.openerp/jbaudoux-relative_paths_explicit_jailroot_support/+merge/205099. This includes mangling of the addons paths.

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

This MP is now obsolete and replaced by:
https://code.launchpad.net/~jbaudoux/anybox.recipe.openerp/1.8.5_relative_paths_jailroot/+merge/237238

Keeping this MP for history until latest gets merged.

Unmerged revisions

423. By Jacques-Etienne Baudoux

Fix format string

422. By Jacques-Etienne Baudoux

pep8

421. By Jacques-Etienne Baudoux

Support buildout option "relative_paths = true"

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 2013-09-05 22:45:15 +0000
3+++ anybox/recipe/openerp/base.py 2013-09-08 17:19:36 +0000
4@@ -111,6 +111,15 @@
5 self.clear_retry = clear_retry == 'true'
6
7 # same as in zc.recipe.eggs
8+ relative_paths = options.get(
9+ 'relative-paths',
10+ buildout['buildout'].get('relative-paths', 'false')
11+ )
12+ if relative_paths == 'true':
13+ self._relative_paths = self.buildout_dir
14+ else:
15+ self._relative_paths = ''
16+ assert relative_paths == 'false'
17 self.extra_paths = [
18 join(self.buildout_dir, p.strip())
19 for p in self.options.get('extra-paths', '').split(os.linesep)
20
21=== modified file 'anybox/recipe/openerp/server.py'
22--- anybox/recipe/openerp/server.py 2013-09-07 11:43:18 +0000
23+++ anybox/recipe/openerp/server.py 2013-09-08 17:19:36 +0000
24@@ -13,6 +13,21 @@
25 SERVER_COMMA_LIST_OPTIONS = ('log_handler', )
26
27
28+def _relative_path(common, path):
29+ """Copied from easy_install"""
30+ r = []
31+ while 1:
32+ dirname, basename = os.path.split(path)
33+ r.append(basename)
34+ if dirname == common:
35+ break
36+ if dirname == path:
37+ raise AssertionError("dirname of %s is the same" % dirname)
38+ path = dirname
39+ r.reverse()
40+ return os.path.join(*r)
41+
42+
43 class ServerRecipe(BaseRecipe):
44 """Recipe for server install and config
45 """
46@@ -266,15 +281,28 @@
47 desc = self.openerp_scripts[name] = dict(entry=entry)
48 return name, desc
49
50+ def _relativitize(self, path):
51+ """Inspired from easy_install"""
52+ if self._relative_paths:
53+ eggs = os.path.normcase(os.path.abspath(
54+ self.b_options['eggs-directory']))
55+ common = os.path.dirname(os.path.commonprefix([path, eggs]))
56+ if (common == self._relative_paths or
57+ common.startswith(os.path.join(self._relative_paths, ''))
58+ ):
59+ return "join(base, %r)" % _relative_path(common, path)
60+ return path
61+
62 def _register_main_startup_script(self, qualified_name):
63 """Register main startup script, usually ``start_openerp`` for install.
64 """
65 desc = self._get_or_create_script('openerp_starter',
66 name=qualified_name)[1]
67 desc.update(
68- arguments='%r, %r, version=%r' % (self._get_server_command(),
69- self.config_path,
70- self.major_version),
71+ arguments='%s, %s, version=%r' % (
72+ self._relativitize(self._get_server_command()),
73+ self._relativitize(self.config_path),
74+ self.major_version),
75 )
76
77 startup_delay = float(self.options.get('startup_delay', 0))
78@@ -305,9 +333,9 @@
79 "from anybox.recipe.openerp import devtools",
80 "devtools.load(for_tests=True)",
81 "")),
82- arguments='%r, %r, version=%r, just_test=True' % (
83- self._get_server_command(),
84- self.config_path,
85+ arguments='%s, %s, version=%r, just_test=True' % (
86+ self._relativitize(self._get_server_command()),
87+ self._relativitize(self.config_path),
88 self.major_version),
89 )
90
91@@ -340,7 +368,8 @@
92 # to resort on hacking sys.argv
93 desc['initialization'] = (
94 "from sys import argv; argv[1:] = ['%s', '-c', '%s.conf.py']" % (
95- gunicorn_entry_point, join(self.etc, qualified_name)))
96+ gunicorn_entry_point,
97+ self._relativitize(join(self.etc, qualified_name))))
98
99 def _register_openerp_command(self, qualified_name):
100 """Register https://launchpad.net/openerp-command for install.
101@@ -403,7 +432,9 @@
102 desc = self._get_or_create_script('openerp_cron_worker',
103 name=qualified_name)[1]
104 desc.update(entry='openerp_cron_worker',
105- arguments='%r, %r' % (script_src, self.config_path),
106+ arguments='%s, %s' % (
107+ self._relativitize(script_src),
108+ self._relativitize(self.config_path)),
109 initialization='',
110 )
111
112@@ -418,7 +449,7 @@
113 initialization = os.linesep.join((
114 "",
115 "from anybox.recipe.openerp.startup import Session",
116- "session = Session(%r)" % self.config_path,
117+ "session = Session(%s)" % self._relativitize(self.config_path),
118 "if len(sys.argv) <= 1:",
119 " print('To start the OpenERP working session, just do:')",
120 " print(' session.open(db=DATABASE_NAME)')",
121@@ -441,8 +472,7 @@
122 initialization=initialization,
123 arguments=self.options.get('arguments', ''),
124 extra_paths=self.extra_paths,
125- # TODO investigate these options:
126- # relative_paths=self._relative_paths,
127+ relative_paths=self._relative_paths,
128 )
129
130 def _install_openerp_scripts(self):
131@@ -476,9 +506,8 @@
132 interpreter='',
133 initialization=initialization,
134 arguments=desc.get('arguments', ''),
135- # TODO investigate these options:
136 extra_paths=self.extra_paths,
137- # relative_paths=self._relative_paths,
138+ relative_paths=self._relative_paths,
139 )
140 self.openerp_installed.append(join(self.bin_dir, script_name))
141

Subscribers

People subscribed via source and target branches