def veth_pair(prefix='veth_', max_length=15): """ Yield a pair of veth devices. This assumes root privileges (currently required by all tests anyway). Both sides of the pair have a pseudo-random suffix (e.g. veth_m6Lz7uMK9c). """ left_side = random_iface_name(prefix, max_length) right_side = random_iface_name(prefix, max_length) try: linkAdd(left_side, linkType='veth', args=('peer', 'name', right_side)) if nmstate.is_nmstate_backend(): cmd.exec_sync(['nmcli', 'dev', 'set', left_side, 'managed', 'yes']) cmd.exec_sync( ['nmcli', 'dev', 'set', right_side, 'managed', 'yes']) except IPRoute2Error as e: pytest.skip('Failed to create a veth pair: %s', e) try: yield left_side, right_side finally: # the peer device is removed by the kernel linkDel(left_side) if nmstate.is_nmstate_backend(): cmd.exec_sync(['nmcli', 'con', 'del', left_side]) cmd.exec_sync(['nmcli', 'con', 'del', right_side])
def test_get_bonding_options(self, bond_module): INTERVAL = '12345' bond_name = random_iface_name() if not bond_module: pytest.skip('Bonding is not available') with open(BONDING_MASTERS, 'w') as bonds: bonds.write('+' + bond_name) bonds.flush() try: # no error is anticipated but let's make sure we can clean up assert self._bond_opts_without_mode(bond_name) == {}, ( 'This test fails when a new bonding option is added to ' 'the kernel. Please run vdsm-tool dump-bonding-options` ' 'and retest.') with open(bonding.BONDING_OPT % (bond_name, 'miimon'), 'w') as opt: opt.write(INTERVAL) assert self._bond_opts_without_mode(bond_name) == { 'miimon': INTERVAL } finally: bonds.write('-' + bond_name)
def bond_device(slaves, prefix='bond', max_length=11): check_sysfs_bond_permission() name = random_iface_name(prefix, max_length) with linkbond.Bond(name, slaves) as bond: bond.create() yield bond.master bond.destroy()
def _atomic_copytree(srcpath, dstpath, remove_src=False): """ Copy srcpath to dstpatch in an atomic manner. It applies atomic directory copy by using the atomicity of overwriting a link (rename syscall). In case the remove_src flag argument is True, the srcpath is deleted. Note: In case of an interruption, it is assured that the destination is intact, pointing to the previous data or the new one. Intermediate temporary files or the srcpath may still exists on the filesystem. """ rand_suffix = random_iface_name(max_length=8) rand_dstpath = dstpath + '.' + rand_suffix rand_dstpath_symlink = rand_dstpath + '.ln' shutil.copytree(srcpath, rand_dstpath) os.symlink(rand_dstpath, rand_dstpath_symlink) old_realdstpath = os.path.realpath(dstpath) old_realdstpath_existed = old_realdstpath != dstpath _fsynctree(rand_dstpath) os.rename(rand_dstpath_symlink, dstpath) if old_realdstpath_existed: fileutils.rm_tree(old_realdstpath) if remove_src: fileutils.rm_tree(srcpath)
def _atomic_copytree(srcpath, dstpath, remove_src=False): """ Copy srcpath to dstpatch in an atomic manner. It applies atomic directory copy by using the atomicity of overwriting a link (rename syscall). In case the remove_src flag argument is True, the srcpath is deleted. Note: In case of an interruption, it is assured that the destination is intact, pointing to the previous data or the new one. Intermediate temporary files or the srcpath may still exists on the filesystem. """ rand_suffix = random_iface_name(max_length=8) rand_dstpath = dstpath + '.' + rand_suffix rand_dstpath_symlink = rand_dstpath + '.ln' shutil.copytree(srcpath, rand_dstpath) os.symlink(rand_dstpath, rand_dstpath_symlink) old_realdstpath = os.path.realpath(dstpath) old_realdstpath_existed = old_realdstpath != dstpath _fsynctree(rand_dstpath) os.rename(rand_dstpath_symlink, dstpath) if old_realdstpath_existed: fileutils.rm_tree(old_realdstpath) if remove_src: fileutils.rm_tree(srcpath)
def bond_device(slaves, prefix='bond', max_length=11): check_sysfs_bond_permission() name = random_iface_name(prefix, max_length) with linkbond.Bond(name, slaves) as bond: bond.create() yield bond.master bond.destroy()
def test_get_bonding_options(self): INTERVAL = '12345' bondName = random_iface_name() with open(BONDING_MASTERS, 'w') as bonds: bonds.write('+' + bondName) bonds.flush() try: # no error is anticipated but let's make sure we can clean up self.assertEqual( self._bond_opts_without_mode(bondName), {}, 'This test fails when a new bonding option is added to ' 'the kernel. Please run vdsm-tool dump-bonding-options` ' 'and retest.', ) with open(bonding.BONDING_OPT % (bondName, 'miimon'), 'w') as opt: opt.write(INTERVAL) self.assertEqual( self._bond_opts_without_mode(bondName), {'miimon': INTERVAL}, ) finally: bonds.write('-' + bondName)
def test_bond_create_failure_on_slave_add(self, bond_with_slaves): bond_name = random_iface_name('bond_', max_length=11) with pytest.raises(IOError): with Bond(bond_name) as broken_bond: broken_bond.create() broken_bond.add_slaves(bond_with_slaves.slaves) assert not Bond(bond_name).exists()
def bond_device(prefix='bond_', max_length=11): bond_name = random_iface_name(prefix, max_length) bond = Bond(bond_name) bond.create() try: yield bond finally: bond.destroy()
def bond_device(prefix='bond_', max_length=11): bond_name = random_iface_name(prefix, max_length) bond = Bond(bond_name) bond.create() try: yield bond finally: bond.destroy()
def veth_pair(prefix='veth_', max_length=15): """ Yield a pair of veth devices. This assumes root privileges (currently required by all tests anyway). Both sides of the pair have a pseudo-random suffix (e.g. veth_m6Lz7uMK9c). """ left_side = random_iface_name(prefix, max_length) right_side = random_iface_name(prefix, max_length) try: linkAdd(left_side, linkType='veth', args=('peer', 'name', right_side)) except IPRoute2Error as e: raise SkipTest('Failed to create a veth pair: %s', e) try: yield left_side, right_side finally: # the peer device is removed by the kernel linkDel(left_side)
def has_sysfs_bond_permission(): BondSysFS = linkbond.sysfs_driver.BondSysFS bond = BondSysFS(random_iface_name('check_', max_length=11)) try: bond.create() bond.destroy() except IOError: return False return True
def has_sysfs_bond_permission(): BondSysFS = linkbond.sysfs_driver.BondSysFS bond = BondSysFS(random_iface_name('check_', max_length=11)) try: bond.create() bond.destroy() except IOError: return False return True
def veth_pair(prefix='veth_', max_length=15): """ Yield a pair of veth devices. This assumes root privileges (currently required by all tests anyway). Both sides of the pair have a pseudo-random suffix (e.g. veth_m6Lz7uMK9c). """ left_side = random_iface_name(prefix, max_length) right_side = random_iface_name(prefix, max_length) try: linkAdd(left_side, linkType='veth', args=('peer', 'name', right_side)) except IPRoute2Error as e: raise SkipTest('Failed to create a veth pair: %s', e) try: yield left_side, right_side finally: # the peer device is removed by the kernel linkDel(left_side)
def test_bond_create_failure_on_slave_add(self): with dummy_devices(2) as (nic1, nic2): with bond_device() as base_bond: base_bond.add_slaves((nic1, nic2)) bond_name = random_iface_name('bond_', max_length=11) with self.assertRaises(IOError): with Bond(bond_name) as broken_bond: broken_bond.create() broken_bond.add_slaves((nic1, nic2)) self.assertFalse(Bond(bond_name).exists())
def test_bond_create_failure_on_slave_add(self): with dummy_devices(2) as (nic1, nic2): with bond_device() as base_bond: base_bond.add_slaves((nic1, nic2)) bond_name = random_iface_name('bond_', max_length=11) with self.assertRaises(IOError): with Bond(bond_name) as broken_bond: broken_bond.create() broken_bond.add_slaves((nic1, nic2)) self.assertFalse(Bond(bond_name).exists())
def _get_bonding_options_name2numeric(): """ Return a map of options values per mode, in a dictionary of dictionaries. All keys are strings. """ bond_name = random_iface_name() opts = {} for mode in range(_MAX_BONDING_MODES + 1): mode = str(mode) # The bond is created per mode to resolve an EBUSY error # that appears randomly when changing bond mode and modifying its # attributes. (Seen only on CI runs) with _bond_device(bond_name, mode): opts[mode] = _bond_opts_name2numeric_filtered(bond_name) return opts
def _get_bonding_options_name2numeric(): """ Return a map of options values per mode, in a dictionary of dictionaries. All keys are strings. """ bond_name = random_iface_name('bondscan-') opts = {} for mode in range(_MAX_BONDING_MODES + 1): mode = str(mode) # The bond is created per mode to resolve an EBUSY error # that appears randomly when changing bond mode and modifying its # attributes. (Seen only on CI runs) with _bond_device(bond_name, mode): opts[mode] = _bond_opts_name2numeric_filtered(bond_name) return opts
def save(self): self._clearDisk() rand_suffix = random_iface_name(max_length=8) rand_netconf_path = self.netconf_path + '.' + rand_suffix rand_nets_path = os.path.join(rand_netconf_path, NETCONF_NETS) rand_bonds_path = os.path.join(rand_netconf_path, NETCONF_BONDS) rand_devs_path = os.path.join(rand_netconf_path, NETCONF_DEVS) self._save_config(self.networks, rand_nets_path) self._save_config(self.bonds, rand_bonds_path) self._save_config(self.devices, rand_devs_path) _atomic_copytree(rand_netconf_path, self.netconf_path, remove_src=True) logging.info( 'Saved new config %r to [%s,%s,%s]' % (self, self.networksPath, self.bondingsPath, self.devicesPath))
def _store_net_config(): """ Declare the current running config as 'safe' and persist this safe config. It is implemented by copying the running config to the persistent (safe) config in an atomic manner. It applies atomic directory copy by using the atomicity of overwriting a link (rename syscall). """ safeconf_dir = CONF_PERSIST_DIR[:-1] rand_suffix = random_iface_name(max_length=8) new_safeconf_dir = safeconf_dir + '.' + rand_suffix new_safeconf_symlink = new_safeconf_dir + '.ln' shutil.copytree(CONF_RUN_DIR[:-1], new_safeconf_dir) os.symlink(new_safeconf_dir, new_safeconf_symlink) real_old_safeconf_dir = os.path.realpath(safeconf_dir) os.rename(new_safeconf_symlink, safeconf_dir) real_old_safeconf_dir_existed = real_old_safeconf_dir != safeconf_dir if real_old_safeconf_dir_existed: fileutils.rm_tree(real_old_safeconf_dir)
def _store_net_config(): """ Declare the current running config as 'safe' and persist this safe config. It is implemented by copying the running config to the persistent (safe) config in an atomic manner. It applies atomic directory copy by using the atomicity of overwriting a link (rename syscall). """ safeconf_dir = CONF_PERSIST_DIR[:-1] rand_suffix = random_iface_name(max_length=8) new_safeconf_dir = safeconf_dir + '.' + rand_suffix new_safeconf_symlink = new_safeconf_dir + '.ln' shutil.copytree(CONF_RUN_DIR[:-1], new_safeconf_dir) os.symlink(new_safeconf_dir, new_safeconf_symlink) real_old_safeconf_dir = os.path.realpath(safeconf_dir) os.rename(new_safeconf_symlink, safeconf_dir) real_old_safeconf_dir_existed = real_old_safeconf_dir != safeconf_dir if real_old_safeconf_dir_existed: fileutils.rm_tree(real_old_safeconf_dir)
def save(self): self._clearDisk() rand_suffix = random_iface_name(max_length=8) rand_netconf_path = self.netconf_path + '.' + rand_suffix rand_nets_path = os.path.join(rand_netconf_path, NETCONF_NETS) rand_bonds_path = os.path.join(rand_netconf_path, NETCONF_BONDS) rand_devs_path = os.path.join(rand_netconf_path, NETCONF_DEVS) self._save_config(self.networks, rand_nets_path) self._save_config(self.bonds, rand_bonds_path) self._save_config(self.devices, rand_devs_path) _atomic_copytree( rand_netconf_path, self.netconf_path, remove_src=True) logging.info( 'Saved new config %r to [%s,%s,%s]' % ( self, self.networksPath, self.bondingsPath, self.devicesPath ) )
def _get_default_bonding_options(): """ Return default options per mode, in a dictionary of dictionaries. All keys are strings. """ bond_name = random_iface_name() with _bond_device(bond_name): default_mode = sysfs_options.properties(bond_name, ('mode',))['mode'] # read default values for all modes opts = {} for mode in range(_MAX_BONDING_MODES + 1): mode = str(mode) # The bond is created per mode to resolve an EBUSY error # that appears randomly when changing bond mode and modifying its # attributes. (Seen only on CI runs) with _bond_device(bond_name, mode): opts[mode] = sysfs_options.properties( bond_name, filter_out_properties=sysfs_options.EXCLUDED_BONDING_ENTRIES) opts[mode]['mode'] = default_mode return opts
def _get_default_bonding_options(): """ Return default options per mode, in a dictionary of dictionaries. All keys are strings. """ bond_name = random_iface_name('bondscan-') with _bond_device(bond_name): default_mode = sysfs_options.properties(bond_name, ('mode',))['mode'] # read default values for all modes opts = {} for mode in range(_MAX_BONDING_MODES + 1): mode = str(mode) # The bond is created per mode to resolve an EBUSY error # that appears randomly when changing bond mode and modifying its # attributes. (Seen only on CI runs) with _bond_device(bond_name, mode): opts[mode] = sysfs_options.properties( bond_name, filter_out_properties=sysfs_options.EXCLUDED_BONDING_ENTRIES) opts[mode]['mode'] = default_mode return opts
def test_get_bonding_options(self): INTERVAL = '12345' bondName = random_iface_name() with open(BONDING_MASTERS, 'w') as bonds: bonds.write('+' + bondName) bonds.flush() try: # no error is anticipated but let's make sure we can clean up self.assertEqual( self._bond_opts_without_mode(bondName), {}, 'This test fails when a new bonding option is added to ' 'the kernel. Please run vdsm-tool dump-bonding-options` ' 'and retest.') with open(bonding.BONDING_OPT % (bondName, 'miimon'), 'w') as opt: opt.write(INTERVAL) self.assertEqual(self._bond_opts_without_mode(bondName), {'miimon': INTERVAL}) finally: bonds.write('-' + bondName)
def __init__(self, prefix='vdsm-', max_length=11): self.devName = random_iface_name(prefix, max_length)
def _create_br_name(): return random_iface_name(prefix=BRIDGE_PREFIX)
def __init__(self, prefix='vdsm-', max_length=11): self.devName = random_iface_name(prefix, max_length)
def iface_name(): return random_iface_name('bond', max_length=11, digit_only=True)
def iface_name(): return random_iface_name('bond', max_length=11, digit_only=True)
def random_interface_name(iface_prefix): return random_iface_name(prefix=iface_prefix)
def _create_br_name(): return random_iface_name(prefix=BRIDGE_PREFIX)