Merge lp:~townsend/libertine/freeze-containers into lp:libertine

Proposed by Christopher Townsend
Status: Merged
Approved by: Christopher Townsend
Approved revision: 384
Merged at revision: 385
Proposed branch: lp:~townsend/libertine/freeze-containers
Merge into: lp:libertine
Diff against target: 261 lines (+60/-28)
6 files modified
python/libertine/ContainersConfig.py (+12/-2)
python/libertine/Libertine.py (+1/-1)
python/libertine/LxcContainer.py (+19/-9)
python/libertine/LxdContainer.py (+20/-10)
tools/libertine-lxc-manager (+5/-4)
tools/libertine-lxd-manager (+3/-2)
To merge this branch: bzr merge lp:~townsend/libertine/freeze-containers
Reviewer Review Type Date Requested Status
Libertine CI Bot continuous-integration Approve
Larry Price Approve
Review via email: mp+315485@code.launchpad.net

Commit message

Add ability to freeze and unfreeze LXC/LXD containers. This is disabled by default for now.

Description of the change

This is the first MP to allow freezing and unfreezing of LXC/LXD containers. More will follow for implementing the full feature.

This MP just adds the ability to freeze and unfreeze. To test, add the following in a container definition in ContainersConfig.json:

freezeOnStop: true

Then observe it's frozen after having done an operation on a container or started and quiting an app.

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

PASSED: Continuous integration, rev:383
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/341/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/670
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/550
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/550
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/550
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/550
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/680
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/661
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/661/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/661
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/661/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/661
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/661/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/661
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/661/artifact/output/*zip*/output.zip

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

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

minor inlines

review: Needs Information
Revision history for this message
Larry Price (larryprice) wrote :

also don't forget to update your copyright years when you touch files ^_^

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

PASSED: Continuous integration, rev:384
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/347/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/676
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/553
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/553
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/553
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/553
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/686
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/667
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/667/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/667
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/667/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/667
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/667/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/667
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/667/artifact/output/*zip*/output.zip

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

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

lgtm - very nice speed improvements

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

FAILED: Autolanding.
More details in the following jenkins job:
https://jenkins.canonical.com/libertine/job/lp-libertine-autoland/158/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/678
    FAILURE: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/555/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/555
    FAILURE: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/555/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/555
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/688
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/669
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/669/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/669
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/669/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/669
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/669/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/669
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/669/artifact/output/*zip*/output.zip

review: Needs Fixing (continuous-integration)
Revision history for this message
Libertine CI Bot (libertine-ci-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'python/libertine/ContainersConfig.py'
2--- python/libertine/ContainersConfig.py 2017-01-12 20:46:05 +0000
3+++ python/libertine/ContainersConfig.py 2017-01-24 20:22:21 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2016 Canonical Ltd.
6+# Copyright 2016-2017 Canonical Ltd.
7 #
8 # This program is free software: you can redistribute it and/or modify it
9 # under the terms of the GNU General Public License version 3, as published
10@@ -102,7 +102,8 @@
11 if not container:
12 return
13
14- if type(value) is str:
15+ if (type(value) is str or
16+ type(value) is bool):
17 container[key] = value
18 elif type(value) is dict:
19 if key not in container:
20@@ -375,6 +376,15 @@
21 self._delete_array_object_by_value(container_id, 'bindMounts', mount_path)
22
23 """
24+ Operations for setting container freeze on stop command.
25+ """
26+ def update_freeze_on_stop(self, container_id, freeze_on_stop=True):
27+ self._set_value_by_key(container_id, 'freezeOnStop', freeze_on_stop)
28+
29+ def get_freeze_on_stop(self, container_id):
30+ return self._get_value_by_key(container_id, 'freezeOnStop') or False
31+
32+ """
33 Fetcher functions for various configuration information.
34 """
35 def get_container_distro(self, container_id):
36
37=== modified file 'python/libertine/Libertine.py'
38--- python/libertine/Libertine.py 2017-01-17 20:28:15 +0000
39+++ python/libertine/Libertine.py 2017-01-24 20:22:21 +0000
40@@ -389,7 +389,7 @@
41
42 if container_type == "lxc":
43 from libertine.LxcContainer import LibertineLXC
44- self.container = LibertineLXC(container_id)
45+ self.container = LibertineLXC(container_id, self.containers_config)
46 elif container_type == "lxd":
47 from libertine.LxdContainer import LibertineLXD
48 self.container = LibertineLXD(container_id, self.containers_config)
49
50=== modified file 'python/libertine/LxcContainer.py'
51--- python/libertine/LxcContainer.py 2017-01-19 15:01:38 +0000
52+++ python/libertine/LxcContainer.py 2017-01-24 20:22:21 +0000
53@@ -1,4 +1,4 @@
54-# Copyright 2015-2016 Canonical Ltd.
55+# Copyright 2015-2017 Canonical Ltd.
56 #
57 # This program is free software: you can redistribute it and/or modify it
58 # under the terms of the GNU General Public License version 3, as published
59@@ -101,8 +101,12 @@
60 def lxc_start(container):
61 lxc_log_file = get_logfile(container)
62
63- if not container.start():
64- return LifecycleResult("Container failed to start.")
65+ if container.state == 'STOPPED':
66+ if not container.start():
67+ return LifecycleResult("Container failed to start.")
68+ elif container.state == 'FROZEN':
69+ if not container.unfreeze():
70+ return LifecycleResult("Container failed to unfreeze.")
71
72 if not container.wait("RUNNING", 10):
73 return LifecycleResult("Container failed to enter the RUNNING state.")
74@@ -114,8 +118,13 @@
75 return LifecycleResult()
76
77
78-def lxc_stop(container):
79- if container.running:
80+def lxc_stop(container, freeze_on_stop=False):
81+ if container.state == 'STOPPED' or not container.running:
82+ return
83+
84+ if freeze_on_stop:
85+ container.freeze()
86+ else:
87 container.stop()
88
89
90@@ -149,13 +158,14 @@
91 A concrete container type implemented using an LXC container.
92 """
93
94- def __init__(self, container_id):
95+ def __init__(self, container_id, config=None):
96 super().__init__(container_id)
97 self.container_type = "lxc"
98 self.container = lxc_container(container_id)
99 self.lxc_manager_interface = None
100 self.window_manager = None
101 self.host_info = HostInfo.HostInfo()
102+ self._freeze_on_stop = config.get_freeze_on_stop(self.container_id)
103
104 if utils.set_session_dbus_env_var():
105 try:
106@@ -180,9 +190,9 @@
107
108 def stop_container(self):
109 if self.lxc_manager_interface:
110- self.lxc_manager_interface.container_service_stop(self.container_id)
111+ self.lxc_manager_interface.container_service_stop(self.container_id, {'freeze': self._freeze_on_stop})
112 else:
113- lxc_stop(self.container)
114+ lxc_stop(self.container, self._freeze_on_stop)
115
116 def run_in_container(self, command_string):
117 cmd_args = shlex.split(command_string)
118@@ -349,4 +359,4 @@
119 utils.terminate_window_manager(psutil.Process(self.window_manager))
120
121 # Tell libertine-lxc-manager that the app has stopped.
122- self.lxc_manager_interface.container_service_stop(self.container_id)
123+ self.lxc_manager_interface.container_service_stop(self.container_id, {'freeze': self._freeze_on_stop})
124
125=== modified file 'python/libertine/LxdContainer.py'
126--- python/libertine/LxdContainer.py 2017-01-19 19:32:58 +0000
127+++ python/libertine/LxdContainer.py 2017-01-24 20:22:21 +0000
128@@ -1,4 +1,4 @@
129-# Copyright 2016 Canonical Ltd.
130+# Copyright 2016-2017 Canonical Ltd.
131 #
132 # This program is free software: you can redistribute it and/or modify it
133 # under the terms of the GNU General Public License version 3, as published
134@@ -140,8 +140,10 @@
135
136
137 def lxd_start(container):
138- if container.status != 'Running':
139+ if container.status == 'Stopped':
140 container.start(wait=True)
141+ elif container.status == 'Frozen':
142+ container.unfreeze(wait=True)
143
144 container.sync(rollback=True) # required for pylxd=2.0.x
145
146@@ -151,15 +153,22 @@
147 return LifecycleResult()
148
149
150-def lxd_stop(container, wait):
151+def lxd_stop(container, wait=True, freeze_on_stop=False):
152 if container.status == 'Stopped':
153 return LifecycleResult()
154
155- container.stop(wait=wait)
156+ if freeze_on_stop:
157+ container.freeze(wait=wait)
158+ else:
159+ container.stop(wait=wait)
160+
161 container.sync(rollback=True) # required for pylxd=2.0.x
162
163- if wait and container.status != 'Stopped':
164- return LifecycleResult("Container {} failed to stop".format(container.name))
165+ if wait:
166+ if freeze_on_stop and container.status != 'Frozen':
167+ return LifecycleResult("Container {} failed to freeze".format(container.name))
168+ elif container.status != 'Stopped':
169+ return LifecycleResult("Container {} failed to stop".format(container.name))
170
171 return LifecycleResult()
172
173@@ -298,6 +307,7 @@
174 self._container = None
175 self._matchbox_pid = None
176 self._manager = None
177+ self._freeze_on_stop = config.get_freeze_on_stop(self.container_id)
178
179 if not _setup_lxd():
180 raise Exception("Failed to setup lxd.")
181@@ -430,9 +440,9 @@
182 return False
183
184 if self._manager:
185- result = LifecycleResult.from_dict(self._manager.container_service_stop(self.container_id, {'wait': wait}))
186+ result = LifecycleResult.from_dict(self._manager.container_service_stop(self.container_id, {'wait': wait, 'freeze': self._freeze_on_stop}))
187 else:
188- result = lxd_stop(self._container, wait)
189+ result = lxd_stop(self._container, wait, self._freeze_on_stop)
190
191 if not result.success:
192 utils.get_logger().error(result.error)
193@@ -509,9 +519,9 @@
194 app.wait()
195
196 if self._manager:
197- self._manager.container_service_stop(self.container_id)
198+ self._manager.container_service_stop(self.container_id, {'freeze': self._freeze_on_stop})
199 else:
200- lxd_stop(self._container, False)
201+ lxd_stop(self._container, False, self._freeze_on_stop)
202
203 def copy_file_to_container(self, source, dest):
204 with open(source, 'rb') as f:
205
206=== modified file 'tools/libertine-lxc-manager'
207--- tools/libertine-lxc-manager 2017-01-19 15:01:38 +0000
208+++ tools/libertine-lxc-manager 2017-01-24 20:22:21 +0000
209@@ -1,7 +1,7 @@
210 #!/usr/bin/python3
211 # -*- coding: utf-8 -*-
212
213-# Copyright (C) 2016 Canonical Ltd.
214+# Copyright (C) 2016-2017 Canonical Ltd.
215 # Author: Christopher Townsend <christopher.townsend@canonical.com>
216
217 # This program is free software: you can redistribute it and/or modify
218@@ -47,16 +47,17 @@
219 if not self._is_pulse_setup:
220 self._setup_pulse()
221
222- if not container.running:
223+ if container.state == 'STOPPED':
224 self._dynamic_bind_mounts(container, container_id)
225
226- return libertine.LxcContainer.lxc_start(container)
227+ libertine.LxcContainer.lxc_start(container)
228
229 return LifecycleResult()
230
231 def stop(self, container_id, options={}):
232 container = libertine.LxcContainer.lxc_container(container_id)
233- libertine.LxcContainer.lxc_stop(container)
234+
235+ libertine.LxcContainer.lxc_stop(container, options.get('freeze', False))
236
237 return LifecycleResult() # no error case
238
239
240=== modified file 'tools/libertine-lxd-manager'
241--- tools/libertine-lxd-manager 2017-01-19 15:01:38 +0000
242+++ tools/libertine-lxd-manager 2017-01-24 20:22:21 +0000
243@@ -1,7 +1,7 @@
244 #!/usr/bin/python3
245 # -*- coding: utf-8 -*-
246
247-# Copyright (C) 2016 Canonical Ltd.
248+# Copyright (C) 2016-2017 Canonical Ltd.
249
250 # This program is free software: you can redistribute it and/or modify
251 # it under the terms of the GNU General Public License as published by
252@@ -50,7 +50,8 @@
253 return LifecycleResult()
254
255 def stop(self, container_id, options={}):
256- return libertine.LxdContainer.lxd_stop(libertine.LxdContainer.lxd_container(self._client, container_id), options.get('wait', False))
257+ return libertine.LxdContainer.lxd_stop(libertine.LxdContainer.lxd_container(self._client, container_id),
258+ options.get('wait', False), options.get('freeze', False))
259
260
261 if __name__ == '__main__':

Subscribers

People subscribed via source and target branches