X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/784cd73790360e7172f9215d23d3edf59e5f8fce..c4929a8bcca4a43dc6434394a91a8ea67d854844:/lib/cmdlib.py diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 66ea5ae..04d26f9 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -741,6 +741,51 @@ def _UpdateAndVerifySubDict(base, updates, type_check): return ret +def _MergeAndVerifyHvState(op_input, obj_input): + """Combines the hv state from an opcode with the one of the object + + @param op_input: The input dict from the opcode + @param obj_input: The input dict from the objects + @return: The verified and updated dict + + """ + if op_input: + invalid_hvs = set(op_input) - constants.HYPER_TYPES + if invalid_hvs: + raise errors.OpPrereqError("Invalid hypervisor(s) in hypervisor state:" + " %s" % utils.CommaJoin(invalid_hvs), + errors.ECODE_INVAL) + if obj_input is None: + obj_input = {} + type_check = constants.HVSTS_PARAMETER_TYPES + return _UpdateAndVerifySubDict(obj_input, op_input, type_check) + + return None + + +def _MergeAndVerifyDiskState(op_input, obj_input): + """Combines the disk state from an opcode with the one of the object + + @param op_input: The input dict from the opcode + @param obj_input: The input dict from the objects + @return: The verified and updated dict + """ + if op_input: + invalid_dst = set(op_input) - constants.DS_VALID_TYPES + if invalid_dst: + raise errors.OpPrereqError("Invalid storage type(s) in disk state: %s" % + utils.CommaJoin(invalid_dst), + errors.ECODE_INVAL) + type_check = constants.DSS_PARAMETER_TYPES + if obj_input is None: + obj_input = {} + return dict((key, _UpdateAndVerifySubDict(obj_input.get(key, {}), value, + type_check)) + for key, value in op_input.items()) + + return None + + def _ReleaseLocks(lu, level, names=None, keep=None): """Releases locks owned by an LU. @@ -971,6 +1016,26 @@ def _CheckInstanceState(lu, instance, req_states, msg=None): (instance.name, msg), errors.ECODE_STATE) +def _CheckMinMaxSpecs(name, ipolicy, value): + """Checks if value is in the desired range. + + @param name: name of the parameter for which we perform the check + @param ipolicy: dictionary containing min, max and std values + @param value: actual value that we want to use + @return: None or element not meeting the criteria + + + """ + if value in [None, constants.VALUE_AUTO]: + return None + max_v = ipolicy[constants.ISPECS_MAX].get(name, value) + min_v = ipolicy[constants.ISPECS_MIN].get(name, value) + if value > max_v or min_v > value: + return ("%s value %s is not in range [%s, %s]" % + (name, value, min_v, max_v)) + return None + + def _ExpandItemName(fn, name, kind): """Expand an item name. @@ -1184,6 +1249,14 @@ def _DecideSelfPromotion(lu, exceptions=None): return mc_now < mc_should +def _CalculateGroupIPolicy(cfg, group): + """Calculate instance policy for group. + + """ + cluster = cfg.GetClusterInfo() + return cluster.SimpleFillIPolicy(group.ipolicy) + + def _CheckNicsBridgesExist(lu, target_nics, target_node): """Check that the brigdes needed by a list of nics exist. @@ -2062,6 +2135,34 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors): msg = "cannot reach the master IP" _ErrorIf(True, constants.CV_ENODENET, node, msg) + def _VerifyInstancePolicy(self, instance): + """Verify instance specs against instance policy set on node group level. + + + """ + cluster = self.cfg.GetClusterInfo() + full_beparams = cluster.FillBE(instance) + ipolicy = cluster.SimpleFillIPolicy(self.group_info.ipolicy) + + mem_size = full_beparams.get(constants.BE_MAXMEM, None) + cpu_count = full_beparams.get(constants.BE_VCPUS, None) + disk_count = len(instance.disks) + disk_sizes = [disk.size for disk in instance.disks] + nic_count = len(instance.nics) + + test_settings = [ + (constants.ISPEC_MEM_SIZE, mem_size), + (constants.ISPEC_CPU_COUNT, cpu_count), + (constants.ISPEC_DISK_COUNT, disk_count), + (constants.ISPEC_NIC_COUNT, nic_count), + ] + map((lambda d: (constants.ISPEC_DISK_SIZE, d)), disk_sizes) + + for (name, value) in test_settings: + test_result = _CheckMinMaxSpecs(name, ipolicy, value) + self._ErrorIf(test_result is not None, + constants.CV_EINSTANCEPOLICY, instance.name, + test_result) + def _VerifyInstance(self, instance, instanceconfig, node_image, diskstatus): """Verify an instance. @@ -2076,6 +2177,8 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors): node_vol_should = {} instanceconfig.MapLVsByNode(node_vol_should) + self._VerifyInstancePolicy(instanceconfig) + for node in node_vol_should: n_img = node_image[node] if n_img.offline or n_img.rpc_fail or n_img.lvm_fail: @@ -3615,6 +3718,29 @@ class LUClusterSetParams(LogicalUnit): self.new_ndparams["oob_program"] = \ constants.NDC_DEFAULTS[constants.ND_OOB_PROGRAM] + if self.op.hv_state: + new_hv_state = _MergeAndVerifyHvState(self.op.hv_state, + self.cluster.hv_state_static) + self.new_hv_state = dict((hv, cluster.SimpleFillHvState(values)) + for hv, values in new_hv_state.items()) + + if self.op.disk_state: + new_disk_state = _MergeAndVerifyDiskState(self.op.disk_state, + self.cluster.disk_state_static) + self.new_disk_state = \ + dict((storage, dict((name, cluster.SimpleFillDiskState(values)) + for name, values in svalues.items())) + for storage, svalues in new_disk_state.items()) + + if self.op.ipolicy: + ipolicy = {} + for key, value in self.op.ipolicy.items(): + utils.ForceDictType(value, constants.ISPECS_PARAMETER_TYPES) + ipolicy[key] = _GetUpdatedParams(cluster.ipolicy.get(key, {}), + value) + objects.InstancePolicy.CheckParameterSyntax(ipolicy) + self.new_ipolicy = ipolicy + if self.op.nicparams: utils.ForceDictType(self.op.nicparams, constants.NICS_PARAMETER_TYPES) self.new_nicparams = cluster.SimpleFillNIC(self.op.nicparams) @@ -3775,12 +3901,18 @@ class LUClusterSetParams(LogicalUnit): self.cluster.beparams[constants.PP_DEFAULT] = self.new_beparams if self.op.nicparams: self.cluster.nicparams[constants.PP_DEFAULT] = self.new_nicparams + if self.op.ipolicy: + self.cluster.ipolicy = self.new_ipolicy if self.op.osparams: self.cluster.osparams = self.new_osp if self.op.ndparams: self.cluster.ndparams = self.new_ndparams if self.op.diskparams: self.cluster.diskparams = self.new_diskparams + if self.op.hv_state: + self.cluster.hv_state_static = self.new_hv_state + if self.op.disk_state: + self.cluster.disk_state_static = self.new_disk_state if self.op.candidate_pool_size is not None: self.cluster.candidate_pool_size = self.op.candidate_pool_size @@ -5369,7 +5501,8 @@ class LUNodeSetParams(LogicalUnit): self.op.node_name = _ExpandNodeName(self.cfg, self.op.node_name) all_mods = [self.op.offline, self.op.master_candidate, self.op.drained, self.op.master_capable, self.op.vm_capable, - self.op.secondary_ip, self.op.ndparams] + self.op.secondary_ip, self.op.ndparams, self.op.hv_state, + self.op.disk_state] if all_mods.count(None) == len(all_mods): raise errors.OpPrereqError("Please pass at least one modification", errors.ECODE_INVAL) @@ -5610,6 +5743,15 @@ class LUNodeSetParams(LogicalUnit): utils.ForceDictType(new_ndparams, constants.NDS_PARAMETER_TYPES) self.new_ndparams = new_ndparams + if self.op.hv_state: + self.new_hv_state = _MergeAndVerifyHvState(self.op.hv_state, + self.node.hv_state_static) + + if self.op.disk_state: + self.new_disk_state = \ + _MergeAndVerifyDiskState(self.op.disk_state, + self.node.disk_state_static) + def Exec(self, feedback_fn): """Modifies a node. @@ -5626,6 +5768,12 @@ class LUNodeSetParams(LogicalUnit): if self.op.powered is not None: node.powered = self.op.powered + if self.op.hv_state: + node.hv_state_static = self.new_hv_state + + if self.op.disk_state: + node.disk_state_static = self.new_disk_state + for attr in ["master_capable", "vm_capable"]: val = getattr(self.op, attr) if val is not None: @@ -5740,6 +5888,7 @@ class LUClusterQuery(NoHooksLU): "os_hvp": os_hvp, "beparams": cluster.beparams, "osparams": cluster.osparams, + "ipolicy": cluster.ipolicy, "nicparams": cluster.nicparams, "ndparams": cluster.ndparams, "candidate_pool_size": cluster.candidate_pool_size, @@ -7468,6 +7617,18 @@ class TLMigrateInstance(Tasklet): self.lu.LogInfo("Not checking memory on the secondary node as" " instance will not be started") + # check if failover must be forced instead of migration + if (not self.cleanup and not self.failover and + i_be[constants.BE_ALWAYS_FAILOVER]): + if self.fallback: + self.lu.LogInfo("Instance configured to always failover; fallback" + " to failover") + self.failover = True + else: + raise errors.OpPrereqError("This instance has been configured to" + " always failover, please allow failover", + errors.ECODE_STATE) + # check bridge existance _CheckInstanceBridgesExist(self.lu, instance, node=target_node) @@ -8078,9 +8239,18 @@ def _ComputeLDParams(disk_template, disk_params): dt_params = disk_params[disk_template] if disk_template == constants.DT_DRBD8: drbd_params = { - constants.RESYNC_RATE: dt_params[constants.DRBD_RESYNC_RATE], - constants.BARRIERS: dt_params[constants.DRBD_DISK_BARRIERS], - constants.NO_META_FLUSH: dt_params[constants.DRBD_META_BARRIERS], + constants.LDP_RESYNC_RATE: dt_params[constants.DRBD_RESYNC_RATE], + constants.LDP_BARRIERS: dt_params[constants.DRBD_DISK_BARRIERS], + constants.LDP_NO_META_FLUSH: dt_params[constants.DRBD_META_BARRIERS], + constants.LDP_DEFAULT_METAVG: dt_params[constants.DRBD_DEFAULT_METAVG], + constants.LDP_DISK_CUSTOM: dt_params[constants.DRBD_DISK_CUSTOM], + constants.LDP_NET_CUSTOM: dt_params[constants.DRBD_NET_CUSTOM], + constants.LDP_DYNAMIC_RESYNC: dt_params[constants.DRBD_DYNAMIC_RESYNC], + constants.LDP_PLAN_AHEAD: dt_params[constants.DRBD_PLAN_AHEAD], + constants.LDP_FILL_TARGET: dt_params[constants.DRBD_FILL_TARGET], + constants.LDP_DELAY_TARGET: dt_params[constants.DRBD_DELAY_TARGET], + constants.LDP_MAX_RATE: dt_params[constants.DRBD_MAX_RATE], + constants.LDP_MIN_RATE: dt_params[constants.DRBD_MIN_RATE], } drbd_params = \ @@ -8091,7 +8261,7 @@ def _ComputeLDParams(disk_template, disk_params): # data LV data_params = { - constants.STRIPES: dt_params[constants.DRBD_DATA_STRIPES], + constants.LDP_STRIPES: dt_params[constants.DRBD_DATA_STRIPES], } data_params = \ objects.FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], @@ -8100,7 +8270,7 @@ def _ComputeLDParams(disk_template, disk_params): # metadata LV meta_params = { - constants.STRIPES: dt_params[constants.DRBD_META_STRIPES], + constants.LDP_STRIPES: dt_params[constants.DRBD_META_STRIPES], } meta_params = \ objects.FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], @@ -8113,7 +8283,7 @@ def _ComputeLDParams(disk_template, disk_params): elif disk_template == constants.DT_PLAIN: params = { - constants.STRIPES: dt_params[constants.LV_STRIPES], + constants.LDP_STRIPES: dt_params[constants.LV_STRIPES], } params = \ objects.FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], @@ -8199,8 +8369,9 @@ def _GenerateDiskTemplate(lu, template_name, names.append(lv_prefix + "_meta") for idx, disk in enumerate(disk_info): disk_index = idx + base_index + drbd_default_metavg = drbd_params[constants.LDP_DEFAULT_METAVG] data_vg = disk.get(constants.IDISK_VG, vgname) - meta_vg = disk.get(constants.IDISK_METAVG, data_vg) + meta_vg = disk.get(constants.IDISK_METAVG, drbd_default_metavg) disk_dev = _GenerateDRBD8Branch(lu, primary_node, remote_node, disk[constants.IDISK_SIZE], [data_vg, meta_vg], @@ -9210,8 +9381,9 @@ class LUInstanceCreate(LogicalUnit): constants.IDISK_SIZE: size, constants.IDISK_MODE: mode, constants.IDISK_VG: data_vg, - constants.IDISK_METAVG: disk.get(constants.IDISK_METAVG, data_vg), } + if constants.IDISK_METAVG in disk: + new_disk[constants.IDISK_METAVG] = disk[constants.IDISK_METAVG] if constants.IDISK_ADOPT in disk: new_disk[constants.IDISK_ADOPT] = disk[constants.IDISK_ADOPT] self.disks.append(new_disk) @@ -12622,6 +12794,11 @@ class LUGroupAdd(LogicalUnit): else: self.op.diskparams = self.cfg.GetClusterInfo().diskparams + if self.op.ipolicy: + cluster = self.cfg.GetClusterInfo() + full_ipolicy = cluster.SimpleFillIPolicy(self.op.ipolicy) + objects.InstancePolicy.CheckParameterSyntax(full_ipolicy) + def BuildHooksEnv(self): """Build hooks env. @@ -12645,7 +12822,8 @@ class LUGroupAdd(LogicalUnit): uuid=self.group_uuid, alloc_policy=self.op.alloc_policy, ndparams=self.op.ndparams, - diskparams=self.op.diskparams) + diskparams=self.op.diskparams, + ipolicy=self.op.ipolicy) self.cfg.AddNodeGroup(group_obj, self.proc.GetECId(), check_uuid=False) del self.remove_locks[locking.LEVEL_NODEGROUP] @@ -12791,6 +12969,7 @@ class _GroupQuery(_QueryBase): lu.needed_locks = {} self._all_groups = lu.cfg.GetAllNodeGroupsInfo() + self._cluster = lu.cfg.GetClusterInfo() name_to_uuid = dict((g.name, g.uuid) for g in self._all_groups.values()) if not self.names: @@ -12856,7 +13035,8 @@ class _GroupQuery(_QueryBase): # Do not pass on node information if it was not requested. group_to_nodes = None - return query.GroupQueryData([self._all_groups[uuid] + return query.GroupQueryData(self._cluster, + [self._all_groups[uuid] for uuid in self.wanted], group_to_nodes, group_to_instances) @@ -12894,6 +13074,9 @@ class LUGroupSetParams(LogicalUnit): self.op.ndparams, self.op.diskparams, self.op.alloc_policy, + self.op.hv_state, + self.op.disk_state, + self.op.ipolicy, ] if all_changes.count(None) == len(all_changes): @@ -12933,6 +13116,25 @@ class LUGroupSetParams(LogicalUnit): utils.ForceDictType(new_templ_params, constants.DISK_DT_TYPES) self.new_diskparams[templ] = new_templ_params + if self.op.hv_state: + self.new_hv_state = _MergeAndVerifyHvState(self.op.hv_state, + self.group.hv_state_static) + + if self.op.disk_state: + self.new_disk_state = \ + _MergeAndVerifyDiskState(self.op.disk_state, + self.group.disk_state_static) + + if self.op.ipolicy: + g_ipolicy = {} + for key, value in self.op.ipolicy.iteritems(): + g_ipolicy[key] = _GetUpdatedParams(self.group.ipolicy.get(key, {}), + value, + use_none=True) + utils.ForceDictType(g_ipolicy[key], constants.ISPECS_PARAMETER_TYPES) + self.new_ipolicy = g_ipolicy + objects.InstancePolicy.CheckParameterSyntax(self.new_ipolicy) + def BuildHooksEnv(self): """Build hooks env. @@ -12966,6 +13168,15 @@ class LUGroupSetParams(LogicalUnit): if self.op.alloc_policy: self.group.alloc_policy = self.op.alloc_policy + if self.op.hv_state: + self.group.hv_state_static = self.new_hv_state + + if self.op.disk_state: + self.group.disk_state_static = self.new_disk_state + + if self.op.ipolicy: + self.group.ipolicy = self.new_ipolicy + self.cfg.Update(self.group, feedback_fn) return result