Merge lp:~larryprice/libertine/container-control-client into lp:libertine

Proposed by Larry Price
Status: Merged
Approved by: Christopher Townsend
Approved revision: 421
Merged at revision: 435
Proposed branch: lp:~larryprice/libertine/container-control-client
Merge into: lp:libertine
Prerequisite: lp:~larryprice/libertine/always-progress
Diff against target: 1325 lines (+279/-217)
26 files modified
debian/python3-libertine.install (+1/-1)
python/libertine/ChrootContainer.py (+2/-2)
python/libertine/ContainerControlClient.py (+5/-1)
python/libertine/Libertine.py (+12/-12)
python/libertine/LxcContainer.py (+7/-9)
python/libertine/LxdContainer.py (+12/-13)
python/libertine/service/container.py (+36/-32)
python/libertine/service/container_control.py (+5/-54)
python/libertine/service/container_control_client.py (+75/-0)
python/libertine/service/operations.py (+2/-2)
python/libertine/service/task_dispatcher.py (+3/-2)
python/libertine/service/tasks/__init__.py (+2/-1)
python/libertine/service/tasks/base_task.py (+6/-0)
python/libertine/service/tasks/create_task.py (+7/-5)
python/libertine/service/tasks/destroy_task.py (+6/-5)
python/libertine/service/tasks/install_task.py (+6/-5)
python/libertine/service/tasks/remove_task.py (+5/-5)
python/libertine/service/tasks/update_task.py (+6/-5)
tests/unit/service/tasks/test_create_task.py (+21/-10)
tests/unit/service/tasks/test_destroy_task.py (+4/-3)
tests/unit/service/tasks/test_install_task.py (+7/-6)
tests/unit/service/tasks/test_remove_task.py (+7/-6)
tests/unit/service/tasks/test_update_task.py (+4/-3)
tests/unit/service/test_container.py (+27/-26)
tests/unit/service/test_task_dispatcher.py (+6/-5)
tools/libertined (+5/-4)
To merge this branch: bzr merge lp:~larryprice/libertine/container-control-client
Reviewer Review Type Date Requested Status
Christopher Townsend Approve
Libertine CI Bot continuous-integration Approve
Review via email: mp+319465@code.launchpad.net

Commit message

Inject client for accessing ContainerControl within containers.

Description of the change

Inject client for accessing ContainerControl within containers. This allows us to both create a version of the client which accesses d-bus when called from libertine-container-manager and create a client which directly manipulates the list of containers and running operations.

To post a comment you must log in.
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
420. By Larry Price

merge

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
421. By Larry Price

fix install

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

PASSED: Continuous integration, rev:421
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/456/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/842
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/693
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/693
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/693
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/693
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/852
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/844
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/844/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/844
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/844/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/844
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/844/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/844
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/844/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
Revision history for this message
Christopher Townsend (townsend) wrote :

Ok, code looks good and my testing didn't render any regressions.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/python3-libertine.install'
2--- debian/python3-libertine.install 2017-02-15 21:12:37 +0000
3+++ debian/python3-libertine.install 2017-03-09 17:44:54 +0000
4@@ -1,4 +1,4 @@
5-usr/lib/python*/*/libertine/Client.py
6+usr/lib/python*/*/libertine/ContainerControlClient.py
7 usr/lib/python*/*/libertine/ContainersConfig.py
8 usr/lib/python*/*/libertine/HostInfo.py
9 usr/lib/python*/*/libertine/Libertine.py
10
11=== modified file 'python/libertine/ChrootContainer.py'
12--- python/libertine/ChrootContainer.py 2017-02-27 20:47:21 +0000
13+++ python/libertine/ChrootContainer.py 2017-03-09 17:44:54 +0000
14@@ -47,8 +47,8 @@
15 A concrete container type implemented using a plain old chroot.
16 """
17
18- def __init__(self, container_id, config):
19- super().__init__(container_id, 'chroot', config)
20+ def __init__(self, container_id, config, service):
21+ super().__init__(container_id, 'chroot', config, service)
22 # FIXME: Disabling seccomp is a temporary measure until we fully understand why we need
23 # it or figure out when we need it.
24 os.environ['PROOT_NO_SECCOMP'] = '1'
25
26=== renamed file 'python/libertine/Client.py' => 'python/libertine/ContainerControlClient.py'
27--- python/libertine/Client.py 2017-03-07 18:38:05 +0000
28+++ python/libertine/ContainerControlClient.py 2017-03-09 17:44:54 +0000
29@@ -19,7 +19,11 @@
30 from . import utils
31
32
33-class Client(object):
34+class ContainerControlClient(object):
35+ """
36+ A client for ContainerControl using D-BUS, to be used in clients
37+ external to the libertine service.
38+ """
39 def __init__(self):
40 self._get_manager()
41
42
43=== modified file 'python/libertine/Libertine.py'
44--- python/libertine/Libertine.py 2017-03-07 21:36:57 +0000
45+++ python/libertine/Libertine.py 2017-03-09 17:44:54 +0000
46@@ -17,7 +17,7 @@
47 import os
48 import shutil
49
50-from . import utils
51+from . import utils, ContainerControlClient
52 from libertine.ContainersConfig import ContainersConfig
53 from libertine.HostInfo import HostInfo
54
55@@ -79,10 +79,11 @@
56
57 :param container_id: The machine-readable container name.
58 """
59- def __init__(self, container_id, container_type, config):
60+ def __init__(self, container_id, container_type, config, service):
61 self.container_type = container_type
62 self.container_id = container_id
63 self._config = config
64+ self._service = service
65 self._app_name = ''
66 self._pid = 0
67 self.root_path = utils.get_libertine_container_rootfs_path(self.container_id)
68@@ -332,8 +333,8 @@
69 """
70 A concrete mock container type. Used for unit testing.
71 """
72- def __init__(self, container_id, config):
73- super().__init__(container_id, 'mock', config)
74+ def __init__(self, container_id, config, service):
75+ super().__init__(container_id, 'mock', config, service)
76
77 def create_libertine_container(self, password=None, multiarch=False):
78 return True
79@@ -386,7 +387,7 @@
80 A sandbox for DEB-packaged X11-based applications.
81 """
82
83- def __init__(self, container_id, containers_config=None):
84+ def __init__(self, container_id, containers_config=None, service=None):
85 """
86 Initializes the container object.
87
88@@ -394,23 +395,22 @@
89 """
90 super().__init__()
91
92- if containers_config is None:
93- containers_config = ContainersConfig()
94- self.containers_config = containers_config
95+ self.containers_config = containers_config or ContainersConfig()
96+ service = service or ContainerControlClient.ContainerControlClient()
97
98 container_type = self.containers_config.get_container_type(container_id)
99
100 if container_type == "lxc":
101 from libertine.LxcContainer import LibertineLXC
102- self.container = LibertineLXC(container_id, self.containers_config)
103+ self.container = LibertineLXC(container_id, self.containers_config, service)
104 elif container_type == "lxd":
105 from libertine.LxdContainer import LibertineLXD
106- self.container = LibertineLXD(container_id, self.containers_config)
107+ self.container = LibertineLXD(container_id, self.containers_config, service)
108 elif container_type == "chroot":
109 from libertine.ChrootContainer import LibertineChroot
110- self.container = LibertineChroot(container_id, self.containers_config)
111+ self.container = LibertineChroot(container_id, self.containers_config, service)
112 elif container_type == "mock":
113- self.container = LibertineMock(container_id, self.containers_config)
114+ self.container = LibertineMock(container_id, self.containers_config, service)
115 else:
116 raise RuntimeError("Unsupported container type %s" % container_type)
117
118
119=== modified file 'python/libertine/LxcContainer.py'
120--- python/libertine/LxcContainer.py 2017-03-03 15:34:16 +0000
121+++ python/libertine/LxcContainer.py 2017-03-09 17:44:54 +0000
122@@ -23,7 +23,7 @@
123 import tempfile
124
125 from .Libertine import BaseContainer
126-from . import utils, HostInfo, Client
127+from . import utils, HostInfo
128
129
130 home_path = os.environ['HOME']
131@@ -157,14 +157,12 @@
132 A concrete container type implemented using an LXC container.
133 """
134
135- def __init__(self, container_id, config):
136- super().__init__(container_id, 'lxc', config)
137+ def __init__(self, container_id, config, service):
138+ super().__init__(container_id, 'lxc', config, service)
139 self.container = lxc_container(container_id)
140 self.host_info = HostInfo.HostInfo()
141 self._freeze_on_stop = config.get_freeze_on_stop(self.container_id)
142
143- self._manager = Client.Client()
144-
145 def _setup_pulse(self):
146 pulse_socket_path = os.path.join(utils.get_libertine_runtime_dir(), 'pulse_socket')
147
148@@ -213,7 +211,7 @@
149 return fd.read().strip('\n') != self.host_info.get_host_timezone()
150
151 def start_container(self):
152- if not self._manager.container_operation_start(self.container_id):
153+ if not self._service.container_operation_start(self.container_id):
154 return False
155
156 if self.container.state == 'RUNNING':
157@@ -236,11 +234,11 @@
158 stopped = False
159 self._config.refresh_database()
160
161- if self._manager.container_operation_finished(self.container_id, self._app_name, self._pid):
162+ if self._service.container_operation_finished(self.container_id, self._app_name, self._pid):
163 self._config.update_container_install_status(self.container_id, self._get_stop_type_string(self._freeze_on_stop))
164
165 if lxc_stop(self.container, self._freeze_on_stop):
166- stopped = self._manager.container_stopped(self.container_id)
167+ stopped = self._service.container_stopped(self.container_id)
168
169 self._config.update_container_install_status(self.container_id, self.container.state.lower())
170
171@@ -397,7 +395,7 @@
172 os.environ.update(environ)
173
174 if not self.start_container():
175- self._manager.container_stopped(self.container_id)
176+ self._service.container_stopped(self.container_id)
177 return
178
179 self._app_name = app_exec_line[0]
180
181=== modified file 'python/libertine/LxdContainer.py'
182--- python/libertine/LxdContainer.py 2017-03-03 15:34:16 +0000
183+++ python/libertine/LxdContainer.py 2017-03-09 17:44:54 +0000
184@@ -22,7 +22,7 @@
185 import subprocess
186 import time
187
188-from . import Libertine, utils, HostInfo, Client
189+from . import Libertine, utils, HostInfo
190
191
192 def _get_devices_map():
193@@ -383,8 +383,8 @@
194
195
196 class LibertineLXD(Libertine.BaseContainer):
197- def __init__(self, name, config):
198- super().__init__(name, 'lxd', config)
199+ def __init__(self, name, config, service):
200+ super().__init__(name, 'lxd', config, service)
201 self._host_info = HostInfo.HostInfo()
202 self._container = None
203 self._freeze_on_stop = config.get_freeze_on_stop(self.container_id)
204@@ -392,15 +392,14 @@
205 if not _setup_lxd():
206 raise Exception("Failed to setup lxd.")
207
208- self._client = pylxd.Client()
209- self._manager = Client.Client()
210+ self._lxd_client = pylxd.Client()
211
212 def create_libertine_container(self, password=None, multiarch=False):
213 if self._try_get_container():
214 utils.get_logger().error("Container already exists")
215 return False
216
217- update_libertine_profile(self._client)
218+ update_libertine_profile(self._lxd_client)
219
220 utils.get_logger().info("Creating container '%s' with distro '%s'" % (self.container_id, self.installed_release))
221 create = subprocess.Popen(shlex.split('lxc launch ubuntu-daily:{distro} {id} --profile '
222@@ -504,7 +503,7 @@
223 if not self._try_get_container():
224 return False
225
226- if not self._manager.container_operation_start(self.container_id):
227+ if not self._service.container_operation_start(self.container_id):
228 return False
229
230 if self._container.status == 'Running':
231@@ -513,12 +512,12 @@
232 requires_remount = self._container.status == 'Stopped'
233
234 if requires_remount:
235- update_libertine_profile(self._client)
236+ update_libertine_profile(self._lxd_client)
237 update_bind_mounts(self._container, self._config, home)
238
239 self._config.update_container_install_status(self.container_id, "starting")
240 if not lxd_start(self._container):
241- self._manager.container_stopped()
242+ self._service.container_stopped()
243 self._config.update_container_install_status(self.container_id, self._container.status.lower())
244 return False
245
246@@ -539,11 +538,11 @@
247 stopped = False
248 self._config.refresh_database()
249
250- if self._manager.container_operation_finished(self.container_id, self._app_name, self._pid):
251+ if self._service.container_operation_finished(self.container_id, self._app_name, self._pid):
252 self._config.update_container_install_status(self.container_id, self._get_stop_type_string(self._freeze_on_stop))
253-
254+
255 if lxd_stop(self._container, freeze_on_stop=self._freeze_on_stop):
256- stopped = self._manager.container_stopped(self.container_id)
257+ stopped = self._service.container_stopped(self.container_id)
258
259 self._config.update_container_install_status(self.container_id, self._container.status.lower())
260
261@@ -598,6 +597,6 @@
262
263 def _try_get_container(self):
264 if self._container is None:
265- self._container = lxd_container(self._client, self.container_id)
266+ self._container = lxd_container(self._lxd_client, self.container_id)
267
268 return self._container is not None
269
270=== modified file 'python/libertine/service/container.py'
271--- python/libertine/service/container.py 2017-03-07 18:38:05 +0000
272+++ python/libertine/service/container.py 2017-03-09 17:44:54 +0000
273@@ -22,11 +22,13 @@
274
275
276 class Container(object):
277- def __init__(self, container_id, config, monitor, callback):
278+ def __init__(self, container_id, config, monitor, client, callback):
279 self._id = container_id
280+ self._config = config
281 self._monitor = monitor
282+ self._client = client
283 self._callback = callback
284- self._config = config
285+
286 self._lock = Lock()
287 self._tasks = []
288
289@@ -53,31 +55,6 @@
290 def tasks(self):
291 return [task.id for task in self._tasks if task.running]
292
293- def search(self, query):
294- utils.get_logger().debug("search container '%s' for package '%s'" % (self.id, query))
295-
296- if utils.is_snap_environment():
297- raise Exception("This operation is not currently supported within the snap")
298-
299- task = SearchTask(self.id, self._cache, query, self._monitor, self._cleanup_task)
300- self._tasks.append(task)
301- task.start()
302-
303- return task.id
304-
305- def app_info(self, package_name):
306- utils.get_logger().debug("get info for package '%s' in container '%s'" % (package_name, self.id))
307-
308- if utils.is_snap_environment():
309- raise Exception("This operation is not currently supported within the snap")
310-
311- related_task_ids = [t.id for t in self._tasks if t.package == package_name and t.running]
312- task = AppInfoTask(self.id, self._cache, package_name, related_task_ids, self._config, self._monitor, self._cleanup_task)
313-
314- self._tasks.append(task)
315- task.start()
316- return task.id
317-
318 def install(self, package_name):
319 utils.get_logger().debug("Install package '%s' from container '%s'" % (package_name, self.id))
320
321@@ -86,7 +63,7 @@
322 utils.get_logger().debug("Install already in progress for '%s':'%s'" % (package_name, self.id))
323 return tasks[0].id
324
325- task = InstallTask(package_name, self.id, self._config, self._lock, self._monitor, self._cleanup_task)
326+ task = InstallTask(package_name, self.id, self._config, self._lock, self._monitor, self._client, self._cleanup_task)
327 self._tasks.append(task)
328 task.start()
329 return task.id
330@@ -99,7 +76,7 @@
331 utils.get_logger().debug("Remove already in progress for '%s':'%s'" % (package_name, self.id))
332 return tasks[0].id
333
334- task = RemoveTask(package_name, self.id, self._config, self._lock, self._monitor, self._cleanup_task)
335+ task = RemoveTask(package_name, self.id, self._config, self._lock, self._monitor, self._client, self._cleanup_task)
336 self._tasks.append(task)
337 task.start()
338 return task.id
339@@ -113,7 +90,7 @@
340 return tasks[0].id
341
342 task = CreateTask(self.id, container_name, distro, container_type, enable_multiarch,
343- self._config, self._lock, self._monitor, self._cleanup_task)
344+ self._config, self._lock, self._monitor, self._client, self._cleanup_task)
345 self._tasks.append(task)
346 task.start()
347 return task.id
348@@ -126,7 +103,7 @@
349 utils.get_logger().debug("Destroy already in progress for '%s'" % self.id)
350 return tasks[0].id
351
352- task = DestroyTask(self.id, self._config, self._lock, self._monitor, self._cleanup_task)
353+ task = DestroyTask(self.id, self._config, self._lock, self._monitor, self._client, self._cleanup_task)
354 self._tasks.append(task)
355 task.start()
356 return task.id
357@@ -139,11 +116,13 @@
358 utils.get_logger().debug("Update already in progress for '%s'" % self.id)
359 return tasks[0].id
360
361- task = UpdateTask(self.id, self._config, self._lock, self._monitor, self._cleanup_task)
362+ task = UpdateTask(self.id, self._config, self._lock, self._monitor, self._client, self._cleanup_task)
363 self._tasks.append(task)
364 task.start()
365 return task.id
366
367+ # Tasks which don't require starting/stopping the container
368+
369 def list_app_ids(self):
370 utils.get_logger().debug("List all app ids in container '%s'" % self.id)
371
372@@ -152,3 +131,28 @@
373 self._tasks.append(task)
374 task.start()
375 return task.id
376+
377+ def search(self, query):
378+ utils.get_logger().debug("search container '%s' for package '%s'" % (self.id, query))
379+
380+ if utils.is_snap_environment():
381+ raise Exception("This operation is not currently supported within the snap")
382+
383+ task = SearchTask(self.id, self._cache, query, self._monitor, self._cleanup_task)
384+ self._tasks.append(task)
385+ task.start()
386+
387+ return task.id
388+
389+ def app_info(self, package_name):
390+ utils.get_logger().debug("get info for package '%s' in container '%s'" % (package_name, self.id))
391+
392+ if utils.is_snap_environment():
393+ raise Exception("This operation is not currently supported within the snap")
394+
395+ related_task_ids = [t.id for t in self._tasks if t.package == package_name and t.running]
396+ task = AppInfoTask(self.id, self._cache, package_name, related_task_ids, self._config, self._monitor, self._cleanup_task)
397+
398+ self._tasks.append(task)
399+ task.start()
400+ return task.id
401
402=== modified file 'python/libertine/service/container_control.py'
403--- python/libertine/service/container_control.py 2017-03-06 19:50:12 +0000
404+++ python/libertine/service/container_control.py 2017-03-09 17:44:54 +0000
405@@ -14,82 +14,33 @@
406
407
408 import dbus
409-import libertine.ContainersConfig
410-import psutil
411
412 from . import constants
413-from collections import Counter
414 from libertine import utils
415
416
417 class ContainerControl(dbus.service.Object):
418- def __init__(self, connection):
419- self._get_running_apps_per_container()
420-
421+ def __init__(self, connection, client):
422 dbus.service.Object.__init__(self, conn=connection, object_path=constants.CONTAINER_CONTROL_OBJECT)
423-
424- def _get_running_apps_per_container(self):
425- self._invalid_apps = dict()
426- self._operations = Counter()
427- config = libertine.ContainersConfig.ContainersConfig()
428-
429- for container in config.get_containers():
430- running_apps = config.get_running_apps(container).copy()
431-
432- for app in running_apps:
433- try:
434- proc = psutil.Process(app['pid'])
435- if app['appExecName'] in proc.cmdline():
436- self._operations[container] += 1
437- else:
438- raise
439- except:
440- utils.get_logger().error("Container app {} is not valid.".format(app['appExecName']))
441- if container not in self._invalid_apps:
442- self._invalid_apps[container] = [{app['appExecName'], app['pid']}]
443- else:
444- self._invalid_apps[container].append({app['appExecName'], app['pid']})
445- config.delete_running_app(container, app)
446- continue
447-
448+ self._client = client
449
450 @dbus.service.method(constants.CONTAINER_CONTROL_INTERFACE,
451 in_signature='s',
452 out_signature='b')
453 def start(self, container):
454 utils.get_logger().debug("start({})".format(container))
455- if self._operations[container] == -1:
456- return False
457-
458- self._operations[container] += 1
459-
460- return True
461-
462+ return self._client.container_operation_start(container)
463
464 @dbus.service.method(constants.CONTAINER_CONTROL_INTERFACE,
465 in_signature='ssi',
466 out_signature='b')
467 def finished(self, container, app_name, pid):
468 utils.get_logger().debug("finished({})".format(container))
469-
470- if container in self._invalid_apps and {app_name, pid} in self._invalid_apps[container]:
471- self._invalid_apps[container].remove({app_name, pid})
472- if not self._invalid_apps[container]:
473- del self._invalid_apps[container]
474- else:
475- self._operations[container] -= 1
476-
477- if self._operations[container] == 0:
478- self._operations[container] = -1
479- return True
480-
481- return False
482+ return self._client.container_operation_finished(container, app_name, pid)
483
484 @dbus.service.method(constants.CONTAINER_CONTROL_INTERFACE,
485 in_signature='s',
486 out_signature='b')
487 def stopped(self, container):
488 utils.get_logger().debug("stopped({})".format(container))
489-
490- del self._operations[container]
491- return True
492+ return self._client.container_operation_stopped(container)
493
494=== added file 'python/libertine/service/container_control_client.py'
495--- python/libertine/service/container_control_client.py 1970-01-01 00:00:00 +0000
496+++ python/libertine/service/container_control_client.py 2017-03-09 17:44:54 +0000
497@@ -0,0 +1,75 @@
498+# Copyright 2017 Canonical Ltd.
499+#
500+# This program is free software: you can redistribute it and/or modify
501+# it under the terms of the GNU General Public License as published by
502+# the Free Software Foundation; version 3 of the License.
503+#
504+# This program is distributed in the hope that it will be useful,
505+# but WITHOUT ANY WARRANTY; without even the implied warranty of
506+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
507+# GNU General Public License for more details.
508+#
509+# You should have received a copy of the GNU General Public License
510+# along with this program. If not, see <http://www.gnu.org/licenses/>.
511+
512+
513+import libertine.ContainersConfig
514+import psutil
515+
516+from collections import Counter
517+from libertine import utils
518+
519+
520+class ContainerControlClient(object):
521+ def __init__(self):
522+ self._get_running_apps_per_container()
523+
524+ def _get_running_apps_per_container(self):
525+ self._invalid_apps = dict()
526+ self._operations = Counter()
527+ config = libertine.ContainersConfig.ContainersConfig()
528+
529+ for container in config.get_containers():
530+ running_apps = config.get_running_apps(container).copy()
531+
532+ for app in running_apps:
533+ try:
534+ proc = psutil.Process(app['pid'])
535+ if app['appExecName'] in proc.cmdline():
536+ self._operations[container] += 1
537+ else:
538+ raise
539+ except:
540+ utils.get_logger().error("Container app {} is not valid.".format(app['appExecName']))
541+ if container not in self._invalid_apps:
542+ self._invalid_apps[container] = [{app['appExecName'], app['pid']}]
543+ else:
544+ self._invalid_apps[container].append({app['appExecName'], app['pid']})
545+ config.delete_running_app(container, app)
546+ continue
547+
548+ def container_operation_start(self, container):
549+ if self._operations[container] == -1:
550+ return False
551+
552+ self._operations[container] += 1
553+
554+ return True
555+
556+ def container_operation_finished(self, container, app_name, pid):
557+ if container in self._invalid_apps and {app_name, pid} in self._invalid_apps[container]:
558+ self._invalid_apps[container].remove({app_name, pid})
559+ if not self._invalid_apps[container]:
560+ del self._invalid_apps[container]
561+ else:
562+ self._operations[container] -= 1
563+
564+ if self._operations[container] == 0:
565+ self._operations[container] = -1
566+ return True
567+
568+ return False
569+
570+ def container_stopped(self, container):
571+ del self._operations[container]
572+ return True
573
574=== modified file 'python/libertine/service/operations.py'
575--- python/libertine/service/operations.py 2017-03-07 18:38:05 +0000
576+++ python/libertine/service/operations.py 2017-03-09 17:44:54 +0000
577@@ -21,10 +21,10 @@
578
579
580 class Operations(dbus.service.Object):
581- def __init__(self, bus_name):
582+ def __init__(self, bus_name, client):
583 super().__init__(bus_name, constants.OPERATIONS_OBJECT)
584
585- self._dispatcher = task_dispatcher.TaskDispatcher(operations_monitor.OperationsMonitor(self.connection))
586+ self._dispatcher = task_dispatcher.TaskDispatcher(operations_monitor.OperationsMonitor(self.connection), client)
587
588 # Information
589
590
591=== modified file 'python/libertine/service/task_dispatcher.py'
592--- python/libertine/service/task_dispatcher.py 2017-03-06 19:50:12 +0000
593+++ python/libertine/service/task_dispatcher.py 2017-03-09 17:44:54 +0000
594@@ -30,8 +30,9 @@
595
596
597 class TaskDispatcher(object):
598- def __init__(self, monitor):
599+ def __init__(self, monitor, client):
600 self._monitor = monitor
601+ self._client = client
602 self._config = libertine.ContainersConfig.ContainersConfig()
603 self._containerless_tasks = []
604 self._tasks = []
605@@ -55,7 +56,7 @@
606 utils.get_logger().debug("using existing container '%s'" % container_id)
607 return container
608
609- container = Container(container_id, self._config, self._monitor, self._cleanup_container)
610+ container = Container(container_id, self._config, self._monitor, self._client, self._cleanup_container)
611 self._containers.append(container)
612
613 return container
614
615=== modified file 'python/libertine/service/tasks/__init__.py'
616--- python/libertine/service/tasks/__init__.py 2017-02-07 12:35:48 +0000
617+++ python/libertine/service/tasks/__init__.py 2017-03-09 17:44:54 +0000
618@@ -12,7 +12,7 @@
619 # You should have received a copy of the GNU General Public License along
620 # with this program. If not, see <http://www.gnu.org/licenses/>.
621
622-from .base_task import BaseTask
623+from .base_task import BaseTask, ContainerBaseTask
624 from .app_info_task import AppInfoTask
625 from .container_info_task import ContainerInfoTask
626 from .create_task import CreateTask
627@@ -27,6 +27,7 @@
628 __all__ = [
629 'AppInfoTask',
630 'BaseTask',
631+ 'ContainerBaseTask',
632 'ContainerInfoTask',
633 'CreateTask',
634 'DestroyTask',
635
636=== modified file 'python/libertine/service/tasks/base_task.py'
637--- python/libertine/service/tasks/base_task.py 2017-03-06 19:50:12 +0000
638+++ python/libertine/service/tasks/base_task.py 2017-03-09 17:44:54 +0000
639@@ -94,3 +94,9 @@
640
641 def _error(self, message):
642 self._monitor.error(self._operation_id, message)
643+
644+
645+class ContainerBaseTask(BaseTask):
646+ def __init__(self, lock, container_id, config, monitor, client, callback):
647+ super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, callback=callback)
648+ self._client = client
649
650=== modified file 'python/libertine/service/tasks/create_task.py'
651--- python/libertine/service/tasks/create_task.py 2017-03-07 18:38:05 +0000
652+++ python/libertine/service/tasks/create_task.py 2017-03-09 17:44:54 +0000
653@@ -13,14 +13,16 @@
654 # along with this program. If not, see <http://www.gnu.org/licenses/>.
655
656
657-from .base_task import BaseTask
658+from .base_task import ContainerBaseTask
659 from libertine import LibertineContainer, utils
660 from libertine.HostInfo import HostInfo
661
662
663-class CreateTask(BaseTask):
664- def __init__(self, container_id, container_name, distro, container_type, enable_multiarch, config, lock, monitor, callback):
665- super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, callback=callback)
666+class CreateTask(ContainerBaseTask):
667+ def __init__(self, container_id, container_name, distro, container_type, enable_multiarch,
668+ config, lock, monitor, client, callback):
669+ super().__init__(lock=lock, container_id=container_id, config=config,
670+ monitor=monitor, client=client, callback=callback)
671 self._name = container_name
672 self._distro = distro
673 self._type = container_type
674@@ -30,7 +32,7 @@
675 utils.get_logger().debug("Creating container '%s'" % self._container)
676
677 try:
678- container = LibertineContainer(self._container, self._config)
679+ container = LibertineContainer(self._container, self._config, self._client)
680
681 if not container.create_libertine_container(password='', multiarch=self._multiarch):
682 self._config.delete_container(self._container)
683
684=== modified file 'python/libertine/service/tasks/destroy_task.py'
685--- python/libertine/service/tasks/destroy_task.py 2017-03-07 18:38:05 +0000
686+++ python/libertine/service/tasks/destroy_task.py 2017-03-09 17:44:54 +0000
687@@ -13,18 +13,19 @@
688 # along with this program. If not, see <http://www.gnu.org/licenses/>.
689
690
691-from .base_task import BaseTask
692+from .base_task import ContainerBaseTask
693 from libertine import LibertineContainer, utils
694
695
696-class DestroyTask(BaseTask):
697- def __init__(self, container_id, config, lock, monitor, callback):
698- super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, callback=callback)
699+class DestroyTask(ContainerBaseTask):
700+ def __init__(self, container_id, config, lock, monitor, client, callback):
701+ super().__init__(lock=lock, container_id=container_id, config=config,
702+ monitor=monitor, client=client, callback=callback)
703
704 def _run(self):
705 utils.get_logger().debug("Destroying container '%s'" % self._container)
706
707- container = LibertineContainer(self._container, self._config)
708+ container = LibertineContainer(self._container, self._config, self._client)
709 if not container.destroy_libertine_container():
710 self._error("Destroying container '%s' failed" % self._container)
711 self._config.update_container_install_status(self._container, "ready")
712
713=== modified file 'python/libertine/service/tasks/install_task.py'
714--- python/libertine/service/tasks/install_task.py 2017-03-07 18:38:05 +0000
715+++ python/libertine/service/tasks/install_task.py 2017-03-09 17:44:54 +0000
716@@ -13,13 +13,14 @@
717 # along with this program. If not, see <http://www.gnu.org/licenses/>.
718
719
720-from .base_task import BaseTask
721+from .base_task import ContainerBaseTask
722 from libertine import LibertineContainer, utils
723
724
725-class InstallTask(BaseTask):
726- def __init__(self, package_name, container_id, config, lock, monitor, callback):
727- super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, callback=callback)
728+class InstallTask(ContainerBaseTask):
729+ def __init__(self, package_name, container_id, config, lock, monitor, client, callback):
730+ super().__init__(lock=lock, container_id=container_id, config=config,
731+ monitor=monitor, client=client, callback=callback)
732 self._package = package_name
733
734 def matches(self, package, klass):
735@@ -31,7 +32,7 @@
736
737 def _run(self):
738 utils.get_logger().debug("Installing package '%s'" % self._package)
739- container = LibertineContainer(self._container, self._config)
740+ container = LibertineContainer(self._container, self._config, self._client)
741 if container.install_package(self._package):
742 self._config.update_package_install_status(self._container, self._package, "installed")
743 else:
744
745=== modified file 'python/libertine/service/tasks/remove_task.py'
746--- python/libertine/service/tasks/remove_task.py 2017-03-07 18:38:05 +0000
747+++ python/libertine/service/tasks/remove_task.py 2017-03-09 17:44:54 +0000
748@@ -13,13 +13,13 @@
749 # along with this program. If not, see <http://www.gnu.org/licenses/>.
750
751
752-from .base_task import BaseTask
753+from .base_task import ContainerBaseTask
754 from libertine import LibertineContainer, utils
755
756
757-class RemoveTask(BaseTask):
758- def __init__(self, package_name, container_id, config, lock, monitor, callback):
759- super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, callback=callback)
760+class RemoveTask(ContainerBaseTask):
761+ def __init__(self, package_name, container_id, config, lock, monitor, client, callback):
762+ super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, client=client, callback=callback)
763 self._package = package_name
764
765 def matches(self, package, klass):
766@@ -31,7 +31,7 @@
767
768 def _run(self):
769 utils.get_logger().debug("Removing package '%s'" % self._package)
770- container = LibertineContainer(self._container, self._config)
771+ container = LibertineContainer(self._container, self._config, self._client)
772 if container.remove_package(self._package):
773 self._config.delete_package(self._container, self._package)
774 else:
775
776=== modified file 'python/libertine/service/tasks/update_task.py'
777--- python/libertine/service/tasks/update_task.py 2017-03-07 18:38:05 +0000
778+++ python/libertine/service/tasks/update_task.py 2017-03-09 17:44:54 +0000
779@@ -13,17 +13,18 @@
780 # along with this program. If not, see <http://www.gnu.org/licenses/>.
781
782
783-from .base_task import BaseTask
784+from .base_task import ContainerBaseTask
785 from libertine import LibertineContainer, utils
786
787
788-class UpdateTask(BaseTask):
789- def __init__(self, container_id, config, lock, monitor, callback):
790- super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, callback=callback)
791+class UpdateTask(ContainerBaseTask):
792+ def __init__(self, container_id, config, lock, monitor, client, callback):
793+ super().__init__(lock=lock, container_id=container_id, config=config,
794+ monitor=monitor, client=client, callback=callback)
795
796 def _run(self):
797 utils.get_logger().debug("Updating container '%s'" % self._container)
798- container = LibertineContainer(self._container, self._config)
799+ container = LibertineContainer(self._container, self._config, self._client)
800 self._config.update_container_install_status(self._container, "updating")
801 if not container.update_libertine_container():
802 self._error("Failed to update container '%s'" % self._container)
803
804=== modified file 'tests/unit/service/tasks/test_create_task.py'
805--- tests/unit/service/tasks/test_create_task.py 2017-03-07 19:41:49 +0000
806+++ tests/unit/service/tasks/test_create_task.py 2017-03-09 17:44:54 +0000
807@@ -23,6 +23,7 @@
808 def setUp(self):
809 self.config = unittest.mock.create_autospec(ContainersConfig)
810 self.lock = unittest.mock.MagicMock()
811+ self.client = unittest.mock.Mock()
812 self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
813
814 self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
815@@ -34,7 +35,8 @@
816 def test_success_creates_lxc_container(self):
817 self.config.container_exists.return_value = False
818 self.monitor.done.return_value = False
819- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.monitor, self.callback)
820+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False,
821+ self.config, self.lock, self.monitor, self.client, self.callback)
822 task._instant_callback = True
823
824 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
825@@ -56,7 +58,8 @@
826 def test_success_creates_chroot_container(self):
827 self.config.container_exists.return_value = False
828 self.monitor.done.return_value = False
829- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'chroot', False, self.config, self.lock, self.monitor, self.callback)
830+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'chroot', False,
831+ self.config, self.lock, self.monitor, self.client, self.callback)
832 task._instant_callback = True
833
834 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
835@@ -76,7 +79,8 @@
836
837 def test_container_runtime_error_sends_error(self):
838 self.config.container_exists.return_value = False
839- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.monitor, self.callback)
840+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False,
841+ self.config, self.lock, self.monitor, self.client, self.callback)
842 task._instant_callback = True
843
844 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
845@@ -97,7 +101,8 @@
846
847 def test_failed_container_exists_sends_error(self):
848 self.config.container_exists.return_value = True
849- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.monitor, self.callback)
850+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False,
851+ self.config, self.lock, self.monitor, self.client, self.callback)
852 task._instant_callback = True
853 task.start().join()
854
855@@ -108,7 +113,8 @@
856 self.config.container_exists.return_value = False
857 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
858 MockHostInfo.return_value.is_distro_valid.return_value = False
859- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'vesty', 'lxc', False, self.config, self.lock, self.monitor, self.callback)
860+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'vesty', 'lxc', False,
861+ self.config, self.lock, self.monitor, self.client, self.callback)
862 task._instant_callback = True
863 task.start().join()
864
865@@ -120,7 +126,8 @@
866 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
867 MockHostInfo.return_value.is_distro_valid.return_value = True
868 MockHostInfo.return_value.has_lxc_support.return_value = False
869- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.monitor, self.callback)
870+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False,
871+ self.config, self.lock, self.monitor, self.client, self.callback)
872 task._instant_callback = True
873 task.start().join()
874
875@@ -131,7 +138,8 @@
876 def test_sets_generic_name_when_empty(self):
877 self.config.container_exists.return_value = False
878 self.monitor.done.return_value = False
879- task = tasks.CreateTask('palpatine', None, 'zesty', 'chroot', False, self.config, self.lock, self.monitor, self.callback)
880+ task = tasks.CreateTask('palpatine', None, 'zesty', 'chroot', False, self.config,
881+ self.lock, self.monitor, self.client, self.callback)
882 task._instant_callback = True
883
884 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
885@@ -153,7 +161,8 @@
886 def test_sets_multiarch(self):
887 self.config.container_exists.return_value = False
888 self.monitor.done.return_value = False
889- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'chroot', True, self.config, self.lock, self.monitor, self.callback)
890+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'chroot', True,
891+ self.config, self.lock, self.monitor, self.client, self.callback)
892 task._instant_callback = True
893
894 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
895@@ -175,7 +184,8 @@
896 def test_sets_default_type(self):
897 self.config.container_exists.return_value = False
898 self.monitor.done.return_value = False
899- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', None, False, self.config, self.lock, self.monitor, self.callback)
900+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', None, False,
901+ self.config, self.lock, self.monitor, self.client, self.callback)
902 task._instant_callback = True
903
904 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
905@@ -197,7 +207,8 @@
906 def test_sets_default_distro(self):
907 self.config.container_exists.return_value = False
908 self.monitor.done.return_value = False
909- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', None, 'lxc', False, self.config, self.lock, self.monitor, self.callback)
910+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', None, 'lxc', False,
911+ self.config, self.lock, self.monitor, self.client, self.callback)
912 task._instant_callback = True
913
914 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
915
916=== modified file 'tests/unit/service/tasks/test_destroy_task.py'
917--- tests/unit/service/tasks/test_destroy_task.py 2017-03-07 19:41:49 +0000
918+++ tests/unit/service/tasks/test_destroy_task.py 2017-03-09 17:44:54 +0000
919@@ -23,6 +23,7 @@
920 def setUp(self):
921 self.config = unittest.mock.create_autospec(ContainersConfig)
922 self.lock = unittest.mock.MagicMock()
923+ self.client = unittest.mock.Mock()
924 self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
925
926 self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
927@@ -34,7 +35,7 @@
928 def test_sends_error_on_non_ready_container(self):
929 self.config._get_value_by_key.return_value = ''
930 self.monitor.done.return_value = False
931- task = tasks.DestroyTask('palpatine', self.config, self.lock, self.monitor, self.callback)
932+ task = tasks.DestroyTask('palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
933 task._instant_callback = True
934
935 with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
936@@ -46,7 +47,7 @@
937
938 def test_sends_error_on_failed_destroy(self):
939 self.config._get_value_by_key.return_value = 'ready'
940- task = tasks.DestroyTask('palpatine', self.config, self.lock, self.monitor, self.callback)
941+ task = tasks.DestroyTask('palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
942 task._instant_callback = True
943
944 with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
945@@ -64,7 +65,7 @@
946 def test_successfully_destroys(self):
947 self.config._get_value_by_key.return_value = 'ready'
948 self.monitor.done.return_value = False
949- task = tasks.DestroyTask('palpatine', self.config, self.lock, self.monitor, self.callback)
950+ task = tasks.DestroyTask('palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
951 task._instant_callback = True
952
953 with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
954
955=== modified file 'tests/unit/service/tasks/test_install_task.py'
956--- tests/unit/service/tasks/test_install_task.py 2017-03-07 19:41:49 +0000
957+++ tests/unit/service/tasks/test_install_task.py 2017-03-09 17:44:54 +0000
958@@ -21,9 +21,10 @@
959
960 class TestInstallTask(TestCase):
961 def setUp(self):
962- self.config = unittest.mock.create_autospec(ContainersConfig)
963- self.lock = unittest.mock.MagicMock()
964- self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
965+ self.config = unittest.mock.create_autospec(ContainersConfig)
966+ self.lock = unittest.mock.MagicMock()
967+ self.client = unittest.mock.Mock()
968+ self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
969
970 self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
971 self.called_with = None
972@@ -33,7 +34,7 @@
973
974 def test_sends_error_on_existing_package(self):
975 self.config.package_exists.return_value = True
976- task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.callback)
977+ task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
978 task._instant_callback = True
979 task.start().join()
980
981@@ -42,7 +43,7 @@
982
983 def test_sends_error_on_failed_install(self):
984 self.config.package_exists.return_value = False
985- task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.callback)
986+ task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
987 task._instant_callback = True
988
989 with unittest.mock.patch('libertine.service.tasks.install_task.LibertineContainer') as MockContainer:
990@@ -57,7 +58,7 @@
991 def test_successfully_install(self):
992 self.config.package_exists.return_value = False
993 self.monitor.done.return_value = False
994- task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.callback)
995+ task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
996 task._instant_callback = True
997
998 with unittest.mock.patch('libertine.service.tasks.install_task.LibertineContainer') as MockContainer:
999
1000=== modified file 'tests/unit/service/tasks/test_remove_task.py'
1001--- tests/unit/service/tasks/test_remove_task.py 2017-03-07 19:41:49 +0000
1002+++ tests/unit/service/tasks/test_remove_task.py 2017-03-09 17:44:54 +0000
1003@@ -21,9 +21,10 @@
1004
1005 class TestRemoveTask(TestCase):
1006 def setUp(self):
1007- self.config = unittest.mock.create_autospec(ContainersConfig)
1008- self.lock = unittest.mock.MagicMock()
1009- self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
1010+ self.config = unittest.mock.create_autospec(ContainersConfig)
1011+ self.lock = unittest.mock.MagicMock()
1012+ self.client = unittest.mock.Mock()
1013+ self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
1014
1015 self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
1016 self.called_with = None
1017@@ -33,7 +34,7 @@
1018
1019 def test_sends_error_on_non_installed_package(self):
1020 self.config.get_package_install_status.return_value = 'installing'
1021- task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.callback)
1022+ task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1023 task._instant_callback = True
1024 task.start().join()
1025
1026@@ -42,7 +43,7 @@
1027
1028 def test_sends_error_on_failed_install(self):
1029 self.config.get_package_install_status.return_value = 'installed'
1030- task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.callback)
1031+ task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1032 task._instant_callback = True
1033
1034 with unittest.mock.patch('libertine.service.tasks.remove_task.LibertineContainer') as MockContainer:
1035@@ -59,7 +60,7 @@
1036 def test_successfully_install(self):
1037 self.config.get_package_install_status.return_value = 'installed'
1038 self.monitor.done.return_value = False
1039- task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.callback)
1040+ task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1041 task._instant_callback = True
1042
1043 with unittest.mock.patch('libertine.service.tasks.remove_task.LibertineContainer') as MockContainer:
1044
1045=== modified file 'tests/unit/service/tasks/test_update_task.py'
1046--- tests/unit/service/tasks/test_update_task.py 2017-03-07 19:41:49 +0000
1047+++ tests/unit/service/tasks/test_update_task.py 2017-03-09 17:44:54 +0000
1048@@ -23,6 +23,7 @@
1049 def setUp(self):
1050 self.config = unittest.mock.create_autospec(ContainersConfig)
1051 self.lock = unittest.mock.MagicMock()
1052+ self.client = unittest.mock.Mock()
1053 self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
1054
1055 self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
1056@@ -33,7 +34,7 @@
1057
1058 def test_sends_error_on_non_existent_container(self):
1059 self.config.container_exists.return_value = False
1060- task = tasks.UpdateTask('palpatine', self.config, self.lock, self.monitor, self.callback)
1061+ task = tasks.UpdateTask('palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1062 task._instant_callback = True
1063
1064 with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
1065@@ -45,7 +46,7 @@
1066
1067 def test_sends_error_on_failed_update(self):
1068 self.config.container_exists.return_value = True
1069- task = tasks.UpdateTask('palpatine', self.config, self.lock, self.monitor, self.callback)
1070+ task = tasks.UpdateTask('palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1071 task._instant_callback = True
1072
1073 with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
1074@@ -63,7 +64,7 @@
1075 def test_successfully_updates(self):
1076 self.config.container_exists.return_value = True
1077 self.monitor.done.return_value = False
1078- task = tasks.UpdateTask('palpatine', self.config, self.lock, self.monitor, self.callback)
1079+ task = tasks.UpdateTask('palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1080 task._instant_callback = True
1081
1082 with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
1083
1084=== modified file 'tests/unit/service/test_container.py'
1085--- tests/unit/service/test_container.py 2017-03-07 20:45:30 +0000
1086+++ tests/unit/service/test_container.py 2017-03-09 17:44:54 +0000
1087@@ -22,11 +22,12 @@
1088 def setUp(self):
1089 self._monitor = unittest.mock.Mock()
1090 self._config = unittest.mock.Mock()
1091+ self._client = unittest.mock.Mock()
1092
1093 def test_search_creates_search_task(self):
1094 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1095 cache = MockCache.return_value
1096- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1097+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1098 with unittest.mock.patch('libertine.service.container.SearchTask') as MockSearchTask:
1099 c.search('darkseid')
1100 MockSearchTask.assert_called_once_with('palpatine', cache, 'darkseid', self._monitor, unittest.mock.ANY)
1101@@ -35,7 +36,7 @@
1102 def test_app_info_creates_app_info_task(self):
1103 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1104 cache = MockCache.return_value
1105- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1106+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1107 with unittest.mock.patch('libertine.service.container.AppInfoTask') as MockAppInfoTask:
1108 c.app_info('force')
1109 MockAppInfoTask.assert_called_once_with('palpatine', cache, 'force', [], self._config, self._monitor, unittest.mock.ANY)
1110@@ -44,7 +45,7 @@
1111 def test_app_info_gets_related_task_info(self):
1112 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1113 cache = MockCache.return_value
1114- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1115+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1116 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
1117 MockInstallTask.return_value.package = 'darkside'
1118 MockInstallTask.return_value.matches.return_value = False
1119@@ -59,99 +60,99 @@
1120
1121 def test_install_creates_install_task(self):
1122 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1123- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1124+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1125 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
1126 c.install('force')
1127- MockInstallTask.assert_called_once_with('force', 'palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
1128+ MockInstallTask.assert_called_once_with('force', 'palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1129 MockInstallTask.return_value.start.assert_called_once_with()
1130
1131 def test_install_only_calls_once_when_unfinished(self):
1132 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1133- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1134+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1135 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
1136 c.install('darkside')
1137 c.install('darkside')
1138 c.install('darkside')
1139- MockInstallTask.assert_called_once_with('darkside', 'palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
1140+ MockInstallTask.assert_called_once_with('darkside', 'palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1141 MockInstallTask.return_value.start.assert_called_once_with()
1142
1143 def test_remove_creates_remove_task(self):
1144 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1145- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1146+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1147 with unittest.mock.patch('libertine.service.container.RemoveTask') as MockRemoveTask:
1148 c.remove('force')
1149- MockRemoveTask.assert_called_once_with('force', 'palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
1150+ MockRemoveTask.assert_called_once_with('force', 'palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1151 MockRemoveTask.return_value.start.assert_called_once_with()
1152
1153 def test_remove_only_calls_once_when_unfinished(self):
1154 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1155- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1156+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1157 with unittest.mock.patch('libertine.service.container.RemoveTask') as MockRemoveTask:
1158 c.remove('darkside')
1159 c.remove('darkside')
1160 c.remove('darkside')
1161- MockRemoveTask.assert_called_once_with('darkside', 'palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
1162+ MockRemoveTask.assert_called_once_with('darkside', 'palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1163 MockRemoveTask.return_value.start.assert_called_once_with()
1164
1165 def test_create_creates_create_task(self):
1166 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1167- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1168+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1169 with unittest.mock.patch('libertine.service.container.CreateTask') as MockCreateTask:
1170 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
1171 MockCreateTask.assert_called_once_with('palpatine', 'Emperor Palpatine', 'zesty', 'lxd', False,
1172- self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
1173+ self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1174 MockCreateTask.return_value.start.assert_called_once_with()
1175
1176 def test_create_only_calls_once_when_unfinished(self):
1177 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1178- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1179+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1180 with unittest.mock.patch('libertine.service.container.CreateTask') as MockCreateTask:
1181 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
1182 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
1183 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
1184 MockCreateTask.assert_called_once_with('palpatine', 'Emperor Palpatine', 'zesty', 'lxd', False,
1185- self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
1186+ self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1187 MockCreateTask.return_value.start.assert_called_once_with()
1188
1189 def test_destroy_creates_destroy_task(self):
1190 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1191- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1192+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1193 with unittest.mock.patch('libertine.service.container.DestroyTask') as MockDestroyTask:
1194 c.destroy()
1195- MockDestroyTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
1196+ MockDestroyTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1197 MockDestroyTask.return_value.start.assert_called_once_with()
1198
1199 def test_destroy_only_calls_once_when_unfinished(self):
1200 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1201- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1202+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1203 with unittest.mock.patch('libertine.service.container.DestroyTask') as MockDestroyTask:
1204 c.destroy()
1205 c.destroy()
1206 c.destroy()
1207- MockDestroyTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
1208+ MockDestroyTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1209 MockDestroyTask.return_value.start.assert_called_once_with()
1210
1211 def test_update_creates_update_task(self):
1212 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1213- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1214+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1215 with unittest.mock.patch('libertine.service.container.UpdateTask') as MockUpdateTask:
1216 c.update()
1217- MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
1218+ MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1219 MockUpdateTask.return_value.start.assert_called_once_with()
1220
1221 def test_update_only_calls_once_when_unfinished(self):
1222 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1223- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1224+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1225 with unittest.mock.patch('libertine.service.container.UpdateTask') as MockUpdateTask:
1226 c.update()
1227 c.update()
1228 c.update()
1229- MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
1230+ MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1231 MockUpdateTask.return_value.start.assert_called_once_with()
1232
1233 def test_list_app_ids_creates_list_app_ids_task(self):
1234 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1235- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1236+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1237 with unittest.mock.patch('libertine.service.container.ListAppIdsTask') as MockListAppIdsTask:
1238 c.list_app_ids()
1239 MockListAppIdsTask.assert_called_once_with('palpatine', self._config, self._monitor, unittest.mock.ANY)
1240@@ -159,7 +160,7 @@
1241
1242 def test_removes_task_during_callback(self):
1243 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1244- c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
1245+ c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1246 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
1247 MockInstallTask.return_value.package = 'force'
1248 c.install('force')
1249@@ -176,7 +177,7 @@
1250 self._container_id = None
1251 def callback(container):
1252 self._container_id = container.id
1253- c = container.Container('palpatine', self._config, self._monitor, callback)
1254+ c = container.Container('palpatine', self._config, self._monitor, self._client, callback)
1255 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
1256 c.install('force')
1257 name, args, kwargs = MockInstallTask.mock_calls[0]
1258
1259=== modified file 'tests/unit/service/test_task_dispatcher.py'
1260--- tests/unit/service/test_task_dispatcher.py 2017-02-07 12:35:48 +0000
1261+++ tests/unit/service/test_task_dispatcher.py 2017-03-09 17:44:54 +0000
1262@@ -20,9 +20,10 @@
1263 class TestTaskDispatcher(TestCase):
1264 def setUp(self):
1265 self._connection = unittest.mock.Mock()
1266+ self._client = unittest.mock.Mock()
1267 self._config_patcher = unittest.mock.patch('libertine.service.task_dispatcher.libertine.ContainersConfig.ContainersConfig')
1268 self._config_patcher.start()
1269- self._dispatcher = task_dispatcher.TaskDispatcher(self._connection)
1270+ self._dispatcher = task_dispatcher.TaskDispatcher(self._connection, self._client)
1271
1272 def tearDown(self):
1273 self._config_patcher.stop()
1274@@ -90,20 +91,20 @@
1275 self._dispatcher.list_app_ids('palpatine')
1276 self._dispatcher.list_app_ids('palpatine')
1277 self._dispatcher.list_app_ids('palpatine')
1278- MockContainer.assert_called_once_with('palpatine', unittest.mock.ANY, self._connection, unittest.mock.ANY)
1279+ MockContainer.assert_called_once_with('palpatine', unittest.mock.ANY, self._connection, self._client, unittest.mock.ANY)
1280
1281 def test_container_callback_removes_container(self):
1282 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
1283 c = MockContainer.return_value
1284 c.id = 'palpatine'
1285 self._dispatcher.list_app_ids('palpatine')
1286- MockContainer.assert_called_once_with('palpatine', unittest.mock.ANY, self._connection, unittest.mock.ANY)
1287+ MockContainer.assert_called_once_with('palpatine', unittest.mock.ANY, self._connection, self._client, unittest.mock.ANY)
1288 name, args, kwargs = MockContainer.mock_calls[0]
1289 args[len(args)-1](MockContainer.return_value)
1290 self._dispatcher.list_app_ids('palpatine')
1291 MockContainer.assert_has_calls([ # verify container constructed twice
1292- unittest.mock.call('palpatine', unittest.mock.ANY, self._connection, unittest.mock.ANY),
1293- unittest.mock.call('palpatine', unittest.mock.ANY, self._connection, unittest.mock.ANY)
1294+ unittest.mock.call('palpatine', unittest.mock.ANY, self._connection, self._client, unittest.mock.ANY),
1295+ unittest.mock.call('palpatine', unittest.mock.ANY, self._connection, self._client, unittest.mock.ANY)
1296 ], any_order=True)
1297
1298 def test_container_info_creates_container_info_task(self):
1299
1300=== modified file 'tools/libertined'
1301--- tools/libertined 2017-03-06 19:50:12 +0000
1302+++ tools/libertined 2017-03-09 17:44:54 +0000
1303@@ -25,7 +25,7 @@
1304 from dbus.mainloop.glib import DBusGMainLoop
1305 from gi.repository import GLib
1306 from libertine import utils
1307-from libertine.service import constants, operations, container_control
1308+from libertine.service import constants, operations, container_control, container_control_client
1309
1310
1311 class OutputRedirector(object):
1312@@ -151,9 +151,10 @@
1313 utils.get_logger().warning("service is already running")
1314 raise
1315
1316- manager = operations.Operations(bus_name)
1317- container_control.ContainerControl(manager.connection)
1318-
1319+ client = container_control_client.ContainerControlClient()
1320+ manager = operations.Operations(bus_name, client)
1321+ container_control.ContainerControl(manager.connection, client)
1322+
1323 try:
1324 loop.run()
1325 except KeyboardInterrupt:

Subscribers

People subscribed via source and target branches