Commit 7736a5f2 authored by Iustin Pop's avatar Iustin Pop

Introduce 'global hypervisor parameters' support

This patch adds support for global hypervisor parameters in instance
creation, instance modification, instance query and at instance load
time.

We basically prevent any query on these parameters, discard them at load
time, and do not allow their modification. Together, this should make
any such parameters go away if existing and not allowed to be added.
Signed-off-by: default avatarIustin Pop <iustin@google.com>
Reviewed-by: default avatarGuido Trotter <ultrotter@google.com>
parent bd14a6ac
......@@ -500,6 +500,21 @@ def _CheckBooleanOpField(op, name):
setattr(op, name, val)
def _CheckGlobalHvParams(params):
"""Validates that given hypervisor params are not global ones.
This will ensure that instances don't get customised versions of
global params.
"""
used_globals = constants.HVC_GLOBALS.intersection(params)
if used_globals:
msg = ("The following hypervisor parameters are global and cannot"
" be customized at instance level, please modify them at"
" cluster level: %s" % ", ".join(used_globals))
raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
def _CheckNodeOnline(lu, node):
"""Ensure that a given node is online.
......@@ -4200,7 +4215,8 @@ class LUQueryInstances(NoHooksLU):
"hvparams",
] + _SIMPLE_FIELDS +
["hv/%s" % name
for name in constants.HVS_PARAMETERS] +
for name in constants.HVS_PARAMETERS
if name not in constants.HVC_GLOBALS] +
["be/%s" % name
for name in constants.BES_PARAMETERS])
_FIELDS_DYNAMIC = utils.FieldSet("oper_state", "oper_ram", "status")
......@@ -4295,7 +4311,7 @@ class LUQueryInstances(NoHooksLU):
cluster = self.cfg.GetClusterInfo()
for instance in instance_list:
iout = []
i_hv = cluster.FillHV(instance)
i_hv = cluster.FillHV(instance, skip_globals=True)
i_be = cluster.FillBE(instance)
i_nicp = [objects.FillDict(cluster.nicparams[constants.PP_DEFAULT],
nic.nicparams) for nic in instance.nics]
......@@ -4382,7 +4398,8 @@ class LUQueryInstances(NoHooksLU):
elif field == "hvparams":
val = i_hv
elif (field.startswith(HVPREFIX) and
field[len(HVPREFIX):] in constants.HVS_PARAMETERS):
field[len(HVPREFIX):] in constants.HVS_PARAMETERS and
field[len(HVPREFIX):] not in constants.HVC_GLOBALS):
val = i_hv.get(field[len(HVPREFIX):], None)
elif field == "beparams":
val = i_be
......@@ -5599,6 +5616,8 @@ class LUCreateInstance(LogicalUnit):
hv_type = hypervisor.GetHypervisor(self.op.hypervisor)
hv_type.CheckParameterSyntax(filled_hvp)
self.hv_full = filled_hvp
# check that we don't specify global parameters on an instance
_CheckGlobalHvParams(self.op.hvparams)
# fill and remember the beparams dict
utils.ForceDictType(self.op.beparams, constants.BES_PARAMETER_TYPES)
......@@ -7292,7 +7311,7 @@ class LUQueryInstanceData(NoHooksLU):
"hypervisor": instance.hypervisor,
"network_port": instance.network_port,
"hv_instance": instance.hvparams,
"hv_actual": cluster.FillHV(instance),
"hv_actual": cluster.FillHV(instance, skip_globals=True),
"be_instance": instance.beparams,
"be_actual": cluster.FillBE(instance),
"serial_no": instance.serial_no,
......@@ -7329,6 +7348,9 @@ class LUSetInstanceParams(LogicalUnit):
self.op.hvparams or self.op.beparams):
raise errors.OpPrereqError("No changes submitted", errors.ECODE_INVAL)
if self.op.hvparams:
_CheckGlobalHvParams(self.op.hvparams)
# Disk validation
disk_addremove = 0
for disk_op, disk_dict in self.op.disks:
......
......@@ -650,6 +650,10 @@ HVC_DEFAULTS = {
},
}
HVC_GLOBALS = frozenset([
HV_MIGRATION_PORT,
])
BEC_DEFAULTS = {
BE_MEMORY: 128,
BE_VCPUS: 1,
......
......@@ -42,19 +42,26 @@ __all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
_TIMESTAMPS = ["ctime", "mtime"]
_UUID = ["uuid"]
def FillDict(defaults_dict, custom_dict):
def FillDict(defaults_dict, custom_dict, skip_keys=[]):
"""Basic function to apply settings on top a default dict.
@type defaults_dict: dict
@param defaults_dict: dictionary holding the default values
@type custom_dict: dict
@param custom_dict: dictionary holding customized value
@type skip_keys: list
@param skip_keys: which keys not to fill
@rtype: dict
@return: dict with the 'full' values
"""
ret_dict = copy.deepcopy(defaults_dict)
ret_dict.update(custom_dict)
for k in skip_keys:
try:
del ret_dict[k]
except KeyError:
pass
return ret_dict
......@@ -777,6 +784,12 @@ class Instance(TaggableObject):
nic.UpgradeConfig()
for disk in self.disks:
disk.UpgradeConfig()
if self.hvparams:
for key in constants.HVC_GLOBALS:
try:
del self.hvparams[key]
except KeyError:
pass
class OS(ConfigObject):
......@@ -887,18 +900,25 @@ class Cluster(TaggableObject):
obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
return obj
def FillHV(self, instance):
def FillHV(self, instance, skip_globals=False):
"""Fill an instance's hvparams dict.
@type instance: L{objects.Instance}
@param instance: the instance parameter to fill
@type skip_globals: boolean
@param skip_globals: if True, the global hypervisor parameters will
not be filled
@rtype: dict
@return: a copy of the instance's hvparams with missing keys filled from
the cluster defaults
"""
if skip_globals:
skip_keys = constants.HVC_GLOBALS
else:
skip_keys = []
return FillDict(self.hvparams.get(instance.hypervisor, {}),
instance.hvparams)
instance.hvparams, skip_keys=skip_keys)
def FillBE(self, instance):
"""Fill an instance's beparams dict.
......@@ -911,7 +931,7 @@ class Cluster(TaggableObject):
"""
return FillDict(self.beparams.get(constants.PP_DEFAULT, {}),
instance.beparams)
instance.beparams)
class BlockDevStatus(ConfigObject):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment