Merge lp:~townsend/libertine/rebuild-running-app-state into lp:libertine
- rebuild-running-app-state
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Larry Price |
Approved revision: | 417 |
Merged at revision: | 412 |
Proposed branch: | lp:~townsend/libertine/rebuild-running-app-state |
Merge into: | lp:libertine |
Diff against target: |
513 lines (+178/-89) 8 files modified
python/libertine/Client.py (+19/-11) python/libertine/ContainersConfig.py (+12/-3) python/libertine/Libertine.py (+2/-0) python/libertine/LxcContainer.py (+23/-27) python/libertine/LxdContainer.py (+20/-22) python/libertine/launcher/session.py (+15/-7) python/libertine/service/manager.py (+12/-19) python/libertine/service/operations_state.py (+75/-0) |
To merge this branch: | bzr merge lp:~townsend/libertine/rebuild-running-app-state |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Larry Price | Approve | ||
Libertine CI Bot | continuous-integration | Approve | |
Review via email: mp+317548@code.launchpad.net |
Commit message
Fix libertined such that it can probe for currently running X apps and rebuild application running state.
Description of the change
Libertine CI Bot (libertine-ci-bot) wrote : | # |
Larry Price (larryprice) wrote : | # |
a few inlines - this is some complex stuff, and it'll be very nice to get it in.
- 409. By Christopher Townsend
-
Changes based on review.
Libertine CI Bot (libertine-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:409
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Libertine CI Bot (libertine-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:409
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 410. By Christopher Townsend
-
Add invalidate method to the Client.
Libertine CI Bot (libertine-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:410
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 411. By Christopher Townsend
-
A few more changes based on review.
Libertine CI Bot (libertine-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:411
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 412. By Christopher Townsend
-
Merge lp:libertine.
- 413. By Christopher Townsend
-
Better handle container state when trying to destroy a container.
Libertine CI Bot (libertine-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:413
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Larry Price (larryprice) wrote : | # |
one inline - i'm about to load up the debs and do some verification
- 414. By Christopher Townsend
-
Only need to instantiate the ContainersConfig object once.
Libertine CI Bot (libertine-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:414
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 415. By Christopher Townsend
-
Missed some variable inits.
Libertine CI Bot (libertine-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:415
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 416. By Christopher Townsend
-
Used wrong init type.
Libertine CI Bot (libertine-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:416
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Larry Price (larryprice) wrote : | # |
So we don't forget, the bug I found EOD is that my bad pids aren't being cleaned up by libertined.
- 417. By Christopher Townsend
-
Fix removal of more than one invalid app.
Libertine CI Bot (libertine-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:417
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'python/libertine/Client.py' |
2 | --- python/libertine/Client.py 2017-02-15 21:25:15 +0000 |
3 | +++ python/libertine/Client.py 2017-02-23 15:25:56 +0000 |
4 | @@ -20,6 +20,9 @@ |
5 | |
6 | class Client(object): |
7 | def __init__(self): |
8 | + self._get_manager() |
9 | + |
10 | + def _get_manager(self): |
11 | self._manager = None |
12 | |
13 | try: |
14 | @@ -33,16 +36,25 @@ |
15 | except dbus.exceptions.DBusException as e: |
16 | utils.get_logger().warning("Exception raised while discovering d-bus service: {}".format(str(e))) |
17 | |
18 | + def _do_operation(self, operation): |
19 | + # It's possible that the service has gone down from when first getting the object. |
20 | + # This catches the dbus excpetion if it did, and tries to reconnect to the service |
21 | + # and then retry the dbus method. |
22 | + while self.valid: |
23 | + try: |
24 | + return operation() |
25 | + except dbus.exceptions.DBusException as e: |
26 | + self._get_manager() |
27 | + else: |
28 | + return False |
29 | + |
30 | @property |
31 | def valid(self): |
32 | return self._manager is not None |
33 | |
34 | def container_operation_start(self, id): |
35 | - if not self.valid: |
36 | - return False |
37 | - |
38 | retries = 0 |
39 | - while not self._manager.get_dbus_method('container_operation_start', self._interface)(id): |
40 | + while not self._do_operation(lambda: self._manager.get_dbus_method('container_operation_start', self._interface)(id)): |
41 | retries += 1 |
42 | if retries > 5: |
43 | return False |
44 | @@ -50,12 +62,8 @@ |
45 | |
46 | return True |
47 | |
48 | - def container_operation_finished(self, id): |
49 | - return self.valid and self._manager.get_dbus_method("container_operation_finished", self._interface)(id) |
50 | + def container_operation_finished(self, id, app_name, pid): |
51 | + return self._do_operation(lambda: self._manager.get_dbus_method("container_operation_finished", self._interface)(id, app_name, pid)) |
52 | |
53 | def container_stopped(self, id): |
54 | - if not self.valid: |
55 | - return False |
56 | - |
57 | - self._manager.get_dbus_method('container_stopped', self._interface)(id) |
58 | - return True |
59 | + return self._do_operation(lambda: self._manager.get_dbus_method('container_stopped', self._interface)(id)) |
60 | |
61 | === modified file 'python/libertine/ContainersConfig.py' |
62 | --- python/libertine/ContainersConfig.py 2017-02-07 14:09:49 +0000 |
63 | +++ python/libertine/ContainersConfig.py 2017-02-23 15:25:56 +0000 |
64 | @@ -364,9 +364,18 @@ |
65 | app_obj = {'appExecName': app_exec_name, 'pid': pid} |
66 | self._set_value_by_key(container_id, 'runningApps', app_obj) |
67 | |
68 | - def delete_running_app(self, container_id, app_exec_name): |
69 | - self._delete_array_object_by_key_value(container_id, 'runningApps', |
70 | - 'appExecName', app_exec_name) |
71 | + def delete_running_app(self, container_id, app_obj): |
72 | + self._delete_array_object_by_value(container_id, 'runningApps', app_obj) |
73 | + |
74 | + def find_running_app_by_name_and_pid(self, container_id, app_exec_name, pid): |
75 | + for app in self.get_running_apps(container_id): |
76 | + if app['appExecName'] == app_exec_name and app['pid'] == pid: |
77 | + return app |
78 | + |
79 | + return None |
80 | + |
81 | + def get_running_apps(self, container_id): |
82 | + return self._get_value_by_key(container_id, 'runningApps') or [] |
83 | |
84 | """ |
85 | Operations for bind-mount maintenance in a Libertine container. |
86 | |
87 | === modified file 'python/libertine/Libertine.py' |
88 | --- python/libertine/Libertine.py 2017-02-09 15:40:37 +0000 |
89 | +++ python/libertine/Libertine.py 2017-02-23 15:25:56 +0000 |
90 | @@ -83,6 +83,8 @@ |
91 | self.container_type = container_type |
92 | self.container_id = container_id |
93 | self._config = config |
94 | + self._app_name = '' |
95 | + self._pid = 0 |
96 | self.root_path = utils.get_libertine_container_rootfs_path(self.container_id) |
97 | self.locale = self._config.get_container_locale(container_id) |
98 | self.language = self._get_language_from_locale() |
99 | |
100 | === modified file 'python/libertine/LxcContainer.py' |
101 | --- python/libertine/LxcContainer.py 2017-02-15 21:12:37 +0000 |
102 | +++ python/libertine/LxcContainer.py 2017-02-23 15:25:56 +0000 |
103 | @@ -14,7 +14,6 @@ |
104 | |
105 | import contextlib |
106 | import crypt |
107 | -import dbus |
108 | import lxc |
109 | import os |
110 | import psutil |
111 | @@ -22,7 +21,6 @@ |
112 | import subprocess |
113 | import sys |
114 | import tempfile |
115 | -import time |
116 | |
117 | from .Libertine import BaseContainer |
118 | from . import utils, HostInfo, Client |
119 | @@ -215,7 +213,8 @@ |
120 | return fd.read().strip('\n') != self.host_info.get_host_timezone() |
121 | |
122 | def start_container(self): |
123 | - self._manager.container_operation_start(self.container_id) |
124 | + if not self._manager.container_operation_start(self.container_id): |
125 | + return False |
126 | |
127 | if self.container.state == 'RUNNING': |
128 | return True |
129 | @@ -231,33 +230,21 @@ |
130 | return True |
131 | |
132 | def stop_container(self): |
133 | - if self._manager.valid: |
134 | - if not self._manager.container_operation_finished(self.container_id): |
135 | - return False |
136 | - |
137 | - if not lxc_stop(self.container, self._freeze_on_stop): |
138 | - return False |
139 | - |
140 | + if (self._manager.container_operation_finished(self.container_id, self._app_name, self._pid) and |
141 | + lxc_stop(self.container, self._freeze_on_stop)): |
142 | return self._manager.container_stopped(self.container_id) |
143 | - else: |
144 | - return lxc_stop(self.container, self._freeze_on_stop) |
145 | + |
146 | + return False |
147 | |
148 | def restart_container(self): |
149 | if self.container.state != 'FROZEN': |
150 | utils.get_logger().warning("Container {} is not frozen. Cannot restart.".format(self.container_id)) |
151 | return False |
152 | |
153 | - orig_freeze = self._freeze_on_stop |
154 | - self._freeze_on_stop = False |
155 | - |
156 | - # We never want to use the manager when restarting. |
157 | - self._manager = None |
158 | - |
159 | - if not (self.stop_container() and self.start_container()): |
160 | + if not (lxc_stop(self.container) and lxc_start(self.container)): |
161 | return False |
162 | |
163 | - self._freeze_on_stop = orig_freeze |
164 | - return self.stop_container() |
165 | + return lxc_stop(self.container, self._freeze_on_stop) |
166 | |
167 | def run_in_container(self, command_string): |
168 | cmd_args = shlex.split(command_string) |
169 | @@ -276,7 +263,14 @@ |
170 | if not self.container.defined: |
171 | return False |
172 | |
173 | - self.container.stop() |
174 | + if self.container.state == 'RUNNING': |
175 | + utils.get_logger().error("Canceling destruction due to running container") |
176 | + return False |
177 | + |
178 | + if self.container.state == 'FROZEN' and not lxc_stop(self.container): |
179 | + utils.get_logger().error("Canceling destruction due to container not stopped") |
180 | + return False |
181 | + |
182 | self.container.destroy() |
183 | return True |
184 | |
185 | @@ -389,10 +383,6 @@ |
186 | self.container.save_config() |
187 | |
188 | def start_application(self, app_exec_line, environ): |
189 | - if not self._manager.valid: |
190 | - utils.get_logger().error("No interface to libertine-lxc-manager. Failing application launch.") |
191 | - return |
192 | - |
193 | os.environ.clear() |
194 | os.environ.update(environ) |
195 | |
196 | @@ -400,11 +390,17 @@ |
197 | self._manager.container_stopped(self.container_id) |
198 | return |
199 | |
200 | + self._app_name = app_exec_line[0] |
201 | + |
202 | app_launch_cmd = "sudo -E -u " + os.environ['USER'] + " env PATH=" + os.environ['PATH'] |
203 | cmd = shlex.split(app_launch_cmd) |
204 | app = self.container.attach(lxc.attach_run_command, |
205 | cmd + app_exec_line) |
206 | - return psutil.Process(app) |
207 | + |
208 | + proc = psutil.Process(app) |
209 | + self._pid = proc.pid |
210 | + |
211 | + return proc |
212 | |
213 | def finish_application(self, app): |
214 | os.waitpid(app.pid, 0) |
215 | |
216 | === modified file 'python/libertine/LxdContainer.py' |
217 | --- python/libertine/LxdContainer.py 2017-02-22 15:35:46 +0000 |
218 | +++ python/libertine/LxdContainer.py 2017-02-23 15:25:56 +0000 |
219 | @@ -14,7 +14,6 @@ |
220 | |
221 | import contextlib |
222 | import crypt |
223 | -import dbus |
224 | import os |
225 | import psutil |
226 | import pylxd |
227 | @@ -368,10 +367,14 @@ |
228 | utils.get_logger().error("No such container '%s'" % self.container_id) |
229 | return False |
230 | |
231 | - if not (self.stop_container(wait=True) or self._container.status == 'Stopped'): |
232 | + if self._container.status == 'Running': |
233 | utils.get_logger().error("Canceling destruction due to running container") |
234 | return False |
235 | |
236 | + if self._container.status == 'Frozen' and not lxd_stop(self._container): |
237 | + utils.get_logger().error("Canceling destruction due to container not stopped") |
238 | + return False |
239 | + |
240 | self._container.delete() |
241 | |
242 | return self._delete_rootfs() |
243 | @@ -398,7 +401,8 @@ |
244 | if not self._try_get_container(): |
245 | return False |
246 | |
247 | - self._manager.container_operation_start(self.container_id) |
248 | + if not self._manager.container_operation_start(self.container_id): |
249 | + return False |
250 | |
251 | if self._container.status == 'Running': |
252 | return True |
253 | @@ -425,16 +429,11 @@ |
254 | if not self._try_get_container(): |
255 | return False |
256 | |
257 | - if self._manager.valid: |
258 | - if not self._manager.container_operation_finished(self.container_id): |
259 | - return False |
260 | - |
261 | - if not lxd_stop(self._container, freeze_on_stop=self._freeze_on_stop): |
262 | - return False |
263 | - |
264 | + if (self._manager.container_operation_finished(self.container_id, self._app_name, self._pid) and |
265 | + lxd_stop(self._container, freeze_on_stop=self._freeze_on_stop)): |
266 | return self._manager.container_stopped(self.container_id) |
267 | - else: |
268 | - return lxd_stop(self._container, freeze_on_stop=self._freeze_on_stop) |
269 | + |
270 | + return False |
271 | |
272 | def restart_container(self, wait=True): |
273 | if not self._try_get_container(): |
274 | @@ -444,17 +443,10 @@ |
275 | utils.get_logger().warning("Container {} is not frozen. Cannot restart.".format(self._container.name)) |
276 | return False |
277 | |
278 | - orig_freeze = self._freeze_on_stop |
279 | - self._freeze_on_stop = False |
280 | - |
281 | - # We never want to use the manager when restarting. |
282 | - self._manager = None |
283 | - |
284 | - if not (self.stop_container(wait=True) and self.start_container()): |
285 | + if not (lxd_stop(self._container) and lxd_start(self._container)): |
286 | return False |
287 | |
288 | - self._freeze_on_stop = orig_freeze |
289 | - return self.stop_container(wait=True) |
290 | + return lxd_stop(self._container, freeze_on_stop=self._freeze_on_stop) |
291 | |
292 | def start_application(self, app_exec_line, environ): |
293 | if not self._try_get_container(): |
294 | @@ -467,10 +459,16 @@ |
295 | if not self.start_container(home=environ['HOME']): |
296 | return False |
297 | |
298 | + self._app_name = app_exec_line[0] |
299 | + |
300 | args = self._lxc_args("sudo -E -u {} env PATH={}".format(environ['USER'], environ['PATH']), environ) |
301 | |
302 | args.extend(app_exec_line) |
303 | - return psutil.Popen(args) |
304 | + |
305 | + proc = psutil.Popen(args) |
306 | + self._pid = proc.pid |
307 | + |
308 | + return proc |
309 | |
310 | def finish_application(self, app): |
311 | app.wait() |
312 | |
313 | === modified file 'python/libertine/launcher/session.py' |
314 | --- python/libertine/launcher/session.py 2016-12-12 19:59:14 +0000 |
315 | +++ python/libertine/launcher/session.py 2017-02-23 15:25:56 +0000 |
316 | @@ -1,4 +1,4 @@ |
317 | -# Copyright 2016 Canonical Ltd. |
318 | +# Copyright 2016-2017 Canonical Ltd. |
319 | # |
320 | # This program is free software: you can redistribute it and/or modify it |
321 | # under the terms of the GNU General Public License version 3, as published |
322 | @@ -234,25 +234,36 @@ |
323 | handler, datum = key.data |
324 | handler(key.fd, datum) |
325 | self._container.finish_application(self._app) |
326 | + |
327 | + if self._config.container_id: |
328 | + self._remove_running_app() |
329 | + |
330 | self._stop_services() |
331 | |
332 | def start_application(self): |
333 | """Connect to the container and start the application running.""" |
334 | self._container.connect() |
335 | self.callback(self._container.disconnect) |
336 | - self._add_running_app() |
337 | self._app = self._container.start_application(self._config.exec_line, |
338 | self._config.session_environ) |
339 | + if self._app: |
340 | + self._add_running_app() |
341 | |
342 | def _add_running_app(self): |
343 | """Add a running app entry to ContainersConfig.json.""" |
344 | if self._config.container_id: |
345 | - ContainersConfig().add_running_app(self._config.container_id, self._config.exec_line[0]) |
346 | + ContainersConfig().add_running_app(self._config.container_id, self._config.exec_line[0], self._app.pid) |
347 | |
348 | def _remove_running_app(self): |
349 | """Remove a running app entry from ContainersConfig.json.""" |
350 | if self._config.container_id: |
351 | - ContainersConfig().delete_running_app(self._config.container_id, self._config.exec_line[0]) |
352 | + containers_config = ContainersConfig() |
353 | + running_app = containers_config.find_running_app_by_name_and_pid(self._config.container_id, |
354 | + self._config.exec_line[0], |
355 | + self._app.pid) |
356 | + |
357 | + if running_app: |
358 | + containers_config.delete_running_app(self._config.container_id, running_app) |
359 | |
360 | def _create_bridge_listener(self, bridge_config): |
361 | """Create a socket bridge listener for a socket bridge configuration. |
362 | @@ -343,9 +354,6 @@ |
363 | signal.signal(signal.SIGINT, self._sigint_handler) |
364 | signal.signal(signal.SIGTERM, self._sigterm_handler) |
365 | |
366 | - if self._config.container_id: |
367 | - self._remove_running_app() |
368 | - |
369 | for bridge_pair in self._config.socket_bridges: |
370 | os.remove(translate_to_real_address(bridge_pair.session_address)) |
371 | |
372 | |
373 | === modified file 'python/libertine/service/manager.py' |
374 | --- python/libertine/service/manager.py 2017-02-15 21:12:37 +0000 |
375 | +++ python/libertine/service/manager.py 2017-02-23 15:25:56 +0000 |
376 | @@ -15,7 +15,7 @@ |
377 | import dbus |
378 | import dbus.service |
379 | import libertine.service.task_dispatcher |
380 | -from collections import Counter |
381 | +import libertine.service.operations_state |
382 | from dbus.mainloop.glib import DBusGMainLoop |
383 | from libertine.service import container |
384 | from libertine import utils |
385 | @@ -29,8 +29,9 @@ |
386 | class Manager(dbus.service.Object): |
387 | def __init__(self): |
388 | utils.get_logger().debug("creating service") |
389 | - self._operations = Counter() |
390 | DBusGMainLoop(set_as_default=True) |
391 | + self._operations_state = libertine.service.operations_state.OperationsState() |
392 | + |
393 | try: |
394 | bus_name = dbus.service.BusName(LIBERTINE_MANAGER_NAME, |
395 | bus=dbus.SessionBus(), |
396 | @@ -124,28 +125,20 @@ |
397 | def container_operation_start(self, container): |
398 | utils.get_logger().debug("container_operation_start({})".format(container)) |
399 | |
400 | - if self._operations[container] == -1: |
401 | - return False |
402 | - |
403 | - self._operations[container] += 1 |
404 | - return True |
405 | + return self._operations_state.operation_start(container) |
406 | |
407 | @dbus.service.method(LIBERTINE_MANAGER_INTERFACE, |
408 | - in_signature='s', |
409 | + in_signature='ssi', |
410 | out_signature='b') |
411 | - def container_operation_finished(self, container): |
412 | + def container_operation_finished(self, container, app_name='', pid=0): |
413 | utils.get_logger().debug("container_operation_finished({})".format(container)) |
414 | - stop = False |
415 | - self._operations[container] -= 1 |
416 | - |
417 | - if self._operations[container] == 0: |
418 | - self._operations[container] -= 1 |
419 | - stop = True |
420 | - |
421 | - return stop |
422 | + |
423 | + return self._operations_state.operation_finished(container, app_name, pid) |
424 | |
425 | @dbus.service.method(LIBERTINE_MANAGER_INTERFACE, |
426 | - in_signature='s') |
427 | + in_signature='s', |
428 | + out_signature='b') |
429 | def container_stopped(self, container): |
430 | utils.get_logger().debug("container_stopped({})".format(container)) |
431 | - del self._operations[container] |
432 | + |
433 | + return self._operations_state.operation_stopped(container) |
434 | |
435 | === added file 'python/libertine/service/operations_state.py' |
436 | --- python/libertine/service/operations_state.py 1970-01-01 00:00:00 +0000 |
437 | +++ python/libertine/service/operations_state.py 2017-02-23 15:25:56 +0000 |
438 | @@ -0,0 +1,75 @@ |
439 | +# Copyright 2017 Canonical Ltd. |
440 | +# |
441 | +# This program is free software: you can redistribute it and/or modify |
442 | +# it under the terms of the GNU General Public License as published by |
443 | +# the Free Software Foundation; version 3 of the License. |
444 | +# |
445 | +# This program is distributed in the hope that it will be useful, |
446 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
447 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
448 | +# GNU General Public License for more details. |
449 | +# |
450 | +# You should have received a copy of the GNU General Public License |
451 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
452 | + |
453 | +import libertine.ContainersConfig |
454 | +import psutil |
455 | + |
456 | +from collections import Counter |
457 | +from libertine import utils |
458 | + |
459 | + |
460 | +class OperationsState(object): |
461 | + def __init__(self): |
462 | + self._get_running_apps_per_container() |
463 | + |
464 | + def _get_running_apps_per_container(self): |
465 | + self._invalid_apps = dict() |
466 | + self._operations = Counter() |
467 | + config = libertine.ContainersConfig.ContainersConfig() |
468 | + |
469 | + for container in config.get_containers(): |
470 | + running_apps = config.get_running_apps(container).copy() |
471 | + |
472 | + for app in running_apps: |
473 | + try: |
474 | + proc = psutil.Process(app['pid']) |
475 | + if app['appExecName'] in proc.cmdline(): |
476 | + self._operations[container] += 1 |
477 | + else: |
478 | + raise |
479 | + except: |
480 | + utils.get_logger().error("Container app {} is not valid.".format(app['appExecName'])) |
481 | + if container not in self._invalid_apps: |
482 | + self._invalid_apps[container] = [{app['appExecName'], app['pid']}] |
483 | + else: |
484 | + self._invalid_apps[container].append({app['appExecName'], app['pid']}) |
485 | + config.delete_running_app(container, app) |
486 | + continue |
487 | + |
488 | + def operation_start(self, container): |
489 | + if self._operations[container] == -1: |
490 | + return False |
491 | + |
492 | + self._operations[container] += 1 |
493 | + |
494 | + return True |
495 | + |
496 | + def operation_finished(self, container, app_name, pid): |
497 | + if container in self._invalid_apps and {app_name, pid} in self._invalid_apps[container]: |
498 | + self._invalid_apps[container].remove({app_name, pid}) |
499 | + if not self._invalid_apps[container]: |
500 | + del self._invalid_apps[container] |
501 | + else: |
502 | + self._operations[container] -= 1 |
503 | + |
504 | + if self._operations[container] == 0: |
505 | + self._operations[container] = -1 |
506 | + return True |
507 | + |
508 | + return False |
509 | + |
510 | + def operation_stopped(self, container): |
511 | + del self._operations[container] |
512 | + |
513 | + return True |
PASSED: Continuous integration, rev:408 /jenkins. canonical. com/libertine/ job/lp- libertine- ci/390/ /jenkins. canonical. com/libertine/ job/build/ 744 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=amd64, release= xenial+ overlay, testname= default/ 612 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=amd64, release= zesty,testname= default/ 612 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=i386, release= xenial+ overlay, testname= default/ 612 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=i386, release= zesty,testname= default/ 612 /jenkins. canonical. com/libertine/ job/build- 0-fetch/ 754 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= xenial+ overlay/ 735 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= xenial+ overlay/ 735/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= zesty/735 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= zesty/735/ artifact/ output/ *zip*/output. zip /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= xenial+ overlay/ 735 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= xenial+ overlay/ 735/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= zesty/735 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= zesty/735/ artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/libertine/ job/lp- libertine- ci/390/ rebuild
https:/