diff --git a/lib/cmdlib.py b/lib/cmdlib.py index ae08146fd9375d1715e13b143a07304ceed0e220..c1eff022380d7992c7bbd22efe49085bb83621bc 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -1610,8 +1610,9 @@ def _CheckIAllocatorOrNode(lu, iallocator_slot, node_slot): cluster-wide iallocator if appropriate. Check that at most one of (iallocator, node) is specified. If none is - specified, then the LU's opcode's iallocator slot is filled with the - cluster-wide default iallocator. + specified, or the iallocator is L{constants.DEFAULT_IALLOCATOR_SHORTCUT}, + then the LU's opcode's iallocator slot is filled with the cluster-wide + default iallocator. @type iallocator_slot: string @param iallocator_slot: the name of the opcode iallocator slot @@ -1621,11 +1622,14 @@ def _CheckIAllocatorOrNode(lu, iallocator_slot, node_slot): """ node = getattr(lu.op, node_slot, None) ialloc = getattr(lu.op, iallocator_slot, None) + if node == []: + node = None if node is not None and ialloc is not None: raise errors.OpPrereqError("Do not specify both, iallocator and node", errors.ECODE_INVAL) - elif node is None and ialloc is None: + elif ((node is None and ialloc is None) or + ialloc == constants.DEFAULT_IALLOCATOR_SHORTCUT): default_iallocator = lu.cfg.GetDefaultIAllocator() if default_iallocator: setattr(lu.op, iallocator_slot, default_iallocator) @@ -7137,9 +7141,10 @@ class LUInstanceRecreateDisks(LogicalUnit): " once: %s" % utils.CommaJoin(duplicates), errors.ECODE_INVAL) - if self.op.iallocator and self.op.nodes: - raise errors.OpPrereqError("Give either the iallocator or the new" - " nodes, not both", errors.ECODE_INVAL) + # We don't want _CheckIAllocatorOrNode selecting the default iallocator + # when neither iallocator nor nodes are specified + if self.op.iallocator or self.op.nodes: + _CheckIAllocatorOrNode(self, "iallocator", "nodes") for (idx, params) in self.op.disks: utils.ForceDictType(params, constants.IDISK_PARAMS_TYPES) diff --git a/lib/constants.py b/lib/constants.py index 1d9787c97c4a585aa74fa54fcad967678d6bd8fe..f3e1870f48ea98cbb97d339a5ca656e17ae1e66f 100644 --- a/lib/constants.py +++ b/lib/constants.py @@ -1455,6 +1455,7 @@ VALID_IALLOCATOR_MODES = frozenset([ IALLOCATOR_MODE_MULTI_ALLOC, ]) IALLOCATOR_SEARCH_PATH = _autoconf.IALLOCATOR_SEARCH_PATH +DEFAULT_IALLOCATOR_SHORTCUT = "." IALLOCATOR_NEVAC_PRI = "primary-only" IALLOCATOR_NEVAC_SEC = "secondary-only" diff --git a/test/ganeti.cmdlib_unittest.py b/test/ganeti.cmdlib_unittest.py index ab5ef6f7cd67b686d0bf67406f891fdce3271b21..f876e53c002e7091b469bb092e692bedfa8865d6 100755 --- a/test/ganeti.cmdlib_unittest.py +++ b/test/ganeti.cmdlib_unittest.py @@ -108,23 +108,26 @@ class TestIAllocatorChecks(testutils.GanetiTestCase): c_i = lambda: cmdlib._CheckIAllocatorOrNode(lu, "iallocator", "node") # Neither node nor iallocator given - op.iallocator = None - op.node = None - c_i() - self.assertEqual(lu.op.iallocator, default_iallocator) - self.assertEqual(lu.op.node, None) + for n in (None, []): + op.iallocator = None + op.node = n + c_i() + self.assertEqual(lu.op.iallocator, default_iallocator) + self.assertEqual(lu.op.node, n) # Both, iallocator and node given - op.iallocator = "test" - op.node = "test" - self.assertRaises(errors.OpPrereqError, c_i) + for a in ("test", constants.DEFAULT_IALLOCATOR_SHORTCUT): + op.iallocator = a + op.node = "test" + self.assertRaises(errors.OpPrereqError, c_i) # Only iallocator given - op.iallocator = other_iallocator - op.node = None - c_i() - self.assertEqual(lu.op.iallocator, other_iallocator) - self.assertEqual(lu.op.node, None) + for n in (None, []): + op.iallocator = other_iallocator + op.node = n + c_i() + self.assertEqual(lu.op.iallocator, other_iallocator) + self.assertEqual(lu.op.node, n) # Only node given op.iallocator = None @@ -133,6 +136,13 @@ class TestIAllocatorChecks(testutils.GanetiTestCase): self.assertEqual(lu.op.iallocator, None) self.assertEqual(lu.op.node, "node") + # Asked for default iallocator, no node given + op.iallocator = constants.DEFAULT_IALLOCATOR_SHORTCUT + op.node = None + c_i() + self.assertEqual(lu.op.iallocator, default_iallocator) + self.assertEqual(lu.op.node, None) + # No node, iallocator or default iallocator op.iallocator = None op.node = None