gi lvm done; added better size support and ability to specify PE size

This commit is contained in:
brent s 2019-11-07 19:42:43 -05:00
parent 00e9c546d7
commit b633b22f59
5 changed files with 78 additions and 9 deletions

25
aif.xsd
View File

@ -30,6 +30,25 @@
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>


<xs:simpleType name="t_lvsize">
<!-- This is *basically* t_disksize except we don't want +/-. -->
<!-- If no suffix is provided, we assume the size is in *extents* instead of sectors like above. -->
<xs:restriction base="xs:string">
<xs:pattern value="\s*([0-9]+)\s*(%|((k|Ki)|[MGTPEZY]i?)?B?|)\s*"/>
<xs:whiteSpace value="collapse"/>
</xs:restriction>
</xs:simpleType>

<xs:simpleType name="t_pesize">
<!-- This is *basically* t_lvsize except we don't allow percentages. -->
<!-- If no suffix is provided, we assume the size is in sectors
UNLESS it's "0", which means use the default (which I *think* is dynamically generated). -->
<xs:restriction base="xs:string">
<xs:pattern value="\s*([0-9]+)\s*(((k|Ki)|[MGTPEZY]i?)?B?|)\s*"/>
<xs:whiteSpace value="collapse"/>
</xs:restriction>
</xs:simpleType>

<xs:simpleType name="t_fstype"> <xs:simpleType name="t_fstype">
<xs:union> <xs:union>
<xs:simpleType> <xs:simpleType>
@ -492,7 +511,8 @@
<xs:complexType> <xs:complexType>
<xs:sequence minOccurs="0" <xs:sequence minOccurs="0"
maxOccurs="unbounded"> maxOccurs="unbounded">
<xs:element name="pvMember" minOccurs="1" maxOccurs="unbounded"> <xs:element name="pvMember" minOccurs="1"
maxOccurs="unbounded">
<xs:complexType> <xs:complexType>
<xs:attribute name="source" <xs:attribute name="source"
use="required" use="required"
@ -504,7 +524,7 @@
use="required"/> use="required"/>
<xs:attribute name="name" type="aif:t_nonempty" <xs:attribute name="name" type="aif:t_nonempty"
use="required"/> use="required"/>
<xs:attribute name="size" type="aif:t_disksize" <xs:attribute name="size" type="aif:t_lvsize"
use="required"/> use="required"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
@ -514,6 +534,7 @@
</xs:all> </xs:all>
<xs:attribute name="id" type="xs:ID" use="required"/> <xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="name" type="aif:t_nonempty" use="required"/> <xs:attribute name="name" type="aif:t_nonempty" use="required"/>
<xs:attribute name="extentSize" type="aif:t_pesize" use="optional" default="0"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
</xs:sequence> </xs:sequence>

View File

@ -1,6 +1,7 @@
import uuid import uuid
## ##
from . import _common from . import _common
import aif.utils
import aif.disk.block as block import aif.disk.block as block
import aif.disk.luks as luks import aif.disk.luks as luks
import aif.disk.mdadm as mdadm import aif.disk.mdadm as mdadm
@ -105,6 +106,14 @@ class VG(object):
self.xml = vg_xml self.xml = vg_xml
self.id = self.xml.attrib('id') self.id = self.xml.attrib('id')
self.name = self.xml.attrib('name') self.name = self.xml.attrib('name')
self.pe_size = self.xml.attrib.get('extentSize', 0)
if self.pe_size:
x = dict(zip(('from_bgn', 'size', 'type'),
aif.utils.convertSizeUnit(self.pe_size)))
if x['type']:
self.pe_size = aif.utils.size.convertStorage(self.pe_size,
x['type'],
target = 'B')
self.lvs = [] self.lvs = []
self.pvs = [] self.pvs = []
# self.tags = [] # self.tags = []
@ -133,7 +142,7 @@ class VG(object):
# opts.append(_BlockDev.ExtraArg.new('--addtag', t)) # opts.append(_BlockDev.ExtraArg.new('--addtag', t))
_BlockDev.lvm.vgcreate(self.name, _BlockDev.lvm.vgcreate(self.name,
[p.devpath for p in self.pvs], [p.devpath for p in self.pvs],
0, self.pe_size,
opts) opts)
for p in self.pvs: for p in self.pvs:
p._parseMeta() p._parseMeta()
@ -190,7 +199,6 @@ class LV(object):
self.xml = lv_xml self.xml = lv_xml
self.id = self.xml.attrib('id') self.id = self.xml.attrib('id')
self.name = self.xml.attrib('name') self.name = self.xml.attrib('name')
self.size = self.xml.attrib('size') # Convert to bytes. Can get max from _BlockDev.lvm.vginfo(<VG>).free TODO
self.vg = vgobj self.vg = vgobj
self.pvs = [] self.pvs = []
if not isinstance(self.vg, VG): if not isinstance(self.vg, VG):
@ -211,6 +219,33 @@ class LV(object):
self.pvs.append(_indexed_pvs[pv_id]) self.pvs.append(_indexed_pvs[pv_id])
if not self.pvs: # We get all in the VG instead since none were explicitly assigned if not self.pvs: # We get all in the VG instead since none were explicitly assigned
self.pvs = self.vg.pvs self.pvs = self.vg.pvs
# Size processing. We have to do this after indexing PVs.
# TODO: allow specify PE size (t_lvsize? as well?)?
# If not x['type'], assume *extents*, not sectors
self.size = self.xml.attrib('size') # Convert to bytes. Can get max from _BlockDev.lvm.vginfo(<VG>).free TODO
x = dict(zip(('from_bgn', 'size', 'type'),
aif.utils.convertSizeUnit(self.xml.attrib['size'])))
# self.size is bytes
self.size = x['size']
_extents = {'size': self.vg.info['extent_size'],
'total': 0} # We can't use self.vg.info['extent_count'] because selective PVs.
_sizes = {'total': 0,
'free': 0}
_vg_pe = self.vg.info['extent_size']
for pv in self.pvs:
_sizes['total'] += pv.info['pv_size']
_sizes['free'] += pv.info['pv_free']
_extents['total'] += int(pv.info['pv_size'] / _extents['size'])
if x['type'] == '%':
self.size = int(_sizes['total'] * (0.01 * self.size))
elif x['type'] is None:
self.size = int(self.size * _extents['size'])
else:
self.size = int(aif.utils.size.convertStorage(x['size'],
x['type'],
target = 'B'))
if self.size >= _sizes['total']:
self.size = 0
return() return()


def create(self): def create(self):

View File

@ -20,9 +20,13 @@ class PV(object):
'aif.disk.block.Partition, ' 'aif.disk.block.Partition, '
'aif.disk.luks.LUKS, or' 'aif.disk.luks.LUKS, or'
'aif.disk.mdadm.Array')) 'aif.disk.mdadm.Array'))
# TODO
self.devpath = self.device.devpath self.devpath = self.device.devpath
pass self.is_pooled = False
self.meta = None
self._parseMeta()

def _parseMeta(self):
pass # TODO




class LV(object): class LV(object):

View File

@ -558,6 +558,12 @@ TL;DR: "It's the safest way to make sure your disk doesn't suffer massive degrad
=== "Why isn't my last GPT partition extending to the last sector?" === "Why isn't my last GPT partition extending to the last sector?"
See above. See above.


=== "Why do partitions take `start`/`stop` attributes but LVs take `size`?"
Using `start`/`stop` attributes makes sense for disk partitions because they operate on actual geometry (positions on-disk); that is, this lets you create a "gap" between partitions on the disk which can be helpful if you want to do any modifications to the partition table afterwards (this is also why partitions are processed in the order they're specified).

LVM (LVs, in particular), however, aren't consecutive. There *is* no concept of a "start" and "stop" for an LV; LVM uses chunks called "(physical) extents" rather than sectors, and VGs don't have geometry since they're essentially a pool of blocks. This is also why the modifiers like `-` and `+` aren't allowed for LV sizes - they're position-based.


== Bug Reports/Feature Requests == Bug Reports/Feature Requests
NOTE: It is possible to submit a bug or feature request without registering in my bugtracker. One of my pet peeves is needing to create an account/register on a bugtracker simply to report a bug! The following links only require an email address to file a bug (which is necessary in case I need any further clarification from you or to keep you updated on the status of the bug/feature request -- so please be sure to use a valid email address). NOTE: It is possible to submit a bug or feature request without registering in my bugtracker. One of my pet peeves is needing to create an account/register on a bugtracker simply to report a bug! The following links only require an email address to file a bug (which is necessary in case I need any further clarification from you or to keep you updated on the status of the bug/feature request -- so please be sure to use a valid email address).



View File

@ -56,15 +56,18 @@
</luksDev> </luksDev>
</luks> </luks>
<lvm> <lvm>
<volumeGroup id="vg1" name="group1"> <volumeGroup id="vg1" name="group1" extentSize="4MiB">
<physicalVolumes> <physicalVolumes>
<pv id="pv1" source="lvm_member1"/> <pv id="pv1" source="lvm_member1"/>
</physicalVolumes> </physicalVolumes>
<logicalVolumes> <logicalVolumes>
<!-- Default is to add all available PVs in PhysicalVolumes... --> <!-- Default is to add all available PVs in PhysicalVolumes... -->
<lv id="lv1" name="logical1" size="80%"/> <lv id="lv1" name="logical1" size="80%"/>
<!-- But you can also explicitly designate them. They have to still be in the same volumeGroup though. --> <lv id="lv2" name="logical2" size="512MiB">
<lv id="lv2" name="logical2" size="20%"> <!-- But you can also explicitly designate them. They have to still be in the same volumeGroup.
This is generally speaking a *terrible* idea, though, because it makes getting the
sizes right virtually *impossible*. If you do this, you should consistently ONLY use
bytes for each LV size and know the size of the PVs/VGs ahead of time. -->
<pvMember source="pv1"/> <pvMember source="pv1"/>
</lv> </lv>
</logicalVolumes> </logicalVolumes>