diff --git a/bdisk/bdisk.xsd b/bdisk/bdisk.xsd index 2ce20e5..e54c4e1 100644 --- a/bdisk/bdisk.xsd +++ b/bdisk/bdisk.xsd @@ -3,9 +3,247 @@ targetNamespace="http://bdisk.square-r00t.net/" xmlns="http://bdisk.square-r00t.net/" elementFormDefault="qualified"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -23,8 +261,9 @@ - + + + @@ -33,8 +272,12 @@ - + + + + + + @@ -43,6 +286,7 @@ + @@ -57,10 +301,30 @@ - + + + + + + + + + + + + + + + + + + - + @@ -114,29 +378,427 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bdisk/confgen.py b/bdisk/confgen.py index 5b10e2e..c6e8ed0 100755 --- a/bdisk/confgen.py +++ b/bdisk/confgen.py @@ -4,7 +4,7 @@ # Go figure. import confparse -import crypt +import datetime import getpass import os import utils @@ -134,7 +134,12 @@ class ConfGenerator(object): self.cfg = c.xml self.append = True else: - self.cfg = lxml.etree.Element('bdisk') + _ns = {None: 'http://bdisk.square-r00t.net/', + 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'} + _xsi = { + '{http://www.w3.org/2001/XMLSchema-instance}schemaLocation': + 'http://bdisk.square-r00t.net bdisk.xsd'} + self.cfg = lxml.etree.Element('bdisk', nsmap = _ns, attrib = _xsi) self.append = False self.profile = lxml.etree.Element('profile') self.cfg.append(self.profile) @@ -155,6 +160,13 @@ class ConfGenerator(object): self.get_pki() self.get_gpg() self.get_sync() + # TODO: make this more specific (script? gui? web? etc.) + # and append comment to bdisk element + _comment = lxml.etree.Comment( + 'Generated {0} by BDisk configuration generator'.format( + str(datetime.datetime.now()) + ) + ) except KeyboardInterrupt: exit('\n\nCaught KeyboardInterrupt; quitting...') return() @@ -472,7 +484,7 @@ class ConfGenerator(object): print('Invalid selection. Starting over.') continue chksum.attrib['hash_algo'] = checksum_type - chksum.attrib['explicit'] = "no" + chksum.attrib['explicit'] = "false" chksum.text = checksum['full_url'] else: # Maybe it's a digest string. @@ -505,7 +517,7 @@ class ConfGenerator(object): continue else: checksum_type = checksum_type[0] - chksum.attrib['explicit'] = "yes" + chksum.attrib['explicit'] = "true" chksum.text = checksum chksum.attrib['hash_algo'] = checksum_type print('\n++ SOURCES || {0} || GPG ++'.format(arch.upper())) @@ -597,7 +609,7 @@ class ConfGenerator(object): usage = ( '{0} for yes, {1} for no...\n')) if _chk_optimizations: - build.attrib['its_full_of_stars'] = 'yes' + build.attrib['its_full_of_stars'] = 'true' print('\n++ BUILD || PATHS ++') # Thankfully, we can simplify a lot of this. _dir_strings = {'base': ('the base directory (used for files that are ' @@ -678,9 +690,9 @@ class ConfGenerator(object): self.profile.append(iso) # We have more than one arch, so we need to ask how they want to handle # it. - _ma_strings = {'yes': ('a multi-arch ISO (both architectures on one ' + _ma_strings = {'true': ('a multi-arch ISO (both architectures on one ' 'ISO)'), - 'no': ('separate image files for ' + 'false': ('separate image files for ' '{0}').format(' and '.join(_arches))} for a in _arches: _ma_strings[a] = 'only build an image file for {0}'.format(a) @@ -712,7 +724,7 @@ class ConfGenerator(object): 'option to configure it a bit later).\nWould you like to sign ' 'the ISO/USB image files with GPG?\n'), usage = ( '{0} for yes, {1} for no...\n')) - _gpg_sign = ('yes' if _gpg_input else 'no') + _gpg_sign = ('true' if _gpg_input else 'false') iso.attrib['sign'] = _gpg_sign self.profile.append(iso) return() @@ -727,21 +739,21 @@ class ConfGenerator(object): 'see the manual for more information). Would you like to ' 'build iPXE support?\n'), usage = ( '{0} for yes, {1} for no...\n')) - _ipxe = ('yes' if _ipxe else 'no') - if _ipxe == 'yes': + _ipxe = ('true' if _ipxe else 'true') + if _ipxe == 'true': print('\n++ iPXE || MINI-ISO ++') _iso = prompt.confirm_or_no(prompt = ( '\nWould you like to build a "mini-ISO" (see the manual) for ' 'bootstrapping iPXE booting from USB or optical media?\n'), usage = ('{0} for yes, {1} for no...\n')) - ipxe.attrib['iso'] = ('yes' if _iso else 'no') + ipxe.attrib['iso'] = ('true' if _iso else 'false') print('\n++ iPXE || SIGNING ++') _sign = prompt.confirm_or_no(prompt = ( '\nBDisk can sign the mini-ISO and other relevant files for ' 'iPXE builds using GPG. Would you like to sign the iPXE build ' 'distributables? (You\'ll have the chance to configure GPG ' 'later).\n'), usage = ('{0} for yes, {1} for no...\n')) - ipxe.attrib['sign'] = ('yes' if _sign else 'no') + ipxe.attrib['sign'] = ('true' if _sign else 'false') _uri = None while not _uri: print('\n++ iPXE || URL ++') @@ -756,7 +768,7 @@ class ConfGenerator(object): else: uri = lxml.etree.SubElement(ipxe, 'uri') uri.text = _uri - if _ipxe == 'yes': + if _ipxe == 'true': self.profile.append(ipxe) return() @@ -782,7 +794,7 @@ class ConfGenerator(object): 'wish to keep persistent keys and certs), you should ' 'DEFINITELY answer no here.\n'), usage = ('{0} for yes, {1} for no...\n')) - pki.attrib['overwrite'] = ('yes' if _overwrite else 'no') + pki.attrib['overwrite'] = ('true' if _overwrite else 'false') for x in ('ca', 'client'): print('\n++ SSL/TLS PKI || {0} ++'.format(x.upper())) _x = None @@ -806,7 +818,7 @@ class ConfGenerator(object): for x in _xpaths: _x = self.profile.xpath(x) for a in _x: - if a == 'yes': + if a == 'true': _sigchk = True break if _sigchk: @@ -850,7 +862,7 @@ class ConfGenerator(object): '\nWould you like to push the key to the SKS keyserver pool ' '(making it much easier for end-users to look it up)?\n'), usage = ('{0} for yes, {1} for no...\n')) - gpg.attrib['publish'] = ('yes' if _gpgpublish else 'no') + gpg.attrib['publish'] = ('true' if _gpgpublish else 'false') print('\n++ GPG || PASSWORD HANDLING ++') _gpgpass_prompt = prompt.confirm_or_no(prompt = ( '\nWould you like BDisk to prompt you for a passphrase? If not, ' @@ -858,7 +870,8 @@ class ConfGenerator(object): 'the configuration (HIGHLY unrecommended) or use a blank ' 'passphrase (also HIGHLY unrecommended).\n'), usage = ('{0} for yes, {1} for no...\n')) - gpg.attrib['prompt_passphrase'] = ('yes' if _gpgpass_prompt else 'no') + gpg.attrib['prompt_passphrase'] = ('true' if _gpgpass_prompt else + 'false') _pass = None if not _gpgpass_prompt: while not _pass: @@ -923,7 +936,7 @@ class ConfGenerator(object): '\nWould you like to sync {0}?\n'.format(_syncs[s])), usage = ('{0} for yes, {1} for no...\n')) elem = lxml.etree.SubElement(sync, s) - elem.attrib['enabled'] = ('yes' if _item_sync_chk else 'no') + elem.attrib['enabled'] = ('true' if _item_sync_chk else 'false') if not _item_sync_chk: continue if s == 'gpg': diff --git a/bdisk/confparse.py b/bdisk/confparse.py index a551e0a..ab3c608 100644 --- a/bdisk/confparse.py +++ b/bdisk/confparse.py @@ -168,7 +168,7 @@ class Conf(object): ## PROFILE/BUILD(/PATHS) self.cfg['build'] = {'paths': {}} build = self.profile.xpath('./build')[0] - _optimize = build.get('its_full_of_stars', 'no') + _optimize = build.get('its_full_of_stars', 'false') self.cfg['build']['optimize'] = transform.xml2py(_optimize) for path in build.xpath('./paths/*'): self.cfg['build']['paths'][path.tag] = path.text @@ -185,7 +185,7 @@ class Conf(object): # We enable all features by default. elem = self.profile.xpath('./{0}'.format(x))[0] for a in self.cfg[x]: - self.cfg[x][a] = transform.xml2py(elem.get(a, 'yes')) + self.cfg[x][a] = transform.xml2py(elem.get(a, 'true')) if x == 'ipxe': self.cfg[x]['uri'] = elem.xpath('./uri/text()')[0] return() diff --git a/bdisk/utils.py b/bdisk/utils.py index 4886086..7dab775 100644 --- a/bdisk/utils.py +++ b/bdisk/utils.py @@ -15,6 +15,7 @@ import uuid import validators import zlib import lxml.etree +import lxml.objectify from bs4 import BeautifulSoup from collections import OrderedDict from dns import resolver @@ -446,12 +447,12 @@ class transform(object): def py2xml(self, value, attrib = True): if value in (False, ''): if attrib: - return("no") + return("false") else: return(None) elif isinstance(value, bool): # We handle the False case above. - return("yes") + return("true") elif isinstance(value, str): return(value) else: @@ -469,7 +470,6 @@ class transform(object): text_out = re.sub('[^\w]', '', text_out) return(text_out) - # noinspection PyDictCreation def url_to_dict(self, orig_url, no_None = False): def _getuserinfo(uinfo_str): if len(uinfo_str) == 0: @@ -659,8 +659,8 @@ class transform(object): return(acct) def xml2py(self, value, attrib = True): - yes = re.compile('^\s*(y(es)?|true|1)\s*$', re.IGNORECASE) - no = re.compile('^\s*(no?|false|0)\s*$', re.IGNORECASE) + yes = re.compile('^\s*(true|1)\s*$', re.IGNORECASE) + no = re.compile('^\s*(false|0)\s*$', re.IGNORECASE) none = re.compile('^\s*(none|)\s*$', re.IGNORECASE) if no.search(value): if attrib: @@ -819,12 +819,18 @@ class xml_supplicant(object): # This is retained so we can "refresh" the profile if needed. self.orig_profile = profile try: - self.xml = lxml.etree.fromstring(raw) + self.orig_xml = lxml.etree.fromstring(raw) + # We need to strip the naked namespace for XPath to work. + self.xml = copy.deepcopy(self.orig_xml) + self.roottree = self.xml.getroottree() + self.tree = self.roottree.getroot() + self.strip_naked_ns() except lxml.etree.XMLSyntaxError: raise ValueError('The configuration provided does not seem to be ' 'valid') self.get_profile(profile = profile) - self.xml = lxml.etree.fromstring(raw) + # This is disabled; we set it above. + #self.xml = lxml.etree.fromstring(raw) self.fmt = XPathFmt() self.max_recurse = int(self.profile.xpath( '//meta/max_recurse/text()')[0]) @@ -969,6 +975,23 @@ class xml_supplicant(object): ).format(element.text)) return(path) + def return_naked_ns(self): + # It's so stupid I have to do this. + return(self.orig_xml.nsmap) + + def strip_naked_ns(self): + # I cannot *believe* that LXML doesn't have this built-in, considering + # how common naked namespaces are. + # https://stackoverflow.com/a/18160164/733214 + for elem in self.roottree.getiterator(): + if not hasattr(elem.tag, 'find'): + continue + i = elem.tag.find('}') + if i >= 0: + elem.tag = elem.tag[i + 1:] + lxml.objectify.deannotate(self.roottree, cleanup_namespaces = True) + return() + def substitute(self, element, recurse_count = 0): if recurse_count >= self.max_recurse: return(element) diff --git a/docs/examples/multi_profile.xml b/docs/examples/multi_profile.xml index d216962..b741664 100644 --- a/docs/examples/multi_profile.xml +++ b/docs/examples/multi_profile.xml @@ -1,286 +1,285 @@ - - - - - BDisk - bdisk - - {xpath%../name/text()} - - A rescue/restore live environment. - - A. Dev Eloper - dev@domain.tld - https://domain.tld/~dev - - https://domain.tld/projname - 1.0.0 - - - 5 - + + 5 + - - archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz$ - archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz\.sig$ - archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz$ - archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz\.sig$ - - - - /var/tmp/BDisk - - - - - $6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1 - - {xpath%//meta/names/uxname/text()} - - - {xpath%//meta/dev/author/text()} - testpassword - - - testuser - Test User - anothertestpassword - - - - - http://archlinux.mirror.domain.tld - /iso/latest - {regex%tarball_x86_64} - sha1sums.txt - {regex%sig_x86_64} - - - http://archlinux32.mirror.domain.tld - /iso/latest - {regex%tarball_i686} - cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e - {regex%sig_i686} - - - - - {variable%bdisk_root}/base - {variable%bdisk_root}/cache - {variable%bdisk_root}/chroots - {variable%bdisk_root}/overlay - {variable%bdisk_root}/templates - /mnt/{xpath%//meta/names/uxname/text()} - {variable%bdisk_root}/distros - {variable%bdisk_root}/results - {variable%bdisk_root}/iso_overlay - {variable%bdisk_root}/http - {variable%bdisk_root}/tftp - {variable%bdisk_root}/pki - - archlinux - - - - {xpath%//meta/dev/website/text()}/ipxe - - - - - {xpath%../../../build/paths/pki/text()}/ca.crt - + + /var/tmp/BDisk + + + + + $6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1 + + {xpath%//meta/names/uxname/text()} + + + {xpath%//meta/dev/author/text()} + testpassword + + + testuser + Test User + anothertestpassword + + + + + http://archlinux.mirror.domain.tld + /iso/latest + {regex%tarball_x86_64} + sha1sums.txt + {regex%sig_x86_64} + + + http://archlinux32.mirror.domain.tld + /iso/latest + {regex%tarball_i686} + cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e + {regex%sig_i686} + + + + + {variable%bdisk_root}/base + {variable%bdisk_root}/cache + {variable%bdisk_root}/chroots + {variable%bdisk_root}/overlay + {variable%bdisk_root}/templates + /mnt/{xpath%//meta/names/uxname/text()} + {variable%bdisk_root}/distros + {variable%bdisk_root}/results + {variable%bdisk_root}/iso_overlay + {variable%bdisk_root}/http + {variable%bdisk_root}/tftp + {variable%bdisk_root}/pki + + archlinux + + + + {xpath%//meta/dev/website/text()}/ipxe + + + + + {xpath%../../../build/paths/pki/text()}/ca.crt + - - - - - - {xpath%../../../build/paths/pki/text()}/index.txt - {xpath%../../../build/paths/pki/text()}/serial - + + + + {xpath%../../../build/paths/pki/text()}/index.txt + {xpath%../../../build/paths/pki/text()}/serial + - {xpath%../../../build/paths/pki/text()}/ca.key - - domain.tld - XX - Some City - Some State - Some Org, Inc. - Department Name - {xpath%../../../../meta/dev/email/text()} - - - - {xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt - - {xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key - - some client name - XX - Some City - Some State - Some Org, Inc. - Department Name - {xpath%../../../../meta/dev/email/text()} - - - - - - - - {xpath%../../../meta/dev/author/text()} - {xpath%../../../meta/dev/email/text()} - for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} | {xpath%../../../meta/desc/text()} - - - - - /srv/http/{xpath%../../meta/names/uxname/text()} - /tftproot/{xpath%../../meta/names/uxname/text()} - /srv/http/isos/{xpath%../../meta/names/uxname/text()} - /srv/http/{xpath%../../meta/names/uxname/text()}/pubkey.asc - - root - mirror.domain.tld - 22 - ~/.ssh/id_ed25519 - - - - - - - AnotherCD - bdisk_alt - {xpath%../name/text()} - - Another rescue/restore live environment. - - Another Dev Eloper - - {xpath%//profile[@name="default"]/meta/dev/email/text()} - {xpath%//profile[@name="default"]/meta/dev/website/text()} - - https://domain.tld/projname - 0.0.1 - 5 - - archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz$ - archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz\.sig$ - archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz$ - archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz\.sig$ - - - /var/tmp/BDisk - - - - atotallyinsecurepassword - - testuser - Test User - atestpassword - - - - - http://archlinux.mirror.domain.tld - /iso/latest - {regex%tarball_x86_64} - sha1sums.txt - {regex%sig_x86_64} - - - http://archlinux32.mirror.domain.tld - /iso/latest - {regex%tarball_i686} - cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e - {regex%sig_i686} - - - - - {variable%bdisk_root}/base - {variable%bdisk_root}/cache - {variable%bdisk_root}/chroots - {variable%bdisk_root}/overlay - {variable%bdisk_root}/templates - /mnt/{xpath%//meta/names/uxname/text()} - {variable%bdisk_root}/distros - {variable%bdisk_root}/results - {variable%bdisk_root}/iso_overlay - {variable%bdisk_root}/http - {variable%bdisk_root}/tftp - {variable%bdisk_root}/pki - - archlinux - - - - {xpath%//meta/dev/website/text()}/ipxe - - - - {xpath%../../../build/paths/pki/text()}/ca.crt - - {xpath%../../../build/paths/pki/text()}/index.txt - {xpath%../../../build/paths/pki/text()}/serial - {xpath%../../../build/paths/pki/text()}/ca.key - - domain.tld - XX - Some City - Some State - Some Org, Inc. - Department Name - {xpath%../../../../meta/dev/email/text()} - - - - {xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt - - {xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key - - some client name - XX - Some City - Some State - Some Org, Inc. - Department Name - {xpath%../../../../meta/dev/email/text()} - - - - - - {xpath%../../../meta/dev/author/text()} - {xpath%../../../meta/dev/email/text()} - for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} | {xpath%../../../meta/desc/text()} - - - - /srv/http/{xpath%../../meta/names/uxname/text()} - /tftproot/{xpath%../../meta/names/uxname/text()} - /srv/http/isos/{xpath%../../meta/names/uxname/text()} - /srv/http/{xpath%../../meta/names/uxname/text()}/pubkey.asc - - root - mirror.domain.tld - 22 - ~/.ssh/id_ed25519 - - - + + + + {xpath%../../../meta/dev/author/text()} + {xpath%../../../meta/dev/email/text()} + for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} | {xpath%../../../meta/desc/text()} + + + + + /srv/http/{xpath%../../meta/names/uxname/text()} + /tftproot/{xpath%../../meta/names/uxname/text()} + /srv/http/isos/{xpath%../../meta/names/uxname/text()} + /srv/http/{xpath%../../meta/names/uxname/text()}/pubkey.asc + + root + mirror.domain.tld + 22 + ~/.ssh/id_ed25519 + + + + + + + AnotherCD + bdisk_alt + {xpath%../name/text()} + + Another rescue/restore live environment. + + Another Dev Eloper + {xpath%//profile[@name="default"]/meta/dev/email/text()} + {xpath%//profile[@name="default"]/meta/dev/website/text()} + + https://domain.tld/projname + 0.0.1 + 5 + + archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz$ + archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz\.sig$ + archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz$ + archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz\.sig$ + + + /var/tmp/BDisk + + + + atotallyinsecurepassword + + testuser + Test User + atestpassword + + + + + http://archlinux.mirror.domain.tld + /iso/latest + {regex%tarball_x86_64} + sha1sums.txt + {regex%sig_x86_64} + + + http://archlinux32.mirror.domain.tld + /iso/latest + {regex%tarball_i686} + cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e + {regex%sig_i686} + + + + + {variable%bdisk_root}/base + {variable%bdisk_root}/cache + {variable%bdisk_root}/chroots + {variable%bdisk_root}/overlay + {variable%bdisk_root}/templates + /mnt/{xpath%//meta/names/uxname/text()} + {variable%bdisk_root}/distros + {variable%bdisk_root}/results + {variable%bdisk_root}/iso_overlay + {variable%bdisk_root}/http + {variable%bdisk_root}/tftp + {variable%bdisk_root}/pki + + archlinux + + + + {xpath%//meta/dev/website/text()}/ipxe + + + + {xpath%../../../build/paths/pki/text()}/ca.crt + + {xpath%../../../build/paths/pki/text()}/index.txt + {xpath%../../../build/paths/pki/text()}/serial + {xpath%../../../build/paths/pki/text()}/ca.key + + domain.tld + XX + Some City + Some State + Some Org, Inc. + Department Name + {xpath%../../../../meta/dev/email/text()} + + + + {xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt + + {xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key + + some client name + XX + Some City + Some State + Some Org, Inc. + Department Name + {xpath%../../../../meta/dev/email/text()} + + + + + + {xpath%../../../meta/dev/author/text()} + {xpath%../../../meta/dev/email/text()} + for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} | {xpath%../../../meta/desc/text()} + + + + /srv/http/{xpath%../../meta/names/uxname/text()} + /tftproot/{xpath%../../meta/names/uxname/text()} + /srv/http/isos/{xpath%../../meta/names/uxname/text()} + /srv/http/{xpath%../../meta/names/uxname/text()}/pubkey.asc + + root + mirror.domain.tld + 22 + ~/.ssh/id_ed25519 + + + diff --git a/docs/examples/regen_multi.py b/docs/examples/regen_multi.py index 2f92570..bf32799 100755 --- a/docs/examples/regen_multi.py +++ b/docs/examples/regen_multi.py @@ -1,13 +1,34 @@ #!/usr/bin/env python3.6 import copy -from lxml import etree +from lxml import etree, objectify -parser = etree.XMLParser(remove_blank_text = True) +#parser = etree.XMLParser(remove_blank_text = True) +parser = etree.XMLParser(remove_blank_text = False) + +# We need to append to a new root because you can't edit nsmap, and you can't +# xpath on an element with a naked namespace (e.g. 'xlmns="..."'). +ns = {None: 'http://bdisk.square-r00t.net/', + 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'} +xsi = {'{http://www.w3.org/2001/XMLSchema-instance}schemaLocation': + 'http://bdisk.square-r00t.net bdisk.xsd'} +new_cfg = etree.Element('bdisk', nsmap = ns, attrib = xsi) +new_cfg.text = '\n ' with open('single_profile.xml', 'rb') as f: xml = etree.fromstring(f.read(), parser) + +roottree = xml.getroottree() +for elem in roottree.getiterator(): + if not hasattr(elem.tag, 'find'): + continue + i = elem.tag.find('}') + if i >= 0: + elem.tag = elem.tag[i + 1:] +objectify.deannotate(roottree, cleanup_namespaces = True) + + single_profile = xml.xpath('/bdisk/profile[1]')[0] alt_profile = copy.deepcopy(single_profile) for c in alt_profile.xpath('//comment()'): @@ -42,18 +63,22 @@ for e in accounts.iter(): if e.tag in accounts_tags: e.text = accounts_tags[e.tag] if e.tag == 'rootpass': - e.attrib['hashed'] = 'no' + e.attrib['hashed'] = 'false' elif e.tag == 'user': - e.attrib['sudo'] = 'no' + e.attrib['sudo'] = 'false' # Delete the second user accounts.remove(accounts[2]) author = alt_profile.xpath('/profile/meta/dev/author')[0] author.addnext(etree.Comment( ' You can reference other profiles within the same configuration. ')) -xml.append(alt_profile) +#xml.append(alt_profile) + +for child in xml.xpath('/bdisk/profile'): + new_cfg.append(copy.deepcopy(child)) +new_cfg.append(alt_profile) with open('multi_profile.xml', 'wb') as f: - f.write(etree.tostring(xml, + f.write(etree.tostring(new_cfg, pretty_print = True, encoding = 'UTF-8', xml_declaration = True)) diff --git a/docs/examples/single_profile.xml b/docs/examples/single_profile.xml index fb159a3..38e05d6 100644 --- a/docs/examples/single_profile.xml +++ b/docs/examples/single_profile.xml @@ -1,11 +1,12 @@ - - BDisk + BDISK + bdisk archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz$ - archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz\.sig$ - + archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz\.sig$ archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz$ archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz\.sig$ @@ -41,56 +41,48 @@ - - $6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1 - - + $6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1 + {xpath%//meta/names/uxname/text()} {xpath%//meta/dev/author/text()} - testpassword - + salt="auto">testpassword - + testuser - Test User - Test User + anothertestpassword - + salt="auto">anothertestpassword http://archlinux.mirror.domain.tld /iso/latest - {regex%tarball_x86_64} + {regex%tarball_x86_64} sha1sums.txt - + explicit="false" + flags="latest">sha1sums.txt {regex%sig_x86_64} - + flags="regex latest">{regex%sig_x86_64} http://archlinux32.mirror.domain.tld /iso/latest - {regex%tarball_i686} + {regex%tarball_i686} - cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e - + explicit="true">cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e {regex%sig_i686} - + flags="regex latest">{regex%sig_i686} - + {variable%bdisk_root}/base {variable%bdisk_root}/cache @@ -107,11 +99,11 @@ archlinux - - + + {xpath%//meta/dev/website/text()}/ipxe - + {xpath%../../../build/paths/pki/text()}/ca.crt @@ -133,8 +125,7 @@ be (securely) prompted for the passphrase to unlock it/add a passphrase to it. --> {xpath%../../../build/paths/pki/text()}/ca.key - + keysize="4096">{xpath%../../../build/paths/pki/text()}/ca.key domain.tld XX @@ -146,16 +137,13 @@ - - {xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt - + {xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt {xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key - + keysize="4096">{xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key - some client name + website.tld XX Some City Some State @@ -169,26 +157,23 @@ blank passphrase for all operations. --> + publish="false" + prompt_passphrase="false"> {xpath%../../../meta/dev/author/text()} {xpath%../../../meta/dev/email/text()} - for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} - | {xpath%../../../meta/desc/text()} - + for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} | {xpath%../../../meta/desc/text()} - /srv/http/{xpath%../../meta/names/uxname/text()} - /tftproot/{xpath%../../meta/names/uxname/text()} - /srv/http/isos/{xpath%../../meta/names/uxname/text()} - /srv/http/{xpath%../../meta/names/uxname/text()}/pubkey.asc - - + /srv/http/{xpath%../../meta/names/uxname/text()} + /tftproot/{xpath%../../meta/names/uxname/text()} + /srv/http/isos/{xpath%../../meta/names/uxname/text()} + /srv/http/{xpath%../../meta/names/uxname/text()}/pubkey.asc + root mirror.domain.tld 22