i *think* i'm done the gi version of disk.lvm. LVM is such a mess.
This commit is contained in:
parent
fbd1d4b0f3
commit
00e9c546d7
10
aif.xsd
10
aif.xsd
@ -357,7 +357,7 @@
|
|||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:all>
|
<xs:all>
|
||||||
<!-- BEGIN BLOCKDEVICES -->
|
<!-- BEGIN BLOCKDEVICES -->
|
||||||
<xs:element name="blockDevices" minOccurs="1">
|
<xs:element name="blockDevices" minOccurs="0" maxOccurs="1">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence minOccurs="1" maxOccurs="unbounded">
|
<xs:sequence minOccurs="1" maxOccurs="unbounded">
|
||||||
<xs:element name="disk" minOccurs="1" maxOccurs="unbounded">
|
<xs:element name="disk" minOccurs="1" maxOccurs="unbounded">
|
||||||
@ -670,7 +670,7 @@
|
|||||||
<xs:element name="system" maxOccurs="1" minOccurs="1">
|
<xs:element name="system" maxOccurs="1" minOccurs="1">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:all>
|
<xs:all>
|
||||||
<xs:element name="rootPassword" minOccurs="1" maxOccurs="1"
|
<xs:element name="rootPassword" minOccurs="0" maxOccurs="1"
|
||||||
type="aif:t_nixpass"/>
|
type="aif:t_nixpass"/>
|
||||||
<xs:element name="locales" minOccurs="1" maxOccurs="1">
|
<xs:element name="locales" minOccurs="1" maxOccurs="1">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
@ -687,10 +687,10 @@
|
|||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
<xs:element name="users" minOccurs="1" maxOccurs="1">
|
<xs:element name="users" minOccurs="0" maxOccurs="1">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element name="user" minOccurs="0" maxOccurs="unbounded">
|
<xs:element name="user" minOccurs="1" maxOccurs="unbounded">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element name="password" minOccurs="0" maxOccurs="1"
|
<xs:element name="password" minOccurs="0" maxOccurs="1"
|
||||||
@ -728,7 +728,7 @@
|
|||||||
<xs:element name="services" minOccurs="0" maxOccurs="1">
|
<xs:element name="services" minOccurs="0" maxOccurs="1">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element name="service" minOccurs="0" maxOccurs="unbounded">
|
<xs:element name="service" minOccurs="1" maxOccurs="unbounded">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:simpleContent>
|
<xs:simpleContent>
|
||||||
<xs:extension base="aif:t_nonempty">
|
<xs:extension base="aif:t_nonempty">
|
||||||
|
@ -107,12 +107,13 @@ class VG(object):
|
|||||||
self.name = self.xml.attrib('name')
|
self.name = self.xml.attrib('name')
|
||||||
self.lvs = []
|
self.lvs = []
|
||||||
self.pvs = []
|
self.pvs = []
|
||||||
self.tags = []
|
# self.tags = []
|
||||||
for te in self.xml.findall('tags/tag'):
|
# for te in self.xml.findall('tags/tag'):
|
||||||
self.tags.append(te.text)
|
# self.tags.append(te.text)
|
||||||
_common.addBDPlugin('lvm')
|
_common.addBDPlugin('lvm')
|
||||||
self.devpath = self.name
|
self.devpath = self.name
|
||||||
self.info = None
|
self.info = None
|
||||||
|
self.created = False
|
||||||
|
|
||||||
def addPV(self, pvobj):
|
def addPV(self, pvobj):
|
||||||
if not isinstance(pvobj, PV):
|
if not isinstance(pvobj, PV):
|
||||||
@ -128,26 +129,31 @@ class VG(object):
|
|||||||
# FUCK. LVM. You can't *specify* a UUID.
|
# FUCK. LVM. You can't *specify* a UUID.
|
||||||
# u = uuid.uuid4()
|
# u = uuid.uuid4()
|
||||||
# opts.append(_BlockDev.ExtraArg.new('--uuid', str(u)))
|
# opts.append(_BlockDev.ExtraArg.new('--uuid', str(u)))
|
||||||
for t in self.tags:
|
# for t in self.tags:
|
||||||
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,
|
0,
|
||||||
opts)
|
opts)
|
||||||
for p in self.pvs:
|
for p in self.pvs:
|
||||||
p._parseMeta()
|
p._parseMeta()
|
||||||
|
self.created = True
|
||||||
self.updateInfo()
|
self.updateInfo()
|
||||||
return()
|
return()
|
||||||
|
|
||||||
def createLV(self, lv_xml = None):
|
def createLV(self, lv_xml = None):
|
||||||
|
if not self.created:
|
||||||
|
raise RuntimeError('VG must be created before LVs can be added')
|
||||||
# If lv_xml is None, we loop through our own XML.
|
# If lv_xml is None, we loop through our own XML.
|
||||||
if lv_xml:
|
if lv_xml:
|
||||||
lv = LV(lv_xml, self)
|
lv = LV(lv_xml, self)
|
||||||
lv.create()
|
lv.create()
|
||||||
self.lvs.append(lv)
|
# self.lvs.append(lv)
|
||||||
else:
|
else:
|
||||||
for le in self.xml.findall('logicalVolumes/lv'):
|
for le in self.xml.findall('logicalVolumes/lv'):
|
||||||
pass
|
lv = LV(le, self)
|
||||||
|
lv.create()
|
||||||
|
# self.lvs.append(lv)
|
||||||
self.updateInfo()
|
self.updateInfo()
|
||||||
return()
|
return()
|
||||||
|
|
||||||
@ -162,6 +168,8 @@ class VG(object):
|
|||||||
return()
|
return()
|
||||||
|
|
||||||
def updateInfo(self):
|
def updateInfo(self):
|
||||||
|
if not self.created:
|
||||||
|
return()
|
||||||
_info = _BlockDev.lvm.vginfo(self.name)
|
_info = _BlockDev.lvm.vginfo(self.name)
|
||||||
# TODO: parity with lvm_fallback.VG.updateInfo
|
# TODO: parity with lvm_fallback.VG.updateInfo
|
||||||
# key names currently (probably) don't match and need to confirm the information's all present
|
# key names currently (probably) don't match and need to confirm the information's all present
|
||||||
@ -182,11 +190,78 @@ 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
|
self.size = self.xml.attrib('size') # Convert to bytes. Can get max from _BlockDev.lvm.vginfo(<VG>).free TODO
|
||||||
self.vg = vg_obj
|
self.vg = vgobj
|
||||||
|
self.pvs = []
|
||||||
if not isinstance(self.vg, VG):
|
if not isinstance(self.vg, VG):
|
||||||
raise ValueError('vg_obj must be of type aif.disk.lvm.VG')
|
raise ValueError('vgobj must be of type aif.disk.lvm.VG')
|
||||||
_common.addBDPlugin('lvm')
|
_common.addBDPlugin('lvm')
|
||||||
|
self.info = None
|
||||||
|
self.devpath = '/dev/{0}/{1}'.format(self.vg.name, self.name)
|
||||||
|
self.created = False
|
||||||
|
self.updateInfo()
|
||||||
|
self._initLV()
|
||||||
|
|
||||||
self.devpath = None
|
def _initLV(self):
|
||||||
pass
|
self.pvs = []
|
||||||
|
_indexed_pvs = {i.id: i for i in self.vg.pvs}
|
||||||
|
for pe in self.xml.findall('pvMember'):
|
||||||
|
pv_id = pe.attrib('source')
|
||||||
|
if pv_id in _indexed_pvs.keys():
|
||||||
|
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
|
||||||
|
return()
|
||||||
|
|
||||||
|
def create(self):
|
||||||
|
if not self.pvs:
|
||||||
|
raise RuntimeError('Cannot create LV with no associated LVs')
|
||||||
|
opts = [_BlockDev.ExtraArg.new('--reportformat', 'json')]
|
||||||
|
# FUCK. LVM. You can't *specify* a UUID.
|
||||||
|
# u = uuid.uuid4()
|
||||||
|
# opts.append(_BlockDev.ExtraArg.new('--uuid', str(u)))
|
||||||
|
# for t in self.tags:
|
||||||
|
# opts.append(_BlockDev.ExtraArg.new('--addtag', t))
|
||||||
|
_BlockDev.lvm.lvcreate(self.vg.name,
|
||||||
|
self.name,
|
||||||
|
self.size,
|
||||||
|
None,
|
||||||
|
[i.devpath for i in self.pvs],
|
||||||
|
opts)
|
||||||
|
self.vg.lvs.append(self)
|
||||||
|
self.created = True
|
||||||
|
self.updateInfo()
|
||||||
|
self.vg.updateInfo()
|
||||||
|
return()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
_BlockDev.lvm.lvactivate(self.vg.name,
|
||||||
|
self.name,
|
||||||
|
True,
|
||||||
|
None)
|
||||||
|
self.updateInfo()
|
||||||
|
return()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
_BlockDev.lvm.lvdeactivate(self.vg.name,
|
||||||
|
self.name,
|
||||||
|
None)
|
||||||
|
self.updateInfo()
|
||||||
|
return()
|
||||||
|
|
||||||
|
def updateInfo(self):
|
||||||
|
if not self.created:
|
||||||
|
return()
|
||||||
|
_info = _BlockDev.lvm.lvinfo(self.vg.name, self.name)
|
||||||
|
# TODO: parity with lvm_fallback.LV.updateInfo
|
||||||
|
# key names currently (probably) don't match and need to confirm the information's all present
|
||||||
|
info = {}
|
||||||
|
for k in dir(_info):
|
||||||
|
if k.startswith('_'):
|
||||||
|
continue
|
||||||
|
elif k in ('copy',):
|
||||||
|
continue
|
||||||
|
v = getattr(_info, k)
|
||||||
|
info[k] = v
|
||||||
|
self.info = info
|
||||||
|
return()
|
||||||
|
@ -104,11 +104,11 @@ class Array(object):
|
|||||||
self.layout = None # TODO: log.warn?
|
self.layout = None # TODO: log.warn?
|
||||||
else:
|
else:
|
||||||
self.layout = None
|
self.layout = None
|
||||||
self.devname = self.xml.attrib['name']
|
self.name = self.xml.attrib['name']
|
||||||
self.fulldevname = '{0}:{1}'.format(self.homehost, self.devname)
|
self.fullname = '{0}:{1}'.format(self.homehost, self.name)
|
||||||
self.devpath = devpath
|
self.devpath = devpath
|
||||||
if not self.devpath:
|
if not self.devpath:
|
||||||
self.devpath = '/dev/md/{0}'.format(self.devname)
|
self.devpath = '/dev/md/{0}'.format(self.name)
|
||||||
self.updateStatus()
|
self.updateStatus()
|
||||||
self.homehost = homehost
|
self.homehost = homehost
|
||||||
self.members = []
|
self.members = []
|
||||||
@ -128,11 +128,11 @@ class Array(object):
|
|||||||
opts = [_BlockDev.ExtraArg.new('--homehost',
|
opts = [_BlockDev.ExtraArg.new('--homehost',
|
||||||
self.homehost),
|
self.homehost),
|
||||||
_BlockDev.ExtraArg.new('--name',
|
_BlockDev.ExtraArg.new('--name',
|
||||||
self.devname)]
|
self.name)]
|
||||||
if self.layout:
|
if self.layout:
|
||||||
opts.append(_BlockDev.ExtraArg.new('--layout',
|
opts.append(_BlockDev.ExtraArg.new('--layout',
|
||||||
self.layout))
|
self.layout))
|
||||||
_BlockDev.md.create(self.devname,
|
_BlockDev.md.create(self.name,
|
||||||
str(self.level),
|
str(self.level),
|
||||||
[i.devpath for i in self.members],
|
[i.devpath for i in self.members],
|
||||||
0,
|
0,
|
||||||
@ -154,7 +154,7 @@ class Array(object):
|
|||||||
if scan:
|
if scan:
|
||||||
target = None
|
target = None
|
||||||
else:
|
else:
|
||||||
target = self.devname
|
target = self.name
|
||||||
_BlockDev.md.activate(target,
|
_BlockDev.md.activate(target,
|
||||||
[i.devpath for i in self.members], # Ignored if scan mode enabled
|
[i.devpath for i in self.members], # Ignored if scan mode enabled
|
||||||
None,
|
None,
|
||||||
@ -164,12 +164,12 @@ class Array(object):
|
|||||||
return()
|
return()
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
_BlockDev.md.deactivate(self.devname)
|
_BlockDev.md.deactivate(self.name)
|
||||||
self.state = 'disassembled'
|
self.state = 'disassembled'
|
||||||
return()
|
return()
|
||||||
|
|
||||||
def updateStatus(self):
|
def updateStatus(self):
|
||||||
_status = _BlockDev.md.detail(self.devname)
|
_status = _BlockDev.md.detail(self.name)
|
||||||
# TODO: parity with mdadm_fallback.Array.updateStatus
|
# TODO: parity with mdadm_fallback.Array.updateStatus
|
||||||
# key names currently (probably) don't match and need to confirm the information's all present
|
# key names currently (probably) don't match and need to confirm the information's all present
|
||||||
info = {}
|
info = {}
|
||||||
|
@ -158,10 +158,10 @@ class Array(object):
|
|||||||
self.layout = None # TODO: log.warn?
|
self.layout = None # TODO: log.warn?
|
||||||
else:
|
else:
|
||||||
self.layout = None
|
self.layout = None
|
||||||
self.devname = self.xml.attrib['name']
|
self.name = self.xml.attrib['name']
|
||||||
self.devpath = devpath
|
self.devpath = devpath
|
||||||
if not self.devpath:
|
if not self.devpath:
|
||||||
self.devpath = '/dev/md/{0}'.format(self.devname)
|
self.devpath = '/dev/md/{0}'.format(self.name)
|
||||||
self.updateStatus()
|
self.updateStatus()
|
||||||
self.homehost = homehost
|
self.homehost = homehost
|
||||||
self.members = []
|
self.members = []
|
||||||
@ -179,7 +179,7 @@ class Array(object):
|
|||||||
if not self.members:
|
if not self.members:
|
||||||
raise RuntimeError('Cannot create an array with no members')
|
raise RuntimeError('Cannot create an array with no members')
|
||||||
cmd = ['mdadm', '--create',
|
cmd = ['mdadm', '--create',
|
||||||
'--name={0}'.format(self.devname),
|
'--name={0}'.format(self.name),
|
||||||
'--bitmap=internal',
|
'--bitmap=internal',
|
||||||
'--level={0}'.format(self.level),
|
'--level={0}'.format(self.level),
|
||||||
'--metadata={0}'.format(self.metadata),
|
'--metadata={0}'.format(self.metadata),
|
||||||
@ -224,7 +224,7 @@ class Array(object):
|
|||||||
def updateStatus(self):
|
def updateStatus(self):
|
||||||
_info = mdstat.parse()
|
_info = mdstat.parse()
|
||||||
for k, v in _info['devices'].items():
|
for k, v in _info['devices'].items():
|
||||||
if k != self.devname:
|
if k != self.name:
|
||||||
del(_info['devices'][k])
|
del(_info['devices'][k])
|
||||||
self.info = copy.deepcopy(_info)
|
self.info = copy.deepcopy(_info)
|
||||||
return()
|
return()
|
||||||
|
@ -31,15 +31,15 @@
|
|||||||
</disk>
|
</disk>
|
||||||
</blockDevices>
|
</blockDevices>
|
||||||
<!-- "Special" devices are processed *in the order they are specified*. This is important if you wish to
|
<!-- "Special" devices are processed *in the order they are specified*. This is important if you wish to
|
||||||
e.g. layer LUKS on top of LVM - you would specify <lvm> before <luks> and reference the
|
e.g. layer LVM on top of LUKS - you would specify <lvm> before <luks> and reference the
|
||||||
<luksDev id="SOMETHING" ... > as <lvmLogical source="SOMETHING" ... />.
|
<luksDev id="SOMETHING" ... > as <pv source="SOMETHING" ... />.
|
||||||
Of course, a limitation of this is you cannot e.g. first assemble a LUKS volume, then an LVM
|
Of course, a limitation of this is you cannot e.g. first assemble a LUKS volume, then an LVM
|
||||||
group, and then another LUKS volume - so plan accordingly and/or perform this in a <post> script. -->
|
group, and then another LUKS volume - so plan accordingly and/or perform that in
|
||||||
|
a <post> script instead. -->
|
||||||
<luks>
|
<luks>
|
||||||
<luksDev id="luks_secrets" name="secrets" source="secrets1">
|
<luksDev id="luks_secrets" name="secrets" source="secrets1">
|
||||||
<!-- You can assign multiple secrets (or "keys") to a LUKS volume. -->
|
<!-- You can assign multiple secrets (or "keys") to a LUKS volume. -->
|
||||||
<secrets
|
<secrets>
|
||||||
>
|
|
||||||
<!-- A simple passphrase. -->
|
<!-- A simple passphrase. -->
|
||||||
<passphrase>secrets1</passphrase>
|
<passphrase>secrets1</passphrase>
|
||||||
</secrets>
|
</secrets>
|
||||||
@ -63,7 +63,7 @@
|
|||||||
<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. -->
|
<!-- 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="20%">
|
||||||
<pvMember source="pv1"/>
|
<pvMember source="pv1"/>
|
||||||
</lv>
|
</lv>
|
||||||
|
63
examples/most_minimal.xml
Normal file
63
examples/most_minimal.xml
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<aif xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://aif-ng.io/"
|
||||||
|
xsi:schemaLocation="http://aif-ng.io/ http://aif-ng.io/aif.xsd"
|
||||||
|
version="v2_rewrite">
|
||||||
|
<storage>
|
||||||
|
<blockDevices>
|
||||||
|
<disk id="sda" device="auto" diskFormat="gpt">
|
||||||
|
<part id="boot" name="BOOT" start="0%" stop="10%" fsType="fat32">
|
||||||
|
<partitionFlag>esp</partitionFlag>
|
||||||
|
</part>
|
||||||
|
<part id="root" name="root" start="10%" stop="100%" fsType="ext4">
|
||||||
|
<partitionFlag>root</partitionFlag>
|
||||||
|
</part>
|
||||||
|
</disk>
|
||||||
|
</blockDevices>
|
||||||
|
<fileSystems>
|
||||||
|
<fs id="esp" source="boot" type="vfat">
|
||||||
|
<opt name="-F">32</opt>
|
||||||
|
</fs>
|
||||||
|
<fs id="rootfs" type="ext4" source="root"/>
|
||||||
|
</fileSystems>
|
||||||
|
<mountPoints>
|
||||||
|
<mount source="rootfs" target="/mnt/aif/"/>
|
||||||
|
<mount source="esp" target="/mnt/aif/boot"/>
|
||||||
|
</mountPoints>
|
||||||
|
</storage>
|
||||||
|
<network hostname="aiftest.square-r00t.net">
|
||||||
|
<iface device="auto">
|
||||||
|
<addresses>
|
||||||
|
<ipv4>
|
||||||
|
<address>dhcp</address>
|
||||||
|
</ipv4>
|
||||||
|
<ipv6>
|
||||||
|
<address>slaac</address>
|
||||||
|
</ipv6>
|
||||||
|
</addresses>
|
||||||
|
<resolvers>
|
||||||
|
<resolver>4.2.2.1</resolver>
|
||||||
|
<resolver>4.2.2.2</resolver>
|
||||||
|
<resolver>4.2.2.3</resolver>
|
||||||
|
</resolvers>
|
||||||
|
</iface>
|
||||||
|
</network>
|
||||||
|
<system timezone="UTC" chrootPath="/mnt/aif" reboot="1">
|
||||||
|
<locales>
|
||||||
|
<locale name="LANG">en_US.UTF-8</locale>
|
||||||
|
</locales>
|
||||||
|
</system>
|
||||||
|
<pacman>
|
||||||
|
<repos>
|
||||||
|
<repo name="core" enabled="true" sigLevel="default" mirror="file:///etc/pacman.d/mirrorlist"/>
|
||||||
|
<repo name="extra" enabled="true" sigLevel="default" mirror="file:///etc/pacman.d/mirrorlist"/>
|
||||||
|
<repo name="community" enabled="true" sigLevel="default" mirror="file:///etc/pacman.d/mirrorlist"/>
|
||||||
|
<repo name="multilib" enabled="true" sigLevel="default" mirror="file:///etc/pacman.d/mirrorlist"/>
|
||||||
|
</repos>
|
||||||
|
<mirrorList>
|
||||||
|
<mirror>http://arch.mirror.square-r00t.net/$repo/os/$arch</mirror>
|
||||||
|
</mirrorList>
|
||||||
|
</pacman>
|
||||||
|
<bootloader type="grub" target="/boot" efi="true"/>
|
||||||
|
</aif>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user