From a794b8d77bf50493b71e9ce758bd16a2f3cde579 Mon Sep 17 00:00:00 2001 From: Thomas Thrainer Date: Wed, 31 Jul 2013 14:59:58 +0200 Subject: [PATCH] Add unit test for LUClusterSetParams Some changes to the test framework were performed while writing this test: - Extended builder for disks - Introduced builder for NICs - Fixed bugs in RpcResultsBuilder Signed-off-by: Thomas Thrainer Reviewed-by: Michele Tartara --- lib/cmdlib/cluster.py | 4 +- test/py/cmdlib/cluster_unittest.py | 486 ++++++++++++++++++++++++- test/py/cmdlib/test_unittest.py | 6 +- test/py/cmdlib/testsupport/cmdlib_testcase.py | 14 +- test/py/cmdlib/testsupport/config_mock.py | 69 +++- test/py/cmdlib/testsupport/rpc_runner_mock.py | 32 +- 6 files changed, 584 insertions(+), 27 deletions(-) diff --git a/lib/cmdlib/cluster.py b/lib/cmdlib/cluster.py index 4e2e8e0..12514f4 100644 --- a/lib/cmdlib/cluster.py +++ b/lib/cmdlib/cluster.py @@ -1094,8 +1094,8 @@ class LUClusterSetParams(LogicalUnit): if self.op.drbd_helper is not None: if not constants.DT_DRBD8 in self.cluster.enabled_disk_templates: - feedback_fn("Note that you specified a drbd user helper, but did" - " enabled the drbd disk template.") + feedback_fn("Note that you specified a drbd user helper, but did not" + " enable the drbd disk template.") new_helper = self.op.drbd_helper if not new_helper: new_helper = None diff --git a/test/py/cmdlib/cluster_unittest.py b/test/py/cmdlib/cluster_unittest.py index 6061440..5250e26 100644 --- a/test/py/cmdlib/cluster_unittest.py +++ b/test/py/cmdlib/cluster_unittest.py @@ -31,6 +31,7 @@ import shutil from ganeti import constants from ganeti import compat +from ganeti import errors from ganeti import ht from ganeti import netutils from ganeti import objects @@ -272,7 +273,7 @@ class TestLUClusterActivateMasterIp(CmdlibTestCase): op = opcodes.OpClusterActivateMasterIp() self.rpc.call_node_activate_master_ip.return_value = \ - RpcResultsBuilder(cfg=self.cfg) \ + self.RpcResultsBuilder() \ .CreateSuccessfulNodeResult(self.master) self.ExecOpCode(op) @@ -284,7 +285,7 @@ class TestLUClusterActivateMasterIp(CmdlibTestCase): op = opcodes.OpClusterActivateMasterIp() self.rpc.call_node_activate_master_ip.return_value = \ - RpcResultsBuilder(cfg=self.cfg) \ + self.RpcResultsBuilder() \ .CreateFailedNodeResult(self.master) \ self.ExecOpCodeExpectOpExecError(op) @@ -295,7 +296,7 @@ class TestLUClusterDeactivateMasterIp(CmdlibTestCase): op = opcodes.OpClusterDeactivateMasterIp() self.rpc.call_node_deactivate_master_ip.return_value = \ - RpcResultsBuilder(cfg=self.cfg) \ + self.RpcResultsBuilder() \ .CreateSuccessfulNodeResult(self.master) self.ExecOpCode(op) @@ -307,7 +308,7 @@ class TestLUClusterDeactivateMasterIp(CmdlibTestCase): op = opcodes.OpClusterDeactivateMasterIp() self.rpc.call_node_deactivate_master_ip.return_value = \ - RpcResultsBuilder(cfg=self.cfg) \ + self.RpcResultsBuilder() \ .CreateFailedNodeResult(self.master) \ self.ExecOpCodeExpectOpExecError(op) @@ -323,7 +324,7 @@ class TestLUClusterConfigQuery(CmdlibTestCase): op = opcodes.OpClusterConfigQuery(output_fields=query.CLUSTER_FIELDS.keys()) self.rpc.call_get_watcher_pause.return_value = \ - RpcResultsBuilder(self.cfg) \ + self.RpcResultsBuilder() \ .CreateSuccessfulNodeResult(self.master, -1) ret = self.ExecOpCode(op) @@ -450,11 +451,10 @@ class TestLUClusterRepairDiskSizes(CmdlibTestCase): pnode = self.master snode = self.cfg.AddNewNode() - inst = self.cfg.AddNewInstance() disk = self.cfg.CreateDisk(dev_type=dev_type, primary_node=pnode, secondary_node=snode) - inst.disks.append(disk) + inst = self.cfg.AddNewInstance(disks=[disk]) return (inst, disk) @@ -463,7 +463,7 @@ class TestLUClusterRepairDiskSizes(CmdlibTestCase): op = opcodes.OpClusterRepairDiskSizes(instances=[inst.name]) self.rpc.call_blockdev_getdimensions.return_value = \ - RpcResultsBuilder(cfg=self.cfg) \ + self.RpcResultsBuilder() \ .CreateFailedNodeResult(self.master) self.ExecOpCode(op) @@ -475,7 +475,7 @@ class TestLUClusterRepairDiskSizes(CmdlibTestCase): op = opcodes.OpClusterRepairDiskSizes() self.rpc.call_blockdev_getdimensions.return_value = \ - RpcResultsBuilder(cfg=self.cfg) \ + self.RpcResultsBuilder() \ .CreateSuccessfulNodeResult(self.master, node_data) return self.ExecOpCode(op) @@ -534,5 +534,473 @@ class TestLUClusterRepairDiskSizes(CmdlibTestCase): self.assertEqual(1, len(changed)) +class TestLUClusterSetParams(CmdlibTestCase): + UID_POOL = [(10, 1000)] + + def testUidPool(self): + op = opcodes.OpClusterSetParams(uid_pool=self.UID_POOL) + self.ExecOpCode(op) + self.assertEqual(self.UID_POOL, self.cluster.uid_pool) + + def testAddUids(self): + old_pool = [(1, 9)] + self.cluster.uid_pool = list(old_pool) + op = opcodes.OpClusterSetParams(add_uids=self.UID_POOL) + self.ExecOpCode(op) + self.assertEqual(set(self.UID_POOL + old_pool), + set(self.cluster.uid_pool)) + + def testRemoveUids(self): + additional_pool = [(1, 9)] + self.cluster.uid_pool = self.UID_POOL + additional_pool + op = opcodes.OpClusterSetParams(remove_uids=self.UID_POOL) + self.ExecOpCode(op) + self.assertEqual(additional_pool, self.cluster.uid_pool) + + def testMasterNetmask(self): + op = opcodes.OpClusterSetParams(master_netmask=0xFFFF0000) + self.ExecOpCode(op) + self.assertEqual(0xFFFF0000, self.cluster.master_netmask) + + def testInvalidDiskparams(self): + for diskparams in [{constants.DT_DISKLESS: {constants.LV_STRIPES: 0}}, + {constants.DT_DRBD8: {constants.RBD_POOL: "pool"}}]: + self.ResetMocks() + op = opcodes.OpClusterSetParams(diskparams=diskparams) + self.ExecOpCodeExpectOpPrereqError(op, "verify diskparams") + + def testValidDiskparams(self): + diskparams = {constants.DT_RBD: {constants.RBD_POOL: "mock_pool"}} + op = opcodes.OpClusterSetParams(diskparams=diskparams) + self.ExecOpCode(op) + self.assertEqual(diskparams[constants.DT_RBD], + self.cluster.diskparams[constants.DT_RBD]) + + def testMinimalDiskparams(self): + diskparams = {constants.DT_RBD: {constants.RBD_POOL: "mock_pool"}} + self.cluster.diskparams = {} + op = opcodes.OpClusterSetParams(diskparams=diskparams) + self.ExecOpCode(op) + self.assertEqual(diskparams, self.cluster.diskparams) + + def testUnsetDrbdHelperWithDrbdDisks(self): + self.cfg.AddNewInstance(disks=[ + self.cfg.CreateDisk(dev_type=constants.LD_DRBD8, create_nodes=True)]) + op = opcodes.OpClusterSetParams(drbd_helper="") + self.ExecOpCodeExpectOpPrereqError(op, "Cannot disable drbd helper") + + def testFileStorageDir(self): + op = opcodes.OpClusterSetParams(file_storage_dir="/random/path") + self.ExecOpCode(op) + + def testSetFileStorageDirToCurrentValue(self): + op = opcodes.OpClusterSetParams( + file_storage_dir=self.cluster.file_storage_dir) + self.ExecOpCode(op) + + self.mcpu.assertLogContainsRegex("file storage dir already set to value") + + def testValidDrbdHelper(self): + node1 = self.cfg.AddNewNode() + node1.offline = True + self.rpc.call_drbd_helper.return_value = \ + self.RpcResultsBuilder() \ + .AddSuccessfulNode(self.master, "/bin/true") \ + .AddOfflineNode(node1) \ + .Build() + op = opcodes.OpClusterSetParams(drbd_helper="/bin/true") + self.ExecOpCode(op) + self.mcpu.assertLogContainsRegex("Not checking drbd helper on offline node") + + def testDrbdHelperFailingNode(self): + self.rpc.call_drbd_helper.return_value = \ + self.RpcResultsBuilder() \ + .AddFailedNode(self.master) \ + .Build() + op = opcodes.OpClusterSetParams(drbd_helper="/bin/true") + self.ExecOpCodeExpectOpPrereqError(op, "Error checking drbd helper") + + def testInvalidDrbdHelper(self): + self.rpc.call_drbd_helper.return_value = \ + self.RpcResultsBuilder() \ + .AddSuccessfulNode(self.master, "/bin/false") \ + .Build() + op = opcodes.OpClusterSetParams(drbd_helper="/bin/true") + self.ExecOpCodeExpectOpPrereqError(op, "drbd helper is /bin/false") + + def testDrbdHelperWithoutDrbdDiskTemplate(self): + drbd_helper = "/bin/random_helper" + self.cluster.enabled_disk_templates = [constants.DT_DISKLESS] + self.rpc.call_drbd_helper.return_value = \ + self.RpcResultsBuilder() \ + .AddSuccessfulNode(self.master, drbd_helper) \ + .Build() + op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper) + self.ExecOpCode(op) + + self.mcpu.assertLogContainsRegex("but did not enable") + + def testResetDrbdHelper(self): + drbd_helper = "" + self.cluster.enabled_disk_templates = [constants.DT_DISKLESS] + op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper) + self.ExecOpCode(op) + + self.assertEqual(None, self.cluster.drbd_usermode_helper) + + def testBeparams(self): + beparams = {constants.BE_VCPUS: 32} + op = opcodes.OpClusterSetParams(beparams=beparams) + self.ExecOpCode(op) + self.assertEqual(32, self.cluster + .beparams[constants.PP_DEFAULT][constants.BE_VCPUS]) + + def testNdparams(self): + ndparams = {constants.ND_EXCLUSIVE_STORAGE: True} + op = opcodes.OpClusterSetParams(ndparams=ndparams) + self.ExecOpCode(op) + self.assertEqual(True, self.cluster + .ndparams[constants.ND_EXCLUSIVE_STORAGE]) + + def testNdparamsResetOobProgram(self): + ndparams = {constants.ND_OOB_PROGRAM: ""} + op = opcodes.OpClusterSetParams(ndparams=ndparams) + self.ExecOpCode(op) + self.assertEqual(constants.NDC_DEFAULTS[constants.ND_OOB_PROGRAM], + self.cluster.ndparams[constants.ND_OOB_PROGRAM]) + + def testHvState(self): + hv_state = {constants.HT_FAKE: {constants.HVST_CPU_TOTAL: 8}} + op = opcodes.OpClusterSetParams(hv_state=hv_state) + self.ExecOpCode(op) + self.assertEqual(8, self.cluster.hv_state_static + [constants.HT_FAKE][constants.HVST_CPU_TOTAL]) + + def testDiskState(self): + disk_state = { + constants.LD_LV: { + "mock_vg": {constants.DS_DISK_TOTAL: 10} + } + } + op = opcodes.OpClusterSetParams(disk_state=disk_state) + self.ExecOpCode(op) + self.assertEqual(10, self.cluster + .disk_state_static[constants.LD_LV]["mock_vg"] + [constants.DS_DISK_TOTAL]) + + def testDefaultIPolicy(self): + ipolicy = constants.IPOLICY_DEFAULTS + op = opcodes.OpClusterSetParams(ipolicy=ipolicy) + self.ExecOpCode(op) + + def testIPolicyNewViolation(self): + import ganeti.constants as C + ipolicy = C.IPOLICY_DEFAULTS + ipolicy[C.ISPECS_MINMAX][0][C.ISPECS_MIN][C.ISPEC_MEM_SIZE] = 128 + ipolicy[C.ISPECS_MINMAX][0][C.ISPECS_MAX][C.ISPEC_MEM_SIZE] = 128 + + self.cfg.AddNewInstance(beparams={C.BE_MINMEM: 512, C.BE_MAXMEM: 512}) + op = opcodes.OpClusterSetParams(ipolicy=ipolicy) + self.ExecOpCode(op) + + self.mcpu.assertLogContainsRegex("instances violate them") + + def testNicparamsNoInstance(self): + nicparams = { + constants.NIC_LINK: "mock_bridge" + } + op = opcodes.OpClusterSetParams(nicparams=nicparams) + self.ExecOpCode(op) + + self.assertEqual("mock_bridge", + self.cluster.nicparams + [constants.PP_DEFAULT][constants.NIC_LINK]) + + def testNicparamsInvalidConf(self): + nicparams = { + constants.NIC_MODE: constants.NIC_MODE_BRIDGED + } + op = opcodes.OpClusterSetParams(nicparams=nicparams) + self.ExecOpCodeExpectException(op, errors.ConfigurationError, "NIC link") + + def testNicparamsInvalidInstanceConf(self): + nicparams = { + constants.NIC_MODE: constants.NIC_MODE_BRIDGED, + constants.NIC_LINK: "mock_bridge" + } + self.cfg.AddNewInstance(nics=[ + self.cfg.CreateNic(nicparams={constants.NIC_LINK: None})]) + op = opcodes.OpClusterSetParams(nicparams=nicparams) + self.ExecOpCodeExpectOpPrereqError(op, "Missing bridged NIC link") + + def testNicparamsMissingIp(self): + nicparams = { + constants.NIC_MODE: constants.NIC_MODE_ROUTED + } + self.cfg.AddNewInstance() + op = opcodes.OpClusterSetParams(nicparams=nicparams) + self.ExecOpCodeExpectOpPrereqError(op, "routed NIC with no ip address") + + def testNicparamsWithInstance(self): + nicparams = { + constants.NIC_LINK: "mock_bridge" + } + self.cfg.AddNewInstance() + op = opcodes.OpClusterSetParams(nicparams=nicparams) + self.ExecOpCode(op) + + def testDefaultHvparams(self): + hvparams = constants.HVC_DEFAULTS + op = opcodes.OpClusterSetParams(hvparams=hvparams) + self.ExecOpCode(op) + + self.assertEqual(hvparams, self.cluster.hvparams) + + def testMinimalHvparams(self): + hvparams = { + constants.HT_FAKE: { + constants.HV_MIGRATION_MODE: constants.HT_MIGRATION_NONLIVE + } + } + self.cluster.hvparams = {} + op = opcodes.OpClusterSetParams(hvparams=hvparams) + self.ExecOpCode(op) + + self.assertEqual(hvparams, self.cluster.hvparams) + + def testOsHvp(self): + os_hvp = { + "mocked_os": { + constants.HT_FAKE: { + constants.HV_MIGRATION_MODE: constants.HT_MIGRATION_NONLIVE + } + }, + "other_os": constants.HVC_DEFAULTS + } + op = opcodes.OpClusterSetParams(os_hvp=os_hvp) + self.ExecOpCode(op) + + self.assertEqual(constants.HT_MIGRATION_NONLIVE, + self.cluster.os_hvp["mocked_os"][constants.HT_FAKE] + [constants.HV_MIGRATION_MODE]) + self.assertEqual(constants.HVC_DEFAULTS, self.cluster.os_hvp["other_os"]) + + def testRemoveOsHvp(self): + os_hvp = {"mocked_os": {constants.HT_FAKE: None}} + op = opcodes.OpClusterSetParams(os_hvp=os_hvp) + self.ExecOpCode(op) + + assert constants.HT_FAKE not in self.cluster.os_hvp["mocked_os"] + + def testDefaultOsHvp(self): + os_hvp = {"mocked_os": constants.HVC_DEFAULTS.copy()} + self.cluster.os_hvp = {"mocked_os": {}} + op = opcodes.OpClusterSetParams(os_hvp=os_hvp) + self.ExecOpCode(op) + + self.assertEqual(os_hvp, self.cluster.os_hvp) + + def testOsparams(self): + osparams = { + "mocked_os": { + "param1": "value1", + "param2": None + }, + "other_os": { + "param1": None + } + } + self.cluster.osparams = {"other_os": {"param1": "value1"}} + op = opcodes.OpClusterSetParams(osparams=osparams) + self.ExecOpCode(op) + + self.assertEqual({"mocked_os": {"param1": "value1"}}, self.cluster.osparams) + + def testEnabledHypervisors(self): + enabled_hypervisors = [constants.HT_XEN_HVM, constants.HT_XEN_PVM] + op = opcodes.OpClusterSetParams(enabled_hypervisors=enabled_hypervisors) + self.ExecOpCode(op) + + self.assertEqual(enabled_hypervisors, self.cluster.enabled_hypervisors) + + def testEnabledHypervisorsWithoutHypervisorParams(self): + enabled_hypervisors = [constants.HT_FAKE] + self.cluster.hvparams = {} + op = opcodes.OpClusterSetParams(enabled_hypervisors=enabled_hypervisors) + self.ExecOpCode(op) + + self.assertEqual(enabled_hypervisors, self.cluster.enabled_hypervisors) + self.assertEqual(constants.HVC_DEFAULTS[constants.HT_FAKE], + self.cluster.hvparams[constants.HT_FAKE]) + + @testutils.patch_object(utils, "FindFile") + def testValidDefaultIallocator(self, find_file_mock): + find_file_mock.return_value = "/random/path" + default_iallocator = "/random/path" + op = opcodes.OpClusterSetParams(default_iallocator=default_iallocator) + self.ExecOpCode(op) + + self.assertEqual(default_iallocator, self.cluster.default_iallocator) + + @testutils.patch_object(utils, "FindFile") + def testInvalidDefaultIallocator(self, find_file_mock): + find_file_mock.return_value = None + default_iallocator = "/random/path" + op = opcodes.OpClusterSetParams(default_iallocator=default_iallocator) + self.ExecOpCodeExpectOpPrereqError(op, "Invalid default iallocator script") + + def testEnabledDiskTemplates(self): + enabled_disk_templates = [constants.DT_DISKLESS, constants.DT_PLAIN] + op = opcodes.OpClusterSetParams( + enabled_disk_templates=enabled_disk_templates) + self.ExecOpCode(op) + + self.assertEqual(enabled_disk_templates, + self.cluster.enabled_disk_templates) + + def testEnabledDiskTemplatesWithoutVgName(self): + enabled_disk_templates = [constants.DT_PLAIN] + self.cluster.volume_group_name = None + op = opcodes.OpClusterSetParams( + enabled_disk_templates=enabled_disk_templates) + self.ExecOpCodeExpectOpPrereqError(op, "specify a volume group") + + def testDisableDiskTemplateWithExistingInstance(self): + enabled_disk_templates = [constants.DT_DISKLESS] + self.cfg.AddNewInstance( + disks=[self.cfg.CreateDisk(dev_type=constants.LD_LV)]) + op = opcodes.OpClusterSetParams( + enabled_disk_templates=enabled_disk_templates) + self.ExecOpCodeExpectOpPrereqError(op, "Cannot disable disk template") + + def testVgNameNoLvmDiskTemplateEnabled(self): + vg_name = "test_vg" + self.cluster.enabled_disk_templates = [constants.DT_DISKLESS] + op = opcodes.OpClusterSetParams(vg_name=vg_name) + self.ExecOpCode(op) + + self.assertEqual(vg_name, self.cluster.volume_group_name) + self.mcpu.assertLogContainsRegex("enable any lvm disk template") + + def testUnsetVgNameWithLvmDiskTemplateEnabled(self): + vg_name = "" + self.cluster.enabled_disk_templates = [constants.DT_PLAIN] + op = opcodes.OpClusterSetParams(vg_name=vg_name) + self.ExecOpCodeExpectOpPrereqError(op, "Cannot unset volume group") + + def testUnsetVgNameWithLvmInstance(self): + vg_name = "" + self.cfg.AddNewInstance( + disks=[self.cfg.CreateDisk(dev_type=constants.LD_LV)]) + op = opcodes.OpClusterSetParams(vg_name=vg_name) + self.ExecOpCodeExpectOpPrereqError(op, "Cannot disable lvm storage") + + def testUnsetVgNameWithNoLvmDiskTemplateEnabled(self): + vg_name = "" + self.cluster.enabled_disk_templates = [constants.DT_DISKLESS] + op = opcodes.OpClusterSetParams(vg_name=vg_name) + self.ExecOpCode(op) + + self.assertEqual(None, self.cluster.volume_group_name) + + def testVgNameToOldName(self): + vg_name = self.cluster.volume_group_name + op = opcodes.OpClusterSetParams(vg_name=vg_name) + self.ExecOpCode(op) + + self.mcpu.assertLogContainsRegex("already in desired state") + + def testVgNameWithFailingNode(self): + vg_name = "test_vg" + op = opcodes.OpClusterSetParams(vg_name=vg_name) + self.rpc.call_vg_list.return_value = \ + self.RpcResultsBuilder() \ + .AddFailedNode(self.master) \ + .Build() + self.ExecOpCode(op) + + self.mcpu.assertLogContainsRegex("Error while gathering data on node") + + def testVgNameWithValidNode(self): + vg_name = "test_vg" + op = opcodes.OpClusterSetParams(vg_name=vg_name) + self.rpc.call_vg_list.return_value = \ + self.RpcResultsBuilder() \ + .AddSuccessfulNode(self.master, {vg_name: 1024 * 1024}) \ + .Build() + self.ExecOpCode(op) + + def testVgNameWithTooSmallNode(self): + vg_name = "test_vg" + op = opcodes.OpClusterSetParams(vg_name=vg_name) + self.rpc.call_vg_list.return_value = \ + self.RpcResultsBuilder() \ + .AddSuccessfulNode(self.master, {vg_name: 1}) \ + .Build() + self.ExecOpCodeExpectOpPrereqError(op, "too small") + + def testMiscParameters(self): + op = opcodes.OpClusterSetParams(candidate_pool_size=123, + maintain_node_health=True, + modify_etc_hosts=True, + prealloc_wipe_disks=True, + reserved_lvs=["/dev/mock_lv"], + use_external_mip_script=True) + self.ExecOpCode(op) + + self.mcpu.assertLogIsEmpty() + self.assertEqual(123, self.cluster.candidate_pool_size) + self.assertEqual(True, self.cluster.maintain_node_health) + self.assertEqual(True, self.cluster.modify_etc_hosts) + self.assertEqual(True, self.cluster.prealloc_wipe_disks) + self.assertEqual(["/dev/mock_lv"], self.cluster.reserved_lvs) + self.assertEqual(True, self.cluster.use_external_mip_script) + + def testAddHiddenOs(self): + self.cluster.hidden_os = ["hidden1", "hidden2"] + op = opcodes.OpClusterSetParams(hidden_os=[(constants.DDM_ADD, "hidden2"), + (constants.DDM_ADD, "hidden3")]) + self.ExecOpCode(op) + + self.assertEqual(["hidden1", "hidden2", "hidden3"], self.cluster.hidden_os) + self.mcpu.assertLogContainsRegex("OS hidden2 already") + + def testRemoveBlacklistedOs(self): + self.cluster.blacklisted_os = ["blisted1", "blisted2"] + op = opcodes.OpClusterSetParams(blacklisted_os=[ + (constants.DDM_REMOVE, "blisted2"), + (constants.DDM_REMOVE, "blisted3")]) + self.ExecOpCode(op) + + self.assertEqual(["blisted1"], self.cluster.blacklisted_os) + self.mcpu.assertLogContainsRegex("OS blisted3 not found") + + def testMasterNetdev(self): + master_netdev = "test_dev" + op = opcodes.OpClusterSetParams(master_netdev=master_netdev) + self.ExecOpCode(op) + + self.assertEqual(master_netdev, self.cluster.master_netdev) + + def testMasterNetdevFailNoForce(self): + master_netdev = "test_dev" + op = opcodes.OpClusterSetParams(master_netdev=master_netdev) + self.rpc.call_node_deactivate_master_ip.return_value = \ + self.RpcResultsBuilder() \ + .CreateFailedNodeResult(self.master) + self.ExecOpCodeExpectOpExecError(op, "Could not disable the master ip") + + def testMasterNetdevFailForce(self): + master_netdev = "test_dev" + op = opcodes.OpClusterSetParams(master_netdev=master_netdev, + force=True) + self.rpc.call_node_deactivate_master_ip.return_value = \ + self.RpcResultsBuilder() \ + .CreateFailedNodeResult(self.master) + self.ExecOpCode(op) + + self.mcpu.assertLogContainsRegex("Could not disable the master ip") + + if __name__ == "__main__": testutils.GanetiTestProgram() diff --git a/test/py/cmdlib/test_unittest.py b/test/py/cmdlib/test_unittest.py index b2e3fb0..95021b3 100644 --- a/test/py/cmdlib/test_unittest.py +++ b/test/py/cmdlib/test_unittest.py @@ -70,7 +70,7 @@ class TestLUTestDelay(CmdlibTestCase): on_nodes=[self.master.name]) self.rpc.call_test_delay.return_value = \ - RpcResultsBuilder(cfg=self.cfg) \ + self.RpcResultsBuilder() \ .AddSuccessfulNode(self.master) \ .Build() @@ -83,7 +83,7 @@ class TestLUTestDelay(CmdlibTestCase): on_nodes=[self.master.name]) self.rpc.call_test_delay.return_value = \ - RpcResultsBuilder(cfg=self.cfg) \ + self.RpcResultsBuilder() \ .AddFailedNode(self.master) \ .Build() @@ -96,7 +96,7 @@ class TestLUTestDelay(CmdlibTestCase): on_nodes=[node1.name, node2.name]) self.rpc.call_test_delay.return_value = \ - RpcResultsBuilder(cfg=self.cfg) \ + self.RpcResultsBuilder() \ .AddSuccessfulNode(node1) \ .AddSuccessfulNode(node2) \ .Build() diff --git a/test/py/cmdlib/testsupport/cmdlib_testcase.py b/test/py/cmdlib/testsupport/cmdlib_testcase.py index 0b62059..9f180c0 100644 --- a/test/py/cmdlib/testsupport/cmdlib_testcase.py +++ b/test/py/cmdlib/testsupport/cmdlib_testcase.py @@ -32,7 +32,8 @@ from cmdlib.testsupport.lock_manager_mock import LockManagerMock from cmdlib.testsupport.netutils_mock import patchNetutils, \ SetupDefaultNetutilsMock from cmdlib.testsupport.processor_mock import ProcessorMock -from cmdlib.testsupport.rpc_runner_mock import CreateRpcRunnerMock +from cmdlib.testsupport.rpc_runner_mock import CreateRpcRunnerMock, \ + RpcResultsBuilder from cmdlib.testsupport.ssh_mock import patchSsh from ganeti import errors @@ -151,6 +152,17 @@ class CmdlibTestCase(testutils.GanetiTestCase): # this test module does not use ssh, no patching performed self._ssh_patcher = None + def RpcResultsBuilder(self, use_node_names=False): + """Creates a pre-configured L{RpcResultBuilder} + + @type use_node_names: bool + @param use_node_names: @see L{RpcResultBuilder} + @rtype: L{RpcResultBuilder} + @return: a pre-configured builder for RPC results + + """ + return RpcResultsBuilder(cfg=self.cfg, use_node_names=use_node_names) + def ExecOpCode(self, opcode): """Executes the given opcode. diff --git a/test/py/cmdlib/testsupport/config_mock.py b/test/py/cmdlib/testsupport/config_mock.py index 7561cea..5e9ecd8 100644 --- a/test/py/cmdlib/testsupport/config_mock.py +++ b/test/py/cmdlib/testsupport/config_mock.py @@ -47,6 +47,7 @@ class ConfigMock(config.ConfigWriter): self._cur_node_id = 1 self._cur_inst_id = 1 self._cur_disk_id = 1 + self._cur_nic_id = 1 super(ConfigMock, self).__init__(cfg_file="/dev/null", _getents=_StubGetEntResolver()) @@ -179,7 +180,7 @@ class ConfigMock(config.ConfigWriter): admin_state=constants.ADMINST_DOWN, nics=None, disks=None, - disk_template=constants.DT_DISKLESS, + disk_template=None, disks_active=False, network_port=None): """Add a new L{objects.Instance} to the cluster configuration @@ -207,9 +208,23 @@ class ConfigMock(config.ConfigWriter): if osparams is None: osparams = {} if nics is None: - nics = [] + nics = [self.CreateNic()] if disks is None: - disks = [] + disks = [self.CreateDisk()] + if disk_template is None: + if len(disks) == 0: + disk_template = constants.DT_DISKLESS + else: + dt_guess_dict = { + constants.LD_LV: constants.DT_PLAIN, + constants.LD_FILE: constants.DT_FILE, + constants.LD_DRBD8: constants.DT_DRBD8, + constants.LD_RBD: constants.DT_RBD, + constants.LD_BLOCKDEV: constants.DT_BLOCK, + constants.LD_EXT: constants.DT_EXT + } + assert constants.LOGICAL_DISK_TYPES == set(dt_guess_dict.keys()) + disk_template = dt_guess_dict[disks[0].dev_type] inst = objects.Instance(uuid=uuid, name=name, @@ -241,7 +256,8 @@ class ConfigMock(config.ConfigWriter): params=None, spindles=None, primary_node=None, - secondary_node=None): + secondary_node=None, + create_nodes=False): """Create a new L{objecs.Disk} object @rtype: L{objects.Disk} @@ -263,6 +279,11 @@ class ConfigMock(config.ConfigWriter): pnode_uuid = logical_id[0] snode_uuid = logical_id[1] + if pnode_uuid is None and create_nodes: + pnode_uuid = self.AddNewNode().uuid + if snode_uuid is None and create_nodes: + snode_uuid = self.AddNewNode().uuid + if pnode_uuid is None or snode_uuid is None: raise AssertionError("Trying to create DRBD disk without nodes!") @@ -300,6 +321,40 @@ class ConfigMock(config.ConfigWriter): params=params, spindles=spindles) + def CreateNic(self, + uuid=None, + name=None, + mac=None, + ip=None, + network=None, + nicparams=None, + netinfo=None): + """Create a new L{objecs.NIC} object + + @rtype: L{objects.NIC} + @return: the newly create NIC object + + """ + nic_id = self._cur_nic_id + self._cur_nic_id += 1 + + if uuid is None: + uuid = self._GetUuid() + if name is None: + name = "mock_nic_%d" % nic_id + if mac is None: + mac = "aa:00:00:aa:%02x:%02x" % (nic_id / 0xff, nic_id % 0xff) + if nicparams is None: + nicparams = {} + + return objects.NIC(uuid=uuid, + name=name, + mac=mac, + ip=ip, + network=network, + nicparams=nicparams, + netinfo=netinfo) + def _OpenConfig(self, accept_foreign): self._config_data = objects.ConfigData( version=constants.CONFIG_VERSION, @@ -329,9 +384,9 @@ class ConfigMock(config.ConfigWriter): file_storage_dir="/tmp", shared_file_storage_dir=None, enabled_hypervisors=list(constants.HYPER_TYPES), - hvparams=constants.HVC_DEFAULTS, + hvparams=constants.HVC_DEFAULTS.copy(), ipolicy=None, - os_hvp={"mocked_os": constants.HVC_DEFAULTS}, + os_hvp={"mocked_os": constants.HVC_DEFAULTS.copy()}, beparams=None, osparams=None, nicparams=None, @@ -347,7 +402,7 @@ class ConfigMock(config.ConfigWriter): blacklisted_os=None, primary_ip_family=None, prealloc_wipe_disks=None, - enabled_disk_templates=list(constants.DISK_TEMPLATES), + enabled_disk_templates=constants.DISK_TEMPLATES.copy(), ) self._cluster.ctime = self._cluster.mtime = time.time() self._cluster.UpgradeConfig() diff --git a/test/py/cmdlib/testsupport/rpc_runner_mock.py b/test/py/cmdlib/testsupport/rpc_runner_mock.py index 23998c5..93845fb 100644 --- a/test/py/cmdlib/testsupport/rpc_runner_mock.py +++ b/test/py/cmdlib/testsupport/rpc_runner_mock.py @@ -121,7 +121,7 @@ class RpcResultsBuilder(object): @param node: @see L{RpcResultsBuilder}. @rtype: L{rpc.RpcResult} """ - return rpc.RpcResult(failed=True, node=self._GetNodeId(node)) + return rpc.RpcResult(failed=True, offline=True, node=self._GetNodeId(node)) def CreateErrorNodeResult(self, node, error_msg=None): """@see L{RpcResultsBuilder} @@ -134,22 +134,44 @@ class RpcResultsBuilder(object): return rpc.RpcResult(data=(False, error_msg), node=self._GetNodeId(node)) def AddSuccessfulNode(self, node, data=None): - """@see L{CreateSuccessfulNode}""" + """@see L{CreateSuccessfulNode} + + @rtype: L{RpcResultsBuilder} + @return: self for chaining + + """ self._results.append(self.CreateSuccessfulNodeResult(node, data)) return self def AddFailedNode(self, node): - """@see L{CreateFailedNode}""" + """@see L{CreateFailedNode} + + @rtype: L{RpcResultsBuilder} + @return: self for chaining + + """ self._results.append(self.CreateFailedNodeResult(node)) return self def AddOfflineNode(self, node): - """@see L{CreateOfflineNode}""" + """@see L{CreateOfflineNode} + + @rtype: L{RpcResultsBuilder} + @return: self for chaining + + """ self._results.append(self.CreateOfflineNodeResult(node)) + return self def AddErrorNode(self, node, error_msg=None): - """@see L{CreateErrorNode}""" + """@see L{CreateErrorNode} + + @rtype: L{RpcResultsBuilder} + @return: self for chaining + + """ self._results.append(self.CreateErrorNodeResult(node, error_msg=error_msg)) + return self def Build(self): """Creates a dictionary holding multi-node results -- 1.7.10.4