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

View File

@ -1,6 +1,7 @@
import uuid
##
from . import _common
import aif.utils
import aif.disk.block as block
import aif.disk.luks as luks
import aif.disk.mdadm as mdadm
@ -105,6 +106,14 @@ class VG(object):
self.xml = vg_xml
self.id = self.xml.attrib('id')
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.pvs = []
# self.tags = []
@ -133,7 +142,7 @@ class VG(object):
# opts.append(_BlockDev.ExtraArg.new('--addtag', t))
_BlockDev.lvm.vgcreate(self.name,
[p.devpath for p in self.pvs],
0,
self.pe_size,
opts)
for p in self.pvs:
p._parseMeta()
@ -190,7 +199,6 @@ class LV(object):
self.xml = lv_xml
self.id = self.xml.attrib('id')
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.pvs = []
if not isinstance(self.vg, VG):
@ -211,6 +219,33 @@ class LV(object):
self.pvs.append(_indexed_pvs[pv_id])
if not self.pvs: # We get all in the VG instead since none were explicitly assigned
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()

def create(self):

View File

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

def _parseMeta(self):
pass # TODO


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?"
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
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>
</luks>
<lvm>
<volumeGroup id="vg1" name="group1">
<volumeGroup id="vg1" name="group1" extentSize="4MiB">
<physicalVolumes>
<pv id="pv1" source="lvm_member1"/>
</physicalVolumes>
<logicalVolumes>
<!-- Default is to add all available PVs in PhysicalVolumes... -->
<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="20%">
<lv id="lv2" name="logical2" size="512MiB">
<!-- 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"/>
</lv>
</logicalVolumes>