class VolumeGroupsTests(unittest.TestCase): def setUp(self): objstore_loc = config.get_object_store() + "_ginger" self._objstore = ObjectStore(objstore_loc) self.task_model = TaskModel(objstore=self._objstore) def test_get_vg_list(self): vgs = vol_group.VolumeGroupsModel(objstore=self._objstore) vgs_list = vgs.get_list() self.assertGreaterEqual(len(vgs_list), 0) def test_create_vg_missing_name(self): vgs = vol_group.VolumeGroupsModel(objstore=self._objstore) pvpaths = ["/dev/sdb1"] params = {"pv_paths": pvpaths} self.assertRaises(MissingParameter, vgs.create, params) def test_create_vg_missing_pvpaths(self): vgs = vol_group.VolumeGroupsModel(objstore=self._objstore) vgname = "testvg" params = {"vg_name": vgname} self.assertRaises(MissingParameter, vgs.create, params) @mock.patch("wok.plugins.ginger.models.utils._create_vg", autospec=True) def test_create_vg(self, mock_create_vg): vgs = vol_group.VolumeGroupsModel(objstore=self._objstore) vgname = "testvg" pvpaths = ["/dev/sdb1"] params = {"vg_name": vgname, "pv_paths": pvpaths} task_obj = vgs.create(params) self.task_model.wait(task_obj.get("id")) mock_create_vg.assert_called_with(vgname, pvpaths) @mock.patch("wok.plugins.ginger.models.utils._extend_vg", autospec=True) def test_extend_vg(self, mock_extend_vg): vg = vol_group.VolumeGroupModel(objstore=self._objstore) vgname = "testvg" pvpaths = ["/dev/sdb2"] vg.extend(vgname, pvpaths) mock_extend_vg.assert_called_with(vgname, pvpaths) @mock.patch("wok.plugins.ginger.models.utils._reduce_vg", autospec=True) def test_reduce_vg(self, mock_reduce_vg): vg = vol_group.VolumeGroupModel(objstore=self._objstore) vgname = "testvg" pvpaths = ["/dev/sdb2"] vg.reduce(vgname, pvpaths) mock_reduce_vg.assert_called_with(vgname, pvpaths) @mock.patch("wok.plugins.ginger.models.utils._remove_vg", autospec=True) def test_delete_vg(self, mock_delete_vg): vg = vol_group.VolumeGroupModel(objstore=self._objstore) vgname = "testvg" vg.delete(vgname) mock_delete_vg.assert_called_with(vgname)
class FirmwareProgressTests(unittest.TestCase): def setUp(self): objstore_loc = config.get_object_store() + '_ginger' self._objstore = ObjectStore(objstore_loc) self.task = TaskModel(objstore=self._objstore) def test_fwprogress_without_update_flash(self): fwprogress = FirmwareProgressModel(objstore=self._objstore) task_info = fwprogress.lookup() self.task.wait(task_info['id']) task_info = self.task.lookup(task_info['id']) self.assertEquals('finished', task_info['status']) self.assertIn('Error', task_info['message']) self.assertEquals('/plugins/ginger/fwprogress', task_info['target_uri'])
class LogicalVolumesTests(unittest.TestCase): def setUp(self): objstore_loc = config.get_object_store() + '_ginger' self._objstore = ObjectStore(objstore_loc) self.task_model = TaskModel(objstore=self._objstore) def test_get_lv_list(self): lvs = log_volume.LogicalVolumesModel(objstore=self._objstore) lvs_list = lvs.get_list() self.assertGreaterEqual(len(lvs_list), 0) def test_create_lv_missing_vgname(self): lvs = log_volume.LogicalVolumesModel(objstore=self._objstore) size = ['10M'] params = {'size': size} self.assertRaises(MissingParameter, lvs.create, params) def test_create_lv_missing_size(self): lvs = log_volume.LogicalVolumesModel(objstore=self._objstore) vgname = 'testvg' params = {'vg_name': vgname} self.assertRaises(MissingParameter, lvs.create, params) @mock.patch('wok.plugins.ginger.model.utils._create_lv', autospec=True) def test_create_lv(self, mock_create_lv): lvs = log_volume.LogicalVolumesModel(objstore=self._objstore) vgname = 'testvg' size = '10M' params = {'vg_name': vgname, 'size': size} task_obj = lvs.create(params) self.task_model.wait(task_obj.get('id')) mock_create_lv.assert_called_with(vgname, size) @mock.patch('wok.plugins.ginger.model.utils._remove_lv', autospec=True) def test_delete_lv(self, mock_delete_lv): lv = log_volume.LogicalVolumeModel(objstore=self._objstore) lvname = '/dev/testvg/lvol0' lv.delete(lvname) mock_delete_lv.assert_called_with(lvname)
class VolumeGroupsTests(unittest.TestCase): def setUp(self): objstore_loc = config.get_object_store() + '_ginger' self._objstore = ObjectStore(objstore_loc) self.task_model = TaskModel(objstore=self._objstore) def test_get_vg_list(self): vgs = vol_group.VolumeGroupsModel(objstore=self._objstore) vgs_list = vgs.get_list() self.assertGreaterEqual(len(vgs_list), 0) def test_create_vg_missing_name(self): vgs = vol_group.VolumeGroupsModel(objstore=self._objstore) pvpaths = ['/dev/sdb1'] params = {'pv_paths': pvpaths} self.assertRaises(MissingParameter, vgs.create, params) def test_create_vg_missing_pvpaths(self): vgs = vol_group.VolumeGroupsModel(objstore=self._objstore) vgname = 'testvg' params = {'vg_name': vgname} self.assertRaises(MissingParameter, vgs.create, params) @mock.patch('wok.plugins.ginger.model.utils._create_vg', autospec=True) def test_create_vg(self, mock_create_vg): vgs = vol_group.VolumeGroupsModel(objstore=self._objstore) vgname = 'testvg' pvpaths = ['/dev/sdb1'] params = {'vg_name': vgname, 'pv_paths': pvpaths} task_obj = vgs.create(params) self.task_model.wait(task_obj.get('id')) mock_create_vg.assert_called_with(vgname, pvpaths) @mock.patch('wok.plugins.ginger.model.utils._extend_vg', autospec=True) def test_extend_vg(self, mock_extend_vg): vg = vol_group.VolumeGroupModel(objstore=self._objstore) vgname = 'testvg' pvpaths = ['/dev/sdb2'] vg.extend(vgname, pvpaths) mock_extend_vg.assert_called_with(vgname, pvpaths) @mock.patch('wok.plugins.ginger.model.utils._reduce_vg', autospec=True) def test_reduce_vg(self, mock_reduce_vg): vg = vol_group.VolumeGroupModel(objstore=self._objstore) vgname = 'testvg' pvpaths = ['/dev/sdb2'] vg.reduce(vgname, pvpaths) mock_reduce_vg.assert_called_with(vgname, pvpaths) @mock.patch('wok.plugins.ginger.model.utils._remove_vg', autospec=True) @mock.patch('wok.plugins.ginger.model.utils.get_lvm_version') @mock.patch('wok.plugins.ginger.model.vol_group.VolumeGroupModel.lookup') def test_delete_vg(self, mock_vg_lookup, mock_lvm_version, mock_delete_vg): mock_lvm_version.return_value = "2.02.98" mock_vg_lookup.return_value = {'vgName': 'testvg', 'Cur LV': 0} vg = vol_group.VolumeGroupModel(objstore=self._objstore) vgname = 'testvg' vg.delete(vgname) mock_delete_vg.assert_called_with(vgname) def test_parse_lvm_version(self): lvm_version_input = " 2.02.98(2) (2012-10-15)" lvm_version = utils._parse_lvm_version(lvm_version_input) if lvm_version != "2.02.98": self.fail() def test_parse_lvm_version_exception(self): lvm_version_input = " wrong version string" self.assertRaises( OperationFailed, utils._parse_lvm_version, lvm_version_input)
class InterfacesTests(unittest.TestCase): def setUp(self): objstore_loc = config.get_object_store() + '_ginger' self._objstore = ObjectStore(objstore_loc) self.task = TaskModel(objstore=self._objstore) @mock.patch('wok.plugins.gingerbase.netinfo.os') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_type') @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.run_command') def test_activate(self, mock_run_command, mock_get_interface_type, mock_os): mock_run_command.return_value = ["", "", 0] mock_os.path.isfile.return_value = True mock_get_interface_type.return_value = "nic" interface = "test_eth0" cmd = ['ip', 'link', 'set', '%s' % interface, 'up'] InterfaceModel(objstore=self._objstore).activate(interface) mock_run_command.assert_called_once_with(cmd) @mock.patch('wok.plugins.gingerbase.netinfo.os') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_type') @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.run_command') def test_activate_no_config_file(self, mock_run_command, mock_get_interface_type, mock_os): mock_run_command.return_value = ["", "", 0] mock_os.path.isfile.return_value = False mock_get_interface_type.return_value = "nic" interface = "test_eth0" calls = [(['ip', 'link', 'set', '%s' % interface, 'up'],), (['ifup', '%s' % interface],)] InterfaceModel(objstore=self._objstore).activate(interface) for i in range(0, 1): x, y = mock_run_command.call_args_list[i] assert x == calls[i] assert mock_run_command.call_count == 1 @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_type') @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.run_command') def test_activate_fail(self, mock_run_command, mock_get_interface_type): mock_run_command.return_value = ["", "Unable to activate", 4] mock_get_interface_type.return_value = "nic" interface = "test_eth0" cmd = ['ip', 'link', 'set', '%s' % interface, 'up'] self.assertRaises(OperationFailed, InterfaceModel(objstore=self._objstore).activate, interface) mock_run_command.assert_called_once_with(cmd) @mock.patch('wok.plugins.gingerbase.netinfo.os') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_type') @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.run_command') def test_deactivate(self, mock_run_command, mock_get_interface_type, mock_os): mock_run_command.return_value = ["", "", 0] mock_os.path.isfile.return_value = True mock_get_interface_type.return_value = "nic" interface = "test_eth0" cmd = ['ip', 'link', 'set', '%s' % interface, 'down'] InterfaceModel(objstore=self._objstore).deactivate(interface) mock_run_command.assert_called_once_with(cmd) @mock.patch('wok.plugins.gingerbase.netinfo.os') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_type') @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.run_command') def test_deactivate_no_config_file(self, mock_run_command, mock_get_interface_type, mock_os): mock_run_command.return_value = ["", "", 0] mock_os.path.isfile.return_value = False mock_get_interface_type.return_value = "nic" interface = "test_eth0" calls = [(['ip', 'link', 'set', '%s' % interface, 'down'],), (['ifdown', '%s' % interface],)] InterfaceModel(objstore=self._objstore).deactivate(interface) for i in range(0, 1): x, y = mock_run_command.call_args_list[i] assert x == calls[i] assert mock_run_command.call_count == 1 @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_type') @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.run_command') def test_deactivate_fail(self, mock_run_command, mock_get_interface_type): mock_run_command.return_value = ["", "Unable to deactivate", 4] mock_get_interface_type.return_value = "nic" interface = "test_eth0" cmd = ['ip', 'link', 'set', '%s' % interface, 'down'] self.assertRaises(OperationFailed, InterfaceModel(objstore=self._objstore).deactivate, interface) mock_run_command.assert_called_once_with(cmd) @mock.patch('os.readlink') def test_netinfo_interface_module_lookup_success(self, mock_readlink): mock_readlink.return_value = '../../../../module/dummy_net_module' module = netinfo.get_interface_kernel_module('dummy_iface') mock_readlink.assert_called_once_with( '/sys/class/net/dummy_iface/device/driver/module') self.assertEqual(module, 'dummy_net_module') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('ethtool.get_devices') @mock.patch('ethtool.get_ipaddr') @mock.patch('ethtool.get_netmask') @mock.patch('wok.plugins.gingerbase.netinfo.macaddr') def test_netinfo_get_interface_info(self, mock_macaddr, mock_netmask, mock_ipaddr, mock_getdevs, mock_get_module): mock_get_module.return_value = 'dummy_net_module' mock_getdevs.return_value = ['dev1', 'dummy_iface', 'dev2'] mock_ipaddr.return_value = '99.99.99.99' mock_netmask.return_value = '255.255.255.0' mock_macaddr.return_value = 'aa:bb:cc:dd:ee:ff' iface_info = netinfo.get_interface_info('dummy_iface') mock_macaddr.assert_called_once_with('dummy_iface') mock_netmask.assert_called_once_with('dummy_iface') mock_ipaddr.assert_called_once_with('dummy_iface') mock_getdevs.assert_called_once_with() mock_get_module.assert_called_once_with('dummy_iface') self.assertEqual(iface_info.get('device'), 'dummy_iface') self.assertEqual(iface_info.get('type'), 'unknown') self.assertEqual(iface_info.get('status'), 'down') self.assertEqual(iface_info.get('ipaddr'), '99.99.99.99') self.assertEqual(iface_info.get('netmask'), '255.255.255.0') self.assertEqual(iface_info.get('macaddr'), 'aa:bb:cc:dd:ee:ff') self.assertEqual(iface_info.get('module'), 'dummy_net_module') @mock.patch('ethtool.get_devices') @mock.patch('wok.plugins.gingerbase.netinfo.is_rdma_enabled') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_info') def test_interface_lookup(self, mock_iface_info, mock_rdma_enabled, mock_getdevs): iface_info_return = { 'device': 'dummy_iface', 'type': 'unknown', 'status': 'down', 'ipaddr': '99.99.99.99', 'netmask': '255.255.255.0', 'macaddr': 'aa:bb:cc:dd:ee:ff', 'module': 'dummy_net_module' } mock_iface_info.return_value = iface_info_return mock_rdma_enabled.return_value = True mock_getdevs.return_value = ['dev1', 'dummy_iface', 'dev2'] iface_model = InterfaceModel(objstore=self._objstore) iface_info = iface_model.lookup('dummy_iface') mock_iface_info.assert_called_once_with('dummy_iface') mock_rdma_enabled.assert_called_once_with('dummy_iface') mock_getdevs.called_once_with() self.assertEqual(iface_info.get('device'), 'dummy_iface') self.assertEqual(iface_info.get('type'), 'unknown') self.assertEqual(iface_info.get('status'), 'down') self.assertEqual(iface_info.get('ipaddr'), '99.99.99.99') self.assertEqual(iface_info.get('netmask'), '255.255.255.0') self.assertEqual(iface_info.get('macaddr'), 'aa:bb:cc:dd:ee:ff') self.assertEqual(iface_info.get('module'), 'dummy_net_module') self.assertTrue(iface_info.get('rdma_enabled')) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') def test_invalid_module_enable_sriov_failure(self, mock_get_module): mock_get_module.return_value = 'unknown' expected_error_msg = "GINNET0076E" with self.assertRaisesRegexp(InvalidOperation, expected_error_msg): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('any_iface_name', {'num_vfs': 4}) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_no_args_failure(self, mock_get_max_VF, mock_get_module): mock_get_max_VF.return_value = '1' mock_get_module.return_value = 'mlx5_core' expected_error_msg = "GINNET0077E" with self.assertRaisesRegexp(InvalidParameter, expected_error_msg): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('any_iface_name', None) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_argument_failure(self, mock_get_max_VF, mock_get_module): mock_get_max_VF.return_value = '1' mock_get_module.return_value = 'mlx5_core' expected_error_msg = "GINNET0079E" with self.assertRaisesRegexp(InvalidParameter, expected_error_msg): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('any_iface_name', 'not_an_int') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_no_system_files_failure(self, mock_get_max_VF, mock_isfile, mock_get_module): mock_get_max_VF.return_value = '8' mock_get_module.return_value = 'mlx5_core' call_file1_not_exist = \ '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' call_file2_not_exist = \ '/sys/class/net/%s/device/mlx5_num_vfs' % 'iface1' mock_isfile.side_effect = [False, False] mock_isfile_calls = [ call(call_file1_not_exist), call(call_file2_not_exist) ] expected_error_msg = "GINNET0078E" with self.assertRaisesRegexp(OperationFailed, expected_error_msg): iface_model = InterfaceModel(objstore=self._objstore) task_obj = iface_model.enable_sriov('iface1', 4) self.task.wait(task_obj['id']) mock_isfile.assert_has_calls(mock_isfile_calls) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') def test_mlx5_sriov_not_enabled_in_FW(self, mock_isfile, mock_get_module): mock_get_module.return_value = 'mlx5_core' file1 = '/sys/class/net/%s/device/sriov_totalvfs' % 'iface1' mock_isfile.return_value = False with self.assertRaisesRegexp(OperationFailed, 'GINNET0082E'): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('iface1', 4) mock_isfile.assert_called_once_with(file1) @mock.patch('os.path.isfile') def test_mlx5_sriov_get_maxVF_value(self, mock_isfile): file1 = '/sys/class/net/%s/device/sriov_totalvfs' % 'iface1' mock_isfile.return_value = True open_ = mock_open(read_data='8\n') with patch.object(builtins, 'open', open_): iface_model = InterfaceModel(objstore=self._objstore) max_vf_str = iface_model._mlx5_SRIOV_get_max_VF('iface1') mock_isfile.assert_called_once_with(file1) self.assertEqual(max_vf_str, '8') self.assertEqual(open_.call_args_list, [call(file1, 'r')]) @mock.patch('os.path.isfile') def test_mlx5_sriov_get_currentVF_value(self, mock_isfile): file1 = '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' mock_isfile.return_value = True open_ = mock_open(read_data='5\n') with patch.object(builtins, 'open', open_): iface_model = InterfaceModel(objstore=self._objstore) curr_vf_str = iface_model._mlx5_SRIOV_get_current_VFs('iface1') mock_isfile.assert_called_once_with(file1) self.assertEqual(curr_vf_str, '5') self.assertEqual(open_.call_args_list, [call(file1, 'r')]) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_fails_if_VF_greater_max(self, mock_get_max_VF, mock_isfile, mock_get_module): mock_get_max_VF.return_value = '8' mock_get_module.return_value = 'mlx5_core' file1 = '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' mock_isfile.return_value = True with self.assertRaisesRegexp(InvalidParameter, 'GINNET0083E'): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('iface1', 16) mock_isfile.assert_called_once_with(file1) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_current_VFs') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_fails_if_VF_equal_to_current( self, mock_get_max_VF, mock_get_current_VF, mock_isfile, mock_get_module ): mock_get_max_VF.return_value = '16' mock_get_current_VF.return_value = '8' mock_get_module.return_value = 'mlx5_core' file1 = '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' mock_isfile.return_value = True with self.assertRaisesRegexp(InvalidParameter, 'GINNET0084E'): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('iface1', 8) mock_isfile.assert_called_once_with(file1) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_current_VFs') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_sriov_fails_if_VF_and_config_value_is_zero( self, mock_get_max_VF, mock_get_current_VF, mock_isfile, mock_get_module ): mock_get_max_VF.return_value = '16' mock_get_current_VF.return_value = '0' mock_get_module.return_value = 'mlx5_core' file1 = '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' mock_isfile.return_value = True with self.assertRaisesRegexp(InvalidParameter, 'GINNET0093E'): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('iface1', 0) mock_isfile.assert_called_once_with(file1) @mock.patch('wok.plugins.ginger.model.interfaces.' 'add_config_to_mlx5_SRIOV_boot_script') @mock.patch('wok.plugins.ginger.model.nw_cfginterfaces_utils.' 'CfgInterfacesHelper.create_interface_cfg_file') @mock.patch('wok.plugins.ginger.model.nw_cfginterfaces_utils.' 'CfgInterfacesHelper.get_interface_list') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_current_VFs') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_success(self, mock_get_max_VF, mock_get_current_VF, mock_isfile, mock_get_module, mock_get_iface_list, mock_create_cfg_file, mock_add_boot_script): mock_get_max_VF.return_value = '8' mock_get_current_VF.return_value = '2' mock_get_module.return_value = 'mlx5_core' file1 = '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' mock_isfile.return_value = True mock_get_iface_list.side_effect = [ set(['iface1', 'iface2']), set(['iface1', 'sriov1', 'sriov2', 'iface2']) ] open_ = mock_open(read_data='') with patch('__builtin__.open', open_): open_.call_args_list = [] iface_model = InterfaceModel(objstore=self._objstore) task_obj = iface_model.enable_sriov('iface1', 4) self.task.wait(task_obj['id']) finished_task = self.task.lookup(task_obj['id']) self.assertEquals(finished_task['status'], 'finished') mock_isfile.assert_called_once_with(file1) self.assertIn(call(file1, 'w'), open_.call_args_list) self.assertEqual(open_().write.mock_calls, [call('0\n'), call('4\n')]) mock_create_cfg_file.assert_has_calls( [call('sriov1'), call('sriov2')] ) mock_add_boot_script.assert_called_once_with('iface1', 4) @mock.patch('wok.plugins.ginger.model.interfaces.' 'add_config_to_mlx5_SRIOV_boot_script') @mock.patch('wok.plugins.ginger.model.nw_cfginterfaces_utils.' 'CfgInterfacesHelper.create_interface_cfg_file') @mock.patch('wok.plugins.ginger.model.nw_cfginterfaces_utils.' 'CfgInterfacesHelper.get_interface_list') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_current_VFs') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_success_zero_VFs(self, mock_get_max_VF, mock_get_current_VF, mock_isfile, mock_get_module, mock_get_iface_list, mock_create_cfg_file, mock_add_boot_script): mock_get_max_VF.return_value = '8' mock_get_current_VF.return_value = '4' mock_get_module.return_value = 'mlx5_core' file1 = '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' mock_isfile.return_value = True mock_get_iface_list.side_effect = [ set(['iface1', 'iface2']), set(['iface1', 'sriov1', 'sriov2', 'iface2']) ] open_ = mock_open(read_data='') with patch.object(builtins, 'open', open_): iface_model = InterfaceModel(objstore=self._objstore) task_obj = iface_model.enable_sriov('iface1', 0) self.task.wait(task_obj['id']) finished_task = self.task.lookup(task_obj['id']) self.assertEquals(finished_task['status'], 'finished') mock_isfile.assert_called_once_with(file1) self.assertEqual(open_.call_args_list, [call(file1, 'w')]) self.assertEqual(open_().write.mock_calls, [call('0\n')]) mock_create_cfg_file.assert_not_called() mock_add_boot_script.assert_called_once_with('iface1', 0) @mock.patch('os.path.isfile') def test_mlx5_sriov_edit_openib_conf(self, mock_isfile): openib_conf_file = ifaces_utils.OPENIB_CONF_FILE sriov_boot_file = ifaces_utils.MLX5_SRIOV_BOOT_FILE conf_file_content = "OPENIBD_PRE_START\nOPENIBD_POST_START\n"\ "OPENIBD_PRE_STOP\nOPENIBD_POST_STOP\n" conf_file_writelines_content = [ "OPENIBD_PRE_START\n", "OPENIBD_POST_START=%s\n" % sriov_boot_file, "OPENIBD_PRE_STOP\n", "OPENIBD_POST_STOP\n" ] mock_isfile.return_value = True open_ = mock_open(read_data=conf_file_content) with patch.object(builtins, 'open', open_): ifaces_utils.add_mlx5_SRIOV_boot_script_in_openib_conf() mock_isfile.assert_called_once_with(openib_conf_file) self.assertEqual( open_.call_args_list, [call(openib_conf_file, 'r'), call(openib_conf_file, 'w')] ) self.assertEqual( open_().writelines.mock_calls, [call(conf_file_writelines_content)] ) @mock.patch('os.path.isfile') def test_mlx5_sriov_edit_openib_conf_notfound(self, mock_isfile): openib_conf_file = ifaces_utils.OPENIB_CONF_FILE mock_isfile.return_value = False with self.assertRaisesRegexp(OperationFailed, 'GINNET0088E'): ifaces_utils.add_mlx5_SRIOV_boot_script_in_openib_conf() mock_isfile.assert_called_once_with(openib_conf_file) @mock.patch('os.path.isfile') def test_mlx5_sriov_openib_conf_variable_notfound(self, mock_isfile): openib_conf_file = ifaces_utils.OPENIB_CONF_FILE sriov_boot_file = ifaces_utils.MLX5_SRIOV_BOOT_FILE conf_file_content = "OPENIBD_PRE_START\n"\ "OPENIBD_PRE_STOP\nOPENIBD_POST_STOP\n" conf_file_write_content = "OPENIBD_POST_START=%s\n" % sriov_boot_file mock_isfile.return_value = True open_ = mock_open(read_data=conf_file_content) with patch.object(builtins, 'open', open_): ifaces_utils.add_mlx5_SRIOV_boot_script_in_openib_conf() mock_isfile.assert_called_once_with(openib_conf_file) self.assertEqual( open_.call_args_list, [call(openib_conf_file, 'r'), call(openib_conf_file, 'a')] ) self.assertEqual(open_().write.mock_calls, [call(conf_file_write_content)]) @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.' 'add_mlx5_SRIOV_boot_script_in_openib_conf') @mock.patch('os.chmod') def test_mlx5_sriov_fresh_boot_script_content(self, mock_chmod, mock_add_openib): ginger_boot_script = ifaces_utils.MLX5_SRIOV_BOOT_FILE template = """#!/bin/sh\n\ # ginger_sriov_start.sh: Connectx-4 SR-IOV init script - created by Ginger\n\ \n# %(iface)s setup\n\ echo 0 > /sys/class/net/%(iface)s/device/sriov_numvfs\n\ echo %(num_vf)s > /sys/class/net/%(iface)s/device/sriov_numvfs\n""" interface = 'dummyiface' num_vfs = '4' template = template % {'iface': interface, 'num_vf': num_vfs} open_ = mock_open(read_data='') with patch.object(builtins, 'open', open_): ifaces_utils.create_initial_mlx5_SRIOV_boot_script(interface, num_vfs) self.assertEqual( open_.call_args_list, [call(ginger_boot_script, 'w+')] ) self.assertEqual( open_().write.mock_calls, [call(template)] ) mock_chmod.assert_called_once_with(ginger_boot_script, 0744) mock_add_openib.assert_called_once_with() @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.' 'add_mlx5_SRIOV_boot_script_in_openib_conf') @mock.patch('os.path.isfile') def test_update_mlx5_sriov_boot_script_append(self, mock_isfile, mock_add_openib): ginger_boot_script = ifaces_utils.MLX5_SRIOV_BOOT_FILE mock_isfile.return_value = True initial_file = """#!/bin/sh\n\ # ginger_sriov_start.sh: Connectx-4 SR-IOV init script - created by Ginger\n\ \n# iface1 setup\n\ echo 0 > /sys/class/net/iface1/device/sriov_numvfs\n\ echo 4 > /sys/class/net/iface1/device/sriov_numvfs\n""" expected_writelines = [ "#!/bin/sh\n", "# ginger_sriov_start.sh: Connectx-4 SR-IOV init script - " "created by Ginger\n", "\n", "# iface1 setup\n", "echo 0 > /sys/class/net/iface1/device/sriov_numvfs\n", "echo 4 > /sys/class/net/iface1/device/sriov_numvfs\n", "# iface2 setup\n", "echo 0 > /sys/class/net/iface2/device/sriov_numvfs\n", "echo 8 > /sys/class/net/iface2/device/sriov_numvfs\n" ] open_ = mock_open(read_data=initial_file) with patch.object(builtins, 'open', open_): ifaces_utils.add_config_to_mlx5_SRIOV_boot_script('iface2', 8) mock_isfile.assert_called_once_with(ginger_boot_script) self.assertEqual( open_.call_args_list, [call(ginger_boot_script, 'r+')] ) self.assertEqual( open_().writelines.mock_calls, [call(expected_writelines)] ) mock_add_openib.assert_called_once_with() @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.' 'add_mlx5_SRIOV_boot_script_in_openib_conf') @mock.patch('os.path.isfile') def test_update_mlx5_sriov_script_modify_line(self, mock_isfile, mock_add_openib): ginger_boot_script = ifaces_utils.MLX5_SRIOV_BOOT_FILE mock_isfile.return_value = True initial_file = """#!/bin/sh\n\ # ginger_sriov_start.sh: Connectx-4 SR-IOV init script - created by Ginger\n\ \n# iface1 setup\n\ echo 0 > /sys/class/net/iface1/device/sriov_numvfs\n\ echo 4 > /sys/class/net/iface1/device/sriov_numvfs\n\ # iface2 setup\n\ echo 0 > /sys/class/net/iface2/device/sriov_numvfs\n\ echo 6 > /sys/class/net/iface2/device/sriov_numvfs\n\ # iface3 setup\n\ echo 0 > /sys/class/net/iface3/device/sriov_numvfs\n\ echo 8 > /sys/class/net/iface3/device/sriov_numvfs\n\ # iface4 setup\n\ echo 0 > /sys/class/net/iface4/device/sriov_numvfs\n\ echo 10 > /sys/class/net/iface4/device/sriov_numvfs\n\ """ expected_writelines = [ "#!/bin/sh\n", "# ginger_sriov_start.sh: Connectx-4 SR-IOV init script - " "created by Ginger\n", "\n", "# iface1 setup\n", "echo 0 > /sys/class/net/iface1/device/sriov_numvfs\n", "echo 4 > /sys/class/net/iface1/device/sriov_numvfs\n", "# iface2 setup\n", "echo 0 > /sys/class/net/iface2/device/sriov_numvfs\n", "echo 6 > /sys/class/net/iface2/device/sriov_numvfs\n", "# iface3 setup\n", "echo 0 > /sys/class/net/iface3/device/sriov_numvfs\n", "echo 2 > /sys/class/net/iface3/device/sriov_numvfs\n", "# iface4 setup\n", "echo 0 > /sys/class/net/iface4/device/sriov_numvfs\n", "echo 10 > /sys/class/net/iface4/device/sriov_numvfs\n", ] open_ = mock_open(read_data=initial_file) with patch.object(builtins, 'open', open_): ifaces_utils.add_config_to_mlx5_SRIOV_boot_script('iface3', 2) mock_isfile.assert_called_once_with(ginger_boot_script) self.assertEqual( open_.call_args_list, [call(ginger_boot_script, 'r+')] ) self.assertEqual( open_().writelines.mock_calls, [call(expected_writelines)] ) mock_add_openib.assert_called_once_with()
class PartitionTests(unittest.TestCase): def setUp(self): objstore_loc = config.get_object_store() + '_ginger' self._objstore = ObjectStore(objstore_loc) self.task_model = TaskModel(objstore=self._objstore) def test_get_part_list(self): parts = diskparts.PartitionsModel() parts_list = parts.get_list() self.assertGreaterEqual(len(parts_list), 0) def test_create_part_missing_device(self): parts = diskparts.PartitionsModel() size = '10M' params = {'partsize': size} self.assertRaises(MissingParameter, parts.create, params) def test_create_part_missing_size(self): parts = diskparts.PartitionsModel() dev = '/dev/sdb' params = {'devname': dev} self.assertRaises(MissingParameter, parts.create, params) @mock.patch('wok.plugins.ginger.model.utils.create_disk_part', autospec=True) def test_create_part(self, mock_create_part): parts = diskparts.PartitionsModel() dev = '/dev/sdb' size = '10M' params = {'devname': dev, 'partsize': size} parts.create(params) mock_create_part.return_value = 'sdb1' mock_create_part.assert_called_with(dev, size) @mock.patch('wok.plugins.ginger.model.utils.change_part_type', autospec=True) def test_change_part_type(self, mock_change_type): part = diskparts.PartitionModel(objstore=self._objstore) part_name = 'sdb1' type = '82' mock_change_type.return_value = 'sdb1' part.change_type(part_name, type) mock_change_type.assert_called_with(part_name, type) @mock.patch('wok.plugins.ginger.model.utils.delete_part', autospec=True) def test_delete_part(self, mock_delete_part): part = diskparts.PartitionModel(objstore=self._objstore) part_name = 'sdb1' part.delete(part_name) mock_delete_part.assert_called_with(part_name) @mock.patch('wok.plugins.ginger.model.utils._makefs', autospec=True) @mock.patch('wok.plugins.ginger.model.utils._is_mntd', autospec=True) def test_format_part(self, mock_is_mntd, mock_makefs): mock_is_mntd.return_value = False part = diskparts.PartitionModel(objstore=self._objstore) name = 'a_partition_name' fstype = 'ext4' task_obj = part.format(name, fstype) self.task_model.wait(task_obj.get('id')) mock_makefs.assert_called_with(fstype, name) @mock.patch('wok.plugins.ginger.model.diskparts.get_partition_details', autospec=True) def test_lookup_invalid_part_returns_404(self, mock_get_part_details): mock_get_part_details.side_effect = [NotFoundError] part = diskparts.PartitionModel(objstore=self._objstore) with self.assertRaises(NotFoundError): part.lookup('/a/invalid/partition')
class FirmwareTests(unittest.TestCase): def setUp(self): objstore_loc = config.get_object_store() + "_ginger" self._objstore = ObjectStore(objstore_loc) self.task = TaskModel(objstore=self._objstore) @mock.patch("wok.plugins.ginger.model.firmware.run_command") def test_model_lookup(self, mock_run_command): return_output = "0 1 2 3 4 5 6 7 8 9 10 11 12 13" mock_run_command.return_value = [return_output, "", 0] firmware_lookup = FirmwareModel(objstore=self._objstore).lookup() mock_run_command.assert_called_once_with("lsmcode") self.assertEquals(firmware_lookup, {"level": "5 6 7 8 9 10 11 12 13"}) @mock.patch("wok.plugins.ginger.model.firmware.run_command") def test_model_lookup_with_product_in_output(self, mock_run_command): return_output = "0 1 2 3 4 Product 6 7 8 9 10 11 12 13" mock_run_command.return_value = [return_output, "", 0] firmware_lookup = FirmwareModel(objstore=self._objstore).lookup() mock_run_command.assert_called_once_with("lsmcode") self.assertEquals(firmware_lookup, {"level": "13"}) @mock.patch("wok.plugins.ginger.model.firmware.detect_live_vm") def test_model_update_fails_with_running_vm(self, mock_detect_vm): mock_detect_vm.return_value = True with self.assertRaises(OperationFailed): FirmwareModel(objstore=self._objstore).upgrade(None, None) @mock.patch("wok.plugins.ginger.model.firmware.detect_live_vm") @mock.patch("wok.plugins.ginger.model.firmware.run_command") def test_model_upgrade(self, mock_run_command, mock_detect_vm): mock_detect_vm.return_value = False mock_run_command.return_value = ["", "", 0] temp = tempfile.NamedTemporaryFile() task = FirmwareModel(objstore=self._objstore).upgrade(None, temp.name) self.task.wait(task["id"]) self.assertTrue(mock_run_command.called, msg="Expected call to run_command. Not called") task_info = self.task.lookup(task["id"]) self.assertEquals("finished", task_info["status"]) self.assertEquals("/plugins/ginger/firmware/upgrade", task_info["target_uri"]) @mock.patch("wok.plugins.ginger.model.firmware.detect_live_vm") @mock.patch("wok.plugins.ginger.model.firmware.run_command") def test_model_upgrade_overwrite_perm_false(self, mock_run_command, mock_detect_vm): mock_detect_vm.return_value = False mock_run_command.return_value = ["", "", 0] temp = tempfile.NamedTemporaryFile() task = FirmwareModel(objstore=self._objstore).upgrade(None, temp.name, False) self.task.wait(task["id"]) self.assertTrue(mock_run_command.called, msg="Expected call to run_command. Not called") task_info = self.task.lookup(task["id"]) self.assertEquals("finished", task_info["status"]) self.assertEquals("/plugins/ginger/firmware/upgrade", task_info["target_uri"]) @mock.patch("wok.plugins.ginger.model.firmware.run_command") def test_model_commit(self, mock_run_command): mock_run_command.return_value = ["", "", 0] command = ["update_flash", "-c"] FirmwareModel(objstore=self._objstore).commit(None) mock_run_command.assert_called_once_with(command) @mock.patch("wok.plugins.ginger.model.firmware.run_command") def test_model_reject(self, mock_run_command): mock_run_command.return_value = ["", "", 0] command = ["update_flash", "-r"] FirmwareModel(objstore=self._objstore).reject(None) mock_run_command.assert_called_once_with(command)
class InterfacesTests(unittest.TestCase): def setUp(self): objstore_loc = config.get_object_store() + '_ginger' self._objstore = ObjectStore(objstore_loc) self.task = TaskModel(objstore=self._objstore) @mock.patch('wok.plugins.gingerbase.netinfo.os') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_type') @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.run_command') def test_activate(self, mock_run_command, mock_get_interface_type, mock_os): mock_run_command.return_value = ["", "", 0] mock_os.path.isfile.return_value = False open_mock = mock.mock_open(read_data='1') mock_get_interface_type.return_value = "nic" interface = "test_eth0" calls = [(['ip', 'link', 'set', '%s' % interface, 'up'], ), (['ifup', '%s' % interface], )] with mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.open', open_mock, create=True): self.assertRaises(OperationFailed, InterfaceModel(objstore=self._objstore).activate, interface) for i in range(0, 1): x, y = mock_run_command.call_args_list[i] assert x == calls[i] assert mock_run_command.call_count == 2 @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_type') @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.run_command') def test_activate_fail(self, mock_run_command, mock_get_interface_type): mock_run_command.return_value = ["", "Unable to activate", 1] mock_get_interface_type.return_value = "nic" interface = "test_eth0" cmd = ['ip', 'link', 'set', '%s' % interface, 'up'] self.assertRaises(OperationFailed, InterfaceModel(objstore=self._objstore).activate, interface) mock_run_command.assert_called_once_with(cmd) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_type') @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.run_command') def test_deactivate(self, mock_run_command, mock_get_interface_type): mock_run_command.return_value = ["", "", 0] mock_get_interface_type.return_value = "nic" interface = "test_eth0" calls = [(['ifdown', '%s' % interface], ), (['ip', 'link', 'set', '%s' % interface, 'down'], )] InterfaceModel(objstore=self._objstore).deactivate(interface) for i in range(0, 1): x, y = mock_run_command.call_args_list[i] assert x == calls[i] assert mock_run_command.call_count == 2 @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_type') @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.run_command') def test_deactivate_fail(self, mock_run_command, mock_get_interface_type): mock_run_command.return_value = ["", "Unable to deactivate", 1] mock_get_interface_type.return_value = "nic" interface = "test_eth0" cmd = ['ifdown', '%s' % interface] self.assertRaises(OperationFailed, InterfaceModel(objstore=self._objstore).deactivate, interface) mock_run_command.assert_called_once_with(cmd) @mock.patch('os.readlink') def test_netinfo_interface_module_lookup_success(self, mock_readlink): mock_readlink.return_value = '../../../../module/dummy_net_module' module = netinfo.get_interface_kernel_module('dummy_iface') mock_readlink.assert_called_once_with( '/sys/class/net/dummy_iface/device/driver/module') self.assertEqual(module, 'dummy_net_module') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('ethtool.get_devices') @mock.patch('ethtool.get_ipaddr') @mock.patch('ethtool.get_netmask') @mock.patch('wok.plugins.gingerbase.netinfo.macaddr') def test_netinfo_get_interface_info(self, mock_macaddr, mock_netmask, mock_ipaddr, mock_getdevs, mock_get_module): mock_get_module.return_value = 'dummy_net_module' mock_getdevs.return_value = ['dev1', 'dummy_iface', 'dev2'] mock_ipaddr.return_value = '99.99.99.99' mock_netmask.return_value = '255.255.255.0' mock_macaddr.return_value = 'aa:bb:cc:dd:ee:ff' iface_info = netinfo.get_interface_info('dummy_iface') mock_macaddr.assert_called_once_with('dummy_iface') mock_netmask.assert_called_once_with('dummy_iface') mock_ipaddr.assert_called_once_with('dummy_iface') mock_getdevs.assert_called_once_with() mock_get_module.assert_called_once_with('dummy_iface') self.assertEqual(iface_info.get('device'), 'dummy_iface') self.assertEqual(iface_info.get('type'), 'unknown') self.assertEqual(iface_info.get('status'), 'down') self.assertEqual(iface_info.get('ipaddr'), '99.99.99.99') self.assertEqual(iface_info.get('netmask'), '255.255.255.0') self.assertEqual(iface_info.get('macaddr'), 'aa:bb:cc:dd:ee:ff') self.assertEqual(iface_info.get('module'), 'dummy_net_module') @mock.patch('ethtool.get_devices') @mock.patch('wok.plugins.gingerbase.netinfo.is_rdma_enabled') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_info') def test_interface_lookup(self, mock_iface_info, mock_rdma_enabled, mock_getdevs): iface_info_return = { 'device': 'dummy_iface', 'type': 'unknown', 'status': 'down', 'ipaddr': '99.99.99.99', 'netmask': '255.255.255.0', 'macaddr': 'aa:bb:cc:dd:ee:ff', 'module': 'dummy_net_module' } mock_iface_info.return_value = iface_info_return mock_rdma_enabled.return_value = True mock_getdevs.return_value = ['dev1', 'dummy_iface', 'dev2'] iface_model = InterfaceModel(objstore=self._objstore) iface_info = iface_model.lookup('dummy_iface') mock_iface_info.assert_called_once_with('dummy_iface') mock_rdma_enabled.assert_called_once_with('dummy_iface') mock_getdevs.called_once_with() self.assertEqual(iface_info.get('device'), 'dummy_iface') self.assertEqual(iface_info.get('type'), 'unknown') self.assertEqual(iface_info.get('status'), 'down') self.assertEqual(iface_info.get('ipaddr'), '99.99.99.99') self.assertEqual(iface_info.get('netmask'), '255.255.255.0') self.assertEqual(iface_info.get('macaddr'), 'aa:bb:cc:dd:ee:ff') self.assertEqual(iface_info.get('module'), 'dummy_net_module') self.assertTrue(iface_info.get('rdma_enabled')) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') def test_invalid_module_enable_sriov_failure(self, mock_get_module): mock_get_module.return_value = 'unknown' expected_error_msg = "GINNET0076E" with self.assertRaisesRegexp(InvalidOperation, expected_error_msg): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('any_iface_name', {'num_vfs': 4}) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_no_args_failure(self, mock_get_max_VF, mock_get_module): mock_get_max_VF.return_value = '1' mock_get_module.return_value = 'mlx5_core' expected_error_msg = "GINNET0077E" with self.assertRaisesRegexp(InvalidParameter, expected_error_msg): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('any_iface_name', None) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_argument_failure(self, mock_get_max_VF, mock_get_module): mock_get_max_VF.return_value = '1' mock_get_module.return_value = 'mlx5_core' expected_error_msg = "GINNET0079E" with self.assertRaisesRegexp(InvalidParameter, expected_error_msg): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('any_iface_name', 'not_an_int') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_no_system_files_failure(self, mock_get_max_VF, mock_isfile, mock_get_module): mock_get_max_VF.return_value = '8' mock_get_module.return_value = 'mlx5_core' call_file1_not_exist = \ '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' call_file2_not_exist = \ '/sys/class/net/%s/device/mlx5_num_vfs' % 'iface1' mock_isfile.side_effect = [False, False] mock_isfile_calls = [ call(call_file1_not_exist), call(call_file2_not_exist) ] expected_error_msg = "GINNET0078E" with self.assertRaisesRegexp(OperationFailed, expected_error_msg): iface_model = InterfaceModel(objstore=self._objstore) task_obj = iface_model.enable_sriov('iface1', 4) self.task.wait(task_obj['id']) mock_isfile.assert_has_calls(mock_isfile_calls) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') def test_mlx5_sriov_not_enabled_in_FW(self, mock_isfile, mock_get_module): mock_get_module.return_value = 'mlx5_core' file1 = '/sys/class/net/%s/device/sriov_totalvfs' % 'iface1' mock_isfile.return_value = False with self.assertRaisesRegexp(OperationFailed, 'GINNET0082E'): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('iface1', 4) mock_isfile.assert_called_once_with(file1) @mock.patch('os.path.isfile') def test_mlx5_sriov_get_maxVF_value(self, mock_isfile): file1 = '/sys/class/net/%s/device/sriov_totalvfs' % 'iface1' mock_isfile.return_value = True open_ = mock_open(read_data='8\n') with patch.object(builtins, 'open', open_): iface_model = InterfaceModel(objstore=self._objstore) max_vf_str = iface_model._mlx5_SRIOV_get_max_VF('iface1') mock_isfile.assert_called_once_with(file1) self.assertEqual(max_vf_str, '8') self.assertEqual(open_.call_args_list, [call(file1, 'r')]) @mock.patch('os.path.isfile') def test_mlx5_sriov_get_currentVF_value(self, mock_isfile): file1 = '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' mock_isfile.return_value = True open_ = mock_open(read_data='5\n') with patch.object(builtins, 'open', open_): iface_model = InterfaceModel(objstore=self._objstore) curr_vf_str = iface_model._mlx5_SRIOV_get_current_VFs('iface1') mock_isfile.assert_called_once_with(file1) self.assertEqual(curr_vf_str, '5') self.assertEqual(open_.call_args_list, [call(file1, 'r')]) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_fails_if_VF_greater_max(self, mock_get_max_VF, mock_isfile, mock_get_module): mock_get_max_VF.return_value = '8' mock_get_module.return_value = 'mlx5_core' file1 = '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' mock_isfile.return_value = True with self.assertRaisesRegexp(InvalidParameter, 'GINNET0083E'): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('iface1', 16) mock_isfile.assert_called_once_with(file1) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_current_VFs') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_fails_if_VF_equal_to_current(self, mock_get_max_VF, mock_get_current_VF, mock_isfile, mock_get_module): mock_get_max_VF.return_value = '16' mock_get_current_VF.return_value = '8' mock_get_module.return_value = 'mlx5_core' file1 = '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' mock_isfile.return_value = True with self.assertRaisesRegexp(InvalidParameter, 'GINNET0084E'): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('iface1', 8) mock_isfile.assert_called_once_with(file1) @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_current_VFs') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_sriov_fails_if_VF_and_config_value_is_zero( self, mock_get_max_VF, mock_get_current_VF, mock_isfile, mock_get_module): mock_get_max_VF.return_value = '16' mock_get_current_VF.return_value = '0' mock_get_module.return_value = 'mlx5_core' file1 = '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' mock_isfile.return_value = True with self.assertRaisesRegexp(InvalidParameter, 'GINNET0093E'): iface_model = InterfaceModel(objstore=self._objstore) iface_model.enable_sriov('iface1', 0) mock_isfile.assert_called_once_with(file1) @mock.patch('wok.plugins.ginger.model.interfaces.' 'add_config_to_mlx5_SRIOV_boot_script') @mock.patch('wok.plugins.ginger.model.nw_cfginterfaces_utils.' 'CfgInterfacesHelper.create_interface_cfg_file') @mock.patch('wok.plugins.ginger.model.nw_cfginterfaces_utils.' 'CfgInterfacesHelper.get_interface_list') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_current_VFs') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_success(self, mock_get_max_VF, mock_get_current_VF, mock_isfile, mock_get_module, mock_get_iface_list, mock_create_cfg_file, mock_add_boot_script): mock_get_max_VF.return_value = '8' mock_get_current_VF.return_value = '2' mock_get_module.return_value = 'mlx5_core' file1 = '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' mock_isfile.return_value = True mock_get_iface_list.side_effect = [ set(['iface1', 'iface2']), set(['iface1', 'sriov1', 'sriov2', 'iface2']) ] open_ = mock_open(read_data='') with patch.object(builtins, 'open', open_): iface_model = InterfaceModel(objstore=self._objstore) task_obj = iface_model.enable_sriov('iface1', 4) self.task.wait(task_obj['id']) finished_task = self.task.lookup(task_obj['id']) self.assertEquals(finished_task['status'], 'finished') mock_isfile.assert_called_once_with(file1) self.assertEqual(open_.call_args_list, [call(file1, 'w'), call(file1, 'w')]) self.assertEqual(open_().write.mock_calls, [call('0\n'), call('4\n')]) mock_create_cfg_file.assert_has_calls([call('sriov1'), call('sriov2')]) mock_add_boot_script.assert_called_once_with('iface1', 4) @mock.patch('wok.plugins.ginger.model.interfaces.' 'add_config_to_mlx5_SRIOV_boot_script') @mock.patch('wok.plugins.ginger.model.nw_cfginterfaces_utils.' 'CfgInterfacesHelper.create_interface_cfg_file') @mock.patch('wok.plugins.ginger.model.nw_cfginterfaces_utils.' 'CfgInterfacesHelper.get_interface_list') @mock.patch('wok.plugins.gingerbase.netinfo.get_interface_kernel_module') @mock.patch('os.path.isfile') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_current_VFs') @mock.patch('wok.plugins.ginger.model.interfaces.InterfaceModel.' '_mlx5_SRIOV_get_max_VF') def test_mlx5_sriov_success_zero_VFs(self, mock_get_max_VF, mock_get_current_VF, mock_isfile, mock_get_module, mock_get_iface_list, mock_create_cfg_file, mock_add_boot_script): mock_get_max_VF.return_value = '8' mock_get_current_VF.return_value = '4' mock_get_module.return_value = 'mlx5_core' file1 = '/sys/class/net/%s/device/sriov_numvfs' % 'iface1' mock_isfile.return_value = True mock_get_iface_list.side_effect = [ set(['iface1', 'iface2']), set(['iface1', 'sriov1', 'sriov2', 'iface2']) ] open_ = mock_open(read_data='') with patch.object(builtins, 'open', open_): iface_model = InterfaceModel(objstore=self._objstore) task_obj = iface_model.enable_sriov('iface1', 0) self.task.wait(task_obj['id']) finished_task = self.task.lookup(task_obj['id']) self.assertEquals(finished_task['status'], 'finished') mock_isfile.assert_called_once_with(file1) self.assertEqual(open_.call_args_list, [call(file1, 'w')]) self.assertEqual(open_().write.mock_calls, [call('0\n')]) mock_create_cfg_file.assert_not_called() mock_add_boot_script.assert_called_once_with('iface1', 0) @mock.patch('os.path.isfile') def test_mlx5_sriov_edit_openib_conf(self, mock_isfile): openib_conf_file = ifaces_utils.OPENIB_CONF_FILE sriov_boot_file = ifaces_utils.MLX5_SRIOV_BOOT_FILE conf_file_content = "OPENIBD_PRE_START\nOPENIBD_POST_START\n"\ "OPENIBD_PRE_STOP\nOPENIBD_POST_STOP\n" conf_file_writelines_content = [ "OPENIBD_PRE_START\n", "OPENIBD_POST_START=%s\n" % sriov_boot_file, "OPENIBD_PRE_STOP\n", "OPENIBD_POST_STOP\n" ] mock_isfile.return_value = True open_ = mock_open(read_data=conf_file_content) with patch.object(builtins, 'open', open_): ifaces_utils.add_mlx5_SRIOV_boot_script_in_openib_conf() mock_isfile.assert_called_once_with(openib_conf_file) self.assertEqual( open_.call_args_list, [call(openib_conf_file, 'r'), call(openib_conf_file, 'w')]) self.assertEqual(open_().writelines.mock_calls, [call(conf_file_writelines_content)]) @mock.patch('os.path.isfile') def test_mlx5_sriov_edit_openib_conf_notfound(self, mock_isfile): openib_conf_file = ifaces_utils.OPENIB_CONF_FILE mock_isfile.return_value = False with self.assertRaisesRegexp(OperationFailed, 'GINNET0088E'): ifaces_utils.add_mlx5_SRIOV_boot_script_in_openib_conf() mock_isfile.assert_called_once_with(openib_conf_file) @mock.patch('os.path.isfile') def test_mlx5_sriov_openib_conf_variable_notfound(self, mock_isfile): openib_conf_file = ifaces_utils.OPENIB_CONF_FILE sriov_boot_file = ifaces_utils.MLX5_SRIOV_BOOT_FILE conf_file_content = "OPENIBD_PRE_START\n"\ "OPENIBD_PRE_STOP\nOPENIBD_POST_STOP\n" conf_file_write_content = "OPENIBD_POST_START=%s\n" % sriov_boot_file mock_isfile.return_value = True open_ = mock_open(read_data=conf_file_content) with patch.object(builtins, 'open', open_): ifaces_utils.add_mlx5_SRIOV_boot_script_in_openib_conf() mock_isfile.assert_called_once_with(openib_conf_file) self.assertEqual( open_.call_args_list, [call(openib_conf_file, 'r'), call(openib_conf_file, 'a')]) self.assertEqual(open_().write.mock_calls, [call(conf_file_write_content)]) @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.' 'add_mlx5_SRIOV_boot_script_in_openib_conf') @mock.patch('os.chmod') def test_mlx5_sriov_fresh_boot_script_content(self, mock_chmod, mock_add_openib): ginger_boot_script = ifaces_utils.MLX5_SRIOV_BOOT_FILE template = """#!/bin/sh\n\ # ginger_sriov_start.sh: Connectx-4 SR-IOV init script - created by Ginger\n\ \n# %(iface)s setup\n\ echo 0 > /sys/class/net/%(iface)s/device/sriov_numvfs\n\ echo %(num_vf)s > /sys/class/net/%(iface)s/device/sriov_numvfs\n""" interface = 'dummyiface' num_vfs = '4' template = template % {'iface': interface, 'num_vf': num_vfs} open_ = mock_open(read_data='') with patch.object(builtins, 'open', open_): ifaces_utils.create_initial_mlx5_SRIOV_boot_script( interface, num_vfs) self.assertEqual(open_.call_args_list, [call(ginger_boot_script, 'w+')]) self.assertEqual(open_().write.mock_calls, [call(template)]) mock_chmod.assert_called_once_with(ginger_boot_script, 0744) mock_add_openib.assert_called_once_with() @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.' 'add_mlx5_SRIOV_boot_script_in_openib_conf') @mock.patch('os.path.isfile') def test_update_mlx5_sriov_boot_script_append(self, mock_isfile, mock_add_openib): ginger_boot_script = ifaces_utils.MLX5_SRIOV_BOOT_FILE mock_isfile.return_value = True initial_file = """#!/bin/sh\n\ # ginger_sriov_start.sh: Connectx-4 SR-IOV init script - created by Ginger\n\ \n# iface1 setup\n\ echo 0 > /sys/class/net/iface1/device/sriov_numvfs\n\ echo 4 > /sys/class/net/iface1/device/sriov_numvfs\n""" expected_writelines = [ "#!/bin/sh\n", "# ginger_sriov_start.sh: Connectx-4 SR-IOV init script - " "created by Ginger\n", "\n", "# iface1 setup\n", "echo 0 > /sys/class/net/iface1/device/sriov_numvfs\n", "echo 4 > /sys/class/net/iface1/device/sriov_numvfs\n", "# iface2 setup\n", "echo 0 > /sys/class/net/iface2/device/sriov_numvfs\n", "echo 8 > /sys/class/net/iface2/device/sriov_numvfs\n" ] open_ = mock_open(read_data=initial_file) with patch.object(builtins, 'open', open_): ifaces_utils.add_config_to_mlx5_SRIOV_boot_script('iface2', 8) mock_isfile.assert_called_once_with(ginger_boot_script) self.assertEqual(open_.call_args_list, [call(ginger_boot_script, 'r+')]) self.assertEqual(open_().writelines.mock_calls, [call(expected_writelines)]) mock_add_openib.assert_called_once_with() @mock.patch('wok.plugins.ginger.model.nw_interfaces_utils.' 'add_mlx5_SRIOV_boot_script_in_openib_conf') @mock.patch('os.path.isfile') def test_update_mlx5_sriov_script_modify_line(self, mock_isfile, mock_add_openib): ginger_boot_script = ifaces_utils.MLX5_SRIOV_BOOT_FILE mock_isfile.return_value = True initial_file = """#!/bin/sh\n\ # ginger_sriov_start.sh: Connectx-4 SR-IOV init script - created by Ginger\n\ \n# iface1 setup\n\ echo 0 > /sys/class/net/iface1/device/sriov_numvfs\n\ echo 4 > /sys/class/net/iface1/device/sriov_numvfs\n\ # iface2 setup\n\ echo 0 > /sys/class/net/iface2/device/sriov_numvfs\n\ echo 6 > /sys/class/net/iface2/device/sriov_numvfs\n\ # iface3 setup\n\ echo 0 > /sys/class/net/iface3/device/sriov_numvfs\n\ echo 8 > /sys/class/net/iface3/device/sriov_numvfs\n\ # iface4 setup\n\ echo 0 > /sys/class/net/iface4/device/sriov_numvfs\n\ echo 10 > /sys/class/net/iface4/device/sriov_numvfs\n\ """ expected_writelines = [ "#!/bin/sh\n", "# ginger_sriov_start.sh: Connectx-4 SR-IOV init script - " "created by Ginger\n", "\n", "# iface1 setup\n", "echo 0 > /sys/class/net/iface1/device/sriov_numvfs\n", "echo 4 > /sys/class/net/iface1/device/sriov_numvfs\n", "# iface2 setup\n", "echo 0 > /sys/class/net/iface2/device/sriov_numvfs\n", "echo 6 > /sys/class/net/iface2/device/sriov_numvfs\n", "# iface3 setup\n", "echo 0 > /sys/class/net/iface3/device/sriov_numvfs\n", "echo 2 > /sys/class/net/iface3/device/sriov_numvfs\n", "# iface4 setup\n", "echo 0 > /sys/class/net/iface4/device/sriov_numvfs\n", "echo 10 > /sys/class/net/iface4/device/sriov_numvfs\n", ] open_ = mock_open(read_data=initial_file) with patch.object(builtins, 'open', open_): ifaces_utils.add_config_to_mlx5_SRIOV_boot_script('iface3', 2) mock_isfile.assert_called_once_with(ginger_boot_script) self.assertEqual(open_.call_args_list, [call(ginger_boot_script, 'r+')]) self.assertEqual(open_().writelines.mock_calls, [call(expected_writelines)]) mock_add_openib.assert_called_once_with()
class StorageVolumesModel(object): def __init__(self, **kargs): self.conn = kargs['conn'] self.objstore = kargs['objstore'] self.task = TaskModel(**kargs) def create(self, pool_name, params): vol_source = ['url', 'capacity'] name = params.get('name') index_list = list(i for i in range(len(vol_source)) if vol_source[i] in params) if len(index_list) != 1: raise InvalidParameter('KCHVOL0018E', {'param': ','.join(vol_source)}) create_param = vol_source[index_list[0]] # Verify if the URL is valid if create_param == 'url': url = params['url'] try: urllib.request.urlopen(url).close() except Exception: raise InvalidParameter('KCHVOL0022E', {'url': url}) all_vol_names = self.get_list(pool_name) if name is None: # the methods listed in 'REQUIRE_NAME_PARAMS' cannot have # 'name' == None if create_param in REQUIRE_NAME_PARAMS: raise InvalidParameter('KCHVOL0016E') # if 'name' is omitted - except for the methods listed in # 'REQUIRE_NAME_PARAMS' - the default volume name will be the # file/URL basename. if create_param == 'url': name = os.path.basename(params['url']) else: name = f'upload-{int(time.time())}' name = get_unique_file_name(all_vol_names, name) params['name'] = name try: create_func = getattr(self, f'_create_volume_with_{create_param}') except AttributeError: raise InvalidParameter('KCHVOL0019E', {'param': create_param}) pool_info = StoragePoolModel(conn=self.conn, objstore=self.objstore).lookup(pool_name) if pool_info['type'] in READONLY_POOL_TYPE: raise InvalidParameter('KCHVOL0012E', {'type': pool_info['type']}) if pool_info['state'] == 'inactive': raise InvalidParameter('KCHVOL0003E', { 'pool': pool_name, 'volume': name }) if name in all_vol_names: raise InvalidParameter('KCHVOL0001E', {'name': name}) params['pool'] = pool_name params['pool_type'] = pool_info['type'] targeturi = '/plugins/kimchi/storagepools/%s/storagevolumes/%s' % ( pool_name, name, ) taskid = AsyncTask(targeturi, create_func, params).id return self.task.lookup(taskid) def _create_volume_with_capacity(self, cb, params): pool_name = params.pop('pool') vol_xml = """ <volume> <name>%(name)s</name> <allocation unit='bytes'>%(allocation)s</allocation> <capacity unit='bytes'>%(capacity)s</capacity> <source> </source> <target> <format type='%(format)s'/> </target> </volume> """ allocation = 0 if params['pool_type'] == 'logical': allocation = params['capacity'] params.setdefault('allocation', allocation) params.setdefault('format', 'qcow2') name = params['name'] try: pool = StoragePoolModel.get_storagepool(pool_name, self.conn) xml = vol_xml % params except KeyError as item: raise MissingParameter('KCHVOL0004E', { 'item': str(item), 'volume': name }) try: pool.createXML(xml, 0) except libvirt.libvirtError as e: raise OperationFailed( 'KCHVOL0007E', { 'name': name, 'pool': pool_name, 'err': e.get_error_message() }, ) vol_info = StorageVolumeModel(conn=self.conn, objstore=self.objstore).lookup( pool_name, name) vol_path = vol_info['path'] if params.get('upload', False): upload_volumes[vol_path] = { 'lock': threading.Lock(), 'offset': 0, 'cb': cb, 'expected_vol_size': params['capacity'], } cb('ready for upload') else: cb('OK', True) def _create_volume_with_url(self, cb, params): pool_name = params['pool'] name = params['name'] url = params['url'] pool_model = StoragePoolModel(conn=self.conn, objstore=self.objstore) pool = pool_model.lookup(pool_name) if pool['type'] in ['dir', 'netfs']: file_path = os.path.join(pool['path'], name) else: file_path = tempfile.mkstemp(prefix=name)[1] with contextlib.closing(urllib.request.urlopen(url)) as response: with open(file_path, 'w') as volume_file: remote_size = response.getheader('Content-Length', '-') downloaded_size = 0 try: while True: chunk_data = response.read(READ_CHUNK_SIZE).decode( 'utf-8') if not chunk_data: break volume_file.write(chunk_data) downloaded_size += len(chunk_data) cb(f'{downloaded_size}/{remote_size}') except (IOError, libvirt.libvirtError) as e: if os.path.isfile(file_path): os.remove(file_path) raise OperationFailed('KCHVOL0007E', { 'name': name, 'pool': pool_name, 'err': str(e) }) if pool['type'] in ['dir', 'netfs']: virt_pool = StoragePoolModel.get_storagepool(pool_name, self.conn) virt_pool.refresh(0) else: def _stream_handler(stream, nbytes, fd): return fd.read(nbytes) virt_stream = virt_vol = None try: task = self.create( pool_name, { 'name': name, 'format': 'raw', 'capacity': downloaded_size, 'allocation': downloaded_size, }, ) self.task.wait(task['id']) virt_vol = StorageVolumeModel.get_storagevolume( pool_name, name, self.conn) virt_stream = self.conn.get().newStream(0) virt_vol.upload(virt_stream, 0, downloaded_size, 0) with open(file_path) as fd: virt_stream.sendAll(_stream_handler, fd) virt_stream.finish() except (IOError, libvirt.libvirtError) as e: try: if virt_stream: virt_stream.abort() if virt_vol: virt_vol.delete(0) except libvirt.libvirtError as e: wok_log.error(str(e)) finally: raise OperationFailed('KCHVOL0007E', { 'name': name, 'pool': pool_name, 'err': str(e) }) finally: os.remove(file_path) cb('OK', True) def get_list(self, pool_name): pool = StoragePoolModel.get_storagepool(pool_name, self.conn) if not pool.isActive(): raise InvalidOperation('KCHVOL0006E', {'pool': pool_name}) try: pool.refresh(0) except Exception as e: wok_log.error(f'Pool refresh failed: {e}') return sorted(pool.listVolumes())
class PartitionTests(unittest.TestCase): def setUp(self): objstore_loc = config.get_object_store() + '_ginger' self._objstore = ObjectStore(objstore_loc) self.task_model = TaskModel(objstore=self._objstore) def test_get_part_list(self): parts = diskparts.PartitionsModel() parts_list = parts.get_list() self.assertGreaterEqual(len(parts_list), 0) def test_create_part_missing_device(self): parts = diskparts.PartitionsModel() size = 10 params = {'partsize': size} self.assertRaises(MissingParameter, parts.create, params) def test_create_part_missing_size(self): parts = diskparts.PartitionsModel() dev = '/dev/sdb' params = {'devname': dev} self.assertRaises(MissingParameter, parts.create, params) @mock.patch('wok.plugins.ginger.model.utils.create_disk_part', autospec=True) def test_create_part(self, mock_create_part): parts = diskparts.PartitionsModel() dev = '/dev/sdb' size = 10 params = {'devname': dev, 'partsize': size} parts.create(params) mock_create_part.return_value = 'sdb1' mock_create_part.assert_called_with(dev, size) @mock.patch('wok.plugins.ginger.model.utils.change_part_type', autospec=True) def test_change_part_type(self, mock_change_type): part = diskparts.PartitionModel(objstore=self._objstore) part_name = 'sdb1' type = '82' mock_change_type.return_value = 'sdb1' part.change_type(part_name, type) mock_change_type.assert_called_with(part_name, type) @mock.patch('wok.plugins.ginger.model.utils.delete_part', autospec=True) def test_delete_part(self, mock_delete_part): part = diskparts.PartitionModel(objstore=self._objstore) part_name = 'sdb1' part.delete(part_name) mock_delete_part.assert_called_with(part_name) @mock.patch('wok.plugins.ginger.model.utils._makefs', autospec=True) @mock.patch('wok.plugins.ginger.model.utils._is_mntd', autospec=True) def test_format_part(self, mock_is_mntd, mock_makefs): mock_is_mntd.return_value = False part = diskparts.PartitionModel(objstore=self._objstore) name = 'a_partition_name' fstype = 'ext4' task_obj = part.format(name, fstype) self.task_model.wait(task_obj.get('id')) mock_makefs.assert_called_with(fstype, name) @mock.patch('wok.plugins.ginger.model.diskparts.get_partition_details', autospec=True) def test_lookup_invalid_part_returns_404(self, mock_get_part_details): mock_get_part_details.side_effect = iter([NotFoundError]) part = diskparts.PartitionModel(objstore=self._objstore) with self.assertRaises(NotFoundError): part.lookup('/a/invalid/partition')
class StorageVolumesModel(object): def __init__(self, **kargs): self.conn = kargs['conn'] self.objstore = kargs['objstore'] self.task = TaskModel(**kargs) def create(self, pool_name, params): vol_source = ['url', 'capacity'] name = params.get('name') index_list = list(i for i in range(len(vol_source)) if vol_source[i] in params) if len(index_list) != 1: raise InvalidParameter( 'KCHVOL0018E', {'param': ','.join(vol_source)}) create_param = vol_source[index_list[0]] # Verify if the URL is valid if create_param == 'url': url = params['url'] try: urllib.request.urlopen(url).close() except Exception: raise InvalidParameter('KCHVOL0022E', {'url': url}) all_vol_names = self.get_list(pool_name) if name is None: # the methods listed in 'REQUIRE_NAME_PARAMS' cannot have # 'name' == None if create_param in REQUIRE_NAME_PARAMS: raise InvalidParameter('KCHVOL0016E') # if 'name' is omitted - except for the methods listed in # 'REQUIRE_NAME_PARAMS' - the default volume name will be the # file/URL basename. if create_param == 'url': name = os.path.basename(params['url']) else: name = f'upload-{int(time.time())}' name = get_unique_file_name(all_vol_names, name) params['name'] = name try: create_func = getattr(self, f'_create_volume_with_{create_param}') except AttributeError: raise InvalidParameter('KCHVOL0019E', {'param': create_param}) pool_info = StoragePoolModel(conn=self.conn, objstore=self.objstore).lookup( pool_name ) if pool_info['type'] in READONLY_POOL_TYPE: raise InvalidParameter('KCHVOL0012E', {'type': pool_info['type']}) if pool_info['state'] == 'inactive': raise InvalidParameter( 'KCHVOL0003E', {'pool': pool_name, 'volume': name}) if name in all_vol_names: raise InvalidParameter('KCHVOL0001E', {'name': name}) params['pool'] = pool_name params['pool_type'] = pool_info['type'] targeturi = '/plugins/kimchi/storagepools/%s/storagevolumes/%s' % ( pool_name, name, ) taskid = AsyncTask(targeturi, create_func, params).id return self.task.lookup(taskid) def _create_volume_with_capacity(self, cb, params): pool_name = params.pop('pool') vol_xml = """ <volume> <name>%(name)s</name> <allocation unit='bytes'>%(allocation)s</allocation> <capacity unit='bytes'>%(capacity)s</capacity> <source> </source> <target> <format type='%(format)s'/> </target> </volume> """ allocation = 0 if params['pool_type'] == 'logical': allocation = params['capacity'] params.setdefault('allocation', allocation) params.setdefault('format', 'qcow2') name = params['name'] try: pool = StoragePoolModel.get_storagepool(pool_name, self.conn) xml = vol_xml % params except KeyError as item: raise MissingParameter( 'KCHVOL0004E', {'item': str(item), 'volume': name}) try: pool.createXML(xml, 0) except libvirt.libvirtError as e: raise OperationFailed( 'KCHVOL0007E', {'name': name, 'pool': pool_name, 'err': e.get_error_message()}, ) vol_info = StorageVolumeModel(conn=self.conn, objstore=self.objstore).lookup( pool_name, name ) vol_path = vol_info['path'] if params.get('upload', False): upload_volumes[vol_path] = { 'lock': threading.Lock(), 'offset': 0, 'cb': cb, 'expected_vol_size': params['capacity'], } cb('ready for upload') else: cb('OK', True) def _create_volume_with_url(self, cb, params): pool_name = params['pool'] name = params['name'] url = params['url'] pool_model = StoragePoolModel(conn=self.conn, objstore=self.objstore) pool = pool_model.lookup(pool_name) if pool['type'] in ['dir', 'netfs']: file_path = os.path.join(pool['path'], name) else: file_path = tempfile.mkstemp(prefix=name)[1] with contextlib.closing(urllib.request.urlopen(url)) as response: with open(file_path, 'w') as volume_file: remote_size = response.getheader('Content-Length', '-') downloaded_size = 0 try: while True: chunk_data = response.read( READ_CHUNK_SIZE).decode('utf-8') if not chunk_data: break volume_file.write(chunk_data) downloaded_size += len(chunk_data) cb(f'{downloaded_size}/{remote_size}') except (IOError, libvirt.libvirtError) as e: if os.path.isfile(file_path): os.remove(file_path) raise OperationFailed( 'KCHVOL0007E', {'name': name, 'pool': pool_name, 'err': str(e)} ) if pool['type'] in ['dir', 'netfs']: virt_pool = StoragePoolModel.get_storagepool(pool_name, self.conn) virt_pool.refresh(0) else: def _stream_handler(stream, nbytes, fd): return fd.read(nbytes) virt_stream = virt_vol = None try: task = self.create( pool_name, { 'name': name, 'format': 'raw', 'capacity': downloaded_size, 'allocation': downloaded_size, }, ) self.task.wait(task['id']) virt_vol = StorageVolumeModel.get_storagevolume( pool_name, name, self.conn ) virt_stream = self.conn.get().newStream(0) virt_vol.upload(virt_stream, 0, downloaded_size, 0) with open(file_path) as fd: virt_stream.sendAll(_stream_handler, fd) virt_stream.finish() except (IOError, libvirt.libvirtError) as e: try: if virt_stream: virt_stream.abort() if virt_vol: virt_vol.delete(0) except libvirt.libvirtError as e: wok_log.error(str(e)) finally: raise OperationFailed( 'KCHVOL0007E', {'name': name, 'pool': pool_name, 'err': str(e)} ) finally: os.remove(file_path) cb('OK', True) def get_list(self, pool_name): pool = StoragePoolModel.get_storagepool(pool_name, self.conn) if not pool.isActive(): raise InvalidOperation('KCHVOL0006E', {'pool': pool_name}) try: pool.refresh(0) except Exception as e: wok_log.error(f'Pool refresh failed: {e}') return sorted(pool.listVolumes())
class BackupArchiveTests(unittest.TestCase): def setUp(self): self.temp_file = tempfile.NamedTemporaryFile(delete=False) objstore_loc = self.temp_file.name self._objstore = ObjectStore(objstore_loc) self.task = TaskModel(objstore=self._objstore) ArchivesModel._archive_dir = '/tmp' ArchivesModel._default_include = [] ArchivesModel._default_exclude = [] def tearDown(self): self.temp_file.close() os.remove(self.temp_file.name) @mock.patch('wok.plugins.ginger.model.backup.run_command') @mock.patch('wok.plugins.ginger.model.backup.get_tar_create_timeout') @mock.patch('wok.plugins.ginger.model.backup._sha256sum') def test_create_and_lookup_backup_file(self, mock_sha256sum, mock_timeout, mock_run_command): include = [] exclude = [] descr = 'test_create_lookup_bkp_file' mock_run_command.return_value = ["", "", 0] mock_timeout.return_value = 10 mock_sha256sum.return_value = 'sha256sum' params = {'include': [], 'exclude': [], 'description': descr} task_obj = ArchivesModel(objstore=self._objstore).create(params) self.task.wait(task_obj['id']) archive_id = task_obj['target_uri'].split("/")[-1] archive_file = os.path.join('/tmp', archive_id + '.tar.gz') cmd = ['tar', '--create', '--gzip', '--absolute-names', '--file', archive_file, '--selinux', '--acl', '--xattrs'] + exclude + include mock_run_command.asert_called_once_with(cmd) mock_sha256sum.asert_called_once_with(archive_file) lookup = ArchiveModel(objstore=self._objstore).lookup(archive_id) self.assertEqual(lookup.get('identity'), archive_id) self.assertEqual(lookup.get('include'), []) self.assertEqual(lookup.get('exclude'), []) self.assertEqual(lookup.get('description'), descr) self.assertEqual(lookup.get('file'), archive_file) @mock.patch('wok.objectstore.ObjectStoreSession.delete') @mock.patch('wok.plugins.ginger.model.backup.ArchivesModel.' '_session_get_list') @mock.patch('os.listdir') def test_archive_list_removes_deleted_tar_entries(self, mock_listdir, mock_get_list, mock_session_delete): mock_listdir.return_value = ['file1.tar.gz', 'file3.tar.gz'] mock_get_list.return_value = ['file1', 'file2', 'file3', 'file4'] ArchivesModel(objstore=self._objstore).get_list() mock_listdir.assert_called_once_with(ArchivesModel._archive_dir) mock_session_delete.assert_has_calls( [ call(ArchivesModel._objstore_type, 'file2'), call(ArchivesModel._objstore_type, 'file4') ] )
class FirmwareTests(unittest.TestCase): def setUp(self): objstore_loc = config.get_object_store() + '_ginger' self._objstore = ObjectStore(objstore_loc) self.task = TaskModel(objstore=self._objstore) @mock.patch('wok.plugins.ginger.model.firmware.run_command') def test_model_lookup(self, mock_run_command): return_output = "0 1 2 3 4 5 6 7 8 9 10 11 12 13" mock_run_command.return_value = [return_output, "", 0] firmware_lookup = FirmwareModel(objstore=self._objstore).lookup() mock_run_command.assert_called_once_with('lsmcode') self.assertEquals(firmware_lookup, {'level': "5 6 7 8 9 10 11 12 13"}) @mock.patch('wok.plugins.ginger.model.firmware.run_command') def test_model_lookup_with_product_in_output(self, mock_run_command): return_output = "0 1 2 3 4 Product 6 7 8 9 10 11 12 13" mock_run_command.return_value = [return_output, "", 0] firmware_lookup = FirmwareModel(objstore=self._objstore).lookup() mock_run_command.assert_called_once_with('lsmcode') self.assertEquals(firmware_lookup, {'level': '13'}) @mock.patch('wok.plugins.ginger.model.firmware.detect_live_vm') def test_model_update_fails_with_running_vm(self, mock_detect_vm): mock_detect_vm.return_value = True with self.assertRaises(OperationFailed): FirmwareModel(objstore=self._objstore).upgrade(None, None) @mock.patch('wok.plugins.ginger.model.firmware.detect_live_vm') @mock.patch('wok.plugins.ginger.model.firmware.run_command') def test_model_upgrade(self, mock_run_command, mock_detect_vm): mock_detect_vm.return_value = False mock_run_command.return_value = ["", "", 0] temp = tempfile.NamedTemporaryFile() task = FirmwareModel(objstore=self._objstore).upgrade(None, temp.name) self.task.wait(task['id']) self.assertTrue(mock_run_command.called, msg='Expected call to run_command. Not called') task_info = self.task.lookup(task['id']) self.assertEquals('finished', task_info['status']) self.assertEquals('/plugins/ginger/firmware/upgrade', task_info['target_uri']) @mock.patch('wok.plugins.ginger.model.firmware.detect_live_vm') @mock.patch('wok.plugins.ginger.model.firmware.run_command') def test_model_upgrade_overwrite_perm_false(self, mock_run_command, mock_detect_vm): mock_detect_vm.return_value = False mock_run_command.return_value = ["", "", 0] temp = tempfile.NamedTemporaryFile() task = FirmwareModel(objstore=self._objstore).upgrade( None, temp.name, False) self.task.wait(task['id']) self.assertTrue(mock_run_command.called, msg='Expected call to run_command. Not called') task_info = self.task.lookup(task['id']) self.assertEquals('finished', task_info['status']) self.assertEquals('/plugins/ginger/firmware/upgrade', task_info['target_uri']) @mock.patch('wok.plugins.ginger.model.firmware.run_command') def test_model_commit(self, mock_run_command): mock_run_command.return_value = ["", "", 0] command = ['update_flash', '-c'] FirmwareModel(objstore=self._objstore).commit(None) mock_run_command.assert_called_once_with(command) @mock.patch('wok.plugins.ginger.model.firmware.run_command') def test_model_reject(self, mock_run_command): mock_run_command.return_value = ["", "", 0] command = ['update_flash', '-r'] FirmwareModel(objstore=self._objstore).reject(None) mock_run_command.assert_called_once_with(command)
class FirmwareTests(unittest.TestCase): def setUp(self): objstore_loc = config.get_object_store() + '_ginger' self._objstore = ObjectStore(objstore_loc) self.task = TaskModel(objstore=self._objstore) @mock.patch('wok.plugins.ginger.model.firmware.run_command') def test_model_lookup(self, mock_run_command): return_output = "0 1 2 3 4 5 6 7 8 9 10 11 12 13" mock_run_command.return_value = [return_output, "", 0] firmware_lookup = FirmwareModel(objstore=self._objstore).lookup() mock_run_command.assert_called_once_with('lsmcode') self.assertEquals( firmware_lookup, {'level': "5 6 7 8 9 10 11 12 13"} ) @mock.patch('wok.plugins.ginger.model.firmware.run_command') def test_model_lookup_with_product_in_output(self, mock_run_command): return_output = "0 1 2 3 4 Product 6 7 8 9 10 11 12 13" mock_run_command.return_value = [return_output, "", 0] firmware_lookup = FirmwareModel(objstore=self._objstore).lookup() mock_run_command.assert_called_once_with('lsmcode') self.assertEquals(firmware_lookup, {'level': '13'}) @mock.patch('wok.plugins.ginger.model.firmware.detect_live_vm') def test_model_update_fails_with_running_vm(self, mock_detect_vm): mock_detect_vm.return_value = True with self.assertRaises(OperationFailed): FirmwareModel(objstore=self._objstore).upgrade(None, None) @mock.patch('wok.plugins.ginger.model.firmware.detect_live_vm') @mock.patch('wok.plugins.ginger.model.firmware.run_command') def test_model_update(self, mock_run_command, mock_detect_vm): mock_detect_vm.return_value = False mock_run_command.return_value = ["", "", 0] temp = tempfile.NamedTemporaryFile() command = ['update_flash', '-f', temp.name] task = FirmwareModel(objstore=self._objstore).upgrade(temp.name) self.task.wait(task['id']) mock_run_command.assert_called_once_with( command, tee='/tmp/fw_tee_log.txt' ) @mock.patch('wok.plugins.ginger.model.firmware.detect_live_vm') @mock.patch('wok.plugins.ginger.model.firmware.run_command') def test_model_update_overwrite_perm_false( self, mock_run_command, mock_detect_vm ): mock_detect_vm.return_value = False mock_run_command.return_value = ["", "", 0] temp = tempfile.NamedTemporaryFile() command = ['update_flash', '-n', '-f', temp.name] task = FirmwareModel(objstore=self._objstore).upgrade(temp.name, False) self.task.wait(task['id']) mock_run_command.assert_called_once_with( command, tee='/tmp/fw_tee_log.txt' ) @mock.patch('wok.plugins.ginger.model.firmware.run_command') def test_model_commit(self, mock_run_command): mock_run_command.return_value = ["", "", 0] command = ['update_flash', '-c'] FirmwareModel(objstore=self._objstore).commit(None) mock_run_command.assert_called_once_with(command) @mock.patch('wok.plugins.ginger.model.firmware.run_command') def test_model_reject(self, mock_run_command): mock_run_command.return_value = ["", "", 0] command = ['update_flash', '-r'] FirmwareModel(objstore=self._objstore).reject(None) mock_run_command.assert_called_once_with(command)
class BackupArchiveTests(unittest.TestCase): def setUp(self): self.temp_file = tempfile.NamedTemporaryFile(delete=False) objstore_loc = self.temp_file.name self._objstore = ObjectStore(objstore_loc) self.task = TaskModel(objstore=self._objstore) ArchivesModel._archive_dir = '/tmp' ArchivesModel._default_include = [] ArchivesModel._default_exclude = [] def tearDown(self): self.temp_file.close() os.remove(self.temp_file.name) @mock.patch('wok.plugins.ginger.model.backup.run_command') @mock.patch('wok.plugins.ginger.model.backup._sha256sum') def test_create_and_lookup_backup_file(self, mock_sha256sum, mock_run_command): include = [] exclude = [] descr = 'test_create_lookup_bkp_file' mock_run_command.return_value = ["", "", 0] mock_sha256sum.return_value = 'sha256sum' params = {'include': [], 'exclude': [], 'description': descr} task_obj = ArchivesModel(objstore=self._objstore).create(params) self.task.wait(task_obj['id']) archive_id = task_obj['target_uri'].split("/")[-1] archive_file = os.path.join('/tmp', archive_id + '.tar.gz') cmd = [ 'tar', '--create', '--ignore-failed-read', '--gzip', '--absolute-names', '--file', archive_file, '--selinux', '--acl', '--xattrs' ] + exclude + include mock_run_command.asert_called_once_with(cmd) mock_sha256sum.asert_called_once_with(archive_file) lookup = ArchiveModel(objstore=self._objstore).lookup(archive_id) self.assertEqual(lookup.get('identity'), archive_id) self.assertEqual(lookup.get('include'), []) self.assertEqual(lookup.get('exclude'), []) self.assertEqual(lookup.get('description'), descr) self.assertEqual(lookup.get('file'), archive_file) @mock.patch('wok.objectstore.ObjectStoreSession.delete') @mock.patch('wok.plugins.ginger.model.backup.ArchivesModel.' '_session_get_list') @mock.patch('os.listdir') def test_archive_list_removes_deleted_tar_entries(self, mock_listdir, mock_get_list, mock_session_delete): mock_listdir.return_value = ['file1.tar.gz', 'file3.tar.gz'] mock_get_list.return_value = ['file1', 'file2', 'file3', 'file4'] ArchivesModel(objstore=self._objstore).get_list() mock_listdir.assert_called_once_with(ArchivesModel._archive_dir) mock_session_delete.assert_has_calls([ call(ArchivesModel._objstore_type, 'file2'), call(ArchivesModel._objstore_type, 'file4') ])