Merge lp:~corey.bryant/charms/trusty/cinder/remove-missing into lp:~openstack-charmers-archive/charms/trusty/cinder/next

Proposed by Corey Bryant
Status: Merged
Merged at revision: 56
Proposed branch: lp:~corey.bryant/charms/trusty/cinder/remove-missing
Merge into: lp:~openstack-charmers-archive/charms/trusty/cinder/next
Diff against target: 251 lines (+62/-16)
5 files modified
config.yaml (+12/-2)
hooks/cinder_hooks.py (+2/-1)
hooks/cinder_utils.py (+19/-2)
unit_tests/test_cinder_hooks.py (+3/-2)
unit_tests/test_cinder_utils.py (+26/-9)
To merge this branch: bzr merge lp:~corey.bryant/charms/trusty/cinder/remove-missing
Reviewer Review Type Date Requested Status
James Page Needs Fixing
OpenStack Charmers Pending
Review via email: mp+237439@code.launchpad.net

Description of the change

OIL has hit failures where physical volumes (from a previous deployment) are missing from the volume group on the current deployment, and vgextend fails. This patch fixes that by adding an option that requests that missing physical volumes be removed from the volume group.

To post a comment you must log in.
Revision history for this message
James Page (james-page) :
review: Needs Fixing
Revision history for this message
James Page (james-page) wrote :

Marking WIP - set back to 'Needs review' when ready for re-review.

Revision history for this message
James Page (james-page) wrote :

======================================================================
FAIL: It writes out all config
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/mock.py", line 1210, in patched
    return func(*args, **keywargs)
  File "/home/jamespage/src/charms/landing/cinder/unit_tests/test_cinder_hooks.py", line 118, in test_config_changed
    False)
  File "/usr/lib/python2.7/dist-packages/mock.py", line 844, in assert_called_with
    raise AssertionError(msg)
AssertionError: Expected call: configure_lvm_storage(['sdb'], 'cinder-volumes', False)
Actual call: configure_lvm_storage(['sdb'], 'cinder-volumes', False, False)

======================================================================
FAIL: It writes out all config
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/mock.py", line 1210, in patched
    return func(*args, **keywargs)
  File "/home/jamespage/src/charms/landing/cinder/unit_tests/test_cinder_hooks.py", line 133, in test_config_changed_block_devices
    True)
  File "/usr/lib/python2.7/dist-packages/mock.py", line 844, in assert_called_with
    raise AssertionError(msg)
AssertionError: Expected call: configure_lvm_storage(['sdb', '/dev/sdc', 'sde'], 'cinder-new', True)
Actual call: configure_lvm_storage(['sdb', '/dev/sdc', 'sde'], 'cinder-new', True, False)

review: Needs Fixing
Revision history for this message
James Page (james-page) wrote :

Probably worth adding a unit test to ensure that switching the config has the desired effect as well.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'config.yaml'
--- config.yaml 2014-10-08 10:42:20 +0000
+++ config.yaml 2014-10-10 20:37:29 +0000
@@ -27,12 +27,16 @@
27 description: |27 description: |
28 The block devices on which to create LVM volume group.28 The block devices on which to create LVM volume group.
2929
30 May also be set to None for deployments that will not need local30 May be set to None for deployments that will not need local
31 storage (eg, Ceph/RBD-backed volumes).31 storage (eg, Ceph/RBD-backed volumes).
3232
33 This can also be a space delimited list of block devices to attempt33 This can also be a space delimited list of block devices to attempt
34 to use in the cinder LVM volume group - each block device detected34 to use in the cinder LVM volume group - each block device detected
35 will be added to the available physical volumes in the volume group.35 will be added to the available physical volumes in the volume group.
36
37 May be set to the path and size of a local file
38 (/path/to/file.img|$sizeG), which will be created and used as a
39 loopback device (for testing only). $sizeG defaults to 5G
36 ceph-osd-replication-count:40 ceph-osd-replication-count:
37 default: 341 default: 3
38 type: int42 type: int
@@ -51,8 +55,14 @@
51 default: "false"55 default: "false"
52 type: string56 type: string
53 description: |57 description: |
54 If true, charm will attempt to overwrite block devices containin58 If true, charm will attempt to overwrite block devices containing
55 previous filesystems or LVM, assuming it is not in use.59 previous filesystems or LVM, assuming it is not in use.
60 remove-missing:
61 default: False
62 type: boolean
63 description: |
64 If True, charm will attempt to remove missing physical volumes from
65 volume group, if logical volumes are not allocated on them.
56 database-user:66 database-user:
57 default: cinder67 default: cinder
58 type: string68 type: string
5969
=== modified file 'hooks/cinder_hooks.py'
--- hooks/cinder_hooks.py 2014-10-01 22:15:34 +0000
+++ hooks/cinder_hooks.py 2014-10-10 20:37:29 +0000
@@ -105,7 +105,8 @@
105 block_devices = conf['block-device'].split()105 block_devices = conf['block-device'].split()
106 configure_lvm_storage(block_devices,106 configure_lvm_storage(block_devices,
107 conf['volume-group'],107 conf['volume-group'],
108 conf['overwrite'] in ['true', 'True', True])108 conf['overwrite'] in ['true', 'True', True],
109 conf['remove-missing'])
109110
110 if openstack_upgrade_available('cinder-common'):111 if openstack_upgrade_available('cinder-common'):
111 do_openstack_upgrade(configs=CONFIGS)112 do_openstack_upgrade(configs=CONFIGS)
112113
=== modified file 'hooks/cinder_utils.py'
--- hooks/cinder_utils.py 2014-10-07 12:27:23 +0000
+++ hooks/cinder_utils.py 2014-10-10 20:37:29 +0000
@@ -267,9 +267,19 @@
267 return list(set(_services))267 return list(set(_services))
268268
269269
270def reduce_lvm_volume_group_missing(volume_group):
271 '''
272 Remove all missing physical volumes from the volume group, if there
273 are no logical volumes allocated on them.
274
275 :param volume_group: str: Name of volume group to reduce.
276 '''
277 subprocess.check_call(['vgreduce', '--removemissing', volume_group])
278
279
270def extend_lvm_volume_group(volume_group, block_device):280def extend_lvm_volume_group(volume_group, block_device):
271 '''281 '''
272 Extend and LVM volume group onto a given block device.282 Extend an LVM volume group onto a given block device.
273283
274 Assumes block device has already been initialized as an LVM PV.284 Assumes block device has already been initialized as an LVM PV.
275285
@@ -279,13 +289,16 @@
279 subprocess.check_call(['vgextend', volume_group, block_device])289 subprocess.check_call(['vgextend', volume_group, block_device])
280290
281291
282def configure_lvm_storage(block_devices, volume_group, overwrite=False):292def configure_lvm_storage(block_devices, volume_group, overwrite=False,
293 remove_missing=False):
283 ''' Configure LVM storage on the list of block devices provided294 ''' Configure LVM storage on the list of block devices provided
284295
285 :param block_devices: list: List of whitelisted block devices to detect296 :param block_devices: list: List of whitelisted block devices to detect
286 and use if found297 and use if found
287 :param overwrite: bool: Scrub any existing block data if block device is298 :param overwrite: bool: Scrub any existing block data if block device is
288 not already in-use299 not already in-use
300 :param remove_missing: bool: Remove missing physical volumes from volume
301 group if logical volume not allocated on them
289 '''302 '''
290 devices = []303 devices = []
291 for block_device in block_devices:304 for block_device in block_devices:
@@ -320,6 +333,10 @@
320 create_lvm_volume_group(volume_group, new_devices[0])333 create_lvm_volume_group(volume_group, new_devices[0])
321 new_devices.remove(new_devices[0])334 new_devices.remove(new_devices[0])
322335
336 # Remove missing physical volumes from volume group
337 if remove_missing:
338 reduce_lvm_volume_group_missing(volume_group)
339
323 if len(new_devices) > 0:340 if len(new_devices) > 0:
324 # Extend the volume group as required341 # Extend the volume group as required
325 for new_device in new_devices:342 for new_device in new_devices:
326343
=== modified file 'unit_tests/test_cinder_hooks.py'
--- unit_tests/test_cinder_hooks.py 2014-10-08 10:53:24 +0000
+++ unit_tests/test_cinder_hooks.py 2014-10-10 20:37:29 +0000
@@ -115,7 +115,7 @@
115 self.assertTrue(conf_https.called)115 self.assertTrue(conf_https.called)
116 self.configure_lvm_storage.assert_called_with(['sdb'],116 self.configure_lvm_storage.assert_called_with(['sdb'],
117 'cinder-volumes',117 'cinder-volumes',
118 False)118 False, False)
119119
120 @patch.object(hooks, 'configure_https')120 @patch.object(hooks, 'configure_https')
121 def test_config_changed_block_devices(self, conf_https):121 def test_config_changed_block_devices(self, conf_https):
@@ -124,13 +124,14 @@
124 self.test_config.set('block-device', 'sdb /dev/sdc sde')124 self.test_config.set('block-device', 'sdb /dev/sdc sde')
125 self.test_config.set('volume-group', 'cinder-new')125 self.test_config.set('volume-group', 'cinder-new')
126 self.test_config.set('overwrite', 'True')126 self.test_config.set('overwrite', 'True')
127 self.test_config.set('remove-missing', True)
127 hooks.hooks.execute(['hooks/config-changed'])128 hooks.hooks.execute(['hooks/config-changed'])
128 self.assertTrue(self.CONFIGS.write_all.called)129 self.assertTrue(self.CONFIGS.write_all.called)
129 self.assertTrue(conf_https.called)130 self.assertTrue(conf_https.called)
130 self.configure_lvm_storage.assert_called_with(131 self.configure_lvm_storage.assert_called_with(
131 ['sdb', '/dev/sdc', 'sde'],132 ['sdb', '/dev/sdc', 'sde'],
132 'cinder-new',133 'cinder-new',
133 True)134 True, True)
134135
135 @patch.object(hooks, 'configure_https')136 @patch.object(hooks, 'configure_https')
136 def test_config_changed_upgrade_available(self, conf_https):137 def test_config_changed_upgrade_available(self, conf_https):
137138
=== modified file 'unit_tests/test_cinder_utils.py'
--- unit_tests/test_cinder_utils.py 2014-04-14 14:41:11 +0000
+++ unit_tests/test_cinder_utils.py 2014-10-10 20:37:29 +0000
@@ -211,11 +211,12 @@
211 ('/mnt/loop0', cinder_utils.DEFAULT_LOOPBACK_SIZE))211 ('/mnt/loop0', cinder_utils.DEFAULT_LOOPBACK_SIZE))
212212
213 @patch.object(cinder_utils, 'clean_storage')213 @patch.object(cinder_utils, 'clean_storage')
214 @patch.object(cinder_utils, 'reduce_lvm_volume_group_missing')
214 @patch.object(cinder_utils, 'extend_lvm_volume_group')215 @patch.object(cinder_utils, 'extend_lvm_volume_group')
215 def test_configure_lvm_storage(self, extend_lvm, clean_storage):216 def test_configure_lvm_storage(self, extend_lvm, reduce_lvm, clean_storage):
216 devices = ['/dev/vdb', '/dev/vdc']217 devices = ['/dev/vdb', '/dev/vdc']
217 self.is_lvm_physical_volume.return_value = False218 self.is_lvm_physical_volume.return_value = False
218 cinder_utils.configure_lvm_storage(devices, 'test', True)219 cinder_utils.configure_lvm_storage(devices, 'test', True, True)
219 clean_storage.assert_has_calls(220 clean_storage.assert_has_calls(
220 [call('/dev/vdb'),221 [call('/dev/vdb'),
221 call('/dev/vdc')]222 call('/dev/vdc')]
@@ -225,24 +226,29 @@
225 call('/dev/vdc')]226 call('/dev/vdc')]
226 )227 )
227 self.create_lvm_volume_group.assert_called_with('test', '/dev/vdb')228 self.create_lvm_volume_group.assert_called_with('test', '/dev/vdb')
229 reduce_lvm.assert_called_with('test')
228 extend_lvm.assert_called_with('test', '/dev/vdc')230 extend_lvm.assert_called_with('test', '/dev/vdc')
229231
230 @patch.object(cinder_utils, 'clean_storage')232 @patch.object(cinder_utils, 'clean_storage')
233 @patch.object(cinder_utils, 'reduce_lvm_volume_group_missing')
231 @patch.object(cinder_utils, 'extend_lvm_volume_group')234 @patch.object(cinder_utils, 'extend_lvm_volume_group')
232 def test_configure_lvm_storage_loopback(self, extend_lvm, clean_storage):235 def test_configure_lvm_storage_loopback(self, extend_lvm, reduce_lvm,
236 clean_storage):
233 devices = ['/mnt/loop0|10']237 devices = ['/mnt/loop0|10']
234 self.ensure_loopback_device.return_value = '/dev/loop0'238 self.ensure_loopback_device.return_value = '/dev/loop0'
235 self.is_lvm_physical_volume.return_value = False239 self.is_lvm_physical_volume.return_value = False
236 cinder_utils.configure_lvm_storage(devices, 'test', True)240 cinder_utils.configure_lvm_storage(devices, 'test', True, True)
237 clean_storage.assert_called_with('/dev/loop0')241 clean_storage.assert_called_with('/dev/loop0')
238 self.ensure_loopback_device.assert_called_with('/mnt/loop0', '10')242 self.ensure_loopback_device.assert_called_with('/mnt/loop0', '10')
239 self.create_lvm_physical_volume.assert_called_with('/dev/loop0')243 self.create_lvm_physical_volume.assert_called_with('/dev/loop0')
240 self.create_lvm_volume_group.assert_called_with('test', '/dev/loop0')244 self.create_lvm_volume_group.assert_called_with('test', '/dev/loop0')
245 reduce_lvm.assert_called_with('test')
241 self.assertFalse(extend_lvm.called)246 self.assertFalse(extend_lvm.called)
242247
243 @patch.object(cinder_utils, 'clean_storage')248 @patch.object(cinder_utils, 'clean_storage')
249 @patch.object(cinder_utils, 'reduce_lvm_volume_group_missing')
244 @patch.object(cinder_utils, 'extend_lvm_volume_group')250 @patch.object(cinder_utils, 'extend_lvm_volume_group')
245 def test_configure_lvm_storage_existing_vg(self, extend_lvm,251 def test_configure_lvm_storage_existing_vg(self, extend_lvm, reduce_lvm,
246 clean_storage):252 clean_storage):
247 def pv_lookup(device):253 def pv_lookup(device):
248 devices = {254 devices = {
@@ -260,19 +266,21 @@
260 devices = ['/dev/vdb', '/dev/vdc']266 devices = ['/dev/vdb', '/dev/vdc']
261 self.is_lvm_physical_volume.side_effect = pv_lookup267 self.is_lvm_physical_volume.side_effect = pv_lookup
262 self.list_lvm_volume_group.side_effect = vg_lookup268 self.list_lvm_volume_group.side_effect = vg_lookup
263 cinder_utils.configure_lvm_storage(devices, 'test', True)269 cinder_utils.configure_lvm_storage(devices, 'test', True, True)
264 clean_storage.assert_has_calls(270 clean_storage.assert_has_calls(
265 [call('/dev/vdc')]271 [call('/dev/vdc')]
266 )272 )
267 self.create_lvm_physical_volume.assert_has_calls(273 self.create_lvm_physical_volume.assert_has_calls(
268 [call('/dev/vdc')]274 [call('/dev/vdc')]
269 )275 )
276 reduce_lvm.assert_called_with('test')
270 extend_lvm.assert_called_with('test', '/dev/vdc')277 extend_lvm.assert_called_with('test', '/dev/vdc')
271 self.assertFalse(self.create_lvm_volume_group.called)278 self.assertFalse(self.create_lvm_volume_group.called)
272279
273 @patch.object(cinder_utils, 'clean_storage')280 @patch.object(cinder_utils, 'clean_storage')
281 @patch.object(cinder_utils, 'reduce_lvm_volume_group_missing')
274 @patch.object(cinder_utils, 'extend_lvm_volume_group')282 @patch.object(cinder_utils, 'extend_lvm_volume_group')
275 def test_configure_lvm_storage_different_vg(self, extend_lvm,283 def test_configure_lvm_storage_different_vg(self, extend_lvm, reduce_lvm,
276 clean_storage):284 clean_storage):
277 def pv_lookup(device):285 def pv_lookup(device):
278 devices = {286 devices = {
@@ -290,15 +298,18 @@
290 devices = ['/dev/vdb', '/dev/vdc']298 devices = ['/dev/vdb', '/dev/vdc']
291 self.is_lvm_physical_volume.side_effect = pv_lookup299 self.is_lvm_physical_volume.side_effect = pv_lookup
292 self.list_lvm_volume_group.side_effect = vg_lookup300 self.list_lvm_volume_group.side_effect = vg_lookup
293 cinder_utils.configure_lvm_storage(devices, 'test', True)301 cinder_utils.configure_lvm_storage(devices, 'test', True, True)
294 clean_storage.assert_called_with('/dev/vdc')302 clean_storage.assert_called_with('/dev/vdc')
295 self.create_lvm_physical_volume.assert_called_with('/dev/vdc')303 self.create_lvm_physical_volume.assert_called_with('/dev/vdc')
304 reduce_lvm.assert_called_with('test')
296 extend_lvm.assert_called_with('test', '/dev/vdc')305 extend_lvm.assert_called_with('test', '/dev/vdc')
297 self.assertFalse(self.create_lvm_volume_group.called)306 self.assertFalse(self.create_lvm_volume_group.called)
298307
299 @patch.object(cinder_utils, 'clean_storage')308 @patch.object(cinder_utils, 'clean_storage')
309 @patch.object(cinder_utils, 'reduce_lvm_volume_group_missing')
300 @patch.object(cinder_utils, 'extend_lvm_volume_group')310 @patch.object(cinder_utils, 'extend_lvm_volume_group')
301 def test_configure_lvm_storage_different_vg_ignore(self, extend_lvm,311 def test_configure_lvm_storage_different_vg_ignore(self, extend_lvm,
312 reduce_lvm,
302 clean_storage):313 clean_storage):
303 def pv_lookup(device):314 def pv_lookup(device):
304 devices = {315 devices = {
@@ -316,13 +327,19 @@
316 devices = ['/dev/vdb', '/dev/vdc']327 devices = ['/dev/vdb', '/dev/vdc']
317 self.is_lvm_physical_volume.side_effect = pv_lookup328 self.is_lvm_physical_volume.side_effect = pv_lookup
318 self.list_lvm_volume_group.side_effect = vg_lookup329 self.list_lvm_volume_group.side_effect = vg_lookup
319 cinder_utils.configure_lvm_storage(devices, 'test', False)330 cinder_utils.configure_lvm_storage(devices, 'test', False, False)
320 self.assertFalse(clean_storage.called)331 self.assertFalse(clean_storage.called)
321 self.assertFalse(self.create_lvm_physical_volume.called)332 self.assertFalse(self.create_lvm_physical_volume.called)
333 self.assertFalse(reduce_lvm.called)
322 self.assertFalse(extend_lvm.called)334 self.assertFalse(extend_lvm.called)
323 self.assertFalse(self.create_lvm_volume_group.called)335 self.assertFalse(self.create_lvm_volume_group.called)
324336
325 @patch('subprocess.check_call')337 @patch('subprocess.check_call')
338 def test_reduce_lvm_volume_group_missing(self, _call):
339 cinder_utils.reduce_lvm_volume_group_missing('test')
340 _call.assert_called_with(['vgreduce', '--removemissing', 'test'])
341
342 @patch('subprocess.check_call')
326 def test_extend_lvm_volume_group(self, _call):343 def test_extend_lvm_volume_group(self, _call):
327 cinder_utils.extend_lvm_volume_group('test', '/dev/sdb')344 cinder_utils.extend_lvm_volume_group('test', '/dev/sdb')
328 _call.assert_called_with(['vgextend', 'test', '/dev/sdb'])345 _call.assert_called_with(['vgextend', 'test', '/dev/sdb'])

Subscribers

People subscribed via source and target branches