return params_copy
+def _UpdateAndVerifySubDict(base, updates, type_check):
+ """Updates and verifies a dict with sub dicts of the same type.
+
+ @param base: The dict with the old data
+ @param updates: The dict with the new data
+ @param type_check: Dict suitable to ForceDictType to verify correct types
+ @returns: A new dict with updated and verified values
+
+ """
+ def fn(old, value):
+ new = _GetUpdatedParams(old, value)
+ utils.ForceDictType(new, type_check)
+ return new
+
+ ret = copy.deepcopy(base)
+ ret.update(dict((key, fn(base.get(key, {}), value))
+ for key, value in updates.items()))
+ 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.
(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.
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.
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.
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:
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)
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
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)
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.
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:
"architecture": (platform.architecture()[0], platform.machine()),
"name": cluster.cluster_name,
"master": cluster.master_node,
- "default_hypervisor": cluster.enabled_hypervisors[0],
+ "default_hypervisor": cluster.primary_hypervisor,
"enabled_hypervisors": cluster.enabled_hypervisors,
"hvparams": dict([(hypervisor_name, cluster.hvparams[hypervisor_name])
for hypervisor_name in cluster.enabled_hypervisors]),
"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,
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)
dt_params = disk_params[disk_template]
if disk_template == constants.DT_DRBD8:
drbd_params = {
- constants.RESYNC_RATE: dt_params[constants.DRBD_RESYNC_RATE]
+ 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 = \
# 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],
# 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],
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],
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],
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)
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.
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]
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:
# 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)
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):
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.
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
elif self.mode == constants.IALLOCATOR_MODE_RELOC:
hypervisor_name = cfg.GetInstanceInfo(self.name).hypervisor
else:
- hypervisor_name = cluster_info.enabled_hypervisors[0]
+ hypervisor_name = cluster_info.primary_hypervisor
node_data = self.rpc.call_node_info(node_list, [cfg.GetVGName()],
[hypervisor_name])