Merge lp:~townsend/libertine/consolidate-managers into lp:libertine
- consolidate-managers
- Merge into devel
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Larry Price | ||||
Approved revision: | 395 | ||||
Merged at revision: | 389 | ||||
Proposed branch: | lp:~townsend/libertine/consolidate-managers | ||||
Merge into: | lp:libertine | ||||
Diff against target: |
932 lines (+166/-475) 19 files modified
data/CMakeLists.txt (+0/-2) data/com.canonical.libertine.LxcManager.service (+0/-3) data/com.canonical.libertine.LxdManager.service (+0/-3) debian/control (+0/-2) debian/python3-libertine-lxc.install (+0/-2) debian/python3-libertine-lxd.install (+0/-2) debian/python3-libertine.install (+0/-1) python/libertine/LxcContainer.py (+81/-36) python/libertine/LxdContainer.py (+46/-54) python/libertine/lifecycle/ContainerLifecycleService.py (+0/-76) python/libertine/lifecycle/ContainerLifecycleServiceRunner.py (+0/-46) python/libertine/lifecycle/LifecycleResult.py (+0/-37) python/libertine/lifecycle/__init__.py (+0/-23) python/libertine/service/manager.py (+36/-0) tools/CMakeLists.txt (+3/-3) tools/libertine-lxc-manager (+0/-109) tools/libertine-lxc-manager.1 (+0/-9) tools/libertine-lxd-manager (+0/-58) tools/libertine-lxd-manager.1 (+0/-9) |
||||
To merge this branch: | bzr merge lp:~townsend/libertine/consolidate-managers | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Larry Price | Approve | ||
Libertine CI Bot | continuous-integration | Approve | |
Review via email: mp+316044@code.launchpad.net |
Commit message
Optimizations regarding the lx[cd] managers:
- Move start/stop counting into libertined and remove the managers.
- Move all start/stop operations to the respective backends.
- Dynamic bind mounts are now handled during the backend's start_container() method.
Description of the change
Libertine CI Bot (libertine-ci-bot) wrote : | # |
- 395. By Christopher Townsend
-
Don't need to set self._config twice.
Libertine CI Bot (libertine-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:395
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 'data/CMakeLists.txt' |
2 | --- data/CMakeLists.txt 2017-01-20 20:37:02 +0000 |
3 | +++ data/CMakeLists.txt 2017-02-01 15:34:03 +0000 |
4 | @@ -9,6 +9,4 @@ |
5 | install(FILES libertine-lxc-sudo libertine-lxd-sudo |
6 | DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/sudoers.d) |
7 | install(FILES com.canonical.libertine.Service.service |
8 | - com.canonical.libertine.LxcManager.service |
9 | - com.canonical.libertine.LxdManager.service |
10 | DESTINATION ${CMAKE_INSTALL_DATADIR}/dbus-1/services) |
11 | |
12 | === removed file 'data/com.canonical.libertine.LxcManager.service' |
13 | --- data/com.canonical.libertine.LxcManager.service 2016-08-19 14:02:31 +0000 |
14 | +++ data/com.canonical.libertine.LxcManager.service 1970-01-01 00:00:00 +0000 |
15 | @@ -1,3 +0,0 @@ |
16 | -[D-BUS Service] |
17 | -Name=com.canonical.libertine.LxcManager |
18 | -Exec=/usr/bin/libertine-lxc-manager |
19 | |
20 | === removed file 'data/com.canonical.libertine.LxdManager.service' |
21 | --- data/com.canonical.libertine.LxdManager.service 2016-12-20 20:23:16 +0000 |
22 | +++ data/com.canonical.libertine.LxdManager.service 1970-01-01 00:00:00 +0000 |
23 | @@ -1,3 +0,0 @@ |
24 | -[D-BUS Service] |
25 | -Name=com.canonical.libertine.LxdManager |
26 | -Exec=/usr/bin/libertine-lxd-manager |
27 | |
28 | === modified file 'debian/control' |
29 | --- debian/control 2017-01-26 16:59:53 +0000 |
30 | +++ debian/control 2017-02-01 15:34:03 +0000 |
31 | @@ -177,7 +177,6 @@ |
32 | python3-libertine, |
33 | python3-lxc, |
34 | uidmap, |
35 | - python3-gi, |
36 | ${misc:Depends}, |
37 | ${python3:Depends} |
38 | Replaces: libertine-tools (<< 1.3) |
39 | @@ -195,7 +194,6 @@ |
40 | python3-libertine, |
41 | python3-pexpect, |
42 | python3-pylxd, |
43 | - python3-gi, |
44 | ${misc:Depends}, |
45 | ${python3:Depends} |
46 | Description: Python3 scripts for the Libertine application sandbox |
47 | |
48 | === modified file 'debian/python3-libertine-lxc.install' |
49 | --- debian/python3-libertine-lxc.install 2016-10-07 21:09:41 +0000 |
50 | +++ debian/python3-libertine-lxc.install 2017-02-01 15:34:03 +0000 |
51 | @@ -1,6 +1,4 @@ |
52 | etc/sudoers.d/libertine-lxc-sudo |
53 | -usr/bin/libertine-lxc-manager |
54 | usr/bin/libertine-lxc-setup |
55 | usr/lib/python*/*/libertine/LxcContainer.py |
56 | -usr/share/dbus-1/services/com.canonical.libertine.LxcManager.service |
57 | usr/share/libertine/libertine-lxc.conf |
58 | |
59 | === modified file 'debian/python3-libertine-lxd.install' |
60 | --- debian/python3-libertine-lxd.install 2016-12-21 20:37:57 +0000 |
61 | +++ debian/python3-libertine-lxd.install 2017-02-01 15:34:03 +0000 |
62 | @@ -1,5 +1,3 @@ |
63 | etc/sudoers.d/libertine-lxd-sudo |
64 | usr/bin/libertine-lxd-setup |
65 | -usr/bin/libertine-lxd-manager |
66 | usr/lib/python*/*/libertine/LxdContainer.py |
67 | -usr/share/dbus-1/services/com.canonical.libertine.LxdManager.service |
68 | |
69 | === modified file 'debian/python3-libertine.install' |
70 | --- debian/python3-libertine.install 2017-01-20 18:43:08 +0000 |
71 | +++ debian/python3-libertine.install 2017-02-01 15:34:03 +0000 |
72 | @@ -4,5 +4,4 @@ |
73 | usr/lib/python*/*/libertine/Libertine.py |
74 | usr/lib/python*/*/libertine/__init__.py |
75 | usr/lib/python*/*/libertine/launcher |
76 | -usr/lib/python*/*/libertine/lifecycle |
77 | usr/lib/python*/*/libertine/utils.py |
78 | |
79 | === modified file 'python/libertine/LxcContainer.py' |
80 | --- python/libertine/LxcContainer.py 2017-01-25 18:48:36 +0000 |
81 | +++ python/libertine/LxcContainer.py 2017-02-01 15:34:03 +0000 |
82 | @@ -22,17 +22,15 @@ |
83 | import subprocess |
84 | import sys |
85 | import tempfile |
86 | +import time |
87 | |
88 | -from .lifecycle import LifecycleResult |
89 | from .Libertine import BaseContainer |
90 | +from .service.manager import LIBERTINE_MANAGER_NAME, LIBERTINE_STORE_PATH |
91 | from . import utils, HostInfo |
92 | |
93 | |
94 | home_path = os.environ['HOME'] |
95 | |
96 | -LIBERTINE_LXC_MANAGER_NAME = "com.canonical.libertine.LxcManager" |
97 | -LIBERTINE_LXC_MANAGER_PATH = "/LxcManager" |
98 | - |
99 | |
100 | def _check_lxc_net_entry(entry): |
101 | lxc_net_file = open('/etc/lxc/lxc-usernet') |
102 | @@ -57,14 +55,6 @@ |
103 | return os.path.join(home_path, '.config', 'lxc') |
104 | |
105 | |
106 | -def get_lxc_manager_dbus_name(): |
107 | - return LIBERTINE_LXC_MANAGER_NAME |
108 | - |
109 | - |
110 | -def get_lxc_manager_dbus_path(): |
111 | - return LIBERTINE_LXC_MANAGER_PATH |
112 | - |
113 | - |
114 | def lxc_container(container_id): |
115 | config_path = utils.get_libertine_containers_dir_path() |
116 | if not os.path.exists(config_path): |
117 | @@ -103,19 +93,23 @@ |
118 | |
119 | if container.state == 'STOPPED': |
120 | if not container.start(): |
121 | - return LifecycleResult("Container failed to start.") |
122 | + utils.get_logger().error("Container failed to start.") |
123 | + return False |
124 | elif container.state == 'FROZEN': |
125 | if not container.unfreeze(): |
126 | - return LifecycleResult("Container failed to unfreeze.") |
127 | + utils.get_logger().error("Container failed to unfreeze.") |
128 | + return False |
129 | |
130 | if not container.wait("RUNNING", 10): |
131 | - return LifecycleResult("Container failed to enter the RUNNING state.") |
132 | + utils.get_logger().error("Container failed to enter the RUNNING state.") |
133 | + return False |
134 | |
135 | if not container.get_ips(timeout=30): |
136 | lxc_stop(container) |
137 | - return LifecycleResult("Not able to connect to the network.") |
138 | + utils.get_logger().error("Not able to connect to the network.") |
139 | + return False |
140 | |
141 | - return LifecycleResult() |
142 | + return True |
143 | |
144 | |
145 | def lxc_stop(container, freeze_on_stop=False): |
146 | @@ -169,27 +163,85 @@ |
147 | if utils.set_session_dbus_env_var(): |
148 | try: |
149 | bus = dbus.SessionBus() |
150 | - self.lxc_manager_interface = bus.get_object(get_lxc_manager_dbus_name(), get_lxc_manager_dbus_path()) |
151 | + self.lxc_manager_interface = bus.get_object(LIBERTINE_MANAGER_NAME, LIBERTINE_STORE_PATH) |
152 | except dbus.exceptions.DBusException: |
153 | pass |
154 | |
155 | + def _setup_pulse(self): |
156 | + pulse_socket_path = os.path.join(utils.get_libertine_runtime_dir(), 'pulse_socket') |
157 | + |
158 | + os.environ['PULSE_SERVER'] = pulse_socket_path |
159 | + |
160 | + lsof_cmd = 'lsof -n %s' % pulse_socket_path |
161 | + args = shlex.split(lsof_cmd) |
162 | + lsof = subprocess.Popen(args, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) |
163 | + lsof.wait() |
164 | + |
165 | + if not os.path.exists(pulse_socket_path) or lsof.returncode == 1: |
166 | + pactl_cmd = ( |
167 | + 'pactl load-module module-native-protocol-unix auth-anonymous=1 socket=%s' |
168 | + % pulse_socket_path) |
169 | + args = shlex.split(pactl_cmd) |
170 | + subprocess.Popen(args).wait() |
171 | + |
172 | + def _dynamic_bind_mounts(self): |
173 | + self._config.refresh_database() |
174 | + mounts = self._sanitize_bind_mounts(utils.get_common_xdg_user_directories() + \ |
175 | + self._config.get_container_bind_mounts(self.container_id)) |
176 | + |
177 | + data_dir = utils.get_libertine_container_home_dir(self.container_id) |
178 | + for user_dir in utils.generate_binding_directories(mounts, home_path): |
179 | + if os.path.isabs(user_dir[1]): |
180 | + path = user_dir[1].strip('/') |
181 | + fullpath = os.path.join(utils.get_libertine_container_rootfs_path(self.container_id), path) |
182 | + else: |
183 | + path = "{}/{}".format(home_path.strip('/'), user_dir[1]) |
184 | + fullpath = os.path.join(data_dir, user_dir[1]) |
185 | + |
186 | + os.makedirs(fullpath, exist_ok=True) |
187 | + |
188 | + utils.get_logger().debug("Mounting {}:{} in container {}".format(user_dir[0], path, self.container_id)) |
189 | + xdg_user_dir_entry = ( |
190 | + "%s %s none bind,create=dir,optional" |
191 | + % (user_dir[0], path) |
192 | + ) |
193 | + self.container.append_config_item("lxc.mount.entry", xdg_user_dir_entry) |
194 | + |
195 | + def _sanitize_bind_mounts(self, mounts): |
196 | + return [mount.replace(" ", "\\040") for mount in mounts] |
197 | + |
198 | def timezone_needs_update(self): |
199 | with open(os.path.join(self.root_path, 'etc', 'timezone'), 'r') as fd: |
200 | return fd.read().strip('\n') != self.host_info.get_host_timezone() |
201 | |
202 | def start_container(self): |
203 | if self.lxc_manager_interface: |
204 | - result = LifecycleResult.from_dict(self.lxc_manager_interface.container_service_start(self.container_id)) |
205 | - else: |
206 | - result = lxc_start(self.container) |
207 | - |
208 | - if not result.success: |
209 | + retries = 0 |
210 | + while not self.lxc_manager_interface.container_operation_start(self.container_id): |
211 | + retries += 1 |
212 | + if retries > 5: |
213 | + return False |
214 | + time.sleep(.5) |
215 | + |
216 | + if self.container.state == 'RUNNING': |
217 | + return True |
218 | + |
219 | + if self.container.state == 'STOPPED': |
220 | + self._dynamic_bind_mounts() |
221 | + self._setup_pulse() |
222 | + |
223 | + if not lxc_start(self.container): |
224 | _dump_lxc_log(result.logfile) |
225 | - raise RuntimeError(result.error) |
226 | + return False |
227 | + |
228 | + return True |
229 | |
230 | def stop_container(self): |
231 | if self.lxc_manager_interface: |
232 | - self.lxc_manager_interface.container_service_stop(self.container_id, {'freeze': self._freeze_on_stop}) |
233 | + stop = self.lxc_manager_interface.container_operation_finished(self.container_id) |
234 | + if stop: |
235 | + lxc_stop(self.container, self._freeze_on_stop) |
236 | + self.lxc_manager_interface.container_stopped(self.container_id) |
237 | else: |
238 | lxc_stop(self.container, self._freeze_on_stop) |
239 | |
240 | @@ -261,10 +313,7 @@ |
241 | self.create_libertine_config() |
242 | |
243 | utils.get_logger().info("starting container ...") |
244 | - try: |
245 | - self.start_container() |
246 | - except RuntimeError as e: |
247 | - utils.get_logger().error("Container failed to start: %s" % e) |
248 | + if not self.start_container(): |
249 | self.destroy_libertine_container() |
250 | return False |
251 | |
252 | @@ -333,11 +382,8 @@ |
253 | os.environ.clear() |
254 | os.environ.update(environ) |
255 | |
256 | - result = LifecycleResult.from_dict(self.lxc_manager_interface.container_service_start(self.container_id)) |
257 | - |
258 | - if not result.success: |
259 | - _dump_lxc_log(get_logfile(self.container)) |
260 | - utils.get_logger().error("%s" % result.error) |
261 | + if not self.start_container(): |
262 | + self.lxc_manager_interface.container_stopped(self.container_id) |
263 | return |
264 | |
265 | self.window_manager = self.container.attach(lxc.attach_run_command, |
266 | @@ -357,5 +403,4 @@ |
267 | |
268 | utils.terminate_window_manager(psutil.Process(self.window_manager)) |
269 | |
270 | - # Tell libertine-lxc-manager that the app has stopped. |
271 | - self.lxc_manager_interface.container_service_stop(self.container_id, {'freeze': self._freeze_on_stop}) |
272 | + self.stop_container() |
273 | |
274 | === modified file 'python/libertine/LxdContainer.py' |
275 | --- python/libertine/LxdContainer.py 2017-01-27 16:43:53 +0000 |
276 | +++ python/libertine/LxdContainer.py 2017-02-01 15:34:03 +0000 |
277 | @@ -22,20 +22,8 @@ |
278 | import subprocess |
279 | import time |
280 | |
281 | -from .lifecycle import LifecycleResult |
282 | from libertine import Libertine, utils, HostInfo |
283 | - |
284 | - |
285 | -LIBERTINE_LXC_MANAGER_NAME = "com.canonical.libertine.LxdManager" |
286 | -LIBERTINE_LXC_MANAGER_PATH = "/LxdManager" |
287 | - |
288 | - |
289 | -def get_lxd_manager_dbus_name(): |
290 | - return LIBERTINE_LXC_MANAGER_NAME |
291 | - |
292 | - |
293 | -def get_lxd_manager_dbus_path(): |
294 | - return LIBERTINE_LXC_MANAGER_PATH |
295 | +from .service.manager import LIBERTINE_MANAGER_NAME, LIBERTINE_STORE_PATH |
296 | |
297 | |
298 | def _get_devices_map(): |
299 | @@ -148,14 +136,15 @@ |
300 | container.sync(rollback=True) # required for pylxd=2.0.x |
301 | |
302 | if container.status != 'Running': |
303 | - return LifecycleResult("Container {} failed to start".format(container.name)) |
304 | + utils.get_logger().error("Container {} failed to start".format(container.name)) |
305 | + return False |
306 | |
307 | - return LifecycleResult() |
308 | + return True |
309 | |
310 | |
311 | def lxd_stop(container, wait=True, freeze_on_stop=False): |
312 | if container.status == 'Stopped': |
313 | - return LifecycleResult() |
314 | + return True |
315 | |
316 | if freeze_on_stop: |
317 | container.freeze(wait=wait) |
318 | @@ -166,11 +155,13 @@ |
319 | |
320 | if wait: |
321 | if freeze_on_stop and container.status != 'Frozen': |
322 | - return LifecycleResult("Container {} failed to freeze".format(container.name)) |
323 | - elif container.status != 'Stopped': |
324 | - return LifecycleResult("Container {} failed to stop".format(container.name)) |
325 | + utils.get_logger().error("Container {} failed to freeze".format(container.name)) |
326 | + return False |
327 | + elif not freeze_on_stop and container.status != 'Stopped': |
328 | + utils.get_logger().error("Container {} failed to stop".format(container.name)) |
329 | + return False |
330 | |
331 | - return LifecycleResult() |
332 | + return True |
333 | |
334 | |
335 | def _lxd_save(entity, error, wait=True): |
336 | @@ -318,7 +309,7 @@ |
337 | try: |
338 | if utils.set_session_dbus_env_var(): |
339 | bus = dbus.SessionBus() |
340 | - self._manager = bus.get_object(get_lxd_manager_dbus_name(), get_lxd_manager_dbus_path()) |
341 | + self._manager = bus.get_object(LIBERTINE_MANAGER_NAME, LIBERTINE_STORE_PATH) |
342 | except PermissionError as e: |
343 | utils.get_logger().warning("Failed to set dbus session env var") |
344 | except dbus.exceptions.DBusException: |
345 | @@ -417,37 +408,52 @@ |
346 | proc = subprocess.Popen(self._lxc_args(command)) |
347 | return proc.wait() |
348 | |
349 | - def start_container(self): |
350 | + def start_container(self, home=env_home_path()): |
351 | if not self._try_get_container(): |
352 | return False |
353 | |
354 | if self._manager: |
355 | - result = LifecycleResult.from_dict(self._manager.container_service_start(self.container_id)) |
356 | - else: |
357 | - result = lxd_start(self._container) |
358 | - |
359 | - if not result.success: |
360 | - utils.get_logger().error(result.error) |
361 | + retries = 0 |
362 | + while not self._manager.container_operation_start(self.container_id): |
363 | + retries += 1 |
364 | + if retries > 5: |
365 | + return False |
366 | + time.sleep(.5) |
367 | + |
368 | + if self._container.status == 'Running': |
369 | + return True |
370 | + |
371 | + requires_remount = self._container.status == 'Stopped' |
372 | + |
373 | + if requires_remount: |
374 | + update_libertine_profile(self._client) |
375 | + update_bind_mounts(self._container, self._config, home) |
376 | + |
377 | + if not lxd_start(self._container): |
378 | return False |
379 | |
380 | if not _wait_for_network(self._container): |
381 | utils.get_logger().warning("Network unavailable in container '{}'".format(self.container_id)) |
382 | |
383 | - return result.success |
384 | + if requires_remount: |
385 | + self.run_in_container("/usr/bin/libertine-lxd-mount-update") |
386 | + |
387 | + return True |
388 | |
389 | def stop_container(self, wait=False): |
390 | if not self._try_get_container(): |
391 | return False |
392 | |
393 | if self._manager: |
394 | - result = LifecycleResult.from_dict(self._manager.container_service_stop(self.container_id, {'wait': wait, 'freeze': self._freeze_on_stop})) |
395 | + stop = self._manager.container_operation_finished(self.container_id) |
396 | + if stop: |
397 | + if not lxd_stop(self._container, freeze_on_stop=self._freeze_on_stop): |
398 | + return False |
399 | + self._manager.container_stopped(self.container_id) |
400 | else: |
401 | - result = lxd_stop(self._container, wait, self._freeze_on_stop) |
402 | - |
403 | - if not result.success: |
404 | - utils.get_logger().error(result.error) |
405 | - |
406 | - return result.success |
407 | + return lxd_stop(self._container, freeze_on_stop=self._freeze_on_stop) |
408 | + |
409 | + return True |
410 | |
411 | def _get_matchbox_pids(self): |
412 | p = subprocess.Popen(self._lxc_args('pgrep matchbox'), stdout=subprocess.PIPE) |
413 | @@ -481,22 +487,11 @@ |
414 | if utils.is_snap_environment(): |
415 | environ['HOME'] = '/home/{}'.format(environ['USER']) |
416 | |
417 | - requires_remount = self._container.status != 'Running' |
418 | - |
419 | - if self._manager: |
420 | - result = LifecycleResult.from_dict(self._manager.container_service_start(self.container_id)) |
421 | - else: |
422 | - update_libertine_profile(self._client) |
423 | - update_bind_mounts(self._container, self._config, environ['HOME']) |
424 | - result = lxd_start(self._container) |
425 | - |
426 | - if not result.success: |
427 | - utils.get_logger().error(result.error) |
428 | + if not self.start_container(home=environ['HOME']): |
429 | + if self._manager: |
430 | + self.lxc_manager_interface.container_stopped(self.container_id) |
431 | return False |
432 | |
433 | - if requires_remount: |
434 | - self.run_in_container("/usr/bin/libertine-lxd-mount-update") |
435 | - |
436 | args = self._lxc_args("sudo -E -u {} env PATH={}".format(environ['USER'], environ['PATH']), environ) |
437 | |
438 | self._start_window_manager(args.copy()) |
439 | @@ -518,10 +513,7 @@ |
440 | |
441 | app.wait() |
442 | |
443 | - if self._manager: |
444 | - self._manager.container_service_stop(self.container_id, {'freeze': self._freeze_on_stop}) |
445 | - else: |
446 | - lxd_stop(self._container, False, self._freeze_on_stop) |
447 | + self.stop_container() |
448 | |
449 | def copy_file_to_container(self, source, dest): |
450 | with open(source, 'rb') as f: |
451 | |
452 | === removed directory 'python/libertine/lifecycle' |
453 | === removed file 'python/libertine/lifecycle/ContainerLifecycleService.py' |
454 | --- python/libertine/lifecycle/ContainerLifecycleService.py 2017-01-19 15:01:38 +0000 |
455 | +++ python/libertine/lifecycle/ContainerLifecycleService.py 1970-01-01 00:00:00 +0000 |
456 | @@ -1,76 +0,0 @@ |
457 | -#!/usr/bin/python3 |
458 | -# -*- coding: utf-8 -*- |
459 | - |
460 | -# Copyright (C) 2016 Canonical Ltd. |
461 | - |
462 | -# This program is free software: you can redistribute it and/or modify |
463 | -# it under the terms of the GNU General Public License as published by |
464 | -# the Free Software Foundation; version 3 of the License. |
465 | -# |
466 | -# This program is distributed in the hope that it will be useful, |
467 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
468 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
469 | -# GNU General Public License for more details. |
470 | -# |
471 | -# You should have received a copy of the GNU General Public License |
472 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
473 | - |
474 | - |
475 | -import dbus.exceptions |
476 | -import dbus.service |
477 | - |
478 | -from .LifecycleResult import LifecycleResult |
479 | -from collections import Counter |
480 | -from dbus.mainloop.glib import DBusGMainLoop |
481 | -from libertine import utils |
482 | - |
483 | - |
484 | -LIBERTINE_CONTAINER_LIFECYCLE_INTERFACE = 'com.canonical.libertine.ContainerLifecycle' |
485 | - |
486 | - |
487 | -class ContainerLifecycleService(dbus.service.Object): |
488 | - def __init__(self, service_name, service_path): |
489 | - self._operations = Counter() |
490 | - |
491 | - DBusGMainLoop(set_as_default=True) |
492 | - try: |
493 | - bus_name = dbus.service.BusName(service_name, |
494 | - bus=dbus.SessionBus(), |
495 | - do_not_queue=True) |
496 | - except dbus.exceptions.NameExistsException: |
497 | - utils.get_logger().error("service is already running") |
498 | - raise |
499 | - super().__init__(bus_name, service_path) |
500 | - |
501 | - def start(self, container): |
502 | - raise NotImplementedError("Subclasses must implement start(container)") |
503 | - |
504 | - def stop(self, container, options={}): |
505 | - raise NotImplementedError("Subclasses must implement stop(container)") |
506 | - |
507 | - @dbus.service.method(LIBERTINE_CONTAINER_LIFECYCLE_INTERFACE, |
508 | - in_signature='s', |
509 | - out_signature='a{ss}') |
510 | - def container_service_start(self, container): |
511 | - utils.get_logger().debug("container_service_start({})".format(container)) |
512 | - |
513 | - result = self.start(container) |
514 | - |
515 | - if result.success: |
516 | - self._operations[container] += 1 |
517 | - |
518 | - return result.to_dict() |
519 | - |
520 | - @dbus.service.method(LIBERTINE_CONTAINER_LIFECYCLE_INTERFACE, |
521 | - in_signature='sa{ss}', |
522 | - out_signature='a{ss}') |
523 | - def container_service_stop(self, container, options={}): |
524 | - utils.get_logger().debug("container_service_stop({}, {})".format(container, options)) |
525 | - self._operations[container] -= 1 |
526 | - result = LifecycleResult() |
527 | - |
528 | - if self._operations[container] == 0: |
529 | - result = self.stop(container, options) |
530 | - del self._operations[container] |
531 | - |
532 | - return result.to_dict() |
533 | |
534 | === removed file 'python/libertine/lifecycle/ContainerLifecycleServiceRunner.py' |
535 | --- python/libertine/lifecycle/ContainerLifecycleServiceRunner.py 2016-12-21 20:39:40 +0000 |
536 | +++ python/libertine/lifecycle/ContainerLifecycleServiceRunner.py 1970-01-01 00:00:00 +0000 |
537 | @@ -1,46 +0,0 @@ |
538 | -#!/usr/bin/python3 |
539 | -# -*- coding: utf-8 -*- |
540 | - |
541 | -# Copyright (C) 2016 Canonical Ltd. |
542 | - |
543 | -# This program is free software: you can redistribute it and/or modify |
544 | -# it under the terms of the GNU General Public License as published by |
545 | -# the Free Software Foundation; version 3 of the License. |
546 | -# |
547 | -# This program is distributed in the hope that it will be useful, |
548 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
549 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
550 | -# GNU General Public License for more details. |
551 | -# |
552 | -# You should have received a copy of the GNU General Public License |
553 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
554 | - |
555 | -import signal |
556 | - |
557 | -from gi.repository import GLib |
558 | -from libertine import utils |
559 | - |
560 | - |
561 | -class ContainerLifecycleServiceRunner(object): |
562 | - def __init__(self, service): |
563 | - self._service = service |
564 | - |
565 | - def _sigterm(self, sig): |
566 | - utils.get_logger().warning("Received SIGTERM") |
567 | - self._shutdown() |
568 | - |
569 | - def _shutdown(self): |
570 | - utils.get_logger().info("Shutting down") |
571 | - GLib.MainLoop().quit() |
572 | - |
573 | - def run(self): |
574 | - GLib.unix_signal_add(GLib.PRIORITY_HIGH, |
575 | - signal.SIGTERM, |
576 | - self._sigterm, |
577 | - None) |
578 | - |
579 | - try: |
580 | - utils.get_logger().info("Starting main loop") |
581 | - GLib.MainLoop().run() |
582 | - except KeyboardInterrupt: |
583 | - self._shutdown() |
584 | |
585 | === removed file 'python/libertine/lifecycle/LifecycleResult.py' |
586 | --- python/libertine/lifecycle/LifecycleResult.py 2016-12-21 18:26:51 +0000 |
587 | +++ python/libertine/lifecycle/LifecycleResult.py 1970-01-01 00:00:00 +0000 |
588 | @@ -1,37 +0,0 @@ |
589 | -#!/usr/bin/python3 |
590 | -# -*- coding: utf-8 -*- |
591 | - |
592 | -# Copyright (C) 2016 Canonical Ltd. |
593 | - |
594 | -# This program is free software: you can redistribute it and/or modify |
595 | -# it under the terms of the GNU General Public License as published by |
596 | -# the Free Software Foundation; version 3 of the License. |
597 | -# |
598 | -# This program is distributed in the hope that it will be useful, |
599 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
600 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
601 | -# GNU General Public License for more details. |
602 | -# |
603 | -# You should have received a copy of the GNU General Public License |
604 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
605 | - |
606 | -class LifecycleResult(object): |
607 | - def __init__(self, error=''): |
608 | - self._error = error |
609 | - |
610 | - @property |
611 | - def error(self): |
612 | - return self._error or '' |
613 | - |
614 | - @property |
615 | - def success(self): |
616 | - return self.error == '' |
617 | - |
618 | - @classmethod |
619 | - def from_dict(kls, d): |
620 | - return LifecycleResult(d.get('error', None)) |
621 | - |
622 | - def to_dict(self): |
623 | - return { |
624 | - 'error': self.error |
625 | - } |
626 | |
627 | === removed file 'python/libertine/lifecycle/__init__.py' |
628 | --- python/libertine/lifecycle/__init__.py 2016-12-21 18:26:51 +0000 |
629 | +++ python/libertine/lifecycle/__init__.py 1970-01-01 00:00:00 +0000 |
630 | @@ -1,23 +0,0 @@ |
631 | -# Copyright 2016 Canonical Ltd. |
632 | -# |
633 | -# This program is free software: you can redistribute it and/or modify it |
634 | -# under the terms of the GNU General Public License version 3, as published |
635 | -# by the Free Software Foundation. |
636 | -# |
637 | -# This program is distributed in the hope that it will be useful, but |
638 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
639 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
640 | -# PURPOSE. See the GNU General Public License for more details. |
641 | -# |
642 | -# You should have received a copy of the GNU General Public License along |
643 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
644 | - |
645 | -from .ContainerLifecycleServiceRunner import ContainerLifecycleServiceRunner |
646 | -from .ContainerLifecycleService import ContainerLifecycleService |
647 | -from .LifecycleResult import LifecycleResult |
648 | - |
649 | -__all__ = [ |
650 | - 'ContainerLifecycleServiceRunner', |
651 | - 'ContainerLifecycleService', |
652 | - 'LifecycleResult' |
653 | - ] |
654 | |
655 | === modified file 'python/libertine/service/manager.py' |
656 | --- python/libertine/service/manager.py 2017-01-24 18:00:57 +0000 |
657 | +++ python/libertine/service/manager.py 2017-02-01 15:34:03 +0000 |
658 | @@ -15,6 +15,7 @@ |
659 | import dbus |
660 | import dbus.service |
661 | import libertine.service.task_dispatcher |
662 | +from collections import Counter |
663 | from dbus.mainloop.glib import DBusGMainLoop |
664 | from libertine.service import container |
665 | from libertine import utils |
666 | @@ -28,6 +29,7 @@ |
667 | class Manager(dbus.service.Object): |
668 | def __init__(self): |
669 | utils.get_logger().debug("creating service") |
670 | + self._operations = Counter() |
671 | DBusGMainLoop(set_as_default=True) |
672 | try: |
673 | bus_name = dbus.service.BusName(LIBERTINE_MANAGER_NAME, |
674 | @@ -120,3 +122,37 @@ |
675 | def remove(self, container_id, package_name): |
676 | utils.get_logger().debug("remove('%s', '%s')" % (container_id, package_name)) |
677 | return self._dispatcher.remove(container_id, package_name) |
678 | + |
679 | + # Container Lifecycle |
680 | + |
681 | + @dbus.service.method(LIBERTINE_MANAGER_INTERFACE, |
682 | + in_signature='s', |
683 | + out_signature='b') |
684 | + def container_operation_start(self, container): |
685 | + utils.get_logger().debug("container_operation_start({})".format(container)) |
686 | + |
687 | + if self._operations[container] == -1: |
688 | + return False |
689 | + |
690 | + self._operations[container] += 1 |
691 | + return True |
692 | + |
693 | + @dbus.service.method(LIBERTINE_MANAGER_INTERFACE, |
694 | + in_signature='s', |
695 | + out_signature='b') |
696 | + def container_operation_finished(self, container): |
697 | + utils.get_logger().debug("container_operation_finished({})".format(container)) |
698 | + stop = False |
699 | + self._operations[container] -= 1 |
700 | + |
701 | + if self._operations[container] == 0: |
702 | + self._operations[container] -= 1 |
703 | + stop = True |
704 | + |
705 | + return stop |
706 | + |
707 | + @dbus.service.method(LIBERTINE_MANAGER_INTERFACE, |
708 | + in_signature='s') |
709 | + def container_stopped(self, container): |
710 | + utils.get_logger().debug("container_stopped({})".format(container)) |
711 | + del self._operations[container] |
712 | |
713 | === modified file 'tools/CMakeLists.txt' |
714 | --- tools/CMakeLists.txt 2016-12-21 20:57:15 +0000 |
715 | +++ tools/CMakeLists.txt 2017-02-01 15:34:03 +0000 |
716 | @@ -1,8 +1,8 @@ |
717 | -install(PROGRAMS libertine-container-manager libertine-launch libertine-lxc-manager libertine-lxd-manager |
718 | +install(PROGRAMS libertine-container-manager libertine-launch |
719 | libertine-xmir libertine-lxc-setup libertine-lxd-setup libertined |
720 | DESTINATION ${CMAKE_INSTALL_BINDIR}) |
721 | -install(FILES libertine-launch.1 libertine-container-manager.1 libertine-lxc-manager.1 |
722 | - libertine-lxd-manager.1 libertine-xmir.1 |
723 | +install(FILES libertine-launch.1 libertine-container-manager.1 |
724 | + libertine-xmir.1 |
725 | DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 |
726 | COMPONENT doc) |
727 | install(FILES completions/libertine-container-manager |
728 | |
729 | === removed file 'tools/libertine-lxc-manager' |
730 | --- tools/libertine-lxc-manager 2017-01-25 18:48:36 +0000 |
731 | +++ tools/libertine-lxc-manager 1970-01-01 00:00:00 +0000 |
732 | @@ -1,109 +0,0 @@ |
733 | -#!/usr/bin/python3 |
734 | -# -*- coding: utf-8 -*- |
735 | - |
736 | -# Copyright (C) 2016-2017 Canonical Ltd. |
737 | -# Author: Christopher Townsend <christopher.townsend@canonical.com> |
738 | - |
739 | -# This program is free software: you can redistribute it and/or modify |
740 | -# it under the terms of the GNU General Public License as published by |
741 | -# the Free Software Foundation; version 3 of the License. |
742 | -# |
743 | -# This program is distributed in the hope that it will be useful, |
744 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
745 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
746 | -# GNU General Public License for more details. |
747 | -# |
748 | -# You should have received a copy of the GNU General Public License |
749 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
750 | - |
751 | -import libertine.LxcContainer |
752 | -import libertine.utils |
753 | -import os |
754 | -import shlex |
755 | -import subprocess |
756 | - |
757 | -from libertine.ContainersConfig import ContainersConfig |
758 | -from libertine.lifecycle import * |
759 | - |
760 | - |
761 | -LIBERTINE_LXC_MANAGER_NAME = libertine.LxcContainer.get_lxc_manager_dbus_name() |
762 | -LIBERTINE_LXC_MANAGER_PATH = libertine.LxcContainer.get_lxc_manager_dbus_path() |
763 | - |
764 | - |
765 | -class Service(ContainerLifecycleService): |
766 | - |
767 | - def __init__(self): |
768 | - super().__init__(LIBERTINE_LXC_MANAGER_NAME, LIBERTINE_LXC_MANAGER_PATH) |
769 | - self._home = os.environ['HOME'] |
770 | - self._containers_config = ContainersConfig() |
771 | - self._is_pulse_setup = False |
772 | - |
773 | - def start(self, container_id): |
774 | - container = libertine.LxcContainer.lxc_container(container_id) |
775 | - |
776 | - if not container.defined: |
777 | - return LifecycleResult("Container {} is not valid".format(container_id)) |
778 | - |
779 | - if not self._is_pulse_setup: |
780 | - self._setup_pulse() |
781 | - |
782 | - if container.state == 'STOPPED': |
783 | - self._dynamic_bind_mounts(container, container_id) |
784 | - |
785 | - libertine.LxcContainer.lxc_start(container) |
786 | - |
787 | - return LifecycleResult() |
788 | - |
789 | - def stop(self, container_id, options={}): |
790 | - container = libertine.LxcContainer.lxc_container(container_id) |
791 | - |
792 | - libertine.LxcContainer.lxc_stop(container, options.get('freeze', False)) |
793 | - |
794 | - return LifecycleResult() # no error case |
795 | - |
796 | - def _setup_pulse(self): |
797 | - pulse_socket_path = os.path.join(libertine.utils.get_libertine_runtime_dir(), 'pulse_socket') |
798 | - |
799 | - lsof_cmd = 'lsof -n %s' % pulse_socket_path |
800 | - args = shlex.split(lsof_cmd) |
801 | - lsof = subprocess.Popen(args, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) |
802 | - lsof.wait() |
803 | - |
804 | - if not os.path.exists(pulse_socket_path) or lsof.returncode == 1: |
805 | - pactl_cmd = ( |
806 | - 'pactl load-module module-native-protocol-unix auth-anonymous=1 socket=%s' |
807 | - % pulse_socket_path) |
808 | - args = shlex.split(pactl_cmd) |
809 | - subprocess.Popen(args).wait() |
810 | - |
811 | - self.is_pulse_setup = True |
812 | - |
813 | - def _dynamic_bind_mounts(self, container, container_id): |
814 | - self._containers_config.refresh_database() |
815 | - mounts = self._sanitize_bind_mounts(libertine.utils.get_common_xdg_user_directories() + \ |
816 | - self._containers_config.get_container_bind_mounts(container_id)) |
817 | - |
818 | - data_dir = libertine.utils.get_libertine_container_home_dir(container_id) |
819 | - for user_dir in libertine.utils.generate_binding_directories(mounts, self._home): |
820 | - if os.path.isabs(user_dir[1]): |
821 | - path = user_dir[1].strip('/') |
822 | - fullpath = os.path.join(libertine.utils.get_libertine_container_rootfs_path(container_id), path) |
823 | - else: |
824 | - path = "{}/{}".format(self._home.strip('/'), user_dir[1]) |
825 | - fullpath = os.path.join(data_dir, user_dir[1]) |
826 | - |
827 | - os.makedirs(fullpath, exist_ok=True) |
828 | - |
829 | - libertine.utils.get_logger().debug("Mounting {}:{} in container {}".format(user_dir[0], path, container_id)) |
830 | - xdg_user_dir_entry = ( |
831 | - "%s %s none bind,create=dir,optional" |
832 | - % (user_dir[0], path) |
833 | - ) |
834 | - container.append_config_item("lxc.mount.entry", xdg_user_dir_entry) |
835 | - |
836 | - def _sanitize_bind_mounts(self, mounts): |
837 | - return [mount.replace(" ", "\\040") for mount in mounts] |
838 | - |
839 | - |
840 | -if __name__ == '__main__': |
841 | - ContainerLifecycleServiceRunner(Service()).run() |
842 | |
843 | === removed file 'tools/libertine-lxc-manager.1' |
844 | --- tools/libertine-lxc-manager.1 2016-04-06 12:31:26 +0000 |
845 | +++ tools/libertine-lxc-manager.1 1970-01-01 00:00:00 +0000 |
846 | @@ -1,9 +0,0 @@ |
847 | -.TH libertine-lxc-manager "1" "April 2016" "libertine-lxc-manager 0.99" "User Commands" |
848 | - |
849 | -.SH NAME |
850 | -libertine-lxc-manager \- monitors LXC activity performed by libertine |
851 | - |
852 | -.SH DESCRIPTION |
853 | -usage: libertine\-lxc\-manager |
854 | -.PP |
855 | -monitors LXC activity performed by libertine |
856 | |
857 | === removed file 'tools/libertine-lxd-manager' |
858 | --- tools/libertine-lxd-manager 2017-01-24 20:21:16 +0000 |
859 | +++ tools/libertine-lxd-manager 1970-01-01 00:00:00 +0000 |
860 | @@ -1,58 +0,0 @@ |
861 | -#!/usr/bin/python3 |
862 | -# -*- coding: utf-8 -*- |
863 | - |
864 | -# Copyright (C) 2016-2017 Canonical Ltd. |
865 | - |
866 | -# This program is free software: you can redistribute it and/or modify |
867 | -# it under the terms of the GNU General Public License as published by |
868 | -# the Free Software Foundation; version 3 of the License. |
869 | -# |
870 | -# This program is distributed in the hope that it will be useful, |
871 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
872 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
873 | -# GNU General Public License for more details. |
874 | -# |
875 | -# You should have received a copy of the GNU General Public License |
876 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
877 | - |
878 | -import libertine.LxdContainer |
879 | -import libertine.utils |
880 | -import pylxd |
881 | - |
882 | -from libertine.ContainersConfig import ContainersConfig |
883 | -from libertine.lifecycle import * |
884 | - |
885 | - |
886 | -LIBERTINE_LXD_MANAGER_NAME = libertine.LxdContainer.get_lxd_manager_dbus_name() |
887 | -LIBERTINE_LXD_MANAGER_PATH = libertine.LxdContainer.get_lxd_manager_dbus_path() |
888 | - |
889 | - |
890 | -class Service(ContainerLifecycleService): |
891 | - |
892 | - def __init__(self): |
893 | - super().__init__(LIBERTINE_LXD_MANAGER_NAME, LIBERTINE_LXD_MANAGER_PATH) |
894 | - self._config = ContainersConfig() |
895 | - self._client = pylxd.Client() |
896 | - |
897 | - def start(self, container_id): |
898 | - container = libertine.LxdContainer.lxd_container(self._client, container_id) |
899 | - |
900 | - if not container: |
901 | - return LifecycleResult("Container {} is not valid".format(container_id)) |
902 | - |
903 | - if container.status != 'Running': |
904 | - libertine.LxdContainer.update_libertine_profile(self._client) |
905 | - |
906 | - libertine.LxdContainer.update_bind_mounts(container, self._config, libertine.LxdContainer.env_home_path()) |
907 | - |
908 | - return libertine.LxdContainer.lxd_start(container) |
909 | - |
910 | - return LifecycleResult() |
911 | - |
912 | - def stop(self, container_id, options={}): |
913 | - return libertine.LxdContainer.lxd_stop(libertine.LxdContainer.lxd_container(self._client, container_id), |
914 | - options.get('wait', False), options.get('freeze', False)) |
915 | - |
916 | - |
917 | -if __name__ == '__main__': |
918 | - ContainerLifecycleServiceRunner(Service()).run() |
919 | |
920 | === removed file 'tools/libertine-lxd-manager.1' |
921 | --- tools/libertine-lxd-manager.1 2016-12-21 20:57:15 +0000 |
922 | +++ tools/libertine-lxd-manager.1 1970-01-01 00:00:00 +0000 |
923 | @@ -1,9 +0,0 @@ |
924 | -.TH libertine-lxd-manager "1" "Dec 2016" "libertine-lxd-manager 0.99" "User Commands" |
925 | - |
926 | -.SH NAME |
927 | -libertine-lxd-manager \- monitors LXD activity performed by libertine |
928 | - |
929 | -.SH DESCRIPTION |
930 | -usage: libertine\-lxd\-manager |
931 | -.PP |
932 | -monitors LXD activity performed by libertine |
PASSED: Continuous integration, rev:394 /jenkins. canonical. com/libertine/ job/lp- libertine- ci/359/ /jenkins. canonical. com/libertine/ job/build/ 696 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=amd64, release= xenial+ overlay, testname= default/ 570 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=amd64, release= zesty,testname= default/ 570 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=i386, release= xenial+ overlay, testname= default/ 570 /jenkins. canonical. com/libertine/ job/test- 0-autopkgtest/ label=i386, release= zesty,testname= default/ 570 /jenkins. canonical. com/libertine/ job/build- 0-fetch/ 706 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= xenial+ overlay/ 687 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= xenial+ overlay/ 687/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= zesty/687 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=amd64, release= zesty/687/ artifact/ output/ *zip*/output. zip /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= xenial+ overlay/ 687 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= xenial+ overlay/ 687/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= zesty/687 /jenkins. canonical. com/libertine/ job/build- 2-binpkg/ arch=i386, release= zesty/687/ 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/359/ rebuild
https:/