Merge lp:~hopem/nova/icehouse-lp1349888 into lp:~ubuntu-server-dev/nova/icehouse
- icehouse-lp1349888
- Merge into icehouse
Proposed by
Edward Hope-Morley
Status: | Merged |
---|---|
Merged at revision: | 706 |
Proposed branch: | lp:~hopem/nova/icehouse-lp1349888 |
Merge into: | lp:~ubuntu-server-dev/nova/icehouse |
Diff against target: |
392 lines (+372/-0) 3 files modified
debian/changelog (+8/-0) debian/patches/fix-creating-bdm-for-failed-volume-attachment.patch (+363/-0) debian/patches/series (+1/-0) |
To merge this branch: | bzr merge lp:~hopem/nova/icehouse-lp1349888 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Server Developers | Pending | ||
Review via email: mp+270414@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
- 707. By Edward Hope-Morley
-
forgot add file
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2015-07-16 10:56:04 +0000 |
3 | +++ debian/changelog 2015-09-08 14:49:18 +0000 |
4 | @@ -1,3 +1,11 @@ |
5 | +nova (1:2014.1.5-0ubuntu1.3) trusty; urgency=medium |
6 | + |
7 | + * Attempting to attach the same volume multiple times can cause |
8 | + bdm record for existing attachment to be deleted. (LP: #1349888) |
9 | + - d/p/fix-creating-bdm-for-failed-volume-attachment.patch |
10 | + |
11 | + -- Edward Hope-Morley <edward.hope-morley@canonical.com> Tue, 08 Sep 2015 12:32:45 +0100 |
12 | + |
13 | nova (1:2014.1.5-0ubuntu1.2) trusty; urgency=medium |
14 | |
15 | * Add rsyslog retry support (LP: #1459046) |
16 | |
17 | === added file 'debian/patches/fix-creating-bdm-for-failed-volume-attachment.patch' |
18 | --- debian/patches/fix-creating-bdm-for-failed-volume-attachment.patch 1970-01-01 00:00:00 +0000 |
19 | +++ debian/patches/fix-creating-bdm-for-failed-volume-attachment.patch 2015-09-08 14:49:18 +0000 |
20 | @@ -0,0 +1,363 @@ |
21 | +From f2061f0b6e94cf364ff565366ab71dfcc68cd2ef Mon Sep 17 00:00:00 2001 |
22 | +From: git-harry <git-harry@live.co.uk> |
23 | +Date: Mon, 4 Aug 2014 15:17:29 +0100 |
24 | +Subject: [PATCH] Fix creating bdm for failed volume attachment |
25 | + |
26 | +This commit modifies the reserve_block_device_name method to return the |
27 | +bdm object, when the corresponding keyword argument is True. This |
28 | +ensures the correct bdm is destroyed if the attach fails. Currently the |
29 | +code assumes only one bdm per volume and so retrieving it can cause the |
30 | +incorrect db entry to be returned. |
31 | + |
32 | +Closes-Bug: #1349888 |
33 | +(cherry picked from commit 339a97d0f2d17f531cfc79e09cd8b8bc75ce6e2a) |
34 | + |
35 | +Conflicts: |
36 | + nova/compute/api.py |
37 | + nova/compute/manager.py |
38 | + nova/compute/rpcapi.py |
39 | + nova/tests/compute/test_compute.py |
40 | + nova/tests/compute/test_rpcapi.py |
41 | + nova/tests/integrated/v3/test_extended_volumes.py |
42 | + |
43 | +Change-Id: I22a6db76d2044331d1a846eb4b6d7338c50270e2 |
44 | +--- |
45 | + nova/compute/api.py | 10 ++--- |
46 | + nova/compute/manager.py | 10 +++-- |
47 | + nova/compute/rpcapi.py | 45 +++++++++++++++++------ |
48 | + nova/tests/compute/test_compute.py | 35 +++++++++--------- |
49 | + nova/tests/compute/test_rpcapi.py | 20 +++++----- |
50 | + nova/tests/integrated/test_api_samples.py | 6 ++- |
51 | + nova/tests/integrated/v3/test_extended_volumes.py | 8 ++-- |
52 | + 7 files changed, 80 insertions(+), 54 deletions(-) |
53 | + |
54 | +diff --git a/nova/compute/api.py b/nova/compute/api.py |
55 | +index fd15df6..5605728 100644 |
56 | +--- a/nova/compute/api.py |
57 | ++++ b/nova/compute/api.py |
58 | +@@ -2786,11 +2786,9 @@ class API(base.Base): |
59 | + # the same time. When db access is removed from |
60 | + # compute, the bdm will be created here and we will |
61 | + # have to make sure that they are assigned atomically. |
62 | +- device = self.compute_rpcapi.reserve_block_device_name( |
63 | +- context, device=device, instance=instance, volume_id=volume_id, |
64 | +- disk_bus=disk_bus, device_type=device_type) |
65 | +- volume_bdm = block_device_obj.BlockDeviceMapping.get_by_volume_id( |
66 | +- context, volume_id) |
67 | ++ volume_bdm = self.compute_rpcapi.reserve_block_device_name( |
68 | ++ context, instance, device, volume_id, disk_bus=disk_bus, |
69 | ++ device_type=device_type) |
70 | + try: |
71 | + volume = self.volume_api.get(context, volume_id) |
72 | + self.volume_api.check_attach(context, volume, instance=instance) |
73 | +@@ -2801,7 +2799,7 @@ class API(base.Base): |
74 | + with excutils.save_and_reraise_exception(): |
75 | + volume_bdm.destroy(context) |
76 | + |
77 | +- return device |
78 | ++ return volume_bdm.device_name |
79 | + |
80 | + @wrap_check_policy |
81 | + @check_instance_lock |
82 | +diff --git a/nova/compute/manager.py b/nova/compute/manager.py |
83 | +index 6c49a64..aace5c2 100644 |
84 | +--- a/nova/compute/manager.py |
85 | ++++ b/nova/compute/manager.py |
86 | +@@ -586,7 +586,7 @@ class ComputeVirtAPI(virtapi.VirtAPI): |
87 | + class ComputeManager(manager.Manager): |
88 | + """Manages the running instances from creation to destruction.""" |
89 | + |
90 | +- target = messaging.Target(version='3.23') |
91 | ++ target = messaging.Target(version='3.35') |
92 | + |
93 | + # How long to wait in seconds before re-issuing a shutdown |
94 | + # signal to a instance during power off. The overall |
95 | +@@ -4226,7 +4226,8 @@ class ComputeManager(manager.Manager): |
96 | + @reverts_task_state |
97 | + @wrap_instance_fault |
98 | + def reserve_block_device_name(self, context, instance, device, |
99 | +- volume_id, disk_bus=None, device_type=None): |
100 | ++ volume_id, disk_bus=None, device_type=None, |
101 | ++ return_bdm_object=False): |
102 | + # NOTE(ndipanov): disk_bus and device_type will be set to None if not |
103 | + # passed (by older clients) and defaulted by the virt driver. Remove |
104 | + # default values on the next major RPC version bump. |
105 | +@@ -4249,7 +4250,10 @@ class ComputeManager(manager.Manager): |
106 | + disk_bus=disk_bus, device_type=device_type) |
107 | + bdm.create(context) |
108 | + |
109 | +- return device_name |
110 | ++ if return_bdm_object: |
111 | ++ return bdm |
112 | ++ else: |
113 | ++ return device_name |
114 | + |
115 | + return do_reserve() |
116 | + |
117 | +diff --git a/nova/compute/rpcapi.py b/nova/compute/rpcapi.py |
118 | +index a1adfbf..2e39fd9 100644 |
119 | +--- a/nova/compute/rpcapi.py |
120 | ++++ b/nova/compute/rpcapi.py |
121 | +@@ -22,6 +22,7 @@ from oslo import messaging |
122 | + from nova import block_device |
123 | + from nova import exception |
124 | + from nova.objects import base as objects_base |
125 | ++from nova.objects import block_device as block_device_obj |
126 | + from nova.openstack.common.gettextutils import _ |
127 | + from nova.openstack.common import jsonutils |
128 | + from nova import rpc |
129 | +@@ -241,6 +242,28 @@ class ComputeAPI(object): |
130 | + 3.21 - Made rebuild take new-world BDM objects |
131 | + 3.22 - Made terminate_instance take new-world BDM objects |
132 | + 3.23 - Added external_instance_event() |
133 | ++ build_and_run_instance was added in Havana and not used or |
134 | ++ documented. |
135 | ++ |
136 | ++ ... Icehouse supports message version 3.23. So, any changes to |
137 | ++ existing methods in 3.x after that point should be done such that they |
138 | ++ can handle the version_cap being set to 3.23. |
139 | ++ |
140 | ++ 3.24 - Update rescue_instance() to take optional rescue_image_ref |
141 | ++ 3.25 - Make detach_volume take an object |
142 | ++ 3.26 - Make live_migration() and |
143 | ++ rollback_live_migration_at_destination() take an object |
144 | ++ ... Removed run_instance() |
145 | ++ 3.27 - Make run_instance() accept a new-world object |
146 | ++ 3.28 - Update get_console_output() to accept a new-world object |
147 | ++ 3.29 - Make check_instance_shared_storage accept a new-world object |
148 | ++ 3.30 - Make remove_volume_connection() accept a new-world object |
149 | ++ 3.31 - Add get_instance_diagnostics |
150 | ++ 3.32 - Add destroy_disks and migrate_data optional parameters to |
151 | ++ rollback_live_migration_at_destination() |
152 | ++ 3.33 - Make build_and_run_instance() take a NetworkRequestList object |
153 | ++ 3.34 - Add get_serial_console method |
154 | ++ 3.35 - Make reserve_block_device_name return a BDM object |
155 | + ''' |
156 | + |
157 | + VERSION_ALIASES = { |
158 | +@@ -795,22 +818,22 @@ class ComputeAPI(object): |
159 | + |
160 | + def reserve_block_device_name(self, ctxt, instance, device, volume_id, |
161 | + disk_bus=None, device_type=None): |
162 | +- version = '3.16' |
163 | + kw = {'instance': instance, 'device': device, |
164 | + 'volume_id': volume_id, 'disk_bus': disk_bus, |
165 | +- 'device_type': device_type} |
166 | +- |
167 | +- if not self.client.can_send_version(version): |
168 | +- # NOTE(russellb) Havana compat |
169 | +- version = self._get_compat_version('3.0', '2.3') |
170 | +- kw['instance'] = jsonutils.to_primitive( |
171 | +- objects_base.obj_to_primitive(instance)) |
172 | +- del kw['disk_bus'] |
173 | +- del kw['device_type'] |
174 | ++ 'device_type': device_type, 'return_bdm_object': True} |
175 | ++ if self.client.can_send_version('3.35'): |
176 | ++ version = '3.35' |
177 | ++ else: |
178 | ++ del kw['return_bdm_object'] |
179 | ++ version = '3.16' |
180 | + |
181 | + cctxt = self.client.prepare(server=_compute_host(None, instance), |
182 | + version=version) |
183 | +- return cctxt.call(ctxt, 'reserve_block_device_name', **kw) |
184 | ++ volume_bdm = cctxt.call(ctxt, 'reserve_block_device_name', **kw) |
185 | ++ if not isinstance(volume_bdm, block_device_obj.BlockDeviceMapping): |
186 | ++ volume_bdm = block_device_obj.BlockDeviceMapping.get_by_volume_id( |
187 | ++ ctxt, volume_id) |
188 | ++ return volume_bdm |
189 | + |
190 | + def backup_instance(self, ctxt, instance, image_id, backup_type, |
191 | + rotation): |
192 | +diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py |
193 | +index 9fd2603..1642fc5 100644 |
194 | +--- a/nova/tests/compute/test_compute.py |
195 | ++++ b/nova/tests/compute/test_compute.py |
196 | +@@ -1731,7 +1731,8 @@ class ComputeTestCase(BaseTestCase): |
197 | + |
198 | + bdms = [] |
199 | + |
200 | +- def fake_rpc_reserve_block_device_name(self, context, **kwargs): |
201 | ++ def fake_rpc_reserve_block_device_name(self, context, instance, device, |
202 | ++ volume_id, **kwargs): |
203 | + bdm = block_device_obj.BlockDeviceMapping( |
204 | + **{'source_type': 'volume', |
205 | + 'destination_type': 'volume', |
206 | +@@ -1740,6 +1741,7 @@ class ComputeTestCase(BaseTestCase): |
207 | + 'device_name': '/dev/vdc'}) |
208 | + bdm.create(context) |
209 | + bdms.append(bdm) |
210 | ++ return bdm |
211 | + |
212 | + self.stubs.Set(cinder.API, 'get', fake_volume_get) |
213 | + self.stubs.Set(cinder.API, 'check_attach', fake_check_attach) |
214 | +@@ -8760,6 +8762,10 @@ class ComputeAPITestCase(BaseTestCase): |
215 | + fake_bdm = fake_block_device.FakeDbBlockDeviceDict( |
216 | + {'source_type': 'volume', 'destination_type': 'volume', |
217 | + 'volume_id': 'fake-volume-id', 'device_name': '/dev/vdb'}) |
218 | ++ bdm = block_device_obj.BlockDeviceMapping()._from_db_object( |
219 | ++ self.context, |
220 | ++ block_device_obj.BlockDeviceMapping(), |
221 | ++ fake_bdm) |
222 | + instance = self._create_fake_instance() |
223 | + fake_volume = {'id': 'fake-volume-id'} |
224 | + |
225 | +@@ -8768,23 +8774,18 @@ class ComputeAPITestCase(BaseTestCase): |
226 | + mock.patch.object(cinder.API, 'check_attach'), |
227 | + mock.patch.object(cinder.API, 'reserve_volume'), |
228 | + mock.patch.object(compute_rpcapi.ComputeAPI, |
229 | +- 'reserve_block_device_name', return_value='/dev/vdb'), |
230 | +- mock.patch.object(db, 'block_device_mapping_get_by_volume_id', |
231 | +- return_value=fake_bdm), |
232 | ++ 'reserve_block_device_name', return_value=bdm), |
233 | + mock.patch.object(compute_rpcapi.ComputeAPI, 'attach_volume') |
234 | + ) as (mock_get, mock_check_attach, mock_reserve_vol, mock_reserve_bdm, |
235 | +- mock_bdm_get, mock_attach): |
236 | ++ mock_attach): |
237 | + |
238 | + self.compute_api.attach_volume( |
239 | + self.context, instance, 'fake-volume-id', |
240 | + '/dev/vdb', 'ide', 'cdrom') |
241 | + |
242 | + mock_reserve_bdm.assert_called_once_with( |
243 | +- self.context, device='/dev/vdb', instance=instance, |
244 | +- volume_id='fake-volume-id', disk_bus='ide', |
245 | +- device_type='cdrom') |
246 | +- mock_bdm_get.assert_called_once_with( |
247 | +- self.context, 'fake-volume-id', []) |
248 | ++ self.context, instance, '/dev/vdb', 'fake-volume-id', |
249 | ++ disk_bus='ide', device_type='cdrom') |
250 | + self.assertEqual(mock_get.call_args, |
251 | + mock.call(self.context, 'fake-volume-id')) |
252 | + self.assertEqual(mock_check_attach.call_args, |
253 | +@@ -8815,8 +8816,12 @@ class ComputeAPITestCase(BaseTestCase): |
254 | + def fake_rpc_attach_volume(self, context, **kwargs): |
255 | + called['fake_rpc_attach_volume'] = True |
256 | + |
257 | +- def fake_rpc_reserve_block_device_name(self, context, **kwargs): |
258 | ++ def fake_rpc_reserve_block_device_name(self, context, instance, device, |
259 | ++ volume_id, **kwargs): |
260 | + called['fake_rpc_reserve_block_device_name'] = True |
261 | ++ bdm = block_device_obj.BlockDeviceMapping() |
262 | ++ bdm['device_name'] = '/dev/vdb' |
263 | ++ return bdm |
264 | + |
265 | + self.stubs.Set(cinder.API, 'get', fake_volume_get) |
266 | + self.stubs.Set(cinder.API, 'check_attach', fake_check_attach) |
267 | +@@ -8828,17 +8833,11 @@ class ComputeAPITestCase(BaseTestCase): |
268 | + self.stubs.Set(compute_rpcapi.ComputeAPI, 'attach_volume', |
269 | + fake_rpc_attach_volume) |
270 | + |
271 | +- self.mox.StubOutWithMock(block_device_obj.BlockDeviceMapping, |
272 | +- 'get_by_volume_id') |
273 | +- block_device_obj.BlockDeviceMapping.get_by_volume_id( |
274 | +- self.context, mox.IgnoreArg()).AndReturn('fake-bdm') |
275 | +- self.mox.ReplayAll() |
276 | +- |
277 | + instance = self._create_fake_instance() |
278 | + self.compute_api.attach_volume(self.context, instance, 1, device=None) |
279 | + self.assertTrue(called.get('fake_check_attach')) |
280 | + self.assertTrue(called.get('fake_reserve_volume')) |
281 | +- self.assertTrue(called.get('fake_reserve_volume')) |
282 | ++ self.assertTrue(called.get('fake_volume_get')) |
283 | + self.assertTrue(called.get('fake_rpc_reserve_block_device_name')) |
284 | + self.assertTrue(called.get('fake_rpc_attach_volume')) |
285 | + |
286 | +diff --git a/nova/tests/compute/test_rpcapi.py b/nova/tests/compute/test_rpcapi.py |
287 | +index d4026ea..1a2b9f5 100644 |
288 | +--- a/nova/tests/compute/test_rpcapi.py |
289 | ++++ b/nova/tests/compute/test_rpcapi.py |
290 | +@@ -24,6 +24,7 @@ from oslo.config import cfg |
291 | + from nova.compute import rpcapi as compute_rpcapi |
292 | + from nova import context |
293 | + from nova import db |
294 | ++from nova.objects import block_device as objects_block_dev |
295 | + from nova.openstack.common import jsonutils |
296 | + from nova import test |
297 | + from nova.tests import fake_block_device |
298 | +@@ -88,7 +89,13 @@ class ComputeRpcAPITestCase(test.TestCase): |
299 | + rpc_mock, prepare_mock, csv_mock |
300 | + ): |
301 | + prepare_mock.return_value = rpcapi.client |
302 | +- rpc_mock.return_value = 'foo' if rpc_method == 'call' else None |
303 | ++ if 'return_bdm_object' in kwargs: |
304 | ++ del kwargs['return_bdm_object'] |
305 | ++ rpc_mock.return_value = objects_block_dev.BlockDeviceMapping() |
306 | ++ elif rpc_method == 'call': |
307 | ++ rpc_mock.return_value = 'foo' |
308 | ++ else: |
309 | ++ rpc_mock.return_value = None |
310 | + csv_mock.side_effect = ( |
311 | + lambda v: orig_prepare(version=v).can_send_version()) |
312 | + |
313 | +@@ -495,14 +502,9 @@ class ComputeRpcAPITestCase(test.TestCase): |
314 | + |
315 | + def test_reserve_block_device_name(self): |
316 | + self._test_compute_api('reserve_block_device_name', 'call', |
317 | +- instance=self.fake_instance, device='device', volume_id='id', |
318 | +- disk_bus='ide', device_type='cdrom', version='3.16') |
319 | +- |
320 | +- # NOTE(russellb) Havana compat |
321 | +- self.flags(compute='havana', group='upgrade_levels') |
322 | +- self._test_compute_api('reserve_block_device_name', 'call', |
323 | +- instance=self.fake_instance, device='device', volume_id='id', |
324 | +- version='2.3') |
325 | ++ instance=self.fake_instance, device='device', |
326 | ++ volume_id='id', disk_bus='ide', device_type='cdrom', |
327 | ++ version='3.35', return_bdm_object=True) |
328 | + |
329 | + def refresh_provider_fw_rules(self): |
330 | + self._test_compute_api('refresh_provider_fw_rules', 'cast', |
331 | +diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py |
332 | +index 3098aff..b2eb41b 100644 |
333 | +--- a/nova/tests/integrated/test_api_samples.py |
334 | ++++ b/nova/tests/integrated/test_api_samples.py |
335 | +@@ -3855,13 +3855,15 @@ class VolumeAttachmentsSampleJsonTest(VolumeAttachmentsSampleBase): |
336 | + extension_name = ("nova.api.openstack.compute.contrib.volumes.Volumes") |
337 | + |
338 | + def test_attach_volume_to_server(self): |
339 | +- device_name = '/dev/vdd' |
340 | + self.stubs.Set(cinder.API, 'get', fakes.stub_volume_get) |
341 | + self.stubs.Set(cinder.API, 'check_attach', lambda *a, **k: None) |
342 | + self.stubs.Set(cinder.API, 'reserve_volume', lambda *a, **k: None) |
343 | ++ device_name = '/dev/vdd' |
344 | ++ bdm = block_device_obj.BlockDeviceMapping() |
345 | ++ bdm['device_name'] = device_name |
346 | + self.stubs.Set(compute_manager.ComputeManager, |
347 | + "reserve_block_device_name", |
348 | +- lambda *a, **k: device_name) |
349 | ++ lambda *a, **k: bdm) |
350 | + self.stubs.Set(compute_manager.ComputeManager, |
351 | + 'attach_volume', |
352 | + lambda *a, **k: None) |
353 | +diff --git a/nova/tests/integrated/v3/test_extended_volumes.py b/nova/tests/integrated/v3/test_extended_volumes.py |
354 | +index 22e0479..9f24208 100644 |
355 | +--- a/nova/tests/integrated/v3/test_extended_volumes.py |
356 | ++++ b/nova/tests/integrated/v3/test_extended_volumes.py |
357 | +@@ -78,20 +78,18 @@ class ExtendedVolumesSampleJsonTests(test_servers.ServersSampleBase): |
358 | + self._verify_response('servers-detail-resp', subs, response, 200) |
359 | + |
360 | + def test_attach_volume(self): |
361 | ++ bdm = block_device_obj.BlockDeviceMapping() |
362 | + device_name = '/dev/vdd' |
363 | +- disk_bus = 'ide' |
364 | +- device_type = 'cdrom' |
365 | ++ bdm['device_name'] = device_name |
366 | + self.stubs.Set(cinder.API, 'get', fakes.stub_volume_get) |
367 | + self.stubs.Set(cinder.API, 'check_attach', lambda *a, **k: None) |
368 | + self.stubs.Set(cinder.API, 'reserve_volume', lambda *a, **k: None) |
369 | + self.stubs.Set(compute_manager.ComputeManager, |
370 | + "reserve_block_device_name", |
371 | +- lambda *a, **k: device_name) |
372 | ++ lambda *a, **k: bdm) |
373 | + self.stubs.Set(compute_manager.ComputeManager, |
374 | + 'attach_volume', |
375 | + lambda *a, **k: None) |
376 | +- self.stubs.Set(block_device_obj.BlockDeviceMapping, 'get_by_volume_id', |
377 | +- classmethod(lambda *a, **k: None)) |
378 | + |
379 | + volume = fakes.stub_volume_get(None, context.get_admin_context(), |
380 | + 'a26887c6-c47b-4654-abb5-dfadf7d3f803') |
381 | +-- |
382 | +1.9.1 |
383 | + |
384 | |
385 | === modified file 'debian/patches/series' |
386 | --- debian/patches/series 2015-07-15 16:35:15 +0000 |
387 | +++ debian/patches/series 2015-09-08 14:49:18 +0000 |
388 | @@ -6,3 +6,4 @@ |
389 | update-run-tests.patch |
390 | add-support-for-syslog-connect-retries.patch |
391 | clean-shutdown.patch |
392 | +fix-creating-bdm-for-failed-volume-attachment.patch |