gi lvm done; added better size support and ability to specify PE size
This commit is contained in:
parent
00e9c546d7
commit
b633b22f59
25
aif.xsd
25
aif.xsd
@ -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>
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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).
|
||||
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user