import os
from functools import total_ordering
-from ceph_volume import sys_info
+from ceph_volume import sys_info, process
from ceph_volume.api import lvm
from ceph_volume.util import disk
from ceph_volume.util.constants import ceph_disk_guids
# LVs can have a vg/lv path, while disks will have /dev/sda
self.abspath = path
self.lv_api = None
+ self.vgs = []
self.lvs = []
self.vg_name = None
self.lv_name = None
- self.pvs_api = []
self.disk_api = {}
self.blkid_api = {}
self.sys_api = {}
self._exists = None
self._is_lvm_member = None
self._parse()
- self.available, self.rejected_reasons = self._check_reject_reasons()
+
+ self.available_lvm, self.rejected_reasons_lvm = self._check_lvm_reject_reasons()
+ self.available_raw, self.rejected_reasons_raw = self._check_raw_reject_reasons()
+ self.available = self.available_lvm and self.available_raw
+ self.rejected_reasons = list(set(self.rejected_reasons_lvm +
+ self.rejected_reasons_raw))
+
self.device_id = self._get_device_id()
def __lt__(self, other):
# here, because most likely, we need to use VGs from this PV.
self._is_lvm_member = False
for path in self._get_pv_paths():
- # check if there was a pv created with the
- # name of device
- pvs = lvm.PVolumes().filter(pv_name=path)
- has_vgs = [pv.vg_name for pv in pvs if pv.vg_name]
- if has_vgs:
- self.vgs = list(set(has_vgs))
+ vgs = lvm.get_device_vgs(path)
+ if vgs:
+ self.vgs.extend(vgs)
# a pv can only be in one vg, so this should be safe
- self.vg_name = has_vgs[0]
+ # FIXME: While the above assumption holds, sda1 and sda2
+ # can each host a PV and VG. I think the vg_name property is
+ # actually unused (not 100% sure) and can simply be removed
+ self.vg_name = vgs[0]
self._is_lvm_member = True
- self.pvs_api = pvs
- for pv in pvs:
- if pv.vg_name and pv.lv_uuid:
- lv = lvm.get_lv(vg_name=pv.vg_name, lv_uuid=pv.lv_uuid)
- if lv:
- self.lvs.append(lv)
- else:
- self.vgs = []
+
+ self.lvs.extend(lvm.get_device_lvs(path))
return self._is_lvm_member
def _get_pv_paths(self):
break
return is_member
+ @property
+ def has_bluestore_label(self):
+ out, err, ret = process.call([
+ 'ceph-bluestore-tool', 'show-label',
+ '--dev', self.abspath], verbose_on_failure=False)
+ if ret:
+ return False
+ return True
+
@property
def is_mapper(self):
return self.path.startswith(('/dev/mapper', '/dev/dm-'))
if lv.tags.get("ceph.type") in ["data", "block"]]
return any(osd_ids)
- def _check_reject_reasons(self):
- """
- This checks a number of potential reject reasons for a drive and
- returns a tuple (boolean, list). The first element denotes whether a
- drive is available or not, the second element lists reasons in case a
- drive is not available.
- """
+
+ def _check_generic_reject_reasons(self):
reasons = [
('removable', 1, 'removable'),
('ro', 1, 'read-only'),
]
rejected = [reason for (k, v, reason) in reasons if
self.sys_api.get(k, '') == v]
+ # reject disks small than 5GB
+ if int(self.sys_api.get('size', 0)) < 5368709120:
+ rejected.append('Insufficient space (<5GB)')
if self.is_ceph_disk_member:
rejected.append("Used by ceph-disk")
+ if self.has_bluestore_label:
+ rejected.append('Has BlueStore device label')
+ return rejected
+
+ def _check_lvm_reject_reasons(self):
+ rejected = self._check_generic_reject_reasons()
+ available_vgs = [vg for vg in self.vgs if vg.free >= 5368709120]
+ if self.vgs and not available_vgs:
+ rejected.append('Insufficient space (<5GB) on vgs')
+
+ return len(rejected) == 0, rejected
+
+ def _check_raw_reject_reasons(self):
+ rejected = self._check_generic_reject_reasons()
+ if len(self.vgs) > 0:
+ rejected.append('LVM detected')
return len(rejected) == 0, rejected