Merge lp:~zulcss/nova/lxc into lp:~ubuntu-server-dev/nova/havana
- lxc
- Merge into havana
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Chuck Short | ||||
Approved revision: | 625 | ||||
Merged at revision: | 621 | ||||
Proposed branch: | lp:~zulcss/nova/lxc | ||||
Merge into: | lp:~ubuntu-server-dev/nova/havana | ||||
Diff against target: |
814 lines (+791/-0) 3 files modified
debian/changelog (+2/-0) debian/patches/native-lxc-hypervisor.patch (+788/-0) debian/patches/series (+1/-0) |
||||
To merge this branch: | bzr merge lp:~zulcss/nova/lxc | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Page | Approve | ||
Chuck Short (community) | Needs Resubmitting | ||
Adam Gandelman (community) | Needs Fixing | ||
Review via email: mp+187796@code.launchpad.net |
Commit message
Description of the change
Adds native lxc driver.
- 621. By Chuck Short
-
Updated native-
lxc-hypervisor. patch
Chuck Short (zulcss) wrote : | # |
> Can you please cleanup pep8 and add unit tests?
>
> I'm concerned shipping this before its even been proposed upstream, especially
> if its not shipping without any test coverage. I'd be okay if it had tests
> run at package build time and you also integrated this driver as something we
> deploy and exercise as part of lp:openstack-ubuntu-testing.
- Added basic testsuite
- Fixed up pep8
James Page (james-page) wrote : | # |
${PYTHON:-python} -m subunit.run discover -t ./ ./nova/tests
=======
FAIL: nova.tests.
tags: worker-0
-------
Empty attachments:
pythonlogging:''
stderr
stdout
Traceback (most recent call last):
File "/«PKGBUILDDIR»
host_stats = self.lxc_
File "/«PKGBUILDDIR»
return self.hostops.
File "/«PKGBUILDDIR»
self.
File "/«PKGBUILDDIR»
disk = self._get_
File "/«PKGBUILDDIR»
hddinfo = os.statvfs(
OSError: [Errno 2] No such file or directory: '/var/lib/lxc'
- 622. By Chuck Short
-
Update patch again
Chuck Short (zulcss) wrote : | # |
> ${PYTHON:-python} -m subunit.run discover -t ./ ./nova/tests
> =======
> FAIL: nova.tests.
> tags: worker-0
> -------
> Empty attachments:
> pythonlogging:''
> stderr
> stdout
>
> Traceback (most recent call last):
> File "/«PKGBUILDDIR»
> test_get_host_stats
> host_stats = self.lxc_
> File "/«PKGBUILDDIR»
> return self.hostops.
> File "/«PKGBUILDDIR»
> self._update_
> File "/«PKGBUILDDIR»
> disk = self._get_
> File "/«PKGBUILDDIR»
> hddinfo = os.statvfs(
> OSError: [Errno 2] No such file or directory: '/var/lib/lxc'
Fixed
James Page (james-page) wrote : | # |
OK _ test suite now runs successfully in a sbuild.
My only other comments is that some DEP headers on the patch would be good.
- 623. By Chuck Short
-
Add dep8 headers
James Page (james-page) wrote : | # |
+Forwarded: Yes
Please could you reference the gerrit topic or suchlike - makes it easier for someone else to track upstream activity.
- 624. By Chuck Short
-
Update dep8
- 625. By Chuck Short
-
Update patch
James Page (james-page) : | # |
Preview Diff
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2013-09-19 19:50:37 +0000 |
3 | +++ debian/changelog 2013-10-02 17:10:37 +0000 |
4 | @@ -17,6 +17,8 @@ |
5 | python-boto, python-paramiko, python-amplib, python-eventlet, |
6 | python-glanceclient, python-oslo.config, python-paramiko, python-six |
7 | * debian/patches/fix-requirements.patch: Rediffed |
8 | + * debian/patches/native-lxc-hypervisor.patch: Add native lxc support. |
9 | + (LP: #1220701) |
10 | |
11 | -- Chuck Short <zulcss@ubuntu.com> Fri, 13 Sep 2013 10:12:52 -0400 |
12 | |
13 | |
14 | === added file 'debian/patches/native-lxc-hypervisor.patch' |
15 | --- debian/patches/native-lxc-hypervisor.patch 1970-01-01 00:00:00 +0000 |
16 | +++ debian/patches/native-lxc-hypervisor.patch 2013-10-02 17:10:37 +0000 |
17 | @@ -0,0 +1,788 @@ |
18 | +Description: Add native LXC support for openstack |
19 | +Author: Chuck Short <zulcss@ubuntu.com> |
20 | +Forwarded: no, https://github.com/zulcss/nova |
21 | +diff -Naurp nova/etc/nova/nova.conf.sample nova.lxc/etc/nova/nova.conf.sample |
22 | +--- nova/etc/nova/nova.conf.sample 2013-09-30 23:23:16.952467626 -0400 |
23 | ++++ nova.lxc/etc/nova/nova.conf.sample 2013-09-30 21:32:00.748464388 -0400 |
24 | +@@ -2202,6 +2202,23 @@ |
25 | + |
26 | + |
27 | + # |
28 | ++# Options defined in nova.virt.lxc.driver |
29 | ++# |
30 | ++ |
31 | ++# Default lxc configuration path (string value) |
32 | ++#lxc_path=/var/lib/lxc |
33 | ++ |
34 | ++# Default cgroups path (string value) |
35 | ++#cgroups_path=/sys/fs/cgroup |
36 | ++ |
37 | ++# Template file for lxc configuration file (string value) |
38 | ++#lxc_config_template=$pybasedir/nova/virt/lxc/config.tmpl |
39 | ++ |
40 | ++# Template file for lxc fstab file (string value) |
41 | ++#lxc_fstab_template=$pybasedir/nova/virt/lxc/fstab.tmpl |
42 | ++ |
43 | ++ |
44 | ++# |
45 | + # Options defined in nova.virt.powervm.driver |
46 | + # |
47 | + |
48 | +diff -Naurp nova/etc/nova/rootwrap.d/compute.filters nova.lxc/etc/nova/rootwrap.d/compute.filters |
49 | +--- nova/etc/nova/rootwrap.d/compute.filters 2013-09-30 23:23:16.952467626 -0400 |
50 | ++++ nova.lxc/etc/nova/rootwrap.d/compute.filters 2013-09-30 12:51:46.540449253 -0400 |
51 | +@@ -209,3 +209,10 @@ rpc.mountd: CommandFilter, rpc.mountd, r |
52 | + |
53 | + # nova/virt/libvirt/utils.py: |
54 | + rbd: CommandFilter, rbd, root |
55 | ++ |
56 | ++# nova/virt/vmutils.py |
57 | ++lxc-info: CommandFilter, lxc-info, root |
58 | ++lxc-ls: CommandFilter, lxc-ls, root |
59 | ++lxc-start: CommandFilter, lxc-start, root |
60 | ++lxc-stop: CommandFilter, lxc-stop, root |
61 | ++lxc-destroy CommandFilter, lxc-destroy, root |
62 | +diff -Naurp nova/nova/tests/virt/lxc/__init__.py nova.lxc/nova/tests/virt/lxc/__init__.py |
63 | +--- nova/nova/tests/virt/lxc/__init__.py 1969-12-31 19:00:00.000000000 -0500 |
64 | ++++ nova.lxc/nova/tests/virt/lxc/__init__.py 2013-09-30 12:52:48.900449283 -0400 |
65 | +@@ -0,0 +1,15 @@ |
66 | ++# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
67 | ++ |
68 | ++# Copyright (c) 2013 Canonical |
69 | ++# |
70 | ++# Licensed under the Apache License, Version 2.0 (the "License"); you may |
71 | ++# not use this file except in compliance with the License. You may obtain |
72 | ++# a copy of the License at |
73 | ++# |
74 | ++# http://www.apache.org/licenses/LICENSE-2.0 |
75 | ++# |
76 | ++# Unless required by applicable law or agreed to in writing, software |
77 | ++# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
78 | ++# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
79 | ++# License for the specific language governing permissions and limitations |
80 | ++# under the License. |
81 | +diff -Naurp nova/nova/tests/virt/lxc/test_driver.py nova.lxc/nova/tests/virt/lxc/test_driver.py |
82 | +--- nova/nova/tests/virt/lxc/test_driver.py 1969-12-31 19:00:00.000000000 -0500 |
83 | ++++ nova.lxc/nova/tests/virt/lxc/test_driver.py 2013-10-01 11:06:44.672830906 -0400 |
84 | +@@ -0,0 +1,126 @@ |
85 | ++# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
86 | ++ |
87 | ++# Copyright (c) 2013 Canonical |
88 | ++# |
89 | ++# Licensed under the Apache License, Version 2.0 (the "License"); you may |
90 | ++# not use this file except in compliance with the License. You may obtain |
91 | ++# a copy of the License at |
92 | ++# |
93 | ++# http://www.apache.org/licenses/LICENSE-2.0 |
94 | ++# |
95 | ++# Unless required by applicable law or agreed to in writing, software |
96 | ++# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
97 | ++# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
98 | ++# License for the specific language governing permissions and limitations |
99 | ++# under the License. |
100 | ++ |
101 | ++import fixtures |
102 | ++import mox |
103 | ++import os |
104 | ++ |
105 | ++from nova.compute import flavors |
106 | ++from nova.compute import power_state |
107 | ++from nova import context |
108 | ++from nova import db |
109 | ++from nova.network import model as network_model |
110 | ++from nova import test |
111 | ++from nova.tests import fake_network_cache_model |
112 | ++from nova import utils |
113 | ++from nova.virt import images |
114 | ++from nova.virt.lxc import driver as lxc_connection |
115 | ++from nova.virt.lxc import vmutils |
116 | ++ |
117 | ++ |
118 | ++class LXCDriverTestCase(test.TestCase): |
119 | ++ def setUp(self): |
120 | ++ super(LXCDriverTestCase, self).setUp() |
121 | ++ self.flags(instances_path=self.useFixture(fixtures.TempDir()).path) |
122 | ++ self.lxc_connection = lxc_connection.LXCDriver(None) |
123 | ++ |
124 | ++ instance_type = db.flavor_get(context.get_admin_context(), 5) |
125 | ++ sys_meta = flavors.save_flavor_info({}, instance_type) |
126 | ++ |
127 | ++ self.instance = { |
128 | ++ 'uuid': '32dfcb37-5af1-552b-357c-be8c3aa38310', |
129 | ++ 'memory_kb': '1024000', |
130 | ++ 'basepath': '/some/path', |
131 | ++ 'bridge_name': 'br100', |
132 | ++ 'vcpus': 2, |
133 | ++ 'project_id': 'fake', |
134 | ++ 'bridge': 'br101', |
135 | ++ 'image_ref': '155d900f-4e14-4e4c-a73d-069cbf4541e6', |
136 | ++ 'root_gb': 10, |
137 | ++ 'ephemeral_gb': 20, |
138 | ++ 'instance_type_id': '5', # m1.small |
139 | ++ 'extra_specs': {}, |
140 | ++ 'system_metadata': sys_meta} |
141 | ++ |
142 | ++ def test_get_info_containers_running(self): |
143 | ++ self.mox.StubOutWithMock(vmutils.VMUtils, 'container_exists') |
144 | ++ vmutils.VMUtils.container_exists(mox.IgnoreArg()).AndReturn(True) |
145 | ++ self.mox.ReplayAll() |
146 | ++ state = self.lxc_connection.get_info(self.instance) |
147 | ++ self.assertEqual(state['state'], power_state.RUNNING) |
148 | ++ |
149 | ++ def test_get_info_containers_not_running(self): |
150 | ++ self.mox.StubOutWithMock(vmutils.VMUtils, 'container_exists') |
151 | ++ vmutils.VMUtils.container_exists(mox.IgnoreArg()).AndReturn(False) |
152 | ++ self.mox.ReplayAll() |
153 | ++ state = self.lxc_connection.get_info(self.instance) |
154 | ++ self.assertEqual(state['state'], power_state.SHUTDOWN) |
155 | ++ |
156 | ++ def test_get_info_containers_no_status(self): |
157 | ++ self.mox.StubOutWithMock(vmutils.VMUtils, 'container_exists') |
158 | ++ vmutils.VMUtils.container_exists(mox.IgnoreArg()).AndReturn('') |
159 | ++ self.mox.ReplayAll() |
160 | ++ state = self.lxc_connection.get_info(self.instance) |
161 | ++ self.assertEqual(state['state'], power_state.NOSTATE) |
162 | ++ |
163 | ++ def test_spawn(self): |
164 | ++ def fake_image_fetch(context, image_id, file_path, |
165 | ++ user_id, project_id): |
166 | ++ pass |
167 | ++ |
168 | ++ self.stubs.Set(images, 'fetch', fake_image_fetch) |
169 | ++ image_meta = {} |
170 | ++ image_meta['id'] = '666' |
171 | ++ fake_net_info = network_model.NetworkInfo([ |
172 | ++ fake_network_cache_model.new_vif()]) |
173 | ++ |
174 | ++ instance_ref = self.instance |
175 | ++ instance_ref['image_ref'] = 123456 # we send an int to test sha1 call |
176 | ++ instance_type = db.flavor_get(context.get_admin_context(), |
177 | ++ instance_ref['instance_type_id']) |
178 | ++ sys_meta = flavors.save_flavor_info({}, instance_type) |
179 | ++ instance_ref['system_metadata'] = sys_meta |
180 | ++ instance = db.instance_create( |
181 | ++ context.get_admin_context(), instance_ref) |
182 | ++ |
183 | ++ self.lxc_connection.spawn(context.get_admin_context(), |
184 | ++ self.instance, image_meta, [], '', |
185 | ++ fake_net_info) |
186 | ++ |
187 | ++ def test_get_console(self): |
188 | ++ with utils.tempdir() as tmpdir: |
189 | ++ self.flags(instances_path=tmpdir) |
190 | ++ |
191 | ++ instance_ref = self.instance |
192 | ++ instance_ref['image_ref'] = 123456 |
193 | ++ instance = db.instance_create( |
194 | ++ context.get_admin_context(), instance_ref) |
195 | ++ |
196 | ++ console_dir = os.path.join(tmpdir, self.instance['uuid']) |
197 | ++ console_log = "%s/console.log" % console_dir |
198 | ++ os.makedirs(console_dir) |
199 | ++ |
200 | ++ f = open(console_log, 'w') |
201 | ++ f.write('0123456789') |
202 | ++ f.close() |
203 | ++ |
204 | ++ output = self.lxc_connection.get_console_output(self.instance) |
205 | ++ |
206 | ++ self.assertEquals('0123456789', output) |
207 | ++ |
208 | ++ def test_get_host_stats(self): |
209 | ++ host_stats = self.lxc_connection.get_host_stats() |
210 | ++ self.assertIsNotNone(host_stats) |
211 | +diff -Naurp nova/nova/virt/lxc/config.tmpl nova.lxc/nova/virt/lxc/config.tmpl |
212 | +--- nova/nova/virt/lxc/config.tmpl 1969-12-31 19:00:00.000000000 -0500 |
213 | ++++ nova.lxc/nova/virt/lxc/config.tmpl 2013-09-30 12:51:46.540449253 -0400 |
214 | +@@ -0,0 +1,52 @@ |
215 | ++# Template used to create this container: /usr/share/lxc/templates/lxc-ubuntu |
216 | ++# Parameters passed to the template: |
217 | ++lxc.network.type = veth |
218 | ++lxc.network.hwaddr = {{ container_hwaddr }} |
219 | ++lxc.network.flags = up |
220 | ++lxc.network.link = {{ container_link }} |
221 | ++lxc.rootfs = {{ container_rootfs }} |
222 | ++lxc.mount = {{ container_fstab }} |
223 | ++lxc.pivotdir = lxc_putold |
224 | ++ |
225 | ++lxc.devttydir = lxc |
226 | ++lxc.tty = 4 |
227 | ++lxc.pts = 1024 |
228 | ++ |
229 | ++lxc.utsname = {{ container_name }} |
230 | ++lxc.cap.drop = sys_module mac_admin mac_override sys_time |
231 | ++lxc.console = {{ console_file }} |
232 | ++ |
233 | ++# When using LXC with apparmor, uncomment the next line to run unconfined: |
234 | ++lxc.aa_profile = unconfined |
235 | ++ |
236 | ++# To support container nesting on an Ubuntu host, uncomment next two lines: |
237 | ++#lxc.aa_profile = lxc-container-default-with-nesting |
238 | ++#lxc.hook.mount = /usr/share/lxc/hooks/mountcgroups |
239 | ++ |
240 | ++lxc.cgroup.devices.deny = a |
241 | ++# Allow any mknod (but not using the node) |
242 | ++lxc.cgroup.devices.allow = c *:* m |
243 | ++lxc.cgroup.devices.allow = b *:* m |
244 | ++# /dev/null and zero |
245 | ++lxc.cgroup.devices.allow = c 1:3 rwm |
246 | ++lxc.cgroup.devices.allow = c 1:5 rwm |
247 | ++# consoles |
248 | ++lxc.cgroup.devices.allow = c 5:1 rwm |
249 | ++lxc.cgroup.devices.allow = c 5:0 rwm |
250 | ++# /dev/{,u}random |
251 | ++lxc.cgroup.devices.allow = c 1:9 rwm |
252 | ++lxc.cgroup.devices.allow = c 1:8 rwm |
253 | ++lxc.cgroup.devices.allow = c 136:* rwm |
254 | ++lxc.cgroup.devices.allow = c 5:2 rwm |
255 | ++# rtc |
256 | ++lxc.cgroup.devices.allow = c 254:0 rm |
257 | ++# fuse |
258 | ++lxc.cgroup.devices.allow = c 10:229 rwm |
259 | ++# tun |
260 | ++lxc.cgroup.devices.allow = c 10:200 rwm |
261 | ++# full |
262 | ++lxc.cgroup.devices.allow = c 1:7 rwm |
263 | ++# hpet |
264 | ++lxc.cgroup.devices.allow = c 10:228 rwm |
265 | ++# kvm |
266 | ++lxc.cgroup.devices.allow = c 10:232 rwm |
267 | +diff -Naurp nova/nova/virt/lxc/driver.py nova.lxc/nova/virt/lxc/driver.py |
268 | +--- nova/nova/virt/lxc/driver.py 1969-12-31 19:00:00.000000000 -0500 |
269 | ++++ nova.lxc/nova/virt/lxc/driver.py 2013-09-30 21:17:31.856463967 -0400 |
270 | +@@ -0,0 +1,145 @@ |
271 | ++# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
272 | ++ |
273 | ++# Copyright 2010 United States Government as represented by the |
274 | ++# Administrator of the National Aeronautics and Space Administration. |
275 | ++# All Rights Reserved. |
276 | ++# Copyright (c) 2013 Canonical Ltd |
277 | ++# |
278 | ++# Licensed under the Apache License, Version 2.0 (the "License"); you may |
279 | ++# not use this file except in compliance with the License. You may obtain |
280 | ++# a copy of the License at |
281 | ++# |
282 | ++# http://www.apache.org/licenses/LICENSE-2.0 |
283 | ++# |
284 | ++# Unless required by applicable law or agreed to in writing, software |
285 | ++# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
286 | ++# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
287 | ++# License for the specific language governing permissions and limitations |
288 | ++# under the License. |
289 | ++ |
290 | ++""" |
291 | ++lxc hypervisor drvier |
292 | ++""" |
293 | ++ |
294 | ++import os |
295 | ++ |
296 | ++from oslo.config import cfg |
297 | ++ |
298 | ++from nova.compute import power_state |
299 | ++from nova.openstack.common.gettextutils import _ # noqa |
300 | ++from nova.openstack.common import log as logging |
301 | ++from nova.virt import driver |
302 | ++from nova.virt.lxc import hostops |
303 | ++from nova.virt.lxc import vmops |
304 | ++from nova.virt import virtapi |
305 | ++ |
306 | ++ |
307 | ++lxc_opts = [ |
308 | ++ cfg.StrOpt('lxc_path', |
309 | ++ default='/var/lib/lxc', |
310 | ++ help='Default lxc configuration path'), |
311 | ++ cfg.StrOpt('cgroups_path', |
312 | ++ default='/sys/fs/cgroup', |
313 | ++ help='Default cgroups path'), |
314 | ++ cfg.StrOpt('lxc_config_template', |
315 | ++ default='$pybasedir/nova/virt/lxc/config.tmpl', |
316 | ++ help='Template file for lxc configuration file'), |
317 | ++ cfg.StrOpt('lxc_fstab_template', |
318 | ++ default='$pybasedir/nova/virt/lxc/fstab.tmpl', |
319 | ++ help='Template file for lxc fstab file'), |
320 | ++ ] |
321 | ++ |
322 | ++CONF = cfg.CONF |
323 | ++CONF.register_opts(lxc_opts) |
324 | ++CONF.import_opt('host', 'nova.netconf') |
325 | ++ |
326 | ++LOG = logging.getLogger(__name__) |
327 | ++ |
328 | ++ |
329 | ++class LXCDriver(driver.ComputeDriver): |
330 | ++ capabilities = { |
331 | ++ "has_imagecache": False, |
332 | ++ "supports_recreate": False, |
333 | ++ } |
334 | ++ |
335 | ++ """lxc hypervisor driver.""" |
336 | ++ |
337 | ++ def __init__(self, virtapi, read_only=False): |
338 | ++ super(LXCDriver, self).__init__(virtapi) |
339 | ++ self.hostops = hostops.HostOps() |
340 | ++ self.vmops = vmops.VMOps() |
341 | ++ |
342 | ++ def init_host(self, host): |
343 | ++ if not os.path.exists("/usr/bin/lxc-version"): |
344 | ++ LOG.error(_('LXC is not installed')) |
345 | ++ |
346 | ++ def list_instances(self): |
347 | ++ return self.vmops.list_instances() |
348 | ++ |
349 | ++ def plug_vifs(self, instance, network_info): |
350 | ++ """Plug VIFs into networks.""" |
351 | ++ pass |
352 | ++ |
353 | ++ def unplug_vifs(self, instance, network_info): |
354 | ++ """Unplug VIFs from networks.""" |
355 | ++ pass |
356 | ++ |
357 | ++ def spawn(self, context, instance, image_meta, injected_files, |
358 | ++ admin_password, network_info=None, block_device_info=None): |
359 | ++ self.vmops.spawn(context, instance, image_meta, injected_files, |
360 | ++ admin_password, network_info, block_device_info) |
361 | ++ |
362 | ++ def reboot(self, context, instance, network_info, reboot_type, |
363 | ++ block_device_info=None, bad_volumes_callback=None): |
364 | ++ pass |
365 | ++ |
366 | ++ def power_off(self, instance): |
367 | ++ self.vmops.power_off(instance) |
368 | ++ |
369 | ++ def power_on(self, context, instance, network_info, block_device_info): |
370 | ++ self.vmops.power_on(instance) |
371 | ++ |
372 | ++ def restore(self, instance): |
373 | ++ pass |
374 | ++ |
375 | ++ def pause(self, instance): |
376 | ++ pass |
377 | ++ |
378 | ++ def unpause(self, instance): |
379 | ++ pass |
380 | ++ |
381 | ++ def suspend(self, instance): |
382 | ++ pass |
383 | ++ |
384 | ++ def resume(self, instance, network_info, block_device_info=None): |
385 | ++ pass |
386 | ++ |
387 | ++ def destroy(self, instance, network_info, block_device_info=None, |
388 | ++ destroy_disks=True, context=None): |
389 | ++ self.vmops.destroy(instance, network_info, block_device_info, |
390 | ++ destroy_disks, context) |
391 | ++ self.virtapi.instance_update(context.get_admin_context(), |
392 | ++ instance['uuid'], {'power_state': power_state.SHUTDOWN}) |
393 | ++ |
394 | ++ def get_info(self, instance): |
395 | ++ state = self.vmops.container_exists(instance) |
396 | ++ if state: |
397 | ++ pstate = power_state.RUNNING |
398 | ++ elif state is False: |
399 | ++ pstate = power_state.SHUTDOWN |
400 | ++ else: |
401 | ++ pstate = power_state.NOSTATE |
402 | ++ return {'state': pstate, |
403 | ++ 'max_mem': 0, |
404 | ++ 'mem': 0, |
405 | ++ 'num_cpu': 2, |
406 | ++ 'cpu_time': 0} |
407 | ++ |
408 | ++ def get_console_output(self, instance): |
409 | ++ return self.vmops.get_console_output(instance) |
410 | ++ |
411 | ++ def get_available_resource(self, nodename): |
412 | ++ return self.hostops.get_compute_stats() |
413 | ++ |
414 | ++ def get_host_stats(self, refresh=False): |
415 | ++ return self.hostops.get_host_stats(refresh) |
416 | +diff -Naurp nova/nova/virt/lxc/fstab.tmpl nova.lxc/nova/virt/lxc/fstab.tmpl |
417 | +--- nova/nova/virt/lxc/fstab.tmpl 1969-12-31 19:00:00.000000000 -0500 |
418 | ++++ nova.lxc/nova/virt/lxc/fstab.tmpl 2013-09-30 12:51:46.540449253 -0400 |
419 | +@@ -0,0 +1,6 @@ |
420 | ++proc proc proc nodev,noexec,nosuid 0 0 |
421 | ++sysfs sys sysfs defaults 0 0 |
422 | ++/sys/fs/fuse/connections sys/fs/fuse/connections none bind 0 0 |
423 | ++/sys/kernel/debug sys/kernel/debug none bind 0 0 |
424 | ++/sys/kernel/security sys/kernel/security none bind 0 0 |
425 | ++/sys/fs/pstore sys/fs/pstore none bind 0 0 |
426 | +diff -Naurp nova/nova/virt/lxc/hostops.py nova.lxc/nova/virt/lxc/hostops.py |
427 | +--- nova/nova/virt/lxc/hostops.py 1969-12-31 19:00:00.000000000 -0500 |
428 | ++++ nova.lxc/nova/virt/lxc/hostops.py 2013-10-01 10:17:22.200760275 -0400 |
429 | +@@ -0,0 +1,132 @@ |
430 | ++# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
431 | ++ |
432 | ++# Copyright 2010 United States Government as represented by the |
433 | ++# Administrator of the National Aeronautics and Space Administration. |
434 | ++# All Rights Reserved. |
435 | ++# Copyright (c) 2013 Canonical Ltd |
436 | ++# |
437 | ++# Licensed under the Apache License, Version 2.0 (the "License"); you may |
438 | ++# not use this file except in compliance with the License. You may obtain |
439 | ++# a copy of the License at |
440 | ++# |
441 | ++# http://www.apache.org/licenses/LICENSE-2.0 |
442 | ++# |
443 | ++# Unless required by applicable law or agreed to in writing, software |
444 | ++# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
445 | ++# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
446 | ++# License for the specific language governing permissions and limitations |
447 | ++# under the License. |
448 | ++ |
449 | ++import multiprocessing |
450 | ++import os |
451 | ++import platform |
452 | ++import sys |
453 | ++ |
454 | ++from oslo.config import cfg |
455 | ++ |
456 | ++from nova.openstack.common.gettextutils import _ # noqa |
457 | ++from nova.openstack.common import jsonutils |
458 | ++from nova.openstack.common import log as logging |
459 | ++ |
460 | ++ |
461 | ++CONF = cfg.CONF |
462 | ++ |
463 | ++log = logging.getLogger(__name__) |
464 | ++ |
465 | ++ |
466 | ++class HostOps(object): |
467 | ++ def __init__(self): |
468 | ++ self._stats = None |
469 | ++ |
470 | ++ def get_host_stats(self, refresh=False): |
471 | ++ if refresh or not self._stats: |
472 | ++ self._update_stats() |
473 | ++ return self._stats |
474 | ++ |
475 | ++ def get_compute_stats(self): |
476 | ++ # Updating host information |
477 | ++ disk = self. _get_disk_info() |
478 | ++ memory = self._get_host_memory() |
479 | ++ |
480 | ++ dic = {'vcpus': 1, |
481 | ++ 'local_gb': disk['total'], |
482 | ++ 'vcpus_used': 0, |
483 | ++ 'memory_mb': memory['total'], |
484 | ++ 'memory_mb_used': memory['total'] - memory['free'], |
485 | ++ 'local_gb_used': disk['total'] - disk['free'], |
486 | ++ 'hypervisor_type': 'lxc', |
487 | ++ 'hypervisor_version': '1.0', |
488 | ++ 'hypervisor_hostname': platform.node(), |
489 | ++ 'cpu_info': '?', |
490 | ++ 'supported_instances': jsonutils.dumps([ |
491 | ++ ('i686', 'lxc', 'lxc'), |
492 | ++ ('x86_64', 'lxc', 'lxc')]), |
493 | ++ } |
494 | ++ return dic |
495 | ++ |
496 | ++ def _update_stats(self): |
497 | ++ memory = self._get_host_memory() |
498 | ++ disk = self._get_disk_info() |
499 | ++ cpu = self._get_cpu_info() |
500 | ++ |
501 | ++ data = {} |
502 | ++ data["vpcus"] = 1 |
503 | ++ data["cpu_info"] = \ |
504 | ++ {'vendor': cpu['vendor'], |
505 | ++ 'model': cpu['features'], |
506 | ++ 'topology': {'cores': 1, |
507 | ++ 'socket': multiprocessing.cpu_count(), |
508 | ++ 'threads': 1} |
509 | ++ } |
510 | ++ data["disk_total"] = disk['total'] |
511 | ++ data["disk_available"] = disk["free"] |
512 | ++ data["disk_used"] = data["disk_total"] - data["disk_available"] |
513 | ++ data["memory_mb"] = memory["total"] |
514 | ++ data["host_memory_total"] = memory["total"] |
515 | ++ data["host_memory_free"] = memory["free"] |
516 | ++ data['hypverisor_type'] = 'lxc' |
517 | ++ data['hypervisor_version'] = '1.0' |
518 | ++ data['hypervisor_hostname'] = platform.node() |
519 | ++ data['supported_instances'] = [('i686', 'lxc', 'lxc'), |
520 | ++ ('x86_64', 'lxc', 'lxc')] |
521 | ++ self._stats = data |
522 | ++ return data |
523 | ++ |
524 | ++ def _get_host_memory(self): |
525 | ++ if sys.platform.upper() not in ['LINUX2', 'LINUX3']: |
526 | ++ return 1 |
527 | ++ |
528 | ++ data = {} |
529 | ++ for line in open('/proc/meminfo'): |
530 | ++ if ':' in line: |
531 | ++ key, value = line.split(":", 1) |
532 | ++ if key in ["MemTotal", "MemFree", "Buffers", "Cached"]: |
533 | ++ data[key] = int(value.split()[0]) |
534 | ++ return{'total': data['MemTotal'], |
535 | ++ 'free': (data["MemFree"] + |
536 | ++ data["Buffers"] + data["Cached"])} |
537 | ++ |
538 | ++ def _get_disk_info(self): |
539 | ++ hddinfo = os.statvfs(CONF.instances_path) |
540 | ++ total = hddinfo.f_frsize * hddinfo.f_blocks |
541 | ++ free = hddinfo.f_frsize * hddinfo.f_bavail |
542 | ++ return {'total': total, 'free': free} |
543 | ++ |
544 | ++ def _get_cpu_info(self): |
545 | ++ cpuinfo = dict() |
546 | ++ cpuinfo['features'] = list() |
547 | ++ if sys.platform.upper() not in ['LINUX2', 'LINUX3']: |
548 | ++ return 0 |
549 | ++ |
550 | ++ f = open('/proc/cpuinfo', 'r') |
551 | ++ for line in f: |
552 | ++ if line.strip(): |
553 | ++ if line.rstrip('\n').startswith('vendor_id'): |
554 | ++ cpuinfo['vendor'] = line.rstrip('\n').split(':')[1] |
555 | ++ if line.rstrip('\n').startswith('model_name'): |
556 | ++ cpuinfo['model'] = line.rstrip('\n').split(':')[1] |
557 | ++ if line.rstrip('\n').startswith('flags'): |
558 | ++ cpuinfo['features'] = line.rstrip('\n').split(':')[1] |
559 | ++ |
560 | ++ cpuinfo['features'] = list(set(cpuinfo['features'])) |
561 | ++ return cpuinfo |
562 | +diff -Naurp nova/nova/virt/lxc/__init__.py nova.lxc/nova/virt/lxc/__init__.py |
563 | +--- nova/nova/virt/lxc/__init__.py 1969-12-31 19:00:00.000000000 -0500 |
564 | ++++ nova.lxc/nova/virt/lxc/__init__.py 2013-09-30 12:51:46.540449253 -0400 |
565 | +@@ -0,0 +1,22 @@ |
566 | ++# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
567 | ++ |
568 | ++# Copyright 2010 United States Government as represented by the |
569 | ++# Administrator of the National Aeronautics and Space Administration. |
570 | ++# All Rights Reserved. |
571 | ++# Copyright (c) 2013 Canonical Ltd |
572 | ++# |
573 | ++# Licensed under the Apache License, Version 2.0 (the "License"); you may |
574 | ++# not use this file except in compliance with the License. You may obtain |
575 | ++# a copy of the License at |
576 | ++# |
577 | ++# http://www.apache.org/licenses/LICENSE-2.0 |
578 | ++# |
579 | ++# Unless required by applicable law or agreed to in writing, software |
580 | ++# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
581 | ++# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
582 | ++# License for the specific language governing permissions and limitations |
583 | ++# under the License. |
584 | ++ |
585 | ++from nova.virt.lxc import driver |
586 | ++ |
587 | ++LXCDriver = driver.LXCDriver |
588 | +diff -Naurp nova/nova/virt/lxc/vmops.py nova.lxc/nova/virt/lxc/vmops.py |
589 | +--- nova/nova/virt/lxc/vmops.py 1969-12-31 19:00:00.000000000 -0500 |
590 | ++++ nova.lxc/nova/virt/lxc/vmops.py 2013-09-30 21:29:17.748464309 -0400 |
591 | +@@ -0,0 +1,146 @@ |
592 | ++# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
593 | ++ |
594 | ++# Copyright 2010 United States Government as represented by the |
595 | ++# Administrator of the National Aeronautics and Space Administration. |
596 | ++# All Rights Reserved. |
597 | ++# Copyright (c) 2013 Canonical Ltd |
598 | ++# |
599 | ++# Licensed under the Apache License, Version 2.0 (the "License"); you may |
600 | ++# not use this file except in compliance with the License. You may obtain |
601 | ++# a copy of the License at |
602 | ++# |
603 | ++# http://www.apache.org/licenses/LICENSE-2.0 |
604 | ++# |
605 | ++# Unless required by applicable law or agreed to in writing, software |
606 | ++# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
607 | ++# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
608 | ++# License for the specific language governing permissions and limitations |
609 | ++# under the License. |
610 | ++ |
611 | ++import os |
612 | ++ |
613 | ++import jinja2 |
614 | ++from oslo.config import cfg |
615 | ++ |
616 | ++from nova.openstack.common.gettextutils import _ |
617 | ++from nova.openstack.common import log as logging |
618 | ++from nova import utils |
619 | ++from nova.virt.disk import api as disk |
620 | ++from nova.virt import images |
621 | ++from nova.virt.libvirt import utils as libvirt_utils |
622 | ++from nova.virt.lxc import vmutils |
623 | ++ |
624 | ++LOG = logging.getLogger(__name__) |
625 | ++ |
626 | ++CONF = cfg.CONF |
627 | ++ |
628 | ++MAX_CONSOLE_BYTES = 102400 |
629 | ++ |
630 | ++ |
631 | ++class VMOps(object): |
632 | ++ def __init__(self): |
633 | ++ self.vmutils = vmutils.VMUtils() |
634 | ++ |
635 | ++ def spawn(self, context, instance, image_meta, injected_files, |
636 | ++ admin_password, network_info=None, block_device_info=None): |
637 | ++ LOG.info(_('Spawning instance')) |
638 | ++ try: |
639 | ++ instance_path = os.path.join(CONF.instances_path, |
640 | ++ instance['uuid']) |
641 | ++ image_path = os.path.join(instance_path, 'disk') |
642 | ++ container_rootfs = os.path.join(instance_path, 'rootfs') |
643 | ++ lxc_container = os.path.join(CONF.lxc_path, instance['uuid']) |
644 | ++ console_file = os.path.join(instance_path, 'console.log') |
645 | ++ |
646 | ++ def _lxc_setup_directories(): |
647 | ++ LOG.info(_('Creating initial LXC directories'), |
648 | ++ instance=instance) |
649 | ++ if not os.path.exists(lxc_container): |
650 | ++ utils.execute('mkdir', '-p', lxc_container, |
651 | ++ run_as_root=True) |
652 | ++ |
653 | ++ if not os.path.exists(container_rootfs): |
654 | ++ utils.execute('mkdir', '-p', container_rootfs, |
655 | ++ run_as_root=True) |
656 | ++ |
657 | ++ if not os.path.exists(instance_path): |
658 | ++ os.mkdir(instance_path) |
659 | ++ |
660 | ++ _lxc_setup_directories() |
661 | ++ |
662 | ++ def _lxc_build_config(): |
663 | ++ LOG.info(_('Build LXC configuration file')) |
664 | ++ for vif in network_info: |
665 | ++ mac_address = vif['address'] |
666 | ++ network_bridge = network_info[0]['network']['bridge'] |
667 | ++ |
668 | ++ tmpl_path, tmpl_file = os.path.split(CONF.lxc_config_template) |
669 | ++ env = jinja2.Environment( |
670 | ++ loader=jinja2.FileSystemLoader(tmpl_path)) |
671 | ++ template = env.get_template(tmpl_file) |
672 | ++ lxc_config = template.render( |
673 | ++ {'container_name': instance['uuid'], |
674 | ++ 'container_rootfs': container_rootfs, |
675 | ++ 'container_link': network_bridge, |
676 | ++ 'container_hwaddr': mac_address, |
677 | ++ 'console_file': console_file, |
678 | ++ 'container_fstab': '%s/%s/fstab' |
679 | ++ % (CONF.lxc_path, instance['uuid'])}) |
680 | ++ |
681 | ++ config_file = os.path.join(CONF.lxc_path, instance['uuid'], |
682 | ++ 'config') |
683 | ++ vmutils.write_to_file(config_file, lxc_config) |
684 | ++ |
685 | ++ fstab_file = os.path.join(CONF.lxc_path, instance['uuid'], |
686 | ++ 'fstab') |
687 | ++ fstab_config = open(CONF.lxc_fstab_template, 'r').read() |
688 | ++ vmutils.write_to_file(fstab_file, fstab_config) |
689 | ++ |
690 | ++ _lxc_build_config() |
691 | ++ |
692 | ++ def _lxc_ready_container(): |
693 | ++ LOG.info(_('Downloading and Mounting image')) |
694 | ++ images.fetch(context, instance['image_ref'], image_path, |
695 | ++ instance['user_id'], instance['project_id']) |
696 | ++ disk.setup_container(image_path, |
697 | ++ container_dir=container_rootfs, |
698 | ++ use_cow=CONF.use_cow_images) |
699 | ++ |
700 | ++ _lxc_ready_container() |
701 | ++ |
702 | ++ def _lxc_start_container(): |
703 | ++ LOG.info(_('Starting LXC container')) |
704 | ++ self.vmutils.start_container(instance) |
705 | ++ |
706 | ++ _lxc_start_container() |
707 | ++ except Exception as ex: |
708 | ++ LOG.exception(ex) |
709 | ++ |
710 | ++ def destroy(self, instance, network_info, block_device_info=None, |
711 | ++ destroy_disks=True, context=None): |
712 | ++ LOG.info(_('Destroying LXC container')) |
713 | ++ container_dir = os.path.join(CONF.instances_path, instance['uuid'], |
714 | ++ 'rootfs') |
715 | ++ instance_dir = os.path.join(CONF.instances_path, instance['uuid']) |
716 | ++ disk.teardown_container(container_dir=container_dir) |
717 | ++ self.vmutils.destroy_container(instance) |
718 | ++ |
719 | ++ def power_off(self, instance): |
720 | ++ self.vmutils.stop_container(instance) |
721 | ++ |
722 | ++ def power_on(self, instance): |
723 | ++ self.vmutils.start_container(instance) |
724 | ++ |
725 | ++ def get_console_output(self, instance): |
726 | ++ console_file = os.path.join(CONF.instances_path, instance['uuid'], |
727 | ++ 'console.log') |
728 | ++ with libvirt_utils.file_open(console_file, 'r') as fp: |
729 | ++ log_data, remaining = utils.last_bytes(fp, |
730 | ++ MAX_CONSOLE_BYTES) |
731 | ++ return log_data |
732 | ++ |
733 | ++ def list_instances(self): |
734 | ++ return self.vmutils.list_containers() |
735 | ++ |
736 | ++ def container_exists(self, instance): |
737 | ++ return self.vmutils.container_exists(instance) |
738 | +diff -Naurp nova/nova/virt/lxc/vmutils.py nova.lxc/nova/virt/lxc/vmutils.py |
739 | +--- nova/nova/virt/lxc/vmutils.py 1969-12-31 19:00:00.000000000 -0500 |
740 | ++++ nova.lxc/nova/virt/lxc/vmutils.py 2013-09-30 21:30:28.124464343 -0400 |
741 | +@@ -0,0 +1,64 @@ |
742 | ++# vim: tabstop=4 shiftwidth=4 softtabstop=4 |
743 | ++ |
744 | ++# Copyright 2010 United States Government as represented by the |
745 | ++# Administrator of the National Aeronautics and Space Administration. |
746 | ++# All Rights Reserved. |
747 | ++# Copyright (c) 2013 Canonical Ltd |
748 | ++# |
749 | ++# Licensed under the Apache License, Version 2.0 (the "License"); you may |
750 | ++# not use this file except in compliance with the License. You may obtain |
751 | ++# a copy of the License at |
752 | ++# |
753 | ++# http://www.apache.org/licenses/LICENSE-2.0 |
754 | ++# |
755 | ++# Unless required by applicable law or agreed to in writing, software |
756 | ++# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
757 | ++# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
758 | ++# License for the specific language governing permissions and limitations |
759 | ++# under the License. |
760 | ++ |
761 | ++ |
762 | ++from nova.openstack.common.gettextutils import _ # noqa |
763 | ++from nova.openstack.common import log as logging |
764 | ++from nova import utils |
765 | ++ |
766 | ++LOG = logging.getLogger(__name__) |
767 | ++ |
768 | ++ |
769 | ++def write_to_file(path, contents): |
770 | ++ utils.execute('tee', path, |
771 | ++ process_input=contents, run_as_root=True) |
772 | ++ |
773 | ++ |
774 | ++class VMUtils(object): |
775 | ++ def __init__(self): |
776 | ++ pass |
777 | ++ |
778 | ++ def container_exists(self, instance): |
779 | ++ (state, out) = utils.execute('lxc-info', '--name', instance['uuid'], |
780 | ++ '-s', run_as_root=True) |
781 | ++ state = state.split()[1] |
782 | ++ if state == 'RUNNING': |
783 | ++ return True |
784 | ++ else: |
785 | ++ return False |
786 | ++ |
787 | ++ def stop_container(self, instance): |
788 | ++ utils.execute('lxc-stop', '-n', instance['uuid'], run_as_root=True) |
789 | ++ |
790 | ++ def start_container(self, instance): |
791 | ++ utils.execute('lxc-start', '-d', '--name', instance['uuid'], |
792 | ++ run_as_root=True) |
793 | ++ |
794 | ++ def destroy_container(self, instance): |
795 | ++ utils.execute('lxc-destroy', '-f', '-n', instance['uuid'], |
796 | ++ run_as_root=True) |
797 | ++ |
798 | ++ def find_container_pid(self, instance): |
799 | ++ (pid, err) = utils.execute('lxc-info', '-n', instance['uuid'], '-p', |
800 | ++ run_as_root=True) |
801 | ++ pid = pid.split()[1] |
802 | ++ return pid |
803 | ++ |
804 | ++ def list_containers(self): |
805 | ++ utils.execute('lxc-ls', '-1', run_as_root=True) |
806 | |
807 | === modified file 'debian/patches/series' |
808 | --- debian/patches/series 2013-08-06 12:33:39 +0000 |
809 | +++ debian/patches/series 2013-10-02 17:10:37 +0000 |
810 | @@ -3,3 +3,4 @@ |
811 | fix-docs-build-without-network.patch |
812 | fix-requirements.patch |
813 | avoid-failing-test.patch |
814 | +native-lxc-hypervisor.patch |
Can you please cleanup pep8 and add unit tests?
I'm concerned shipping this before its even been proposed upstream, especially if its not shipping without any test coverage. I'd be okay if it had tests run at package build time and you also integrated this driver as something we deploy and exercise as part of lp:openstack-ubuntu-testing.