From 90e99856b5f0f833fe016ef9203f46329a11491e Mon Sep 17 00:00:00 2001 From: Adeodato Simo <dato@google.com> Date: Thu, 9 Dec 2010 15:16:23 +0000 Subject: [PATCH] Add the "alloc_policy" attribute to node groups This can be set at group creation time and via OpSetGroupParams. The default is "preferred", and existing node groups from previous Ganeti version will get the attribute set to this value. Signed-off-by: Adeodato Simo <dato@google.com> Reviewed-by: Guido Trotter <ultrotter@google.com> --- doc/hooks.rst | 10 ++++++++++ lib/cli.py | 5 +++++ lib/client/gnt_group.py | 15 +++++++++------ lib/cmdlib.py | 27 ++++++++++++++++++++++++--- lib/config.py | 4 ++++ lib/constants.py | 10 ++++++++++ lib/objects.py | 4 ++++ lib/opcodes.py | 2 ++ lib/rapi/client.py | 5 ++++- lib/rapi/rlib2.py | 19 +++++++++++++++++-- man/gnt-group.rst | 27 +++++++++++++++++++++++++-- qa/qa_rapi.py | 1 + 12 files changed, 115 insertions(+), 14 deletions(-) diff --git a/doc/hooks.rst b/doc/hooks.rst index 282ed938e..5d8bbc2c9 100644 --- a/doc/hooks.rst +++ b/doc/hooks.rst @@ -181,6 +181,16 @@ Adds a node group to the cluster. :pre-execution: master node :post-execution: master node +OP_GROUP_SET_PARAMS ++++++++++++++++++++ + +Changes a node group's parameters. + +:directory: group-modify +:env. vars: GROUP_NAME, NEW_ALLOC_POLICY +:pre-execution: master node +:post-execution: master node + OP_REMOVE_GROUP +++++++++++++++ diff --git a/lib/cli.py b/lib/cli.py index 069c6e902..e5e31a3da 100644 --- a/lib/cli.py +++ b/lib/cli.py @@ -48,6 +48,7 @@ __all__ = [ # Command line options "ADD_UIDS_OPT", "ALLOCATABLE_OPT", + "ALLOC_POLICY_OPT", "ALL_OPT", "AUTO_PROMOTE_OPT", "AUTO_REPLACE_OPT", @@ -1117,6 +1118,10 @@ NODE_PARAMS_OPT = cli_option("--node-parameters", dest="ndparams", type="keyval", default=None, help="Node parameters") +ALLOC_POLICY_OPT = cli_option("--alloc-policy", dest="alloc_policy", + action="store", metavar="POLICY", default=None, + help="Allocation policy for the node group") + #: Options provided by all commands COMMON_OPTS = [DEBUG_OPT] diff --git a/lib/client/gnt_group.py b/lib/client/gnt_group.py index b427647db..d3b477bec 100644 --- a/lib/client/gnt_group.py +++ b/lib/client/gnt_group.py @@ -31,12 +31,12 @@ from ganeti import utils #: default list of fields for L{ListGroups} -_LIST_DEF_FIELDS = ["name", "node_cnt", "pinst_cnt"] +_LIST_DEF_FIELDS = ["name", "node_cnt", "pinst_cnt", "alloc_policy"] #: headers (and full field list) for L{ListGroups} _LIST_HEADERS = { - "name": "Group", "uuid": "UUID", + "name": "Group", "uuid": "UUID", "alloc_policy": "AllocPolicy", "node_cnt": "Nodes", "node_list": "NodeList", "pinst_cnt": "Instances", "pinst_list": "InstanceList", "ctime": "CTime", "mtime": "MTime", "serial_no": "SerialNo", @@ -54,7 +54,8 @@ def AddGroup(opts, args): """ (group_name,) = args - op = opcodes.OpAddGroup(group_name=group_name, ndparams=opts.ndparams) + op = opcodes.OpAddGroup(group_name=group_name, ndparams=opts.ndparams, + alloc_policy=opts.alloc_policy) SubmitOpCode(op, opts=opts) @@ -118,13 +119,15 @@ def SetGroupParams(opts, args): """ all_changes = { "ndparams": opts.ndparams, + "alloc_policy": opts.alloc_policy, } if all_changes.values().count(None) == len(all_changes): ToStderr("Please give at least one of the parameters.") return 1 - op = opcodes.OpSetGroupParams(group_name=args[0], **all_changes) + op = opcodes.OpSetGroupParams(group_name=args[0], # pylint: disable-msg=W0142 + **all_changes) result = SubmitOrSend(op, opts) if result: @@ -167,7 +170,7 @@ def RenameGroup(opts, args): commands = { "add": ( - AddGroup, ARGS_ONE_GROUP, [DRY_RUN_OPT, NODE_PARAMS_OPT], + AddGroup, ARGS_ONE_GROUP, [DRY_RUN_OPT, ALLOC_POLICY_OPT, NODE_PARAMS_OPT], "<group_name>", "Add a new node group to the cluster"), "list": ( ListGroups, ARGS_MANY_GROUPS, @@ -178,7 +181,7 @@ commands = { (utils.CommaJoin(_LIST_HEADERS), utils.CommaJoin(_LIST_DEF_FIELDS))), "modify": ( SetGroupParams, ARGS_ONE_GROUP, - [DRY_RUN_OPT, SUBMIT_OPT, NODE_PARAMS_OPT], + [DRY_RUN_OPT, SUBMIT_OPT, ALLOC_POLICY_OPT, NODE_PARAMS_OPT], "<group_name>", "Alters the parameters of a node group"), "remove": ( RemoveGroup, ARGS_ONE_GROUP, [DRY_RUN_OPT], diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 112f81983..d5d09f35d 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -10179,6 +10179,8 @@ class LUAddGroup(LogicalUnit): _OP_PARAMS = [ _PGroupName, ("ndparams", None, ht.TOr(ht.TDict, ht.TNone)), + ("alloc_policy", None, ht.TOr(ht.TNone, + ht.TElemOf(constants.VALID_ALLOC_POLICIES))), ] REQ_BGL = False @@ -10227,6 +10229,7 @@ class LUAddGroup(LogicalUnit): """ group_obj = objects.NodeGroup(name=self.op.group_name, members=[], uuid=self.group_uuid, + alloc_policy=self.op.alloc_policy, ndparams=self.op.ndparams) self.cfg.AddNodeGroup(group_obj, self.proc.GetECId(), check_uuid=False) @@ -10247,7 +10250,8 @@ class LUQueryGroups(NoHooksLU): _FIELDS_DYNAMIC = utils.FieldSet() - _SIMPLE_FIELDS = ["name", "uuid", "ctime", "mtime", "serial_no"] + _SIMPLE_FIELDS = ["name", "uuid", "alloc_policy", + "ctime", "mtime", "serial_no"] _FIELDS_STATIC = utils.FieldSet( "node_cnt", "node_list", "pinst_cnt", "pinst_list", *_SIMPLE_FIELDS) @@ -10345,12 +10349,14 @@ class LUSetGroupParams(LogicalUnit): """Modifies the parameters of a node group. """ - HPATH = None - HTYPE = None + HPATH = "group-modify" + HTYPE = constants.HTYPE_GROUP _OP_PARAMS = [ _PGroupName, ("ndparams", None, ht.TOr(ht.TDict, ht.TNone)), + ("alloc_policy", None, ht.TOr(ht.TNone, + ht.TElemOf(constants.VALID_ALLOC_POLICIES))), ] REQ_BGL = False @@ -10358,6 +10364,7 @@ class LUSetGroupParams(LogicalUnit): def CheckArguments(self): all_changes = [ self.op.ndparams, + self.op.alloc_policy, ] if all_changes.count(None) == len(all_changes): @@ -10386,6 +10393,17 @@ class LUSetGroupParams(LogicalUnit): utils.ForceDictType(self.op.ndparams, constants.NDS_PARAMETER_TYPES) self.new_ndparams = self.group.SimpleFillND(self.op.ndparams) + def BuildHooksEnv(self): + """Build hooks env. + + """ + env = { + "GROUP_NAME": self.op.group_name, + "NEW_ALLOC_POLICY": self.op.alloc_policy, + } + mn = self.cfg.GetMasterNode() + return env, [mn], [mn] + def Exec(self, feedback_fn): """Modifies the node group. @@ -10396,6 +10414,9 @@ class LUSetGroupParams(LogicalUnit): self.group.ndparams = self.new_ndparams result.append(("ndparams", str(self.group.ndparams))) + if self.op.alloc_policy: + self.group.alloc_policy = self.op.alloc_policy + self.cfg.Update(self.group, feedback_fn) return result diff --git a/lib/config.py b/lib/config.py index 97a4f6498..6116b8da1 100644 --- a/lib/config.py +++ b/lib/config.py @@ -868,6 +868,9 @@ class ConfigWriter: def AddNodeGroup(self, group, ec_id, check_uuid=True): """Add a node group to the configuration. + This method calls group.UpgradeConfig() to fill any missing attributes + according to their default values. + @type group: L{objects.NodeGroup} @param group: the NodeGroup object to add @type ec_id: string @@ -895,6 +898,7 @@ class ConfigWriter: group.serial_no = 1 group.ctime = group.mtime = time.time() + group.UpgradeConfig() self._config_data.nodegroups[group.uuid] = group self._config_data.cluster.serial_no += 1 diff --git a/lib/constants.py b/lib/constants.py index 184419b29..5dd9838a1 100644 --- a/lib/constants.py +++ b/lib/constants.py @@ -1202,3 +1202,13 @@ PGREP = "pgrep" # Name of the node group that gets created at cluster init or upgrade INITIAL_NODE_GROUP_NAME = "default" + +# Possible values for NodeGroup.alloc_policy +ALLOC_POLICY_PREFERRED = "preferred" +ALLOC_POLICY_LAST_RESORT = "last_resort" +ALLOC_POLICY_UNALLOCABLE = "unallocable" +VALID_ALLOC_POLICIES = [ + ALLOC_POLICY_PREFERRED, + ALLOC_POLICY_LAST_RESORT, + ALLOC_POLICY_UNALLOCABLE, + ] diff --git a/lib/objects.py b/lib/objects.py index 62b749c39..666b51465 100644 --- a/lib/objects.py +++ b/lib/objects.py @@ -956,6 +956,7 @@ class NodeGroup(ConfigObject): "members", "ndparams", "serial_no", + "alloc_policy", ] + _TIMESTAMPS + _UUID def ToDict(self): @@ -990,6 +991,9 @@ class NodeGroup(ConfigObject): if self.serial_no is None: self.serial_no = 1 + if self.alloc_policy is None: + self.alloc_policy = constants.ALLOC_POLICY_PREFERRED + # We only update mtime, and not ctime, since we would not be able to provide # a correct value for creation time. if self.mtime is None: diff --git a/lib/opcodes.py b/lib/opcodes.py index 74bd75065..1416bb064 100644 --- a/lib/opcodes.py +++ b/lib/opcodes.py @@ -728,6 +728,7 @@ class OpAddGroup(OpCode): __slots__ = [ "group_name", "ndparams", + "alloc_policy", ] @@ -744,6 +745,7 @@ class OpSetGroupParams(OpCode): __slots__ = [ "group_name", "ndparams", + "alloc_policy", ] diff --git a/lib/rapi/client.py b/lib/rapi/client.py index 47ac42299..096463ee7 100644 --- a/lib/rapi/client.py +++ b/lib/rapi/client.py @@ -1408,11 +1408,13 @@ class GanetiRapiClient(object): "/%s/groups/%s" % (GANETI_RAPI_VERSION, group), None, None) - def CreateGroup(self, name, dry_run=False): + def CreateGroup(self, name, alloc_policy=None, dry_run=False): """Creates a new node group. @type name: str @param name: the name of node group to create + @type alloc_policy: str + @param alloc_policy: the desired allocation policy for the group, if any @type dry_run: bool @param dry_run: whether to peform a dry run @@ -1426,6 +1428,7 @@ class GanetiRapiClient(object): body = { "name": name, + "alloc_policy": alloc_policy } return self._SendRequest(HTTP_POST, "/%s/groups" % GANETI_RAPI_VERSION, diff --git a/lib/rapi/rlib2.py b/lib/rapi/rlib2.py index 6c265ecec..418c0034d 100644 --- a/lib/rapi/rlib2.py +++ b/lib/rapi/rlib2.py @@ -74,6 +74,7 @@ N_FIELDS = ["name", "offline", "master_candidate", "drained", ] + _COMMON_FIELDS G_FIELDS = ["name", "uuid", + "alloc_policy", "node_cnt", "node_list", "ctime", "mtime", "serial_no", ] # "tags" is missing to be able to use _COMMON_FIELDS here. @@ -531,6 +532,21 @@ class R_2_nodes_name_storage_repair(baserlib.R_Generic): return baserlib.SubmitJob([op]) +def _ParseCreateGroupRequest(data, dry_run): + """Parses a request for creating a node group. + + @rtype: L{opcodes.OpAddGroup} + @return: Group creation opcode + + """ + group_name = baserlib.CheckParameter(data, "name") + alloc_policy = baserlib.CheckParameter(data, "alloc_policy", default=None) + + return opcodes.OpAddGroup(group_name=group_name, + alloc_policy=alloc_policy, + dry_run=dry_run) + + class R_2_groups(baserlib.R_Generic): """/2/groups resource. @@ -557,8 +573,7 @@ class R_2_groups(baserlib.R_Generic): """ baserlib.CheckType(self.request_body, dict, "Body contents") - group_name = baserlib.CheckParameter(self.request_body, "name") - op = opcodes.OpAddGroup(group_name=group_name, dry_run=self.dryRun()) + op = _ParseCreateGroupRequest(self.request_body, self.dryRun()) return baserlib.SubmitJob([op]) diff --git a/man/gnt-group.rst b/man/gnt-group.rst index 61be0a777..6d71f4b05 100644 --- a/man/gnt-group.rst +++ b/man/gnt-group.rst @@ -25,6 +25,7 @@ ADD | **add** | [--node-parameters=*NDPARAMS*] +| [--alloc-policy=*POLICY*] | {*group*} Creates a new group with the given name. The node group will be @@ -34,17 +35,36 @@ The ``--node-parameters`` option allows you to set default node parameters for nodes in the group. Please see **ganeti**(7) for more information about supported key=value pairs. +The ``--alloc-policy`` option allows you to set an allocation policy for +the group at creation time. Possible values are: + +unallocable + nodes in the group should not be candidates for instance allocation, + and the operation (e.g., instance creation) should fail if only + groups in this state could be found to satisfy the requirements. + +last_resort + nodes in the group should not be used for instance allocations, + unless this would be the only way to have the operation succeed. + +preferred + nodes in the group can be used freely for allocation of instances + (this is the default). Note that prioritization among groups in this + state will be deferred to the iallocator plugin that's being used. + + MODIFY ~~~~~~ | **modify** | [--node-parameters=*NDPARAMS*] +| [--alloc-policy=*POLICY*] | {*group*} Modifies some parameters from the node group. -The ``--node-parameters`` option is documented in the **add** command -above. +The ``--node-parameters`` and ``--alloc-policy`` optiosn are documented +in the **add** command above. REMOVE ~~~~~~ @@ -93,6 +113,9 @@ pinst_cnt pinst_list the list of primary instances in the group +alloc_policy + the current allocation policy for the group + ctime the creation time of the group; note that this field contains spaces and as such it's harder to parse diff --git a/qa/qa_rapi.py b/qa/qa_rapi.py index 86374e573..ea74bb5f8 100644 --- a/qa/qa_rapi.py +++ b/qa/qa_rapi.py @@ -96,6 +96,7 @@ NODE_FIELDS = ("name", "dtotal", "dfree", GROUP_FIELDS = frozenset([ "name", "uuid", + "alloc_policy", "node_cnt", "node_list", ]) -- GitLab