diff --git a/doc/iallocator.rst b/doc/iallocator.rst index 582f00a2b69591c106d2101f5cabf887cb765ae1..6ecd62696d617e704a8cc44bc7a90ae52c6dc664 100644 --- a/doc/iallocator.rst +++ b/doc/iallocator.rst @@ -205,19 +205,19 @@ in the ``request`` dictionary: name the name of the instance; if the request is a realocation, then this name will be found in the list of instances (see below), otherwise - is the FQDN of the new instance + is the FQDN of the new instance; type *string* required_nodes how many nodes should the algorithm return; while this information can be deduced from the instace's disk template, it's better if this computation is left to Ganeti as then allocator scripts are - less sensitive to changes to the disk templates + less sensitive to changes to the disk templates; type *integer* disk_space_total the total disk space that will be used by this instance on the (new) nodes; again, this information can be computed from the list of instance disks and its template type, but Ganeti is better - suited to compute it + suited to compute it; type *integer* .. pyassert:: @@ -274,13 +274,13 @@ Relocation: relocate_from a list of nodes to move the instance away from (note that with Ganeti 2.0, this list will always contain a single node, the - current secondary of the instance) + current secondary of the instance); type *list of strings* As for ``multi-relocate``, it needs the three following request arguments: instances - a list of instance names to relocate + a list of instance names to relocate; type *list of strings* reloc_mode a string indicating the relocation mode; there are three possible @@ -292,13 +292,13 @@ arguments: this argument is only accepted when ``reloc_mode``, as explained above, is *change_group*; if present, it must either be the empty list, or contain a list of group UUIDs that should be considered for - relocating instances to + relocating instances to; type *list of strings* Finally, in the case of multi-evacuate, there's one single request argument (in addition to ``type``): evac_nodes - the names of the nodes to be evacuated + the names of the nodes to be evacuated; type *list of strings* Response message ~~~~~~~~~~~~~~~~ diff --git a/lib/cmdlib.py b/lib/cmdlib.py index dab6f26bc467ee3348c948180ce176a192cfe4a9..16dde30a9f80fc2ce30027c7f5adbdae7295e06f 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -12020,11 +12020,13 @@ class IAllocator(object): self.success = self.info = self.result = None try: - (fn, keyset, self._result_check) = self._MODE_DATA[self.mode] + (fn, keydata, self._result_check) = self._MODE_DATA[self.mode] except KeyError: raise errors.ProgrammerError("Unknown mode '%s' passed to the" " IAllocator" % self.mode) + keyset = [n for (n, _) in keydata] + for key in kwargs: if key not in keyset: raise errors.ProgrammerError("Invalid input parameter '%s' to" @@ -12035,7 +12037,7 @@ class IAllocator(object): if key not in kwargs: raise errors.ProgrammerError("Missing input parameter '%s' to" " IAllocator" % key) - self._BuildInputData(compat.partial(fn, self)) + self._BuildInputData(compat.partial(fn, self), keydata) def _ComputeClusterData(self): """Compute the generic allocator input data. @@ -12310,7 +12312,7 @@ class IAllocator(object): "target_groups": self.target_groups, } - def _BuildInputData(self, fn): + def _BuildInputData(self, fn, keydata): """Build input data structures. """ @@ -12318,23 +12320,47 @@ class IAllocator(object): request = fn() request["type"] = self.mode + for keyname, keytype in keydata: + if keyname not in request: + raise errors.ProgrammerError("Request parameter %s is missing" % + keyname) + val = request[keyname] + if not keytype(val): + raise errors.ProgrammerError("Request parameter %s doesn't pass" + " validation, value %s, expected" + " type %s" % (keyname, val, keytype)) self.in_data["request"] = request self.in_text = serializer.Dump(self.in_data) + _STRING_LIST = ht.TListOf(ht.TString) _MODE_DATA = { constants.IALLOCATOR_MODE_ALLOC: (_AddNewInstance, - ["name", "memory", "disks", "disk_template", "os", "tags", "nics", - "vcpus", "hypervisor"], ht.TList), + [ + ("name", ht.TString), + ("memory", ht.TInt), + ("disks", ht.TListOf(ht.TDict)), + ("disk_template", ht.TString), + ("os", ht.TString), + ("tags", _STRING_LIST), + ("nics", ht.TListOf(ht.TDict)), + ("vcpus", ht.TInt), + ("hypervisor", ht.TString), + ], ht.TList), constants.IALLOCATOR_MODE_RELOC: - (_AddRelocateInstance, ["name", "relocate_from"], ht.TList), + (_AddRelocateInstance, + [("name", ht.TString), ("relocate_from", _STRING_LIST)], + ht.TList), constants.IALLOCATOR_MODE_MEVAC: - (_AddEvacuateNodes, ["evac_nodes"], - ht.TListOf(ht.TAnd(ht.TIsLength(2), - ht.TListOf(ht.TString)))), + (_AddEvacuateNodes, [("evac_nodes", _STRING_LIST)], + ht.TListOf(ht.TAnd(ht.TIsLength(2), _STRING_LIST))), constants.IALLOCATOR_MODE_MRELOC: - (_AddMultiRelocate, ["instances", "reloc_mode", "target_groups"], + (_AddMultiRelocate, [ + ("instances", _STRING_LIST), + ("reloc_mode", ht.TElemOf(constants.IALLOCATOR_MRELOC_MODES)), + ("target_groups", _STRING_LIST), + ], ht.TListOf(ht.TListOf(ht.TStrictDict(True, False, { # pylint: disable-msg=E1101 # Class '...' has no 'OP_ID' member