Merge lp:~townsend/libertine/consolidate-managers into lp:libertine

Proposed by Christopher Townsend
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
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.

To post a comment you must log in.
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:394
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/359/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/696
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/570
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/570
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/570
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/570
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/706
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/687
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/687/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/687
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/687/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/687
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/687/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/687
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/687/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/359/rebuild

review: Approve (continuous-integration)
395. By Christopher Townsend

Don't need to set self._config twice.

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:395
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/360/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/697
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/571
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/571
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/571
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/571
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/707
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/688
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/688/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/688
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/688/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/688
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/688/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/688
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/688/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/360/rebuild

review: Approve (continuous-integration)
Revision history for this message
Larry Price (larryprice) wrote :

lgtm

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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

Subscribers

People subscribed via source and target branches