Revision 294254b1

b/lib/cmdlib/cluster.py
57 57
  GetUpdatedIPolicy, ComputeNewInstanceViolations, GetUpdatedParams, \
58 58
  CheckOSParams, CheckHVParams, AdjustCandidatePool, CheckNodePVs, \
59 59
  ComputeIPolicyInstanceViolation, AnnotateDiskParams, SupportsOob, \
60
  CheckIpolicyVsDiskTemplates
60
  CheckIpolicyVsDiskTemplates, CheckDiskAccessModeValidity, \
61
  CheckDiskAccessModeConsistency
61 62

  
62 63
import ganeti.masterd.instance
63 64

  
......
704 705
        utils.ForceDictType(dt_params, constants.DISK_DT_TYPES)
705 706
      try:
706 707
        utils.VerifyDictOptions(self.op.diskparams, constants.DISK_DT_DEFAULTS)
708
        CheckDiskAccessModeValidity(self.op.diskparams)
707 709
      except errors.OpPrereqError, err:
708 710
        raise errors.OpPrereqError("While verify diskparams options: %s" % err,
709 711
                                   errors.ECODE_INVAL)
......
1024 1026
          self.new_diskparams[dt_name] = dt_params
1025 1027
        else:
1026 1028
          self.new_diskparams[dt_name].update(dt_params)
1029
      CheckDiskAccessModeConsistency(self.op.diskparams, self.cfg)
1027 1030

  
1028 1031
    # os hypervisor parameters
1029 1032
    self.new_os_hvp = objects.FillDict(cluster.os_hvp, {})
b/lib/cmdlib/common.py
1133 1133
    raise errors.OpPrereqError("The following disk template are allowed"
1134 1134
                               " by the ipolicy, but not enabled on the"
1135 1135
                               " cluster: %s" % utils.CommaJoin(not_enabled))
1136

  
1137

  
1138
def CheckDiskAccessModeValidity(parameters):
1139
  """Checks if the access parameter is legal.
1140

  
1141
  @see: L{CheckDiskAccessModeConsistency} for cluster consistency checks.
1142
  @raise errors.OpPrereqError: if the check fails.
1143

  
1144
  """
1145
  if constants.DT_RBD in parameters:
1146
    access = parameters[constants.DT_RBD].get(constants.RBD_ACCESS,
1147
                                              constants.DISK_KERNELSPACE)
1148
    if access not in constants.DISK_VALID_ACCESS_MODES:
1149
      valid_vals_str = utils.CommaJoin(constants.DISK_VALID_ACCESS_MODES)
1150
      raise errors.OpPrereqError("Invalid value of '{d}:{a}': '{v}' (expected"
1151
                                 " one of {o})".format(d=constants.DT_RBD,
1152
                                                       a=constants.RBD_ACCESS,
1153
                                                       v=access,
1154
                                                       o=valid_vals_str))
1155

  
1156

  
1157
def CheckDiskAccessModeConsistency(parameters, cfg, group=None):
1158
  """Checks if the access param is consistent with the cluster configuration.
1159

  
1160
  @note: requires a configuration lock to run.
1161
  @param parameters: the parameters to validate
1162
  @param cfg: the cfg object of the cluster
1163
  @param group: if set, only check for consistency within this group.
1164
  @raise errors.OpPrereqError: if the LU attempts to change the access parameter
1165
                               to an invalid value, such as "pink bunny".
1166
  @raise errors.OpPrereqError: if the LU attempts to change the access parameter
1167
                               to an inconsistent value, such as asking for RBD
1168
                               userspace access to the chroot hypervisor.
1169

  
1170
  """
1171
  CheckDiskAccessModeValidity(parameters)
1172

  
1173
  if constants.DT_RBD in parameters:
1174
    access = parameters[constants.DT_RBD].get(constants.RBD_ACCESS,
1175
                                              constants.DISK_KERNELSPACE)
1176

  
1177
    #Check the combination of instance hypervisor, disk template and access
1178
    #protocol is sane.
1179
    inst_uuids = cfg.GetNodeGroupInstances(group) if group else \
1180
                 cfg.GetInstanceList()
1181

  
1182
    for entry in inst_uuids:
1183
      #hyp, disk, access
1184
      inst = cfg.GetInstanceInfo(entry)
1185
      hv = inst.hypervisor
1186
      dt = inst.disk_template
1187

  
1188
      #do not check for disk types that don't have this setting.
1189
      if dt != constants.DT_RBD:
1190
        continue
1191

  
1192
      if not IsValidDiskAccessModeCombination(hv, dt, access):
1193
        raise errors.OpPrereqError("Instance {i}: cannot use '{a}' access"
1194
                                   " setting with {h} hypervisor and {d} disk"
1195
                                   " type.".format(i=inst.name,
1196
                                                   a=access,
1197
                                                   h=hv,
1198
                                                   d=dt))
1199

  
1200

  
1201
def IsValidDiskAccessModeCombination(hv, disk_template, mode):
1202
  """Checks if an hypervisor can read a disk template with given mode.
1203

  
1204
  @param hv: the hypervisor that will access the data
1205
  @param disk_template: the disk template the data is stored as
1206
  @param mode: how the hypervisor should access the data
1207
  @return: True if the hypervisor can read a given read disk_template
1208
           in the specified mode.
1209

  
1210
  """
1211
  if mode == constants.DISK_KERNELSPACE:
1212
    return True
1213

  
1214
  if (hv == constants.HT_KVM and
1215
      disk_template == constants.DT_RBD and
1216
      mode == constants.DISK_USERSPACE):
1217
    return True
1218

  
1219
  # Everything else:
1220
  return False
b/lib/cmdlib/group.py
39 39
  CheckNodeGroupInstances, GetUpdatedIPolicy, \
40 40
  ComputeNewInstanceViolations, GetDefaultIAllocator, ShareAll, \
41 41
  CheckInstancesNodeGroups, LoadNodeEvacResult, MapInstanceLvsToNodes, \
42
  CheckIpolicyVsDiskTemplates
42
  CheckIpolicyVsDiskTemplates, CheckDiskAccessModeValidity, \
43
  CheckDiskAccessModeConsistency
43 44

  
44 45
import ganeti.masterd.instance
45 46

  
......
406 407
      raise errors.OpPrereqError("Please pass at least one modification",
407 408
                                 errors.ECODE_INVAL)
408 409

  
410
    if self.op.diskparams:
411
      CheckDiskAccessModeValidity(self.op.diskparams)
412

  
409 413
  def ExpandNames(self):
410 414
    # This raises errors.OpPrereqError on its own:
411 415
    self.group_uuid = self.cfg.LookupNodeGroup(self.op.group_name)
......
500 504
      # As we've all subdicts of diskparams ready, lets merge the actual
501 505
      # dict with all updated subdicts
502 506
      self.new_diskparams = objects.FillDict(diskparams, new_diskparams)
507

  
503 508
      try:
504 509
        utils.VerifyDictOptions(self.new_diskparams, constants.DISK_DT_DEFAULTS)
510
        CheckDiskAccessModeConsistency(self.new_diskparams, self.cfg,
511
                                       group=self.group)
505 512
      except errors.OpPrereqError, err:
506 513
        raise errors.OpPrereqError("While verify diskparams options: %s" % err,
507 514
                                   errors.ECODE_INVAL)
b/lib/cmdlib/instance.py
49 49
  IsExclusiveStorageEnabledNode, CheckHVParams, CheckOSParams, \
50 50
  AnnotateDiskParams, GetUpdatedParams, ExpandInstanceUuidAndName, \
51 51
  ComputeIPolicySpecViolation, CheckInstanceState, ExpandNodeUuidAndName, \
52
  CheckDiskTemplateEnabled
52
  CheckDiskTemplateEnabled, IsValidDiskAccessModeCombination
53 53
from ganeti.cmdlib.instance_storage import CreateDisks, \
54 54
  CheckNodesFreeDiskPerVG, WipeDisks, WipeOrCleanupDisks, WaitForSync, \
55 55
  IsExclusiveStorageEnabledNodeUuid, CreateSingleBlockDev, ComputeDisks, \
......
1168 1168
        dsk[constants.IDISK_SIZE] = \
1169 1169
          int(float(node_disks[dsk[constants.IDISK_ADOPT]]))
1170 1170

  
1171
    # Check disk access param to be compatible with specified hypervisor
1172
    node_info = self.cfg.GetNodeInfo(self.op.pnode_uuid)
1173
    node_group = self.cfg.GetNodeGroup(node_info.group)
1174
    disk_params = self.cfg.GetGroupDiskParams(node_group)
1175
    access_type = disk_params[self.op.disk_template].get(
1176
      constants.RBD_ACCESS, constants.DISK_KERNELSPACE
1177
    )
1178

  
1179
    if not IsValidDiskAccessModeCombination(self.op.hypervisor,
1180
                                            self.op.disk_template,
1181
                                            access_type):
1182
      raise errors.OpPrereqError("Selected hypervisor (%s) cannot be"
1183
                                 " used with %s disk access param" %
1184
                                 (self.op.hypervisor, access_type),
1185
                                  errors.ECODE_STATE)
1186

  
1171 1187
    # Verify instance specs
1172 1188
    spindle_use = self.be_full.get(constants.BE_SPINDLE_USE, None)
1173 1189
    ispec = {
b/lib/config.py
667 667
            constants.NDS_PARAMETER_TYPES)
668 668
    _helper_ipolicy("cluster", cluster.ipolicy, True)
669 669

  
670
    if constants.DT_RBD in cluster.diskparams:
671
      access = cluster.diskparams[constants.DT_RBD][constants.RBD_ACCESS]
672
      if access not in constants.DISK_VALID_ACCESS_MODES:
673
        result.append(
674
          "Invalid value of '%s:%s': '%s' (expected one of %s)" % (
675
            constants.DT_RBD, constants.RBD_ACCESS, access,
676
            utils.CommaJoin(constants.DISK_VALID_ACCESS_MODES)
677
          )
678
        )
679

  
670 680
    # per-instance checks
671 681
    for instance_uuid in data.instances:
672 682
      instance = data.instances[instance_uuid]

Also available in: Unified diff