adding XML/XSD support for hashtype attr
This commit is contained in:
		
							parent
							
								
									0c0f6ee81b
								
							
						
					
					
						commit
						af732a1d64
					
				@ -15,14 +15,15 @@ from lxml import etree
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BootSync(object):
 | 
					class BootSync(object):
 | 
				
			||||||
    def __init__(self, cfg = None, *args, **kwargs):
 | 
					    def __init__(self, cfg = None, validate = True, *args, **kwargs):
 | 
				
			||||||
        if not cfg:
 | 
					        if not cfg:
 | 
				
			||||||
            self.cfgfile = '/etc/bootsync.xml'
 | 
					            self.cfgfile = '/etc/bootsync.xml'
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self.cfgfile = os.path.abspath(os.path.expanduser(cfg))
 | 
					            self.cfgfile = os.path.abspath(os.path.expanduser(cfg))
 | 
				
			||||||
        self.ns = '{http://git.square-r00t.net/OpTools/tree/sys/BootSync/}'
 | 
					        self.ns = None
 | 
				
			||||||
        self.cfg = None
 | 
					        self.cfg = None
 | 
				
			||||||
        self.xml = None
 | 
					        self.xml = None
 | 
				
			||||||
 | 
					        self.schema = None
 | 
				
			||||||
        # This is the current live kernel.
 | 
					        # This is the current live kernel.
 | 
				
			||||||
        self.currentKernVer = self._getRunningKernel()
 | 
					        self.currentKernVer = self._getRunningKernel()
 | 
				
			||||||
        # This is the installed kernel from the package manager.
 | 
					        # This is the installed kernel from the package manager.
 | 
				
			||||||
@ -33,15 +34,13 @@ class BootSync(object):
 | 
				
			|||||||
        self.dummy_uuid = None
 | 
					        self.dummy_uuid = None
 | 
				
			||||||
        self.syncs = {}
 | 
					        self.syncs = {}
 | 
				
			||||||
        ##
 | 
					        ##
 | 
				
			||||||
        self.getCfg()
 | 
					        self.getCfg(validate = validate)
 | 
				
			||||||
        self.chkMounts()
 | 
					        self.chkMounts()
 | 
				
			||||||
        self.chkReboot()
 | 
					        self.chkReboot()
 | 
				
			||||||
        self.getHashes()
 | 
					        self.getHashes()
 | 
				
			||||||
        self.getBlkids()
 | 
					        self.getBlkids()
 | 
				
			||||||
        # self.sync()
 | 
					 | 
				
			||||||
        # self.writeConfs()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getCfg(self):
 | 
					    def getCfg(self, validate = True):
 | 
				
			||||||
        if not os.path.isfile(self.cfgfile):
 | 
					        if not os.path.isfile(self.cfgfile):
 | 
				
			||||||
            raise FileNotFoundError('Configuration file {0} does not exist!'.format(self.cfgfile))
 | 
					            raise FileNotFoundError('Configuration file {0} does not exist!'.format(self.cfgfile))
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
@ -53,6 +52,19 @@ class BootSync(object):
 | 
				
			|||||||
            # self.logger.error('{0} is invalid XML'.format(self.cfgfile))
 | 
					            # self.logger.error('{0} is invalid XML'.format(self.cfgfile))
 | 
				
			||||||
            raise ValueError(('{0} does not seem to be valid XML. '
 | 
					            raise ValueError(('{0} does not seem to be valid XML. '
 | 
				
			||||||
                              'See sample.config.xml for an example configuration.').format(self.cfgfile))
 | 
					                              'See sample.config.xml for an example configuration.').format(self.cfgfile))
 | 
				
			||||||
 | 
					        self.ns = self.cfg.nsmap.get(None, 'http://git.square-r00t.net/OpTools/tree/sys/BootSync/')
 | 
				
			||||||
 | 
					        self.ns = '{{{0}}}'.format(self.ns)
 | 
				
			||||||
 | 
					        if validate:
 | 
				
			||||||
 | 
					            if not self.schema:
 | 
				
			||||||
 | 
					                from urllib.request import urlopen
 | 
				
			||||||
 | 
					                xsi = self.cfg.nsmap.get('xsi', 'http://www.w3.org/2001/XMLSchema-instance')
 | 
				
			||||||
 | 
					                schemaLocation = '{{{0}}}schemaLocation'.format(xsi)
 | 
				
			||||||
 | 
					                schemaURL = self.cfg.attrib.get(schemaLocation,
 | 
				
			||||||
 | 
					                                                ('http://git.square-r00t.net/OpTools/plain/sys/BootSync/bootsync.xsd'))
 | 
				
			||||||
 | 
					                with urlopen(schemaURL) as url:
 | 
				
			||||||
 | 
					                    self.schema = url.read()
 | 
				
			||||||
 | 
					            self.schema = etree.XMLSchema(etree.XML(self.schema))
 | 
				
			||||||
 | 
					            self.schema.assertValid(self.xml)
 | 
				
			||||||
        return()
 | 
					        return()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def chkMounts(self):
 | 
					    def chkMounts(self):
 | 
				
			||||||
@ -278,6 +290,11 @@ class BootSync(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def parseArgs():
 | 
					def parseArgs():
 | 
				
			||||||
    args = argparse.ArgumentParser(description = ('Sync files to assist using mdadm RAID arrays with UEFI'))
 | 
					    args = argparse.ArgumentParser(description = ('Sync files to assist using mdadm RAID arrays with UEFI'))
 | 
				
			||||||
 | 
					    args.add_argument('-V', '--no-validate',
 | 
				
			||||||
 | 
					                      dest = 'validate',
 | 
				
			||||||
 | 
					                      action = 'store_false',
 | 
				
			||||||
 | 
					                      help = ('If specified, do not attempt to validate the configuration file (-c/--cfg) against'
 | 
				
			||||||
 | 
					                              'its schema (otherwise it is fetched dynamically and requires network connection)'))
 | 
				
			||||||
    args.add_argument('-c', '--cfg',
 | 
					    args.add_argument('-c', '--cfg',
 | 
				
			||||||
                      dest = 'cfg',
 | 
					                      dest = 'cfg',
 | 
				
			||||||
                      default = '/etc/bootsync.xml',
 | 
					                      default = '/etc/bootsync.xml',
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,28 @@
 | 
				
			|||||||
        </xs:restriction>
 | 
					        </xs:restriction>
 | 
				
			||||||
    </xs:simpleType>
 | 
					    </xs:simpleType>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <xs:simpleType name="hashtype_choice">
 | 
				
			||||||
 | 
					        <xs:restriction base="xs:string">
 | 
				
			||||||
 | 
					            <xs:enumeration value="false"/>
 | 
				
			||||||
 | 
					            <!-- https://docs.python.org/3/library/hashlib.html#hash-algorithms -->
 | 
				
			||||||
 | 
					            <xs:enumeration value="md5"/><!-- Not available on FIPS-compliant Python -->
 | 
				
			||||||
 | 
					            <xs:enumeration value="sha1"/>
 | 
				
			||||||
 | 
					            <xs:enumeration value="sha224"/>
 | 
				
			||||||
 | 
					            <xs:enumeration value="sha256"/>
 | 
				
			||||||
 | 
					            <xs:enumeration value="sha384"/>
 | 
				
			||||||
 | 
					            <xs:enumeration value="sha512"/>
 | 
				
			||||||
 | 
					            <xs:enumeration value="blake2b"/>
 | 
				
			||||||
 | 
					            <xs:enumeration value="blake2s"/>
 | 
				
			||||||
 | 
					            <!-- The below are only available for more recent versions of system's OpenSSL. -->
 | 
				
			||||||
 | 
					            <xs:enumeration value="sha3_224"/>
 | 
				
			||||||
 | 
					            <xs:enumeration value="sha3_256"/>
 | 
				
			||||||
 | 
					            <xs:enumeration value="sha3_384"/>
 | 
				
			||||||
 | 
					            <xs:enumeration value="sha3_512"/>
 | 
				
			||||||
 | 
					            <xs:enumeration value="shake_128"/>
 | 
				
			||||||
 | 
					            <xs:enumeration value="shake_256"/>
 | 
				
			||||||
 | 
					        </xs:restriction>
 | 
				
			||||||
 | 
					    </xs:simpleType>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <xs:element name="bootsync">
 | 
					    <xs:element name="bootsync">
 | 
				
			||||||
        <xs:complexType>
 | 
					        <xs:complexType>
 | 
				
			||||||
            <xs:sequence>
 | 
					            <xs:sequence>
 | 
				
			||||||
@ -56,11 +78,14 @@
 | 
				
			|||||||
                                        <xs:extension base="relpath">
 | 
					                                        <xs:extension base="relpath">
 | 
				
			||||||
                                            <xs:attribute name="isKernel" type="xs:boolean"
 | 
					                                            <xs:attribute name="isKernel" type="xs:boolean"
 | 
				
			||||||
                                                          use="optional" default="false"/>
 | 
					                                                          use="optional" default="false"/>
 | 
				
			||||||
 | 
					                                            <xs:attribute name="hashtype" type="hashtype_choice"
 | 
				
			||||||
 | 
					                                                          use="optional" default="md5"/>
 | 
				
			||||||
                                        </xs:extension>
 | 
					                                        </xs:extension>
 | 
				
			||||||
                                    </xs:simpleContent>
 | 
					                                    </xs:simpleContent>
 | 
				
			||||||
                                </xs:complexType>
 | 
					                                </xs:complexType>
 | 
				
			||||||
                            </xs:element>
 | 
					                            </xs:element>
 | 
				
			||||||
                        </xs:sequence>
 | 
					                        </xs:sequence>
 | 
				
			||||||
 | 
					                        <xs:attribute name="hashtype" type="hashtype_choice" use="optional" default="md5"/>
 | 
				
			||||||
                    </xs:complexType>
 | 
					                    </xs:complexType>
 | 
				
			||||||
                    <xs:unique name="filechk_unique">
 | 
					                    <xs:unique name="filechk_unique">
 | 
				
			||||||
                        <xs:selector xpath="bootsync:file"/>
 | 
					                        <xs:selector xpath="bootsync:file"/>
 | 
				
			||||||
@ -76,9 +101,12 @@
 | 
				
			|||||||
                                    <xs:attribute name="target" type="relpath" use="required"/>
 | 
					                                    <xs:attribute name="target" type="relpath" use="required"/>
 | 
				
			||||||
                                    <!-- TODO: make this optional? -->
 | 
					                                    <!-- TODO: make this optional? -->
 | 
				
			||||||
                                    <xs:attribute name="pattern" type="xs:string" use="required"/>
 | 
					                                    <xs:attribute name="pattern" type="xs:string" use="required"/>
 | 
				
			||||||
 | 
					                                    <xs:attribute name="hashtype" type="hashtype_choice"
 | 
				
			||||||
 | 
					                                                  use="optional" default="md5"/>
 | 
				
			||||||
                                </xs:complexType>
 | 
					                                </xs:complexType>
 | 
				
			||||||
                            </xs:element>
 | 
					                            </xs:element>
 | 
				
			||||||
                        </xs:sequence>
 | 
					                        </xs:sequence>
 | 
				
			||||||
 | 
					                        <xs:attribute name="hashtype" type="hashtype_choice" use="optional" default="md5"/>
 | 
				
			||||||
                    </xs:complexType>
 | 
					                    </xs:complexType>
 | 
				
			||||||
                    <xs:unique name="syncpath_unique_source">
 | 
					                    <xs:unique name="syncpath_unique_source">
 | 
				
			||||||
                        <xs:selector xpath="bootsync:path"/>
 | 
					                        <xs:selector xpath="bootsync:path"/>
 | 
				
			||||||
 | 
				
			|||||||
@ -17,33 +17,72 @@ SEE prep.txt FOR WHAT MUST BE DONE BEFORE RUNNING BOOTSYNC.
 | 
				
			|||||||
        <part path="/dev/sdb1" mount="/mnt/boot1"/>
 | 
					        <part path="/dev/sdb1" mount="/mnt/boot1"/>
 | 
				
			||||||
        <part path="/dev/sdd1" mount="/mnt/boot2"/>
 | 
					        <part path="/dev/sdd1" mount="/mnt/boot2"/>
 | 
				
			||||||
    </partitions>
 | 
					    </partitions>
 | 
				
			||||||
    <!-- If specified, the files in this container are checksummed to determine if a sync is required.
 | 
					    <!--
 | 
				
			||||||
         If fileChecks isn't provided, we will always sync no matter what.
 | 
					         If fileChecks isn't provided, we will still sync syncPaths (which IS required).
 | 
				
			||||||
         These files will be evaluated to and synced to the ESP partitions with the same relative path.
 | 
					         These files will be evaluated to and synced to the ESP partitions with the same relative path.
 | 
				
			||||||
         i.e. (part[@mount])/(file)
 | 
					         i.e. (part[@mount])/(file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         fileChecks[@hashtype] attribute is used to checksum all <file> children,
 | 
				
			||||||
 | 
					         unless they specify their own hashtype attribute (the default is hashtype="md5" for speed optimizations).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         Guaranteed valid hashtype values are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            sha1
 | 
				
			||||||
 | 
					            sha224
 | 
				
			||||||
 | 
					            sha256
 | 
				
			||||||
 | 
					            sha384
 | 
				
			||||||
 | 
					            sha512
 | 
				
			||||||
 | 
					            blake2b
 | 
				
			||||||
 | 
					            blake2s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         If you have a non-FIPS-compliant Python (you very most likely do), the following hashtype is also available:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            md5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         If you have a recent enough OpenSSL (and python3), you have the additional hashtype values available:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            sha3_224
 | 
				
			||||||
 | 
					            sha3_256
 | 
				
			||||||
 | 
					            sha3_384
 | 
				
			||||||
 | 
					            sha3_512
 | 
				
			||||||
 | 
					            shake_128
 | 
				
			||||||
 | 
					            shake_256
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         Additionally, the value "false" is always available to disable hashing for a specific <file> object or to set
 | 
				
			||||||
 | 
					         the default. No checksumming will be done in this case and the file will always be overwritten on every run.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         This is *highly not recommended* for solid-state disks or if you have large files you plan on syncing to
 | 
				
			||||||
 | 
					         the alternate ESPs (e.g. loop-mounted ISO/IMG files).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
         "isKernel" is by default false, but if true it is treated specially to get a kernel version.
 | 
					         "isKernel" is by default false, but if true it is treated specially to get a kernel version.
 | 
				
			||||||
         This is to notify you if a reboot is required. If no <file> item is isKernel="true", no reboot requirement
 | 
					         This is to notify you if a reboot is required. If no <file> item is isKernel="true", no reboot requirement
 | 
				
			||||||
         detection will be done.
 | 
					         detection will be done.
 | 
				
			||||||
         Only *the last* <file> with isKernel="true" listed is used as the kernel identifier. -->
 | 
					         Only *the last* <file> with isKernel="true" listed is used as the kernel identifier.
 | 
				
			||||||
    <fileChecks>
 | 
					    -->
 | 
				
			||||||
        <!-- RELATIVE paths to /boot -->
 | 
					    <fileChecks hashtype="sha1">
 | 
				
			||||||
 | 
					        <!-- RELATIVE paths to /boot on your / mount. -->
 | 
				
			||||||
        <file>initramfs-linux.img</file>
 | 
					        <file>initramfs-linux.img</file>
 | 
				
			||||||
        <file>intel-ucode.img</file>
 | 
					        <file>intel-ucode.img</file>
 | 
				
			||||||
        <file>memtest86+/memtest.bin</file>
 | 
					        <file>memtest86+/memtest.bin</file>
 | 
				
			||||||
        <file isKernel="true">vmlinuz-linux</file>
 | 
					        <file isKernel="true" hashtype="sha512">vmlinuz-linux</file>
 | 
				
			||||||
    </fileChecks>
 | 
					    </fileChecks>
 | 
				
			||||||
    <!-- These are system paths to sync to the ESPs. They are synced recursively.
 | 
					    <!--
 | 
				
			||||||
 | 
					        These are system paths to sync to the ESPs. They are synced recursively.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "hashtype" is also supported for syncPaths and path objects just as the same with fileChecks
 | 
				
			||||||
 | 
					            and file objects (see above).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            "source" should be absolute.
 | 
					            "source" should be absolute.
 | 
				
			||||||
            "target" should be relative (to the ESP mount).
 | 
					            "target" should be relative (to the ESP mount).
 | 
				
			||||||
            "pattern" is a regex to match to restrict *filenames* to sync. Use ".*" for all files. -->
 | 
					            "pattern" is a regex to match to restrict *filenames* to sync. Use ".*" for all files.
 | 
				
			||||||
    <syncPaths>
 | 
					    -->
 | 
				
			||||||
 | 
					    <syncPaths hashtype="sha1">
 | 
				
			||||||
        <!-- For example, these are grub theme files. -->
 | 
					        <!-- For example, these are grub theme files. -->
 | 
				
			||||||
        <path source="/usr/share/grub/themes" target="grub/themes" pattern=".*"/>
 | 
					        <path source="/usr/share/grub/themes" target="grub/themes" pattern=".*"/>
 | 
				
			||||||
        <!-- These are grub modules - specifically, UEFI. -->
 | 
					        <!-- These are grub modules - specifically, UEFI. -->
 | 
				
			||||||
        <path source="/usr/lib/grub/x86_64-efi" target="grub/x86_64-efi" pattern="^.*\.(mod|lst|sh)$"/>
 | 
					        <path source="/usr/lib/grub/x86_64-efi" target="grub/x86_64-efi" pattern="^.*\.(mod|lst|sh)$"/>
 | 
				
			||||||
        <!-- And these are ISO files, in case you're like me and do loop mounting in Grub for rescue situations.
 | 
					        <!-- And these are ISO files, in case you're like me and do loop mounting in Grub for rescue situations.
 | 
				
			||||||
             (e.g. https://wiki.archlinux.org/index.php/Multiboot_USB_drive#Using_GRUB_and_loopback_devices) -->
 | 
					             (e.g. https://wiki.archlinux.org/index.php/Multiboot_USB_drive#Using_GRUB_and_loopback_devices) -->
 | 
				
			||||||
        <path source="/boot/iso" target="iso" pattern="^.*\.(iso|img)$"/>
 | 
					        <path hashtype="false" source="/boot/iso" target="iso" pattern="^.*\.(iso|img)$"/>
 | 
				
			||||||
    </syncPaths>
 | 
					    </syncPaths>
 | 
				
			||||||
</bootsync>
 | 
					</bootsync>
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user