Move udev rules blacklisting to utils layer

Also add udevadm_settle() to utils

Change-Id: I9bce65fa545c93b3f9b556171c9030baa3795b3e
Closes-Bug: #1477537
This commit is contained in:
Alexander Gordeev 2015-07-27 18:58:15 +03:00
parent 355c08a049
commit dee9f2eb7e
8 changed files with 307 additions and 105 deletions

View File

@ -127,37 +127,11 @@ class Manager(object):
lu.vgremove_all()
lu.pvremove_all()
# Here is udev's rules blacklisting to be done:
# by adding symlinks to /dev/null in /etc/udev/rules.d for already
# existent rules in /lib/.
# 'parted' generates too many udev events in short period of time
# so we should increase processing speed for those events,
# otherwise partitioning is doomed.
empty_rule_path = os.path.join(CONF.udev_rules_dir,
os.path.basename(CONF.udev_empty_rule))
with open(empty_rule_path, 'w') as f:
f.write('#\n')
LOG.debug("Enabling udev's rules blacklisting")
for rule in os.listdir(CONF.udev_rules_lib_dir):
dst = os.path.join(CONF.udev_rules_dir, rule)
if os.path.isdir(dst):
continue
if dst.endswith('.rules'):
# for successful blacklisting already existent file with name
# from /etc which overlaps with /lib should be renamed prior
# symlink creation.
try:
if os.path.exists(dst):
os.rename(dst, dst[:-len('.rules')] +
CONF.udev_rename_substr)
utils.execute('udevadm', 'settle', '--quiet')
except OSError:
LOG.debug("Skipping udev rule %s blacklising" % dst)
else:
os.symlink(empty_rule_path, dst)
utils.execute('udevadm', 'settle', '--quiet')
utils.execute('udevadm', 'control', '--reload-rules',
check_exit_code=[0])
utils.blacklist_udev_rules(udev_rules_dir=CONF.udev_rules_dir,
udev_rules_lib_dir=CONF.udev_rules_lib_dir,
udev_rename_substr=CONF.udev_rename_substr,
udev_empty_rule=CONF.udev_empty_rule)
for parted in self.driver.partition_scheme.parteds:
for prt in parted.partitions:
@ -191,36 +165,10 @@ class Manager(object):
raise errors.PartitionNotFoundError(
'Partition %s not found after creation' % prt.name)
# disable udev's rules blacklisting
LOG.debug("Disabling udev's rules blacklisting")
for rule in os.listdir(CONF.udev_rules_dir):
src = os.path.join(CONF.udev_rules_dir, rule)
if os.path.isdir(src):
continue
if src.endswith('.rules'):
if os.path.islink(src):
try:
os.remove(src)
utils.execute('udevadm', 'settle', '--quiet')
except OSError:
LOG.debug(
"Skipping udev rule %s de-blacklisting" % src)
elif src.endswith(CONF.udev_rename_substr):
try:
if os.path.exists(src):
os.rename(src, src[:-len(CONF.udev_rename_substr)] +
'.rules')
utils.execute('udevadm', 'settle', '--quiet')
except OSError:
LOG.debug("Skipping udev rule %s de-blacklisting" % src)
utils.execute('udevadm', 'control', '--reload-rules',
check_exit_code=[0])
# NOTE(agordeev): re-create all the links which were skipped by udev
# while blacklisted
# NOTE(agordeev): do subsystem match, otherwise it will stuck
utils.execute('udevadm', 'trigger', '--subsystem-match=block',
check_exit_code=[0])
utils.execute('udevadm', 'settle', '--quiet', check_exit_code=[0])
utils.unblacklist_udev_rules(
udev_rules_dir=CONF.udev_rules_dir,
udev_rename_substr=CONF.udev_rename_substr)
# If one creates partitions with the same boundaries as last time,
# there might be md and lvm metadata on those partitions. To prevent

View File

@ -268,12 +268,10 @@ class TestManager(unittest2.TestCase):
mock.call('swap', '', '', '/dev/mapper/os-swap')]
self.assertEqual(mock_fu_mf_expected_calls, mock_fu_mf.call_args_list)
@mock.patch('six.moves.builtins.open')
@mock.patch.object(os, 'symlink')
@mock.patch.object(os, 'remove')
@mock.patch.object(os, 'path')
@mock.patch.object(os, 'listdir')
@mock.patch.object(utils, 'execute')
@mock.patch.object(manager.os.path, 'exists')
@mock.patch.object(manager.utils, 'blacklist_udev_rules')
@mock.patch.object(manager.utils, 'unblacklist_udev_rules')
@mock.patch.object(manager.utils, 'execute')
@mock.patch.object(mu, 'mdclean_all')
@mock.patch.object(lu, 'lvremove_all')
@mock.patch.object(lu, 'vgremove_all')
@ -292,11 +290,9 @@ class TestManager(unittest2.TestCase):
mock_pu_spf, mock_pu_sgt, mock_mu_m, mock_lu_p,
mock_lu_v, mock_lu_l, mock_fu_mf, mock_pvr,
mock_vgr, mock_lvr, mock_mdr, mock_exec,
mock_os_ld, mock_os_p, mock_os_r, mock_os_s,
mock_open):
mock_os_ld.return_value = ['not_a_rule', 'fake.rules']
mock_os_p.exists.return_value = True
mock_unbl, mock_bl, mock_os_path):
mock_hu_lbd.return_value = test_nailgun.LIST_BLOCK_DEVICES_SAMPLE
mock_os_path.return_value = True
self.mgr.driver.partition_scheme.mds = [
objects.MD('fake_md1', 'mirror', devices=['/dev/sda1',
'/dev/sdb1']),
@ -310,12 +306,10 @@ class TestManager(unittest2.TestCase):
['/dev/sdb3', '/dev/sdc1'])],
mock_mu_m.call_args_list)
@mock.patch('six.moves.builtins.open')
@mock.patch.object(os, 'symlink')
@mock.patch.object(os, 'remove')
@mock.patch.object(os, 'path')
@mock.patch.object(os, 'listdir')
@mock.patch.object(utils, 'execute')
@mock.patch.object(manager.os.path, 'exists')
@mock.patch.object(manager.utils, 'blacklist_udev_rules')
@mock.patch.object(manager.utils, 'unblacklist_udev_rules')
@mock.patch.object(manager.utils, 'execute')
@mock.patch.object(mu, 'mdclean_all')
@mock.patch.object(lu, 'lvremove_all')
@mock.patch.object(lu, 'vgremove_all')
@ -334,12 +328,16 @@ class TestManager(unittest2.TestCase):
mock_pu_spf, mock_pu_sgt, mock_mu_m, mock_lu_p,
mock_lu_v, mock_lu_l, mock_fu_mf, mock_pvr,
mock_vgr, mock_lvr, mock_mdr, mock_exec,
mock_os_ld, mock_os_p, mock_os_r, mock_os_s,
mock_open):
mock_os_ld.return_value = ['not_a_rule', 'fake.rules']
mock_os_p.exists.return_value = True
mock_unbl, mock_bl, mock_os_path):
mock_os_path.return_value = True
mock_hu_lbd.return_value = test_nailgun.LIST_BLOCK_DEVICES_SAMPLE
self.mgr.do_partitioning()
mock_unbl.assert_called_once_with(udev_rules_dir='/etc/udev/rules.d',
udev_rename_substr='.renamedrule')
mock_bl.assert_called_once_with(udev_rules_dir='/etc/udev/rules.d',
udev_rules_lib_dir='/lib/udev/rules.d',
udev_empty_rule='empty_rule',
udev_rename_substr='.renamedrule')
mock_pu_ml_expected_calls = [mock.call('/dev/sda', 'gpt'),
mock.call('/dev/sdb', 'gpt'),
mock.call('/dev/sdc', 'gpt')]

View File

@ -247,19 +247,20 @@ localhost.localdomain)
mock_mddisplay.return_value = [{'name': '/dev/md11'}]
self.assertRaises(errors.MDRemovingError, mu.mdclean_all)
@mock.patch.object(utils, 'udevadm_settle')
@mock.patch.object(utils, 'execute')
@mock.patch.object(mu, 'get_mdnames')
def test_mdremove_ok(self, mock_get_mdn, mock_exec):
def test_mdremove_ok(self, mock_get_mdn, mock_exec, mock_udev):
# should check if md exists
# should run mdadm command to remove md device
mock_get_mdn.return_value = ['/dev/md0']
expected_calls = [
mock.call('udevadm', 'settle', '--quiet', check_exit_code=[0]),
mock.call('mdadm', '--stop', '/dev/md0', check_exit_code=[0]),
mock.call('mdadm', '--remove', '/dev/md0', check_exit_code=[0, 1])
]
mu.mdremove('/dev/md0')
self.assertEqual(mock_exec.call_args_list, expected_calls)
mock_udev.assert_called_once_with()
@mock.patch.object(mu, 'get_mdnames')
def test_mdremove_notfound(self, mock_get_mdn):

View File

@ -31,9 +31,10 @@ class TestPartitionUtils(unittest2.TestCase):
pu.wipe('/dev/fake')
mock_label.assert_called_once_with('/dev/fake')
@mock.patch.object(utils, 'udevadm_settle')
@mock.patch.object(pu, 'reread_partitions')
@mock.patch.object(utils, 'execute')
def test_make_label(self, mock_exec, mock_rerd):
def test_make_label(self, mock_exec, mock_rerd, mock_udev):
# should run parted OS command
# in order to create label on a device
mock_exec.return_value = ('out', '')
@ -41,21 +42,22 @@ class TestPartitionUtils(unittest2.TestCase):
# gpt by default
pu.make_label('/dev/fake')
mock_exec_expected_calls = [
mock.call('udevadm', 'settle', '--quiet', check_exit_code=[0]),
mock.call('parted', '-s', '/dev/fake', 'mklabel', 'gpt',
check_exit_code=[0, 1])]
self.assertEqual(mock_exec_expected_calls, mock_exec.call_args_list)
mock_rerd.assert_called_once_with('/dev/fake', out='out')
mock_udev.assert_called_once_with()
mock_exec.reset_mock()
mock_rerd.reset_mock()
mock_udev.reset_mock()
# label is set explicitly
pu.make_label('/dev/fake', label='msdos')
mock_exec_expected_calls = [
mock.call('udevadm', 'settle', '--quiet', check_exit_code=[0]),
mock.call('parted', '-s', '/dev/fake', 'mklabel', 'msdos',
check_exit_code=[0, 1])]
self.assertEqual(mock_exec_expected_calls, mock_exec.call_args_list)
mock_udev.assert_called_once_with()
mock_rerd.assert_called_once_with('/dev/fake', out='out')
def test_make_label_wrong_label(self):
@ -64,9 +66,10 @@ class TestPartitionUtils(unittest2.TestCase):
self.assertRaises(errors.WrongPartitionLabelError,
pu.make_label, '/dev/fake', 'wrong')
@mock.patch.object(utils, 'udevadm_settle')
@mock.patch.object(pu, 'reread_partitions')
@mock.patch.object(utils, 'execute')
def test_set_partition_flag(self, mock_exec, mock_rerd):
def test_set_partition_flag(self, mock_exec, mock_rerd, mock_udev):
# should run parted OS command
# in order to set flag on a partition
mock_exec.return_value = ('out', '')
@ -74,20 +77,21 @@ class TestPartitionUtils(unittest2.TestCase):
# default state is 'on'
pu.set_partition_flag('/dev/fake', 1, 'boot')
mock_exec_expected_calls = [
mock.call('udevadm', 'settle', '--quiet', check_exit_code=[0]),
mock.call('parted', '-s', '/dev/fake', 'set', '1', 'boot', 'on',
check_exit_code=[0, 1])]
mock_udev.assert_called_once_with()
self.assertEqual(mock_exec_expected_calls, mock_exec.call_args_list)
mock_rerd.assert_called_once_with('/dev/fake', out='out')
mock_exec.reset_mock()
mock_rerd.reset_mock()
mock_udev.reset_mock()
# if state argument is given use it
pu.set_partition_flag('/dev/fake', 1, 'boot', state='off')
mock_exec_expected_calls = [
mock.call('udevadm', 'settle', '--quiet', check_exit_code=[0]),
mock.call('parted', '-s', '/dev/fake', 'set', '1', 'boot', 'off',
check_exit_code=[0, 1])]
mock_udev.assert_called_once_with()
self.assertEqual(mock_exec_expected_calls, mock_exec.call_args_list)
mock_rerd.assert_called_once_with('/dev/fake', out='out')
@ -107,10 +111,11 @@ class TestPartitionUtils(unittest2.TestCase):
pu.set_partition_flag,
'/dev/fake', 1, 'boot', state='wrong')
@mock.patch.object(utils, 'udevadm_settle')
@mock.patch.object(pu, 'reread_partitions')
@mock.patch.object(pu, 'info')
@mock.patch.object(utils, 'execute')
def test_make_partition(self, mock_exec, mock_info, mock_rerd):
def test_make_partition(self, mock_exec, mock_info, mock_rerd, mock_udev):
# should run parted OS command
# in order to create new partition
mock_exec.return_value = ('out', '')
@ -122,10 +127,10 @@ class TestPartitionUtils(unittest2.TestCase):
}
pu.make_partition('/dev/fake', 100, 200, 'primary')
mock_exec_expected_calls = [
mock.call('udevadm', 'settle', '--quiet', check_exit_code=[0]),
mock.call('parted', '-a', 'optimal', '-s', '/dev/fake', 'unit',
'MiB', 'mkpart', 'primary', '100', '200',
check_exit_code=[0, 1])]
mock_udev.assert_called_once_with()
self.assertEqual(mock_exec_expected_calls, mock_exec.call_args_list)
mock_rerd.assert_called_once_with('/dev/fake', out='out')
@ -165,10 +170,12 @@ class TestPartitionUtils(unittest2.TestCase):
self.assertEqual(mock_info.call_args_list,
[mock.call('/dev/fake')] * 3)
@mock.patch.object(utils, 'udevadm_settle')
@mock.patch.object(pu, 'reread_partitions')
@mock.patch.object(pu, 'info')
@mock.patch.object(utils, 'execute')
def test_remove_partition(self, mock_exec, mock_info, mock_rerd):
def test_remove_partition(self, mock_exec, mock_info, mock_rerd,
mock_udev):
# should run parted OS command
# in order to remove partition
mock_exec.return_value = ('out', '')
@ -192,9 +199,9 @@ class TestPartitionUtils(unittest2.TestCase):
}
pu.remove_partition('/dev/fake', 1)
mock_exec_expected_calls = [
mock.call('udevadm', 'settle', '--quiet', check_exit_code=[0]),
mock.call('parted', '-s', '/dev/fake', 'rm', '1',
check_exit_code=[0, 1])]
mock_udev.assert_called_once_with()
self.assertEqual(mock_exec_expected_calls, mock_exec.call_args_list)
mock_rerd.assert_called_once_with('/dev/fake', out='out')
@ -224,17 +231,19 @@ class TestPartitionUtils(unittest2.TestCase):
self.assertRaises(errors.PartitionNotFoundError, pu.remove_partition,
'/dev/fake', 3)
@mock.patch.object(utils, 'udevadm_settle')
@mock.patch.object(utils, 'execute')
def test_set_gpt_type(self, mock_exec):
def test_set_gpt_type(self, mock_exec, mock_udev):
pu.set_gpt_type('dev', 'num', 'type')
mock_exec_expected_calls = [
mock.call('udevadm', 'settle', '--quiet', check_exit_code=[0]),
mock.call('sgdisk', '--typecode=%s:%s' % ('num', 'type'), 'dev',
check_exit_code=[0])]
self.assertEqual(mock_exec_expected_calls, mock_exec.call_args_list)
mock_udev.assert_called_once_with()
@mock.patch.object(utils, 'udevadm_settle')
@mock.patch.object(utils, 'execute')
def test_info(self, mock_exec):
def test_info(self, mock_exec, mock_udev):
mock_exec.return_value = [
'BYT;\n'
'/dev/fake:476940MiB:scsi:512:4096:msdos:ATA 1BD14;\n'
@ -261,27 +270,29 @@ class TestPartitionUtils(unittest2.TestCase):
actual = pu.info('/dev/fake')
self.assertEqual(expected, actual)
mock_exec_expected_calls = [
mock.call('udevadm', 'settle', '--quiet', check_exit_code=[0]),
mock.call('parted', '-s', '/dev/fake', '-m', 'unit', 'MiB',
'print', 'free', check_exit_code=[0])]
self.assertEqual(mock_exec_expected_calls, mock_exec.call_args_list)
mock_udev.assert_called_once_with()
@mock.patch.object(utils, 'execute')
def test_reread_partitions_ok(self, mock_exec):
pu.reread_partitions('/dev/fake', out='')
self.assertEqual(mock_exec.call_args_list, [])
@mock.patch.object(utils, 'udevadm_settle')
@mock.patch.object(time, 'sleep')
@mock.patch.object(utils, 'execute')
def test_reread_partitions_device_busy(self, mock_exec, mock_sleep):
def test_reread_partitions_device_busy(self, mock_exec, mock_sleep,
mock_udev):
mock_exec.return_value = ('', '')
pu.reread_partitions('/dev/fake', out='_Device or resource busy_')
mock_exec_expected = [
mock.call('partprobe', '/dev/fake', check_exit_code=[0, 1]),
mock.call('udevadm', 'settle', '--quiet', check_exit_code=[0]),
]
self.assertEqual(mock_exec.call_args_list, mock_exec_expected)
mock_sleep.assert_called_once_with(2)
mock_udev.assert_called_once_with()
@mock.patch.object(utils, 'execute')
def test_reread_partitions_timeout(self, mock_exec):

View File

@ -212,3 +212,178 @@ class ExecuteTestCase(unittest2.TestCase):
# by default files are sorted in backward direction
self.assertEqual(filename, 'file1')
mock_oslistdir.assert_called_once_with('/some/path')
@mock.patch.object(utils, 'execute')
def test_udevadm_settle(self, mock_exec):
utils.udevadm_settle()
mock_exec.assert_called_once_with('udevadm', 'settle', '--quiet',
check_exit_code=[0])
@mock.patch.object(utils, 'open', create=True, new_callable=mock.mock_open)
@mock.patch.object(utils, 'os', autospec=True)
@mock.patch.object(utils, 'execute')
@mock.patch.object(utils, 'udevadm_settle')
class TestUdevRulesBlacklisting(unittest2.TestCase):
@staticmethod
def _fake_join(path1, path2):
return '{0}/{1}'.format(path1, path2)
def test_blacklist_udev_rules_rule_exists(self, mock_udev, mock_execute,
mock_os, mock_open):
mock_os.path.join.side_effect = self._fake_join
mock_os.path.basename.return_value = 'fake_basename'
mock_os.listdir.return_value = ['fake.rules', 'fake_err.rules']
mock_os.path.isdir.return_value = False
mock_os.path.exists.return_value = True
mock_os.rename.side_effect = [None, OSError]
utils.blacklist_udev_rules('/etc/udev/rules.d', '/lib/udev/rules.d',
'.renamedrule', 'empty_rule')
self.assertEqual([mock.call('/etc/udev/rules.d/fake.rules'),
mock.call('/etc/udev/rules.d/fake_err.rules')],
mock_os.path.exists.call_args_list)
self.assertEqual([mock.call('/etc/udev/rules.d/fake.rules',
'/etc/udev/rules.d/fake.renamedrule'),
mock.call('/etc/udev/rules.d/fake_err.rules',
'/etc/udev/rules.d/fake_err.renamedrule')],
mock_os.rename.call_args_list)
self.assertEqual([mock.call('/etc/udev/rules.d', 'fake_basename'),
mock.call('/etc/udev/rules.d', 'fake.rules'),
mock.call('/etc/udev/rules.d', 'fake_err.rules')],
mock_os.path.join.call_args_list)
mock_os.symlink.assert_called_once_with(
'/etc/udev/rules.d/fake_basename',
'/etc/udev/rules.d/fake.rules')
self.assertEqual(2 * [mock.call()], mock_udev.call_args_list)
def test_blacklist_udev_rules_rule_doesnot_exist(self, mock_udev,
mock_execute, mock_os,
mock_open):
mock_os.path.join.side_effect = self._fake_join
mock_os.path.basename.return_value = 'fake_basename'
mock_os.listdir.return_value = ['fake.rules']
mock_os.path.isdir.return_value = False
mock_os.path.exists.return_value = False
utils.blacklist_udev_rules('/etc/udev/rules.d', '/lib/udev/rules.d',
'.renamedrule', 'empty_rule')
self.assertFalse(mock_os.rename.called)
mock_os.path.isdir.assert_called_once_with(
'/etc/udev/rules.d/fake.rules')
mock_os.path.exists.assert_called_once_with(
'/etc/udev/rules.d/fake.rules')
self.assertEqual([mock.call('/etc/udev/rules.d', 'fake_basename'),
mock.call('/etc/udev/rules.d', 'fake.rules')],
mock_os.path.join.call_args_list)
mock_os.symlink.assert_called_once_with(
'/etc/udev/rules.d/fake_basename',
'/etc/udev/rules.d/fake.rules')
mock_udev.assert_called_once_with()
def test_blacklist_udev_rules_not_a_rule(self, mock_udev, mock_execute,
mock_os, mock_open):
mock_os.path.join.side_effect = self._fake_join
mock_os.path.basename.return_value = 'fake_basename'
mock_os.listdir.return_value = ['not_a_rule', 'dir']
mock_os.path.isdir.side_effect = [False, True]
utils.blacklist_udev_rules('/etc/udev/rules.d', '/lib/udev/rules.d',
'.renamedrule', 'empty_rule')
self.assertFalse(mock_udev.called)
self.assertFalse(mock_os.symlink.called)
self.assertFalse(mock_os.rename.called)
self.assertFalse(mock_os.path.exists.called)
mock_os.listdir.assert_called_once_with('/lib/udev/rules.d')
self.assertEqual([mock.call('/etc/udev/rules.d/not_a_rule'),
mock.call('/etc/udev/rules.d/dir')],
mock_os.path.isdir.call_args_list)
self.assertEqual([mock.call('/etc/udev/rules.d', 'fake_basename'),
mock.call('/etc/udev/rules.d', 'not_a_rule'),
mock.call('/etc/udev/rules.d', 'dir')],
mock_os.path.join.call_args_list)
def test_blacklist_udev_rules_create_empty_rule(self, mock_udev,
mock_execute, mock_os,
mock_open):
mock_os.path.join.side_effect = self._fake_join
mock_os.path.basename.return_value = 'fake_basename'
utils.blacklist_udev_rules('/etc/udev/rules.d', '/lib/udev/rules.d',
'.renamedrule', 'empty_rule')
mock_open.assert_called_once_with('/etc/udev/rules.d/fake_basename',
'w')
file_handler = mock_open.return_value.__enter__.return_value
file_handler.write.assert_called_once_with('#\n')
mock_os.path.basename.assert_called_once_with('empty_rule')
def test_blacklist_udev_rules_execute(self, mock_udev, mock_execute,
mock_os, mock_open):
utils.blacklist_udev_rules('/etc/udev/rules.d', '/lib/udev/rules.d',
'.renamedrule', 'empty_rule')
mock_execute.assert_called_once_with(
'udevadm', 'control', '--reload-rules', check_exit_code=[0])
def test_unblacklist_udev_rules_remove(self, mock_udev, mock_execute,
mock_os, mock_open):
mock_os.path.join.side_effect = self._fake_join
mock_os.listdir.return_value = ['fake.rules', 'fake_err.rules']
mock_os.remove.side_effect = [None, OSError]
mock_os.path.isdir.side_effect = 2 * [False]
mock_os.path.islink.return_value = True
utils.unblacklist_udev_rules('/etc/udev/rules.d', '.renamedrule')
self.assertFalse(mock_os.path.exists.called)
self.assertFalse(mock_os.rename.called)
mock_os.listdir.assert_called_once_with('/etc/udev/rules.d')
expected_rules_calls = [mock.call('/etc/udev/rules.d/fake.rules'),
mock.call('/etc/udev/rules.d/fake_err.rules')]
self.assertEqual(expected_rules_calls,
mock_os.path.islink.call_args_list)
self.assertEqual(expected_rules_calls,
mock_os.remove.call_args_list)
self.assertEqual(2 * [mock.call()], mock_udev.call_args_list)
def test_unblacklist_udev_rules_executes(self, mock_udev, mock_execute,
mock_os, mock_open):
utils.unblacklist_udev_rules('/etc/udev/rules.d', '.renamedrule')
self.assertEqual([mock.call('udevadm', 'control', '--reload-rules',
check_exit_code=[0]),
mock.call('udevadm', 'trigger',
'--subsystem-match=block',
check_exit_code=[0])],
mock_execute.call_args_list)
def test_unblacklist_udev_rules_rename(self, mock_udev, mock_execute,
mock_os, mock_open):
mock_os.path.join.side_effect = self._fake_join
mock_os.listdir.return_value = ['fake.renamedrule',
'fake_err.renamedrule']
mock_os.rename.side_effect = [None, OSError]
mock_os.path.isdir.side_effect = 2 * [False]
utils.unblacklist_udev_rules('/etc/udev/rules.d', '.renamedrule')
self.assertFalse(mock_os.path.islink.called)
self.assertFalse(mock_os.remove.called)
mock_os.listdir.assert_called_once_with('/etc/udev/rules.d')
self.assertEqual([mock.call('/etc/udev/rules.d/fake.renamedrule'),
mock.call('/etc/udev/rules.d/fake_err.renamedrule')],
mock_os.path.exists.call_args_list)
self.assertEqual([mock.call('/etc/udev/rules.d/fake.renamedrule',
'/etc/udev/rules.d/fake.rules'),
mock.call('/etc/udev/rules.d/fake_err.renamedrule',
'/etc/udev/rules.d/fake_err.rules')],
mock_os.rename.call_args_list)
self.assertEqual(2 * [mock.call()], mock_udev.call_args_list)
def test_unblacklist_udev_rules_not_a_rule(self, mock_udev, mock_execute,
mock_os, mock_open):
mock_os.path.join.side_effect = self._fake_join
mock_os.listdir.return_value = ['not_a_rule', 'dir']
mock_os.path.isdir.side_effect = [False, True]
utils.unblacklist_udev_rules('/etc/udev/rules.d', '.renamedrule')
mock_os.listdir.assert_called_once_with('/etc/udev/rules.d')
self.assertEqual([mock.call('/etc/udev/rules.d', 'not_a_rule'),
mock.call('/etc/udev/rules.d', 'dir')],
mock_os.path.join.call_args_list)
self.assertEqual([mock.call('/etc/udev/rules.d/not_a_rule'),
mock.call('/etc/udev/rules.d/dir')],
mock_os.path.isdir.call_args_list)
self.assertFalse(mock_os.path.exists.called)
self.assertFalse(mock_os.remove.called)
self.assertFalse(mock_os.rename.called)
mock_udev.assert_called_once_with()

View File

@ -142,7 +142,7 @@ def mdremove(mdname):
# too busy with events when we start to modifiy md devices hard.
# Thus `udevadm settle` is helping to avoid the later failure and
# to prevent strange behaviour of md device.
utils.execute('udevadm', 'settle', '--quiet', check_exit_code=[0])
utils.udevadm_settle()
utils.execute('mdadm', '--stop', mdname, check_exit_code=[0])
utils.execute('mdadm', '--remove', mdname, check_exit_code=[0, 1])

View File

@ -49,7 +49,7 @@ def parse_partition_info(output):
def info(dev):
utils.execute('udevadm', 'settle', '--quiet', check_exit_code=[0])
utils.udevadm_settle()
output = utils.execute('parted', '-s', dev, '-m',
'unit', 'MiB',
'print', 'free',
@ -80,7 +80,7 @@ def make_label(dev, label='gpt'):
if label not in ('gpt', 'msdos'):
raise errors.WrongPartitionLabelError(
'Wrong partition label type: %s' % label)
utils.execute('udevadm', 'settle', '--quiet', check_exit_code=[0])
utils.udevadm_settle()
out, err = utils.execute('parted', '-s', dev, 'mklabel', label,
check_exit_code=[0, 1])
LOG.debug('Parted output: \n%s' % out)
@ -109,7 +109,7 @@ def set_partition_flag(dev, num, flag, state='on'):
if state not in ('on', 'off'):
raise errors.WrongPartitionSchemeError(
'Wrong partition flag state: %s' % state)
utils.execute('udevadm', 'settle', '--quiet', check_exit_code=[0])
utils.udevadm_settle()
out, err = utils.execute('parted', '-s', dev, 'set', str(num),
flag, state, check_exit_code=[0, 1])
LOG.debug('Parted output: \n%s' % out)
@ -130,7 +130,7 @@ def set_gpt_type(dev, num, type_guid):
# TODO(kozhukalov): check whether type_guid is valid
LOG.debug('Setting partition GUID: dev=%s num=%s guid=%s' %
(dev, num, type_guid))
utils.execute('udevadm', 'settle', '--quiet', check_exit_code=[0])
utils.udevadm_settle()
utils.execute('sgdisk', '--typecode=%s:%s' % (num, type_guid),
dev, check_exit_code=[0])
@ -154,7 +154,7 @@ def make_partition(dev, begin, end, ptype):
'Invalid boundaries: begin and end '
'are not inside available free space')
utils.execute('udevadm', 'settle', '--quiet', check_exit_code=[0])
utils.udevadm_settle()
out, err = utils.execute(
'parted', '-a', 'optimal', '-s', dev, 'unit', 'MiB',
'mkpart', ptype, str(begin), str(end), check_exit_code=[0, 1])
@ -167,7 +167,7 @@ def remove_partition(dev, num):
if not any(x['fstype'] != 'free' and x['num'] == num
for x in info(dev)['parts']):
raise errors.PartitionNotFoundError('Partition %s not found' % num)
utils.execute('udevadm', 'settle', '--quiet', check_exit_code=[0])
utils.udevadm_settle()
out, err = utils.execute('parted', '-s', dev, 'rm',
str(num), check_exit_code=[0, 1])
reread_partitions(dev, out=out)
@ -191,4 +191,4 @@ def reread_partitions(dev, out='Device or resource busy', timeout=60):
time.sleep(2)
out, err = utils.execute('partprobe', dev, check_exit_code=[0, 1])
LOG.debug('Partprobe output: \n%s' % out)
utils.execute('udevadm', 'settle', '--quiet', check_exit_code=[0])
utils.udevadm_settle()

View File

@ -265,3 +265,72 @@ def guess_filename(path, regexp, sort=True, reverse=True):
if re.search(regexp, filename):
return filename
return None
def blacklist_udev_rules(udev_rules_dir, udev_rules_lib_dir,
udev_rename_substr, udev_empty_rule):
"""Blacklist udev rules
Here is udev's rules blacklisting to be done:
by adding symlinks to /dev/null in /etc/udev/rules.d for already
existent rules in /lib/.
'parted' generates too many udev events in short period of time
so we should increase processing speed for those events,
otherwise partitioning is doomed.
"""
empty_rule_path = os.path.join(udev_rules_dir,
os.path.basename(udev_empty_rule))
with open(empty_rule_path, 'w') as f:
f.write('#\n')
for rule in os.listdir(udev_rules_lib_dir):
dst = os.path.join(udev_rules_dir, rule)
if os.path.isdir(dst):
continue
if dst.endswith('.rules'):
# for successful blacklisting already existent file with name
# from /etc which overlaps with /lib should be renamed prior
# symlink creation.
try:
if os.path.exists(dst):
os.rename(dst, dst[:-len('.rules')] + udev_rename_substr)
udevadm_settle()
except OSError:
LOG.debug("Skipping udev rule %s blacklising" % dst)
else:
os.symlink(empty_rule_path, dst)
udevadm_settle()
execute('udevadm', 'control', '--reload-rules', check_exit_code=[0])
def unblacklist_udev_rules(udev_rules_dir, udev_rename_substr):
"""disable udev's rules blacklisting"""
for rule in os.listdir(udev_rules_dir):
src = os.path.join(udev_rules_dir, rule)
if os.path.isdir(src):
continue
if src.endswith('.rules'):
if os.path.islink(src):
try:
os.remove(src)
udevadm_settle()
except OSError:
LOG.debug(
"Skipping udev rule %s de-blacklisting" % src)
elif src.endswith(udev_rename_substr):
try:
if os.path.exists(src):
os.rename(src, src[:-len(udev_rename_substr)] + '.rules')
udevadm_settle()
except OSError:
LOG.debug("Skipping udev rule %s de-blacklisting" % src)
execute('udevadm', 'control', '--reload-rules', check_exit_code=[0])
# NOTE(agordeev): re-create all the links which were skipped by udev
# while blacklisted
# NOTE(agordeev): do subsystem match, otherwise it will stuck
execute('udevadm', 'trigger', '--subsystem-match=block',
check_exit_code=[0])
udevadm_settle()
def udevadm_settle():
execute('udevadm', 'settle', '--quiet', check_exit_code=[0])