filesystem and mounting done, other minor tweaks. need to do lvm, mdadm, luks
This commit is contained in:
		
							parent
							
								
									33ea96d1e1
								
							
						
					
					
						commit
						d4de31dd67
					
				
							
								
								
									
										3
									
								
								aif.xsd
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								aif.xsd
									
									
									
									
									
								
							| @ -262,6 +262,7 @@ | ||||
|         </xs:simpleContent> | ||||
|     </xs:complexType> | ||||
| 
 | ||||
|     <!-- TODO: "swap" shouldn't be here. Split off into a different type. --> | ||||
|     <xs:simpleType name="t_filepath"> | ||||
|         <xs:restriction base="xs:string"> | ||||
|             <xs:pattern value="((/[^/]+)+/?|swap)"/> | ||||
| @ -384,6 +385,7 @@ | ||||
|                                                         </xs:complexType> | ||||
|                                                     </xs:element> | ||||
|                                                 </xs:sequence> | ||||
|                                                 <xs:attribute name="id" type="xs:ID" use="required"/> | ||||
|                                                 <xs:attribute name="device" type="aif:t_diskdev" use="required"/> | ||||
|                                                 <xs:attribute name="diskFormat" type="aif:t_diskfmt" use="required"/> | ||||
|                                             </xs:complexType> | ||||
| @ -406,6 +408,7 @@ | ||||
|                                                     <xs:element name="opt" minOccurs="0" maxOccurs="unbounded" | ||||
|                                                                 type="aif:t_cmdopts"/> | ||||
|                                                 </xs:sequence> | ||||
|                                                 <xs:attribute name="id" type="xs:ID" use="required"/> | ||||
|                                                 <xs:attribute name="source" type="xs:IDREF" use="required"/> | ||||
|                                                 <!-- We validate this in-code because there's way too many and | ||||
|                                                      it's way too variable per-host. --> | ||||
|  | ||||
| @ -19,6 +19,44 @@ EXTERNAL_DEPS = ['blkinfo', | ||||
|                  'validators'] | ||||
| # PARTED FLAG INDEXING | ||||
| PARTED_FSTYPES = sorted(list(dict(vars(parted.filesystem))['fileSystemType'].keys())) | ||||
| PARTED_FSTYPES_GUIDS = {'affs0': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'affs1': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'affs2': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'affs3': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'affs4': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'affs5': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'affs6': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'affs7': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'amufs': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'amufs0': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'amufs1': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'amufs2': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'amufs3': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'amufs4': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'amufs5': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'apfs1': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'apfs2': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'asfs': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'btrfs': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'ext2': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'ext3': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'ext4': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'fat16': uuid.UUID(hex = 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7'), | ||||
|                         'fat32': uuid.UUID(hex = 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7'), | ||||
|                         'hfs': uuid.UUID(hex = '48465300-0000-11AA-AA11-00306543ECAC'), | ||||
|                         'hfs+': uuid.UUID(hex = '48465300-0000-11AA-AA11-00306543ECAC'), | ||||
|                         'hfsx': uuid.UUID(hex = '48465300-0000-11AA-AA11-00306543ECAC'), | ||||
|                         'hp-ufs': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'jfs': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'linux-swap(v0)': uuid.UUID(hex = '0657FD6D-A4AB-43C4-84E5-0933C84B4F4F'), | ||||
|                         'linux-swap(v1)': uuid.UUID(hex = '0657FD6D-A4AB-43C4-84E5-0933C84B4F4F'), | ||||
|                         'nilfs2': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'ntfs': uuid.UUID(hex = 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7'), | ||||
|                         'reiserfs': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'sun-ufs': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'swsusp': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4'), | ||||
|                         'udf': uuid.UUID(hex = 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7'), | ||||
|                         'xfs': uuid.UUID(hex = '0FC63DAF-8483-4772-8E79-3D69D8477DE4')} | ||||
| PARTED_FLAGS = sorted(list(parted.partition.partitionFlag.values())) | ||||
| PARTED_IDX_FLAG = dict(parted.partition.partitionFlag) | ||||
| PARTED_FLAG_IDX = {v: k for k, v in PARTED_IDX_FLAG.items()} | ||||
| @ -125,6 +163,7 @@ GPT_FSTYPE_GUIDS = ((1, 'EFI System', uuid.UUID(hex = 'C12A7328-F81F-11D2-BA4B-0 | ||||
|                     (87, 'Plan 9 partition', uuid.UUID(hex = 'C91818F9-8025-47AF-89D2-F030D7000C2C')), | ||||
|                     (88, 'HiFive Unleashed FSBL', uuid.UUID(hex = '5B193300-FC78-40CD-8002-E86C45580B47')), | ||||
|                     (89, 'HiFive Unleashed BBL', uuid.UUID(hex = '2E54B353-1271-4842-806F-E436D6AF6985'))) | ||||
| GPT_GUID_IDX = {k[2]: k[0] for k in GPT_FSTYPE_GUIDS} | ||||
| # MSDOS FSTYPES IDENTIFIERS | ||||
| # Second verse, same as the first - kind of. The msdos type identifers just use a byte identifier rather than UUID. | ||||
| # https://git.kernel.org/pub/scm/utils/util-linux/util-linux.git/plain/include/pt-mbr-partnames.h | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| import re | ||||
| import os | ||||
| import uuid | ||||
| ## | ||||
| import parted | ||||
| import blkinfo | ||||
| import psutil  # Do I need this if I can have libblockdev's mounts API? Is there a way to get current mounts? | ||||
| ## | ||||
| import aif.constants | ||||
| @ -10,7 +11,7 @@ from . import _common | ||||
| 
 | ||||
| _BlockDev = _common.BlockDev | ||||
| 
 | ||||
| 
 | ||||
| # TODO: LOGGING! | ||||
| class Partition(object): | ||||
|     def __init__(self, part_xml, diskobj, start_sector, partnum, tbltype, part_type = None): | ||||
|         # Belive it or not, dear reader, but this *entire method* is just to set attributes. | ||||
| @ -32,7 +33,49 @@ class Partition(object): | ||||
|                 self.part_type = _BlockDev.PartTypeReq.EXTENDED | ||||
|             elif part_type == 'logical': | ||||
|                 self.part_type = _BlockDev.PartTypeReq.LOGICAL | ||||
|         elif tbltype == 'gpt': | ||||
|             self.part_type = _BlockDev.PartTypeReq.NORMAL | ||||
|         self.flags = [] | ||||
|         self.partnum = partnum | ||||
|         self.fs_type = self.xml.attrib['fsType'] | ||||
|         self.disk = diskobj | ||||
|         self.device = self.disk.path | ||||
|         self.devpath = '{0}{1}'.format(self.device, self.partnum) | ||||
|         self.is_hiformatted = False | ||||
|         sizes = {} | ||||
|         for s in ('start', 'stop'): | ||||
|             x = dict(zip(('from_bgn', 'size', 'type'), | ||||
|                          aif.utils.convertSizeUnit(self.xml.attrib[s]))) | ||||
|             sectors = x['size'] | ||||
|             if x['type'] == '%': | ||||
|                 sectors = int(int(self.disk.size / self.disk.sector_size) * (0.01 * x['size'])) | ||||
|             else: | ||||
|                 sectors = int(aif.utils.size.convertStorage(x['size'], | ||||
|                                                             x['type'], | ||||
|                                                             target = 'B') / self.disk.sector_size) | ||||
|             sizes[s] = (sectors, x['from_bgn']) | ||||
|         if sizes['start'][1] is not None: | ||||
|             if sizes['start'][1]: | ||||
|                 self.begin = sizes['start'][0] + 0 | ||||
|             else: | ||||
|                 self.begin = int(self.disk.size / self.disk.sector_size) - sizes['start'][0] | ||||
|         else: | ||||
|             self.begin = sizes['start'][0] + start_sector | ||||
|         if sizes['stop'][1] is not None: | ||||
|             if sizes['stop'][1]: | ||||
|                 self.end = sizes['stop'][0] + 0 | ||||
|             else: | ||||
|                 # This *technically* should be - 34, at least for gpt, but the alignment optimizer fixes it for us. | ||||
|                 self.end = (int(self.disk.size / self.disk.sector_size) - 1) - sizes['stop'][0] | ||||
|         else: | ||||
|             self.end = self.begin + sizes['stop'][0] | ||||
|         self.size = (self.end - self.begin) | ||||
|         self.part_name = self.xml.attrib.get('name') | ||||
|         self.partition = None | ||||
|         self._initFlags() | ||||
|         self._initFstype() | ||||
| 
 | ||||
|     def _initFlags(self): | ||||
|         for f in self.xml.findall('partitionFlag'): | ||||
|             # *Technically* we could use e.g. getattr(_BlockDev.PartFlag, f.text.upper()), *but* we lose compat | ||||
|             # with parted's flags if we do that. :| So we do some funky logic both here and in the constants. | ||||
| @ -43,56 +86,40 @@ class Partition(object): | ||||
|             else: | ||||
|                 continue | ||||
|             self.flags.append(_BlockDev.PartFlag(flag_id)) | ||||
|         self.partnum = partnum | ||||
|         self.fstype = self.xml.attrib['fsType'].lower() | ||||
|         if self.fstype not in aif.constants.PARTED_FSTYPES:  # There isn't a way to do this with BlockDev? :| | ||||
|             raise ValueError(('{0} is not a valid partition filesystem type; ' | ||||
|                               'must be one of: {1}').format(self.xml.attrib['fsType'], | ||||
|                                                             ', '.join(sorted(aif.constants.PARTED_FSTYPES)))) | ||||
|         self.disk = diskobj | ||||
|         self.device = self.disk.path | ||||
|         self.devpath = '{0}{1}'.format(self.device.path, partnum) | ||||
|         self.is_hiformatted = False | ||||
|         sizes = {} | ||||
|         for s in ('start', 'stop'): | ||||
|             x = dict(zip(('from_bgn', 'size', 'type'), | ||||
|                          aif.utils.convertSizeUnit(self.xml.attrib[s]))) | ||||
|             sectors = x['size'] | ||||
|             if x['type'] == '%': | ||||
|                 sectors = int(self.device.getLength() / x['size']) | ||||
|         return() | ||||
| 
 | ||||
|     def _initFstype(self): | ||||
|         _err = ('{0} is not a valid partition filesystem type; ' | ||||
|                 'must be one of {1} or an fdisk-compatible GPT GUID').format( | ||||
|                                                             self.xml.attrib['fsType'], | ||||
|                                                             ', '.join(sorted(aif.constants.PARTED_FSTYPES))) | ||||
|         if self.fs_type in aif.constants.PARTED_FSTYPES_GUIDS.keys(): | ||||
|             self.fs_type = aif.constants.PARTED_FSTYPES_GUIDS[self.fs_type] | ||||
|         else: | ||||
|                 sectors = int(aif.utils.size.convertStorage(x['size'], | ||||
|                                                             x['type'], | ||||
|                                                             target = 'B') / self.device.sectorSize) | ||||
|             sizes[s] = (sectors, x['from_bgn']) | ||||
|         if sizes['start'][1] is not None: | ||||
|             if sizes['start'][1]: | ||||
|                 self.begin = sizes['start'][0] + 0 | ||||
|             else: | ||||
|                 self.begin = self.device.getLength() - sizes['start'][0]  # TODO: is there a way to get this in BD? | ||||
|         else: | ||||
|             self.begin = sizes['start'][0] + start_sector | ||||
|         if sizes['stop'][1] is not None: | ||||
|             if sizes['stop'][1]: | ||||
|                 self.end = sizes['stop'][0] + 0 | ||||
|             else: | ||||
|                 # This *technically* should be - 34, at least for gpt, but the alignment optimizer fixes it for us. | ||||
|                 self.end = (self.device.getLength() - 1) - sizes['stop'][0]  # TODO: is there a way to get this in BD? | ||||
|         else: | ||||
|             self.end = self.begin + sizes['stop'][0] | ||||
|         # TECHNICALLY we could craft the Geometry object with "length = ...", but it doesn't let us be explicit | ||||
|         # in configs. So we manually crunch the numbers and do it all at the end. | ||||
|         # TODO: switch parted objects to BlockDev | ||||
|         # self.geometry = parted.Geometry(device = self.device, | ||||
|         #                                 start = self.begin, | ||||
|         #                                 end = self.end) | ||||
|         # self.filesystem = parted.FileSystem(type = self.fstype, | ||||
|         #                                     geometry = self.geometry) | ||||
|         # self.partition = parted.Partition(disk = diskobj, | ||||
|         #                                   type = self.part_type, | ||||
|         #                                   geometry = self.geometry, | ||||
|         #                                   fs = self.filesystem) | ||||
|         self.part_name = self.xml.attrib.get('name') | ||||
|             try: | ||||
|                 self.fs_type = uuid.UUID(hex = self.fs_type) | ||||
|             except ValueError: | ||||
|                 raise ValueError(_err) | ||||
|             if self.fs_type not in aif.constants.GPT_GUID_IDX.keys(): | ||||
|                 raise ValueError(_err) | ||||
|         return() | ||||
| 
 | ||||
|     def format(self): | ||||
|         # This is a safeguard. We do *not* want to partition a disk that is mounted. | ||||
|         aif.utils.checkMounted(self.devpath) | ||||
|         self.partition = _BlockDev.part.create_part(self.device, | ||||
|                                                     self.part_type, | ||||
|                                                     self.begin, | ||||
|                                                     self.size, | ||||
|                                                     _BlockDev.PartAlign.OPTIMAL) | ||||
|         self.devpath = self.partition.path | ||||
|         _BlockDev.part.set_part_type(self.device, self.devpath, str(self.fs_type).upper()) | ||||
|         if self.part_name: | ||||
|             _BlockDev.part.set_part_name(self.device, self.devpath, self.part_name) | ||||
|         if self.flags: | ||||
|             for f in self.flags: | ||||
|                 _BlockDev.part.set_part_flag(self.device, self.devpath, f, True) | ||||
|         return() | ||||
| 
 | ||||
|     # | ||||
|     # def detect(self): | ||||
| @ -101,34 +128,89 @@ class Partition(object): | ||||
| 
 | ||||
| class Disk(object): | ||||
|     def __init__(self, disk_xml): | ||||
|         # TODO: BlockDev.part.set_disk_flag(<disk>, | ||||
|         #                                   BlockDev.PartDiskFlag(1), | ||||
|         #                                   True) ?? | ||||
|         #   https://lazka.github.io/pgi-docs/BlockDev-2.0/enums.html#BlockDev.PartDiskFlag | ||||
|         #   https://unix.stackexchange.com/questions/325886/bios-gpt-do-we-need-a-boot-flag | ||||
|         self.xml = disk_xml | ||||
|         self.devpath = self.xml.attrib['device'] | ||||
|         self.devpath = os.path.realpath(self.xml.attrib['device']) | ||||
|         aif.disk._common.addBDPlugin('part') | ||||
|         self.is_lowformatted = None | ||||
|         self.is_hiformatted = None | ||||
|         self.is_partitioned = None | ||||
|         self.partitions = None | ||||
|         self._initDisk() | ||||
|         aif.disk._common.addBDPlugin('part') | ||||
| 
 | ||||
|     def _initDisk(self): | ||||
|         pass | ||||
|         if self.devpath == 'auto': | ||||
|             self.devpath = '/dev/{0}'.format(blkinfo.BlkDiskInfo().get_disks()[0]['kname']) | ||||
|         if not os.path.isfile(self.devpath): | ||||
|             raise ValueError('{0} does not exist; please specify an explicit device path'.format(self.devpath)) | ||||
|         self.table_type = self.xml.attrib.get('diskFormat', 'gpt').lower() | ||||
|         if self.table_type in ('bios', 'mbr', 'dos', 'msdos'): | ||||
|             self.table_type = _BlockDev.PartTableType.MSDOS | ||||
|         elif self.table_type == 'gpt': | ||||
|             self.table_type = _BlockDev.PartTableType.GPT | ||||
|         else: | ||||
|             raise ValueError(('Disk format {0} is not valid for this architecture;' | ||||
|                               'must be one of: gpt or msdos'.format(self.table_type))) | ||||
|         self.device = self.disk = _BlockDev.part.get_disk_spec(self.devpath) | ||||
|         self.is_lowformatted = False | ||||
|         self.is_hiformatted = False | ||||
|         self.is_partitioned = False | ||||
|         self.partitions = [] | ||||
|         return() | ||||
| 
 | ||||
|     def diskFormat(self): | ||||
|         pass | ||||
|         if self.is_lowformatted: | ||||
|             return () | ||||
|         # This is a safeguard. We do *not* want to low-format a disk that is mounted. | ||||
|         aif.utils.checkMounted(self.devpath) | ||||
|         # TODO: BlockDev.part.set_disk_flag(<disk>, | ||||
|         #                                   BlockDev.PartDiskFlag(1), | ||||
|         #                                   True) ?? | ||||
|         #   https://lazka.github.io/pgi-docs/BlockDev-2.0/enums.html#BlockDev.PartDiskFlag | ||||
|         #   https://unix.stackexchange.com/questions/325886/bios-gpt-do-we-need-a-boot-flag | ||||
|         _BlockDev.part.create_table(self.devpath, self.table_type, True) | ||||
|         self.is_lowformatted = True | ||||
|         self.is_partitioned = False | ||||
|         return() | ||||
| 
 | ||||
|     def getPartitions(self): | ||||
|         pass | ||||
|         # For GPT, this *technically* should be 34 -- or, more precisely, 2048 (see FAQ in manual), but the alignment | ||||
|         # optimizer fixes it for us automatically. | ||||
|         # But for DOS tables, it's required. | ||||
|         if self.table_type == 'msdos': | ||||
|             start_sector = 2048 | ||||
|         else: | ||||
|             start_sector = 0 | ||||
|         self.partitions = [] | ||||
|         xml_partitions = self.xml.findall('part') | ||||
|         for idx, part in enumerate(xml_partitions): | ||||
|             partnum = idx + 1 | ||||
|             if self.table_type == 'gpt': | ||||
|                 p = Partition(part, self.disk, start_sector, partnum, self.table_type) | ||||
|             else: | ||||
|                 parttype = 'primary' | ||||
|                 if len(xml_partitions) > 4: | ||||
|                     if partnum == 4: | ||||
|                         parttype = 'extended' | ||||
|                     elif partnum > 4: | ||||
|                         parttype = 'logical' | ||||
|                 p = Partition(part, self.disk, start_sector, partnum, self.table_type, part_type = parttype) | ||||
|             start_sector = p.end + 1 | ||||
|             self.partitions.append(p) | ||||
|         return() | ||||
| 
 | ||||
|     def partFormat(self): | ||||
|         pass | ||||
| 
 | ||||
| 
 | ||||
| class Mount(object): | ||||
|     def __init__(self, mount_xml, partobj): | ||||
|         pass | ||||
|         _common.addBDPlugin('fs') | ||||
|         if self.is_partitioned: | ||||
|             return() | ||||
|         if not self.is_lowformatted: | ||||
|             self.diskFormat() | ||||
|         # This is a safeguard. We do *not* want to partition a disk that is mounted. | ||||
|         aif.utils.checkMounted(self.devpath) | ||||
|         if not self.partitions: | ||||
|             self.getPartitions() | ||||
|         if not self.partitions: | ||||
|             return() | ||||
|         for p in self.partitions: | ||||
|             p.format() | ||||
|             p.is_hiformatted = True | ||||
|         self.is_partitioned = True | ||||
|         return () | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| # https://github.com/dcantrell/pyparted/blob/master/examples/query_device_capacity.py | ||||
| # TODO: Remember to replicate genfstab behaviour. | ||||
| 
 | ||||
| import os | ||||
| import re | ||||
| try: | ||||
|     # https://stackoverflow.com/a/34812552/733214 | ||||
| @ -12,6 +13,7 @@ except ImportError: | ||||
|     # We should never get here. util-linux is part of core (base) in Arch and uses "libmount". | ||||
|     import pylibmount as mount | ||||
| ## | ||||
| import blkinfo | ||||
| import parted  # https://www.gnu.org/software/parted/api/index.html | ||||
| import psutil | ||||
| ## | ||||
| @ -48,14 +50,14 @@ class Partition(object): | ||||
|                     self.part_type = parted.PARTITION_LOGICAL | ||||
|         else: | ||||
|             self.part_type = parted.PARTITION_NORMAL | ||||
|         self.fstype = self.xml.attrib['fsType'].lower() | ||||
|         if self.fstype not in aif.constants.PARTED_FSTYPES: | ||||
|         self.fs_type = self.xml.attrib['fsType'].lower() | ||||
|         if self.fs_type not in aif.constants.PARTED_FSTYPES: | ||||
|             raise ValueError(('{0} is not a valid partition filesystem type; ' | ||||
|                               'must be one of: {1}').format(self.xml.attrib['fsType'], | ||||
|                                                             ', '.join(sorted(aif.constants.PARTED_FSTYPES)))) | ||||
|         self.disk = diskobj | ||||
|         self.device = self.disk.device | ||||
|         self.devpath = '{0}{1}'.format(self.device.path, partnum) | ||||
|         self.devpath = '{0}{1}'.format(self.device.path, self.partnum) | ||||
|         self.is_hiformatted = False | ||||
|         sizes = {} | ||||
|         for s in ('start', 'stop'): | ||||
| @ -63,7 +65,7 @@ class Partition(object): | ||||
|                          aif.utils.convertSizeUnit(self.xml.attrib[s]))) | ||||
|             sectors = x['size'] | ||||
|             if x['type'] == '%': | ||||
|                 sectors = int(self.device.getLength() / x['size']) | ||||
|                 sectors = int(self.device.getLength() * (0.01 * x['size'])) | ||||
|             else: | ||||
|                 sectors = int(aif.utils.size.convertStorage(x['size'], | ||||
|                                                             x['type'], | ||||
| @ -89,7 +91,7 @@ class Partition(object): | ||||
|         self.geometry = parted.Geometry(device = self.device, | ||||
|                                         start = self.begin, | ||||
|                                         end = self.end) | ||||
|         self.filesystem = parted.FileSystem(type = self.fstype, | ||||
|         self.filesystem = parted.FileSystem(type = self.fs_type, | ||||
|                                             geometry = self.geometry) | ||||
|         self.partition = parted.Partition(disk = diskobj, | ||||
|                                           type = self.part_type, | ||||
| @ -116,7 +118,8 @@ class Partition(object): | ||||
| class Disk(object): | ||||
|     def __init__(self, disk_xml): | ||||
|         self.xml = disk_xml | ||||
|         self.devpath = self.xml.attrib['device'] | ||||
|         self.id = self.xml.attrib['id'] | ||||
|         self.devpath = os.path.realpath(self.xml.attrib['device']) | ||||
|         self.is_lowformatted = None | ||||
|         self.is_hiformatted = None | ||||
|         self.is_partitioned = None | ||||
| @ -124,15 +127,19 @@ class Disk(object): | ||||
|         self._initDisk() | ||||
| 
 | ||||
|     def _initDisk(self): | ||||
|         self.tabletype = self.xml.attrib.get('diskFormat', 'gpt').lower() | ||||
|         if self.tabletype in ('bios', 'mbr', 'dos'): | ||||
|             self.tabletype = 'msdos' | ||||
|         if self.devpath == 'auto': | ||||
|             self.devpath = '/dev/{0}'.format(blkinfo.BlkDiskInfo().get_disks()[0]['kname']) | ||||
|         if not os.path.isfile(self.devpath): | ||||
|             raise ValueError('{0} does not exist; please specify an explicit device path'.format(self.devpath)) | ||||
|         self.table_type = self.xml.attrib.get('diskFormat', 'gpt').lower() | ||||
|         if self.table_type in ('bios', 'mbr', 'dos'): | ||||
|             self.table_type = 'msdos' | ||||
|         validlabels = parted.getLabels() | ||||
|         if self.tabletype not in validlabels: | ||||
|         if self.table_type not in validlabels: | ||||
|             raise ValueError(('Disk format {0} is not valid for this architecture;' | ||||
|                               'must be one of: {1}'.format(self.tabletype, ', '.join(list(validlabels))))) | ||||
|                               'must be one of: {1}'.format(self.table_type, ', '.join(list(validlabels))))) | ||||
|         self.device = parted.getDevice(self.devpath) | ||||
|         self.disk = parted.freshDisk(self.device, self.tabletype) | ||||
|         self.disk = parted.freshDisk(self.device, self.table_type) | ||||
|         self.is_lowformatted = False | ||||
|         self.is_hiformatted = False | ||||
|         self.is_partitioned = False | ||||
| @ -143,9 +150,7 @@ class Disk(object): | ||||
|         if self.is_lowformatted: | ||||
|             return() | ||||
|         # This is a safeguard. We do *not* want to low-format a disk that is mounted. | ||||
|         for p in psutil.disk_partitions(all = True): | ||||
|             if self.devpath in p: | ||||
|                 raise RuntimeError('{0} is mounted; we are cowardly refusing to low-format it'.format(self.devpath)) | ||||
|         aif.utils.checkMounted(self.devpath) | ||||
|         self.disk.deleteAllPartitions() | ||||
|         self.disk.commit() | ||||
|         self.is_lowformatted = True | ||||
| @ -156,7 +161,7 @@ class Disk(object): | ||||
|         # For GPT, this *technically* should be 34 -- or, more precisely, 2048 (see FAQ in manual), but the alignment | ||||
|         # optimizer fixes it for us automatically. | ||||
|         # But for DOS tables, it's required. | ||||
|         if self.tabletype == 'msdos': | ||||
|         if self.table_type == 'msdos': | ||||
|             start_sector = 2048 | ||||
|         else: | ||||
|             start_sector = 0 | ||||
| @ -164,8 +169,8 @@ class Disk(object): | ||||
|         xml_partitions = self.xml.findall('part') | ||||
|         for idx, part in enumerate(xml_partitions): | ||||
|             partnum = idx + 1 | ||||
|             if self.tabletype == 'gpt': | ||||
|                 p = Partition(part, self.disk, start_sector, partnum, self.tabletype) | ||||
|             if self.table_type == 'gpt': | ||||
|                 p = Partition(part, self.disk, start_sector, partnum, self.table_type) | ||||
|             else: | ||||
|                 parttype = 'primary' | ||||
|                 if len(xml_partitions) > 4: | ||||
| @ -173,7 +178,7 @@ class Disk(object): | ||||
|                         parttype = 'extended' | ||||
|                     elif partnum > 4: | ||||
|                         parttype = 'logical' | ||||
|                 p = Partition(part, self.disk, start_sector, partnum, self.tabletype, part_type = parttype) | ||||
|                 p = Partition(part, self.disk, start_sector, partnum, self.table_type, part_type = parttype) | ||||
|             start_sector = p.end + 1 | ||||
|             self.partitions.append(p) | ||||
|         return() | ||||
| @ -184,9 +189,7 @@ class Disk(object): | ||||
|         if not self.is_lowformatted: | ||||
|             self.diskFormat() | ||||
|         # This is a safeguard. We do *not* want to partition a disk that is mounted. | ||||
|         for p in psutil.disk_partitions(all = True): | ||||
|             if self.devpath in p: | ||||
|                 raise RuntimeError('{0} is mounted; we are cowardly refusing to low-format it'.format(self.devpath)) | ||||
|         aif.utils.checkMounted(self.devpath) | ||||
|         if not self.partitions: | ||||
|             self.getPartitions() | ||||
|         if not self.partitions: | ||||
| @ -198,9 +201,3 @@ class Disk(object): | ||||
|             p.is_hiformatted = True | ||||
|         self.is_partitioned = True | ||||
|         return() | ||||
| 
 | ||||
| 
 | ||||
| class Mount(object): | ||||
|     def __init__(self, mount_xml, partobj): | ||||
|         self.xml = mount_xml | ||||
|         pass | ||||
|  | ||||
| @ -1,3 +1,114 @@ | ||||
| import os | ||||
| import subprocess | ||||
| ## | ||||
| import psutil | ||||
| ## | ||||
| import aif.disk.block as block | ||||
| import aif.disk.luks as luks | ||||
| import aif.disk.lvm as lvm | ||||
| import aif.disk.mdadm as mdadm | ||||
| import aif.utils | ||||
| from . import _common | ||||
| 
 | ||||
| BlockDev = _common.BlockDev | ||||
| _BlockDev = _common.BlockDev | ||||
| 
 | ||||
| 
 | ||||
| FS_FSTYPES = aif.utils.kernelFilesystems() | ||||
| 
 | ||||
| 
 | ||||
| class FS(object): | ||||
|     def __init__(self, fs_xml, sourceobj): | ||||
|         # http://storaged.org/doc/udisks2-api/latest/gdbus-org.freedesktop.UDisks2.Filesystem.html#gdbus-interface-org-freedesktop-UDisks2-Filesystem.top_of_page | ||||
|         # http://storaged.org/doc/udisks2-api/latest/ ? | ||||
|         self.xml = fs_xml | ||||
|         self.id = self.xml.attrib['id'] | ||||
|         if not isinstance(sourceobj, (block.Disk, | ||||
|                                       block.Partition, | ||||
|                                       luks.LUKS, | ||||
|                                       lvm.LV, | ||||
|                                       mdadm.Array)): | ||||
|             raise ValueError(('sourceobj must be of type ' | ||||
|                               'aif.disk.block.Partition, ' | ||||
|                               'aif.disk.luks.LUKS, ' | ||||
|                               'aif.disk.lvm.LV, or' | ||||
|                               'aif.disk.mdadm.Array')) | ||||
|         self.source = sourceobj | ||||
|         self.devpath = sourceobj.devpath | ||||
|         self.formatted = False | ||||
|         self.fstype = self.xml.attrib.get('type') | ||||
|         if self.fstype not in FS_FSTYPES: | ||||
|             raise ValueError('{0} is not a supported filesystem type on this system'.format(self.fstype)) | ||||
| 
 | ||||
|     def format(self): | ||||
|         if self.formatted: | ||||
|             return () | ||||
|         # This is a safeguard. We do *not* want to high-format a disk that is mounted. | ||||
|         aif.utils.checkMounted(self.devpath) | ||||
|         # TODO: Can I format with DBus/gobject-introspection? I feel like I *should* be able to, but BlockDev's fs | ||||
|         #  plugin is *way* too limited in terms of filesystems and UDisks doesn't let you format that high-level. | ||||
|         # TODO! Logging | ||||
|         cmd = ['mkfs', | ||||
|                '-t', self.fstype] | ||||
|         for o in self.xml.findall('opt'): | ||||
|             cmd.append(o.attrib['name']) | ||||
|             if o.text: | ||||
|                 cmd.append(o.text) | ||||
|         cmd.append(self.devpath) | ||||
|         subprocess.run(cmd) | ||||
|         self.formatted = True | ||||
|         return() | ||||
| 
 | ||||
| 
 | ||||
| class Mount(object): | ||||
|     # http://storaged.org/doc/udisks2-api/latest/gdbus-org.freedesktop.UDisks2.Filesystem.html#gdbus-method-org-freedesktop-UDisks2-Filesystem.Mount | ||||
|     def __init__(self, mount_xml, fsobj): | ||||
|         self.xml = mount_xml | ||||
|         if not isinstance(fsobj, FS): | ||||
|             raise ValueError('partobj must be of type aif.disk.filesystem.FS') | ||||
|         _common.addBDPlugin('fs')  # We *could* use the UDisks dbus to mount too, but best to stay within libblockdev. | ||||
|         self.id = self.xml.attrib['id'] | ||||
|         self.fs = fsobj | ||||
|         self.source = self.fs.devpath | ||||
|         self.target = os.path.realpath(self.xml.attrib['target']) | ||||
|         self.opts = {} | ||||
|         for o in self.xml.findall('opt'): | ||||
|             self.opts[o.attrib['name']] = o.text | ||||
|         self.mounted = False | ||||
| 
 | ||||
|     def _parseOpts(self): | ||||
|         opts = [] | ||||
|         for k, v in self.opts.items(): | ||||
|             if v and v is not True:  # Python's boolean determination is weird sometimes. | ||||
|                 opts.append('{0}={1}'.format(k, v)) | ||||
|             else: | ||||
|                 opts.append(k) | ||||
|         return(opts) | ||||
| 
 | ||||
|     def mount(self): | ||||
|         if self.mounted: | ||||
|             return() | ||||
|         os.makedirs(self.target, exist_ok = True) | ||||
|         opts = self._parseOpts() | ||||
|         _BlockDev.fs.mount(self.source, | ||||
|                            self.target, | ||||
|                            self.fs.fstype, | ||||
|                            (','.join(opts) if opts else None)) | ||||
|         self.mounted = True | ||||
|         return() | ||||
| 
 | ||||
|     def unmount(self, lazy = False, force = False): | ||||
|         self.updateMount() | ||||
|         if not self.mounted and not force: | ||||
|             return() | ||||
|         _BlockDev.fs.unmount(self.target, | ||||
|                              lazy, | ||||
|                              force) | ||||
|         self.mounted = False | ||||
|         return() | ||||
| 
 | ||||
|     def updateMount(self): | ||||
|         if self.source in [p.device for p in psutil.disk_partitions(all = True)]: | ||||
|             self.mounted = True | ||||
|         else: | ||||
|             self.mounted = False | ||||
|         return() | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| import os | ||||
| import re | ||||
| import subprocess | ||||
| ## | ||||
| import psutil | ||||
| @ -8,56 +7,26 @@ import aif.disk.block_fallback as block | ||||
| import aif.disk.luks_fallback as luks | ||||
| import aif.disk.lvm_fallback as lvm | ||||
| import aif.disk.mdadm_fallback as mdadm | ||||
| import aif.utils | ||||
| 
 | ||||
| # I wish there was a better way of doing this. | ||||
| # https://unix.stackexchange.com/a/98680 | ||||
| FS_FSTYPES = [] | ||||
| with open('/proc/filesystems', 'r') as fh: | ||||
|     for line in fh.readlines(): | ||||
|         l = [i.strip() for i in line.split()] | ||||
|         if not l: | ||||
|             continue | ||||
|         if len(l) == 1: | ||||
|             FS_FSTYPES.append(l[0]) | ||||
|         else: | ||||
|             FS_FSTYPES.append(l[1]) | ||||
| _mod_dir = os.path.join('/lib/modules', | ||||
|                         os.uname().release, | ||||
|                         'kernel/fs') | ||||
| _strip_mod_suffix = re.compile(r'(?P<fsname>)\.ko(\.(x|g)?z)?$', re.IGNORECASE) | ||||
| try: | ||||
|     for i in os.listdir(_mod_dir): | ||||
|         path = os.path.join(_mod_dir, i) | ||||
|         fs_name = None | ||||
|         if os.path.isdir(path): | ||||
|             fs_name = i | ||||
|         elif os.path.isfile(path): | ||||
|             mod_name = _strip_mod_suffix.search(i) | ||||
|             fs_name = mod_name.group('fsname') | ||||
|         if fs_name: | ||||
|             # The kernel *probably* has autoloading enabled, but in case it doesn't... | ||||
|             # TODO: logging! | ||||
|             if os.getuid() == 0: | ||||
|                 subprocess.run(['modprobe', fs_name]) | ||||
|                 FS_FSTYPES.append(fs_name) | ||||
| except FileNotFoundError: | ||||
|     # We're running on a kernel that doesn't have modules | ||||
|     pass | ||||
| 
 | ||||
| FS_FSTYPES = aif.utils.kernelFilesystems() | ||||
| 
 | ||||
| 
 | ||||
| class FS(object): | ||||
|     def __init__(self, fs_xml, sourceobj): | ||||
|         self.xml = fs_xml | ||||
|         if not isinstance(sourceobj, (aif.disk.block_fallback.Disk, | ||||
|                                       aif.disk.block_fallback.Partition, | ||||
|                                       aif.disk.luks_fallback.LUKS, | ||||
|                                       aif.disk.lvm_fallback.LV, | ||||
|                                       aif.disk.mdadm_fallback.Array)): | ||||
|         if not isinstance(sourceobj, (block.Disk, | ||||
|                                       block.Partition, | ||||
|                                       luks.LUKS, | ||||
|                                       lvm.LV, | ||||
|                                       mdadm.Array)): | ||||
|             raise ValueError(('sourceobj must be of type ' | ||||
|                               'aif.disk.block.Partition, ' | ||||
|                               'aif.disk.luks.LUKS, ' | ||||
|                               'aif.disk.lvm.LV, or' | ||||
|                               'aif.disk.mdadm.Array')) | ||||
|         self.id = self.xml.attrib['id'] | ||||
|         self.source = sourceobj | ||||
|         self.devpath = sourceobj.devpath | ||||
|         self.formatted = False | ||||
| @ -67,10 +36,7 @@ class FS(object): | ||||
|         if self.formatted: | ||||
|             return () | ||||
|         # This is a safeguard. We do *not* want to high-format a disk that is mounted. | ||||
|         for p in psutil.disk_partitions(all = True): | ||||
|             if self.devpath in p: | ||||
|                 raise RuntimeError(('{0} is mounted;' | ||||
|                                     'we are cowardly refusing to apply a filesystem to it').format(self.devpath)) | ||||
|         aif.utils.checkMounted(self.devpath) | ||||
|         # TODO! Logging | ||||
|         cmd = ['mkfs', | ||||
|                '-t', self.fstype] | ||||
| @ -80,5 +46,67 @@ class FS(object): | ||||
|                 cmd.append(o.text) | ||||
|         cmd.append(self.devpath) | ||||
|         subprocess.run(cmd) | ||||
|         self.is_hiformatted = True | ||||
|         self.formatted = True | ||||
|         return() | ||||
| 
 | ||||
| 
 | ||||
| class Mount(object): | ||||
|     def __init__(self, mount_xml, fsobj): | ||||
|         self.xml = mount_xml | ||||
|         self.id = self.xml.attrib['id'] | ||||
|         if not isinstance(fsobj, FS): | ||||
|             raise ValueError('partobj must be of type aif.disk.filesystem.FS') | ||||
|         self.id = self.xml.attrib['id'] | ||||
|         self.fs = fsobj | ||||
|         self.source = self.fs.devpath | ||||
|         self.target = os.path.realpath(self.xml.attrib['target']) | ||||
|         self.opts = {} | ||||
|         for o in self.xml.findall('opt'): | ||||
|             self.opts[o.attrib['name']] = o.text | ||||
|         self.mounted = False | ||||
| 
 | ||||
|     def _parseOpts(self): | ||||
|         opts = [] | ||||
|         for k, v in self.opts.items(): | ||||
|             if v and v is not True:  # Python's boolean determination is weird sometimes. | ||||
|                 opts.append('{0}={1}'.format(k, v)) | ||||
|             else: | ||||
|                 opts.append(k) | ||||
|         return(opts) | ||||
| 
 | ||||
|     def mount(self): | ||||
|         if self.mounted: | ||||
|             return() | ||||
|         os.makedirs(self.target, exist_ok = True) | ||||
|         opts = self._parseOpts() | ||||
|         # TODO: logging | ||||
|         cmd = ['/usr/bin/mount', | ||||
|                '--types', self.fs.fstype] | ||||
|         if opts: | ||||
|             cmd.extend(['--options', ','.join(opts)]) | ||||
|         cmd.extend([self.source, self.target]) | ||||
|         subprocess.run(cmd) | ||||
|         self.mounted = True | ||||
|         return() | ||||
| 
 | ||||
|     def unmount(self, lazy = False, force = False): | ||||
|         self.updateMount() | ||||
|         if not self.mounted and not force: | ||||
|             return() | ||||
|         # TODO: logging | ||||
|         cmd = ['/usr/bin/umount'] | ||||
|         if lazy: | ||||
|             cmd.append('--lazy') | ||||
|         if force: | ||||
|             cmd.append('--force') | ||||
|         cmd.append(self.target) | ||||
|         subprocess.run(cmd) | ||||
|         self.mounted = False | ||||
|         return() | ||||
| 
 | ||||
|     def updateMount(self): | ||||
|         if self.source in [p.device for p in psutil.disk_partitions(all = True)]: | ||||
|             self.mounted = True | ||||
|         else: | ||||
|             self.mounted = False | ||||
|         return() | ||||
|  | ||||
							
								
								
									
										86
									
								
								aif/utils.py
									
									
									
									
									
								
							
							
						
						
									
										86
									
								
								aif/utils.py
									
									
									
									
									
								
							| @ -1,25 +1,14 @@ | ||||
| import os | ||||
| import re | ||||
| import subprocess | ||||
| ## | ||||
| import psutil | ||||
| 
 | ||||
| 
 | ||||
| def hasBin(binary_name): | ||||
|     paths = [] | ||||
|     for p in os.environ.get('PATH', '/usr/bin:/bin').split(':'): | ||||
|         if binary_name in os.listdir(os.path.realpath(p)): | ||||
|             return(os.path.join(p, binary_name)) | ||||
|     return(False) | ||||
| 
 | ||||
| 
 | ||||
| def xmlBool(xmlobj): | ||||
|     # https://bugs.launchpad.net/lxml/+bug/1850221 | ||||
|     if isinstance(xmlobj, bool): | ||||
|         return (xmlobj) | ||||
|     if xmlobj.lower() in ('1', 'true'): | ||||
|         return(True) | ||||
|     elif xmlobj.lower() in ('0', 'false'): | ||||
|         return(False) | ||||
|     else: | ||||
|         return(None) | ||||
| def checkMounted(devpath): | ||||
|     if devpath in [p.device for p in psutil.disk_partitions(all = True)]: | ||||
|         raise RuntimeError('{0} is mounted; we are cowardly refusing to destructive operations on it'.format(devpath)) | ||||
|     return() | ||||
| 
 | ||||
| 
 | ||||
| def collapseKeys(d, keylist = None): | ||||
| @ -45,6 +34,65 @@ def collapseValues(d, vallist = None): | ||||
|     return(vallist) | ||||
| 
 | ||||
| 
 | ||||
| def hasBin(binary_name): | ||||
|     paths = [] | ||||
|     for p in os.environ.get('PATH', '/usr/bin:/bin').split(':'): | ||||
|         if binary_name in os.listdir(os.path.realpath(p)): | ||||
|             return(os.path.join(p, binary_name)) | ||||
|     return(False) | ||||
| 
 | ||||
| 
 | ||||
| def kernelFilesystems(): | ||||
|     # I wish there was a better way of doing this. | ||||
|     # https://unix.stackexchange.com/a/98680 | ||||
|     FS_FSTYPES = ['swap'] | ||||
|     with open('/proc/filesystems', 'r') as fh: | ||||
|         for line in fh.readlines(): | ||||
|             l = [i.strip() for i in line.split()] | ||||
|             if not l: | ||||
|                 continue | ||||
|             if len(l) == 1: | ||||
|                 FS_FSTYPES.append(l[0]) | ||||
|             else: | ||||
|                 FS_FSTYPES.append(l[1]) | ||||
|     _mod_dir = os.path.join('/lib/modules', | ||||
|                             os.uname().release, | ||||
|                             'kernel/fs') | ||||
|     _strip_mod_suffix = re.compile(r'(?P<fsname>)\.ko(\.(x|g)?z)?$', re.IGNORECASE) | ||||
|     try: | ||||
|         for i in os.listdir(_mod_dir): | ||||
|             path = os.path.join(_mod_dir, i) | ||||
|             fs_name = None | ||||
|             if os.path.isdir(path): | ||||
|                 fs_name = i | ||||
|             elif os.path.isfile(path): | ||||
|                 mod_name = _strip_mod_suffix.search(i) | ||||
|                 fs_name = mod_name.group('fsname') | ||||
|             if fs_name: | ||||
|                 # The kernel *probably* has autoloading enabled, but in case it doesn't... | ||||
|                 # TODO: logging! | ||||
|                 if os.getuid() == 0: | ||||
|                     subprocess.run(['modprobe', fs_name]) | ||||
|                     FS_FSTYPES.append(fs_name) | ||||
|     except FileNotFoundError: | ||||
|         # We're running on a kernel that doesn't have modules | ||||
|         pass | ||||
|     FS_FSTYPES = sorted(list(set(FS_FSTYPES))) | ||||
|     return(FS_FSTYPES) | ||||
| 
 | ||||
| 
 | ||||
| def xmlBool(xmlobj): | ||||
|     # https://bugs.launchpad.net/lxml/+bug/1850221 | ||||
|     if isinstance(xmlobj, bool): | ||||
|         return (xmlobj) | ||||
|     if xmlobj.lower() in ('1', 'true'): | ||||
|         return(True) | ||||
|     elif xmlobj.lower() in ('0', 'false'): | ||||
|         return(False) | ||||
|     else: | ||||
|         return(None) | ||||
| 
 | ||||
| 
 | ||||
| class _Sizer(object): | ||||
|     def __init__(self): | ||||
|         # We use different methods for converting between storage and BW, and different multipliers for each subtype. | ||||
| @ -188,6 +236,7 @@ size = _Sizer() | ||||
| 
 | ||||
| 
 | ||||
| # We do this as base level so they aren't compiled on every invocation/instantiation. | ||||
| # Unfortunately it has to be at the bottom so we can call the instantiated _Sizer() class. | ||||
| # parted lib can do SI or IEC. So can we. | ||||
| _pos_re = re.compile((r'^(?P<pos_or_neg>-|\+)?\s*' | ||||
|                       r'(?P<size>[0-9]+)\s*' | ||||
| @ -212,3 +261,4 @@ def convertSizeUnit(pos): | ||||
|     else: | ||||
|         raise ValueError('Invalid size specified: {0}'.format(orig_pos)) | ||||
|     return((from_beginning, _size, amt_type)) | ||||
| 
 | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
|      version="v2_rewrite"><!-- When we release, this should match the tagged release (e.g. 0.2.0) --> | ||||
|     <storage> | ||||
|         <blockDevices> | ||||
|             <disk device="/dev/sda" diskFormat="gpt"> | ||||
|             <disk id="sda" device="/dev/sda" diskFormat="gpt"> | ||||
|                 <!-- Partitions are numbered *in the order they are specified*. --> | ||||
|                 <!-- e.g. "boot" would be /dev/sda1, "secrets1" would be /dev/sda2, etc. --> | ||||
|                 <part id="boot" name="BOOT" label="/boot" start="0%" stop="10%" fsType="fat32"> | ||||
| @ -23,7 +23,7 @@ | ||||
|                 <part id="raid1_d2" start="55%" stop="80%" fsType="ext4"> | ||||
|                     <partitionFlag>raid</partitionFlag> | ||||
|                 </part> | ||||
|                 <part id="swap" start="80%" stop="90%" fsType="linux-swap(v1)"> | ||||
|                 <part id="swapdisk" start="80%" stop="90%" fsType="linux-swap(v1)"> | ||||
|                     <partitionFlag>swap</partitionFlag> | ||||
|                 </part> | ||||
|                 <!-- You can also create a partition with no flags (and not use). --> | ||||
| @ -38,7 +38,8 @@ | ||||
|         <luks> | ||||
|             <luksDev id="luks_secrets" name="secrets" source="secrets1"> | ||||
|                 <!-- You can assign multiple secrets (or "keys") to a LUKS volume. --> | ||||
|                 <secrets> | ||||
|                 <secrets | ||||
|                 > | ||||
|                     <!-- A simple passphrase. --> | ||||
|                     <passphrase>secrets1</passphrase> | ||||
|                 </secrets> | ||||
| @ -77,19 +78,29 @@ | ||||
|             </array> | ||||
|         </mdadm> | ||||
|         <fileSystems> | ||||
|             <fs source="boot" type="vfat"> | ||||
|             <fs id="esp" source="boot" type="vfat"> | ||||
|                 <!-- Supports mkfs arguments. Leave off the filesystem type and device name, obviously; | ||||
|                      those are handled by the above attributes. --> | ||||
|                 <opt name="-F">32</opt> | ||||
|                 <opt name="-n">ESP</opt> | ||||
|             </fs> | ||||
|             <fs source="luks_secrets" type="ext4"> | ||||
|             <fs id="luks" source="luks_secrets" type="ext4"> | ||||
|                 <opt name="-L">seekrit</opt> | ||||
|             </fs> | ||||
|             <fs  id="swap" source="swap" type="swap"/> | ||||
|             <fs id="vg1-lv1" source="lv1" type="ext4"/> | ||||
|             <fs id="mdraid" source="mdadm1" type="ext4"/> | ||||
|         </fileSystems> | ||||
|         <mountPoints> | ||||
|             <!-- And you use the id to reference mountpoints as well. --> | ||||
|             <mount source="luks_secrets" target="/mnt/aif"> | ||||
|             <!-- And you use the id to reference mountpoints as well. Important to note, we mount *filesystems*, | ||||
|                  not partitions/disks/etc. --> | ||||
|             <!-- Note that targets should be *outside* of the chroot! | ||||
|                  e.g. /aif/storage/mountPoints[@target="/mnt/aif/boot"] | ||||
|                       and | ||||
|                       /aif/system[@chrootPath="/mnt/aif"] | ||||
|                       would lead to the filesystem being accessible *inside* the chroot (and thus the completed install) | ||||
|                       at /boot. --> | ||||
|             <mount source="luks" target="/mnt/aif"> | ||||
|                 <opt name="rw"/> | ||||
|                 <opt name="relatime"/> | ||||
|                 <opt name="compress">lzo</opt> | ||||
| @ -98,10 +109,10 @@ | ||||
|                 <opt name="subvolid">5</opt> | ||||
|                 <opt name="subvol">/</opt> | ||||
|             </mount> | ||||
|             <mount source="boot" target="/mnt/aif/boot"/> | ||||
|             <mount source="esp" target="/mnt/aif/boot"/> | ||||
|             <mount source="swap" target="swap"/> | ||||
|             <mount source="lv1" target="/mnt/aif/mnt/pool"/> | ||||
|             <mount source="mdadm1" target="/mnt/aif/mnt/raid"/> | ||||
|             <mount source="vg1-lv1" target="/mnt/aif/mnt/pool"/> | ||||
|             <mount source="mdraid" target="/mnt/aif/mnt/raid"/> | ||||
|         </mountPoints> | ||||
|     </storage> | ||||
|     <network hostname="aiftest.square-r00t.net"> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 brent s
						brent s