Commit 294254b1 authored by Raffa Santi's avatar Raffa Santi Committed by Thomas Thrainer
Browse files

Check validity of the access protocol parameter



* Prevent incompatible hypervisor/disk template/access type
  combinations from being reached through the command line.
* Prevent the access config from taking illegal values such as "pink
  bunny" through the command line.
Signed-off-by: default avatarSanti Raffa <rsanti@google.com>
Signed-off-by: default avatarThomas Thrainer <thomasth@google.com>
Reviewed-by: default avatarThomas Thrainer <thomasth@google.com>
parent 117a85a0
......@@ -57,7 +57,8 @@ from ganeti.cmdlib.common import ShareAll, RunPostHook, \
GetUpdatedIPolicy, ComputeNewInstanceViolations, GetUpdatedParams, \
CheckOSParams, CheckHVParams, AdjustCandidatePool, CheckNodePVs, \
ComputeIPolicyInstanceViolation, AnnotateDiskParams, SupportsOob, \
CheckIpolicyVsDiskTemplates
CheckIpolicyVsDiskTemplates, CheckDiskAccessModeValidity, \
CheckDiskAccessModeConsistency
import ganeti.masterd.instance
......@@ -704,6 +705,7 @@ class LUClusterSetParams(LogicalUnit):
utils.ForceDictType(dt_params, constants.DISK_DT_TYPES)
try:
utils.VerifyDictOptions(self.op.diskparams, constants.DISK_DT_DEFAULTS)
CheckDiskAccessModeValidity(self.op.diskparams)
except errors.OpPrereqError, err:
raise errors.OpPrereqError("While verify diskparams options: %s" % err,
errors.ECODE_INVAL)
......@@ -1024,6 +1026,7 @@ class LUClusterSetParams(LogicalUnit):
self.new_diskparams[dt_name] = dt_params
else:
self.new_diskparams[dt_name].update(dt_params)
CheckDiskAccessModeConsistency(self.op.diskparams, self.cfg)
# os hypervisor parameters
self.new_os_hvp = objects.FillDict(cluster.os_hvp, {})
......
......@@ -1133,3 +1133,88 @@ def CheckIpolicyVsDiskTemplates(ipolicy, enabled_disk_templates):
raise errors.OpPrereqError("The following disk template are allowed"
" by the ipolicy, but not enabled on the"
" cluster: %s" % utils.CommaJoin(not_enabled))
def CheckDiskAccessModeValidity(parameters):
"""Checks if the access parameter is legal.
@see: L{CheckDiskAccessModeConsistency} for cluster consistency checks.
@raise errors.OpPrereqError: if the check fails.
"""
if constants.DT_RBD in parameters:
access = parameters[constants.DT_RBD].get(constants.RBD_ACCESS,
constants.DISK_KERNELSPACE)
if access not in constants.DISK_VALID_ACCESS_MODES:
valid_vals_str = utils.CommaJoin(constants.DISK_VALID_ACCESS_MODES)
raise errors.OpPrereqError("Invalid value of '{d}:{a}': '{v}' (expected"
" one of {o})".format(d=constants.DT_RBD,
a=constants.RBD_ACCESS,
v=access,
o=valid_vals_str))
def CheckDiskAccessModeConsistency(parameters, cfg, group=None):
"""Checks if the access param is consistent with the cluster configuration.
@note: requires a configuration lock to run.
@param parameters: the parameters to validate
@param cfg: the cfg object of the cluster
@param group: if set, only check for consistency within this group.
@raise errors.OpPrereqError: if the LU attempts to change the access parameter
to an invalid value, such as "pink bunny".
@raise errors.OpPrereqError: if the LU attempts to change the access parameter
to an inconsistent value, such as asking for RBD
userspace access to the chroot hypervisor.
"""
CheckDiskAccessModeValidity(parameters)
if constants.DT_RBD in parameters:
access = parameters[constants.DT_RBD].get(constants.RBD_ACCESS,
constants.DISK_KERNELSPACE)
#Check the combination of instance hypervisor, disk template and access
#protocol is sane.
inst_uuids = cfg.GetNodeGroupInstances(group) if group else \
cfg.GetInstanceList()
for entry in inst_uuids:
#hyp, disk, access
inst = cfg.GetInstanceInfo(entry)
hv = inst.hypervisor
dt = inst.disk_template
#do not check for disk types that don't have this setting.
if dt != constants.DT_RBD:
continue
if not IsValidDiskAccessModeCombination(hv, dt, access):
raise errors.OpPrereqError("Instance {i}: cannot use '{a}' access"
" setting with {h} hypervisor and {d} disk"
" type.".format(i=inst.name,
a=access,
h=hv,
d=dt))
def IsValidDiskAccessModeCombination(hv, disk_template, mode):
"""Checks if an hypervisor can read a disk template with given mode.
@param hv: the hypervisor that will access the data
@param disk_template: the disk template the data is stored as
@param mode: how the hypervisor should access the data
@return: True if the hypervisor can read a given read disk_template
in the specified mode.
"""
if mode == constants.DISK_KERNELSPACE:
return True
if (hv == constants.HT_KVM and
disk_template == constants.DT_RBD and
mode == constants.DISK_USERSPACE):
return True
# Everything else:
return False
......@@ -39,7 +39,8 @@ from ganeti.cmdlib.common import MergeAndVerifyHvState, \
CheckNodeGroupInstances, GetUpdatedIPolicy, \
ComputeNewInstanceViolations, GetDefaultIAllocator, ShareAll, \
CheckInstancesNodeGroups, LoadNodeEvacResult, MapInstanceLvsToNodes, \
CheckIpolicyVsDiskTemplates
CheckIpolicyVsDiskTemplates, CheckDiskAccessModeValidity, \
CheckDiskAccessModeConsistency
import ganeti.masterd.instance
......@@ -406,6 +407,9 @@ class LUGroupSetParams(LogicalUnit):
raise errors.OpPrereqError("Please pass at least one modification",
errors.ECODE_INVAL)
if self.op.diskparams:
CheckDiskAccessModeValidity(self.op.diskparams)
def ExpandNames(self):
# This raises errors.OpPrereqError on its own:
self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name)
......@@ -500,8 +504,11 @@ class LUGroupSetParams(LogicalUnit):
# As we've all subdicts of diskparams ready, lets merge the actual
# dict with all updated subdicts
self.new_diskparams = objects.FillDict(diskparams, new_diskparams)
try:
utils.VerifyDictOptions(self.new_diskparams, constants.DISK_DT_DEFAULTS)
CheckDiskAccessModeConsistency(self.new_diskparams, self.cfg,
group=self.group)
except errors.OpPrereqError, err:
raise errors.OpPrereqError("While verify diskparams options: %s" % err,
errors.ECODE_INVAL)
......
......@@ -49,7 +49,7 @@ from ganeti.cmdlib.common import INSTANCE_DOWN, \
IsExclusiveStorageEnabledNode, CheckHVParams, CheckOSParams, \
AnnotateDiskParams, GetUpdatedParams, ExpandInstanceUuidAndName, \
ComputeIPolicySpecViolation, CheckInstanceState, ExpandNodeUuidAndName, \
CheckDiskTemplateEnabled
CheckDiskTemplateEnabled, IsValidDiskAccessModeCombination
from ganeti.cmdlib.instance_storage import CreateDisks, \
CheckNodesFreeDiskPerVG, WipeDisks, WipeOrCleanupDisks, WaitForSync, \
IsExclusiveStorageEnabledNodeUuid, CreateSingleBlockDev, ComputeDisks, \
......@@ -1168,6 +1168,22 @@ class LUInstanceCreate(LogicalUnit):
dsk[constants.IDISK_SIZE] = \
int(float(node_disks[dsk[constants.IDISK_ADOPT]]))
# Check disk access param to be compatible with specified hypervisor
node_info = self.cfg.GetNodeInfo(self.op.pnode_uuid)
node_group = self.cfg.GetNodeGroup(node_info.group)
disk_params = self.cfg.GetGroupDiskParams(node_group)
access_type = disk_params[self.op.disk_template].get(
constants.RBD_ACCESS, constants.DISK_KERNELSPACE
)
if not IsValidDiskAccessModeCombination(self.op.hypervisor,
self.op.disk_template,
access_type):
raise errors.OpPrereqError("Selected hypervisor (%s) cannot be"
" used with %s disk access param" %
(self.op.hypervisor, access_type),
errors.ECODE_STATE)
# Verify instance specs
spindle_use = self.be_full.get(constants.BE_SPINDLE_USE, None)
ispec = {
......
......@@ -667,6 +667,16 @@ class ConfigWriter(object):
constants.NDS_PARAMETER_TYPES)
_helper_ipolicy("cluster", cluster.ipolicy, True)
if constants.DT_RBD in cluster.diskparams:
access = cluster.diskparams[constants.DT_RBD][constants.RBD_ACCESS]
if access not in constants.DISK_VALID_ACCESS_MODES:
result.append(
"Invalid value of '%s:%s': '%s' (expected one of %s)" % (
constants.DT_RBD, constants.RBD_ACCESS, access,
utils.CommaJoin(constants.DISK_VALID_ACCESS_MODES)
)
)
# per-instance checks
for instance_uuid in data.instances:
instance = data.instances[instance_uuid]
......
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