Merge lp:~hopem/nova/icehouse-lp1349888 into lp:~ubuntu-server-dev/nova/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
Reviewer Review Type Date Requested Status
Ubuntu Server Developers Pending
Review via email: mp+270414@code.launchpad.net
To post a comment you must log in.
lp:~hopem/nova/icehouse-lp1349888 updated
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

Subscribers

People subscribed via source and target branches