Beispiel #1
0
 def testBoundarySizeCases(self):
     medpv1 = self._MED_PV.Copy()
     medpv2 = self._MED_PV.Copy()
     (errmsgs, (small, big)) = utils.LvmExclusiveCheckNodePvs(
         [medpv1, medpv2, self._MED_PV])
     self.assertFalse(errmsgs)
     self.assertEqual(small, self._MED_PV.size)
     self.assertEqual(big, self._MED_PV.size)
     # Just within the margins
     medpv1.size = self._MED_PV.size * (1 - constants.PART_MARGIN +
                                        self._EPS)
     medpv2.size = self._MED_PV.size * (1 + constants.PART_MARGIN -
                                        self._EPS)
     (errmsgs, (small, big)) = utils.LvmExclusiveCheckNodePvs(
         [medpv1, medpv2, self._MED_PV])
     self.assertFalse(errmsgs)
     self.assertEqual(small, medpv1.size)
     self.assertEqual(big, medpv2.size)
     # Just outside the margins
     medpv1.size = self._MED_PV.size * (1 - constants.PART_MARGIN -
                                        self._EPS)
     medpv2.size = self._MED_PV.size * (1 + constants.PART_MARGIN)
     (errmsgs, (small, big)) = utils.LvmExclusiveCheckNodePvs(
         [medpv1, medpv2, self._MED_PV])
     self.assertTrue(errmsgs)
     self.assertEqual(small, medpv1.size)
     self.assertEqual(big, medpv2.size)
     medpv1.size = self._MED_PV.size * (1 - constants.PART_MARGIN)
     medpv2.size = self._MED_PV.size * (1 + constants.PART_MARGIN +
                                        self._EPS)
     (errmsgs, (small, big)) = utils.LvmExclusiveCheckNodePvs(
         [medpv1, medpv2, self._MED_PV])
     self.assertTrue(errmsgs)
     self.assertEqual(small, medpv1.size)
     self.assertEqual(big, medpv2.size)
Beispiel #2
0
 def testEqualPvs(self):
     (errmsgs, (small,
                big)) = utils.LvmExclusiveCheckNodePvs([self._MED_PV] * 2)
     self.assertFalse(errmsgs)
     self.assertEqual(small, self._MED_PV.size)
     self.assertEqual(big, self._MED_PV.size)
     (errmsgs, (small,
                big)) = utils.LvmExclusiveCheckNodePvs([self._SMALL_PV] * 3)
     self.assertFalse(errmsgs)
     self.assertEqual(small, self._SMALL_PV.size)
     self.assertEqual(big, self._SMALL_PV.size)
Beispiel #3
0
 def testTooDifferentPvs(self):
     (errmsgs,
      (small,
       big)) = utils.LvmExclusiveCheckNodePvs([self._MED_PV, self._BIG_PV])
     self.assertEqual(len(errmsgs), 1)
     self.assertEqual(small, self._MED_PV.size)
     self.assertEqual(big, self._BIG_PV.size)
     (errmsgs, (small, big)) = utils.LvmExclusiveCheckNodePvs(
         [self._MED_PV, self._SMALL_PV])
     self.assertEqual(len(errmsgs), 1)
     self.assertEqual(small, self._SMALL_PV.size)
     self.assertEqual(big, self._MED_PV.size)
Beispiel #4
0
def CheckNodePVs(nresult, exclusive_storage):
    """Check node PVs.

  """
    pvlist_dict = nresult.get(constants.NV_PVLIST, None)
    if pvlist_dict is None:
        return (["Can't get PV list from node"], None)
    pvlist = map(objects.LvmPvInfo.FromDict, pvlist_dict)
    errlist = []
    # check that ':' is not present in PV names, since it's a
    # special character for lvcreate (denotes the range of PEs to
    # use on the PV)
    for pv in pvlist:
        if ":" in pv.name:
            errlist.append("Invalid character ':' in PV '%s' of VG '%s'" %
                           (pv.name, pv.vg_name))
    es_pvinfo = None
    if exclusive_storage:
        (errmsgs, es_pvinfo) = utils.LvmExclusiveCheckNodePvs(pvlist)
        errlist.extend(errmsgs)
        shared_pvs = nresult.get(constants.NV_EXCLUSIVEPVS, None)
        if shared_pvs:
            for (pvname, lvlist) in shared_pvs:
                # TODO: Check that LVs are really unrelated (snapshots, DRBD meta...)
                errlist.append("PV %s is shared among unrelated LVs (%s)" %
                               (pvname, utils.CommaJoin(lvlist)))
    return (errlist, es_pvinfo)
Beispiel #5
0
 def testOnePv(self):
     (errmsgs, (small,
                big)) = utils.LvmExclusiveCheckNodePvs([self._MED_PV])
     self.assertFalse(errmsgs)
     self.assertEqual(small, self._MED_PV.size)
     self.assertEqual(big, self._MED_PV.size)
Beispiel #6
0
  def Create(cls, unique_id, children, size, spindles, params, excl_stor,
             dyn_params, **kwargs):
    """Create a new logical volume.

    """
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
      raise errors.ProgrammerError("Invalid configuration data %s" %
                                   str(unique_id))
    vg_name, lv_name = unique_id
    cls._ValidateName(vg_name)
    cls._ValidateName(lv_name)
    pvs_info = cls.GetPVInfo([vg_name])
    if not pvs_info:
      if excl_stor:
        msg = "No (empty) PVs found"
      else:
        msg = "Can't compute PV info for vg %s" % vg_name
      base.ThrowError(msg)
    pvs_info.sort(key=(lambda pv: pv.free), reverse=True)

    pvlist = [pv.name for pv in pvs_info]
    if compat.any(":" in v for v in pvlist):
      base.ThrowError("Some of your PVs have the invalid character ':' in their"
                      " name, this is not supported - please filter them out"
                      " in lvm.conf using either 'filter' or 'preferred_names'")

    current_pvs = len(pvlist)
    desired_stripes = params[constants.LDP_STRIPES]
    stripes = min(current_pvs, desired_stripes)

    if excl_stor:
      if spindles is None:
        base.ThrowError("Unspecified number of spindles: this is required"
                        "when exclusive storage is enabled, try running"
                        " gnt-cluster repair-disk-sizes")
      (err_msgs, _) = utils.LvmExclusiveCheckNodePvs(pvs_info)
      if err_msgs:
        for m in err_msgs:
          logging.warning(m)
      req_pvs = cls._ComputeNumPvs(size, pvs_info)
      if spindles < req_pvs:
        base.ThrowError("Requested number of spindles (%s) is not enough for"
                        " a disk of %d MB (at least %d spindles needed)",
                        spindles, size, req_pvs)
      else:
        req_pvs = spindles
      pvlist = cls._GetEmptyPvNames(pvs_info, req_pvs)
      current_pvs = len(pvlist)
      if current_pvs < req_pvs:
        base.ThrowError("Not enough empty PVs (spindles) to create a disk of %d"
                        " MB: %d available, %d needed",
                        size, current_pvs, req_pvs)
      assert current_pvs == len(pvlist)
      # We must update stripes to be sure to use all the desired spindles
      stripes = current_pvs
      if stripes > desired_stripes:
        # Don't warn when lowering stripes, as it's no surprise
        logging.warning("Using %s stripes instead of %s, to be able to use"
                        " %s spindles", stripes, desired_stripes, current_pvs)

    else:
      if stripes < desired_stripes:
        logging.warning("Could not use %d stripes for VG %s, as only %d PVs are"
                        " available.", desired_stripes, vg_name, current_pvs)
      free_size = sum([pv.free for pv in pvs_info])
      # The size constraint should have been checked from the master before
      # calling the create function.
      if free_size < size:
        base.ThrowError("Not enough free space: required %s,"
                        " available %s", size, free_size)

    # If the free space is not well distributed, we won't be able to
    # create an optimally-striped volume; in that case, we want to try
    # with N, N-1, ..., 2, and finally 1 (non-stripped) number of
    # stripes
    cmd = ["lvcreate", "-L%dm" % size, "-n%s" % lv_name]
    for stripes_arg in range(stripes, 0, -1):
      result = utils.RunCmd(cmd + ["-i%d" % stripes_arg] + [vg_name] + pvlist)
      if not result.failed:
        break
    if result.failed:
      base.ThrowError("LV create failed (%s): %s",
                      result.fail_reason, result.output)
    return LogicalVolume(unique_id, children, size, params,
                         dyn_params, **kwargs)