... | ... |
@@ -429,22 +429,6 @@ function lib_installed_from_git { |
429 | 429 |
[[ -n $(pip list --format=columns 2>/dev/null | awk "/^$safe_name/ {print \$3}") ]] |
430 | 430 |
} |
431 | 431 |
|
432 |
-# check that everything that's in LIBS_FROM_GIT was actually installed |
|
433 |
-# correctly, this helps double check issues with library fat fingering. |
|
434 |
-function check_libs_from_git { |
|
435 |
- local lib="" |
|
436 |
- local not_installed="" |
|
437 |
- for lib in $(echo ${LIBS_FROM_GIT} | tr "," " "); do |
|
438 |
- if ! lib_installed_from_git "$lib"; then |
|
439 |
- not_installed+=" $lib" |
|
440 |
- fi |
|
441 |
- done |
|
442 |
- # if anything is not installed, say what it is. |
|
443 |
- if [[ -n "$not_installed" ]]; then |
|
444 |
- die $LINENO "The following LIBS_FROM_GIT were not installed correct: $not_installed" |
|
445 |
- fi |
|
446 |
-} |
|
447 |
- |
|
448 | 432 |
# setup a library by name. If we are trying to use the library from |
449 | 433 |
# git, we'll do a git based install, otherwise we'll punt and the |
450 | 434 |
# library should be installed by a requirements pull from another |
... | ... |
@@ -555,6 +539,13 @@ function _setup_package_with_constraints_edit { |
555 | 555 |
|
556 | 556 |
setup_package $project_dir "$flags" $extras |
557 | 557 |
|
558 |
+ # If this project is in LIBS_FROM_GIT, verify it was actually installed |
|
559 |
+ # correctly. This helps catch errors caused by constraints mismatches. |
|
560 |
+ if use_library_from_git "$project_dir"; then |
|
561 |
+ if ! lib_installed_from_git "$project_dir"; then |
|
562 |
+ die $LINENO "The following LIBS_FROM_GIT was not installed correctly: $project_dir" |
|
563 |
+ fi |
|
564 |
+ fi |
|
558 | 565 |
} |
559 | 566 |
|
560 | 567 |
# ``pip install -e`` the package, which processes the dependencies |
... | ... |
@@ -20,6 +20,14 @@ Write the local.conf file for use by devstack |
20 | 20 |
bash shell variables, and will be ordered so that variables used by |
21 | 21 |
later entries appear first. |
22 | 22 |
|
23 |
+ As a special case, the variable ``LIBS_FROM_GIT`` will be |
|
24 |
+ constructed automatically from the projects which appear in the |
|
25 |
+ ``required-projects`` list defined by the job. To instruct |
|
26 |
+ devstack to install a library from source rather than pypi, simply |
|
27 |
+ add that library to the job's ``required-projects`` list. To |
|
28 |
+ override the automatically-generated value, set ``LIBS_FROM_GIT`` |
|
29 |
+ in ``devstack_localrc`` to the desired value. |
|
30 |
+ |
|
23 | 31 |
.. zuul:rolevar:: devstack_local_conf |
24 | 32 |
:type: dict |
25 | 33 |
|
... | ... |
@@ -75,3 +83,7 @@ Write the local.conf file for use by devstack |
75 | 75 |
A dictionary mapping a plugin name to a git repo location. If the |
76 | 76 |
location is a non-empty string, then an ``enable_plugin`` line will |
77 | 77 |
be emmitted for the plugin name. |
78 |
+ |
|
79 |
+ If a plugin declares a dependency on another plugin (via |
|
80 |
+ ``plugin_requires`` in the plugin's settings file), this role will |
|
81 |
+ automatically emit ``enable_plugin`` lines in the correct order. |
... | ... |
@@ -207,17 +207,17 @@ class PluginGraph(DependencyGraph): |
207 | 207 |
class LocalConf(object): |
208 | 208 |
|
209 | 209 |
def __init__(self, localrc, localconf, base_services, services, plugins, |
210 |
- base_dir): |
|
210 |
+ base_dir, projects): |
|
211 | 211 |
self.localrc = [] |
212 | 212 |
self.meta_sections = {} |
213 | 213 |
self.plugin_deps = {} |
214 | 214 |
self.base_dir = base_dir |
215 |
+ self.projects = projects |
|
215 | 216 |
if plugins: |
216 | 217 |
self.handle_plugins(plugins) |
217 | 218 |
if services or base_services: |
218 | 219 |
self.handle_services(base_services, services or {}) |
219 |
- if localrc: |
|
220 |
- self.handle_localrc(localrc) |
|
220 |
+ self.handle_localrc(localrc) |
|
221 | 221 |
if localconf: |
222 | 222 |
self.handle_localconf(localconf) |
223 | 223 |
|
... | ... |
@@ -241,9 +241,22 @@ class LocalConf(object): |
241 | 241 |
self.localrc.append('enable_service {}'.format(k)) |
242 | 242 |
|
243 | 243 |
def handle_localrc(self, localrc): |
244 |
- vg = VarGraph(localrc) |
|
245 |
- for k, v in vg.getVars(): |
|
246 |
- self.localrc.append('{}={}'.format(k, v)) |
|
244 |
+ lfg = False |
|
245 |
+ if localrc: |
|
246 |
+ vg = VarGraph(localrc) |
|
247 |
+ for k, v in vg.getVars(): |
|
248 |
+ self.localrc.append('{}={}'.format(k, v)) |
|
249 |
+ if k == 'LIBS_FROM_GIT': |
|
250 |
+ lfg = True |
|
251 |
+ |
|
252 |
+ if not lfg and self.projects: |
|
253 |
+ required_projects = [] |
|
254 |
+ for project_name, project_info in self.projects.items(): |
|
255 |
+ if project_info.get('required'): |
|
256 |
+ required_projects.append(project_info['short_name']) |
|
257 |
+ if required_projects: |
|
258 |
+ self.localrc.append('LIBS_FROM_GIT={}'.format( |
|
259 |
+ ','.join(required_projects))) |
|
247 | 260 |
|
248 | 261 |
def handle_localconf(self, localconf): |
249 | 262 |
for phase, phase_data in localconf.items(): |
... | ... |
@@ -277,6 +290,7 @@ def main(): |
277 | 277 |
local_conf=dict(type='dict'), |
278 | 278 |
base_dir=dict(type='path'), |
279 | 279 |
path=dict(type='str'), |
280 |
+ projects=dict(type='dict'), |
|
280 | 281 |
) |
281 | 282 |
) |
282 | 283 |
|
... | ... |
@@ -286,7 +300,8 @@ def main(): |
286 | 286 |
p.get('base_services'), |
287 | 287 |
p.get('services'), |
288 | 288 |
p.get('plugins'), |
289 |
- p.get('base_dir')) |
|
289 |
+ p.get('base_dir'), |
|
290 |
+ p.get('projects')) |
|
290 | 291 |
lc.write(p['path']) |
291 | 292 |
|
292 | 293 |
module.exit_json() |
... | ... |
@@ -56,7 +56,8 @@ class TestDevstackLocalConf(unittest.TestCase): |
56 | 56 |
p.get('base_services'), |
57 | 57 |
p.get('services'), |
58 | 58 |
p.get('plugins'), |
59 |
- p.get('base_dir')) |
|
59 |
+ p.get('base_dir'), |
|
60 |
+ p.get('projects')) |
|
60 | 61 |
lc.write(p['path']) |
61 | 62 |
|
62 | 63 |
plugins = [] |
... | ... |
@@ -66,6 +67,7 @@ class TestDevstackLocalConf(unittest.TestCase): |
66 | 66 |
plugins.append(line.split()[1]) |
67 | 67 |
self.assertEqual(['bar', 'baz', 'foo'], plugins) |
68 | 68 |
|
69 |
+ |
|
69 | 70 |
def test_plugin_deps(self): |
70 | 71 |
"Test that plugins with dependencies work" |
71 | 72 |
os.makedirs(os.path.join(self.tmpdir, 'foo-plugin', 'devstack')) |
... | ... |
@@ -101,20 +103,80 @@ class TestDevstackLocalConf(unittest.TestCase): |
101 | 101 |
plugins=plugins, |
102 | 102 |
base_dir=self.tmpdir, |
103 | 103 |
path=os.path.join(self.tmpdir, 'test.local.conf')) |
104 |
+ |
|
105 |
+ def test_libs_from_git(self): |
|
106 |
+ "Test that LIBS_FROM_GIT is auto-generated" |
|
107 |
+ projects = { |
|
108 |
+ 'git.openstack.org/openstack/nova': { |
|
109 |
+ 'required': True, |
|
110 |
+ 'short_name': 'nova', |
|
111 |
+ }, |
|
112 |
+ 'git.openstack.org/openstack/oslo.messaging': { |
|
113 |
+ 'required': True, |
|
114 |
+ 'short_name': 'oslo.messaging', |
|
115 |
+ }, |
|
116 |
+ 'git.openstack.org/openstack/devstack-plugin': { |
|
117 |
+ 'required': False, |
|
118 |
+ 'short_name': 'devstack-plugin', |
|
119 |
+ }, |
|
120 |
+ } |
|
121 |
+ p = dict(base_services=[], |
|
122 |
+ base_dir='./test', |
|
123 |
+ path=os.path.join(self.tmpdir, 'test.local.conf'), |
|
124 |
+ projects=projects) |
|
104 | 125 |
lc = LocalConf(p.get('localrc'), |
105 | 126 |
p.get('local_conf'), |
106 | 127 |
p.get('base_services'), |
107 | 128 |
p.get('services'), |
108 | 129 |
p.get('plugins'), |
109 |
- p.get('base_dir')) |
|
130 |
+ p.get('base_dir'), |
|
131 |
+ p.get('projects')) |
|
110 | 132 |
lc.write(p['path']) |
111 | 133 |
|
112 |
- plugins = [] |
|
134 |
+ lfg = None |
|
113 | 135 |
with open(p['path']) as f: |
114 | 136 |
for line in f: |
115 |
- if line.startswith('enable_plugin'): |
|
116 |
- plugins.append(line.split()[1]) |
|
117 |
- self.assertEqual(['foo', 'bar'], plugins) |
|
137 |
+ if line.startswith('LIBS_FROM_GIT'): |
|
138 |
+ lfg = line.strip().split('=')[1] |
|
139 |
+ self.assertEqual('nova,oslo.messaging', lfg) |
|
140 |
+ |
|
141 |
+ def test_overridelibs_from_git(self): |
|
142 |
+ "Test that LIBS_FROM_GIT can be overridden" |
|
143 |
+ localrc = {'LIBS_FROM_GIT': 'oslo.db'} |
|
144 |
+ projects = { |
|
145 |
+ 'git.openstack.org/openstack/nova': { |
|
146 |
+ 'required': True, |
|
147 |
+ 'short_name': 'nova', |
|
148 |
+ }, |
|
149 |
+ 'git.openstack.org/openstack/oslo.messaging': { |
|
150 |
+ 'required': True, |
|
151 |
+ 'short_name': 'oslo.messaging', |
|
152 |
+ }, |
|
153 |
+ 'git.openstack.org/openstack/devstack-plugin': { |
|
154 |
+ 'required': False, |
|
155 |
+ 'short_name': 'devstack-plugin', |
|
156 |
+ }, |
|
157 |
+ } |
|
158 |
+ p = dict(localrc=localrc, |
|
159 |
+ base_services=[], |
|
160 |
+ base_dir='./test', |
|
161 |
+ path=os.path.join(self.tmpdir, 'test.local.conf'), |
|
162 |
+ projects=projects) |
|
163 |
+ lc = LocalConf(p.get('localrc'), |
|
164 |
+ p.get('local_conf'), |
|
165 |
+ p.get('base_services'), |
|
166 |
+ p.get('services'), |
|
167 |
+ p.get('plugins'), |
|
168 |
+ p.get('base_dir'), |
|
169 |
+ p.get('projects')) |
|
170 |
+ lc.write(p['path']) |
|
171 |
+ |
|
172 |
+ lfg = None |
|
173 |
+ with open(p['path']) as f: |
|
174 |
+ for line in f: |
|
175 |
+ if line.startswith('LIBS_FROM_GIT'): |
|
176 |
+ lfg = line.strip().split('=')[1] |
|
177 |
+ self.assertEqual('oslo.db', lfg) |
|
118 | 178 |
|
119 | 179 |
def test_plugin_circular_deps(self): |
120 | 180 |
"Test that plugins with circular dependencies fail" |
... | ... |
@@ -1398,11 +1398,6 @@ fi |
1398 | 1398 |
# Check the status of running services |
1399 | 1399 |
service_check |
1400 | 1400 |
|
1401 |
-# ensure that all the libraries we think we installed from git, |
|
1402 |
-# actually were. |
|
1403 |
-check_libs_from_git |
|
1404 |
- |
|
1405 |
- |
|
1406 | 1401 |
# Configure nova cellsv2 |
1407 | 1402 |
# ---------------------- |
1408 | 1403 |
|