holy cats. xml generation's almost done

This commit is contained in:
brent s 2017-05-15 02:47:04 -04:00
parent 3f8c626fca
commit 372b51b1a6
5 changed files with 238 additions and 42 deletions

View File

@ -1,11 +1,19 @@
#!/usr/bin/env python3 #!/usr/bin/env python3


try: xmldebug = True
from lxml import etree
lxml_avail = True if not xmldebug:
except ImportError: try:
import xml.etree.ElementTree as etree # https://docs.python.org/3/library/xml.etree.elementtree.html from lxml import etree
lxml_avail = True
except ImportError:
import xml.etree.ElementTree as etree # https://docs.python.org/3/library/xml.etree.elementtree.html
lxml_avail = False
else:
# debugging
import xml.etree.ElementTree as etree
lxml_avail = False lxml_avail = False
# end debugging
import argparse import argparse
import crypt import crypt
import datetime import datetime
@ -131,10 +139,10 @@ class aifgen(object):
def ifacePrompt(nethelp): def ifacePrompt(nethelp):
ifaces = {} ifaces = {}
moreIfaces = True moreIfaces = True
print('\nPlease enter the name of the interface you would like to use.\n' + print('\tNOTE: You must specify the "persistent device naming" name of the device when configuring.\n' +
'\tCan instead be \'auto\' for automatic configuration of the first found interface\n' + '\tYou can instead specify \'auto\' for automatic configuration of the first found interface\n' +
'\twith an active link. (You can only specify one auto device per system, and all subsequent\n' '\twith an active link. (You can only specify one auto device per system, and all other\n'
'\tinterface entries will be ignored.)\n') '\tinterface entries will be ignored by AIF-NG.)\n')
while moreIfaces: while moreIfaces:
ifacein = chkPrompt('* Interface device: ', nethelp) ifacein = chkPrompt('* Interface device: ', nethelp)
addrin = chkPrompt(('** Address for {0} in CIDR format (can be an IPv4 or IPv6 address; ' + addrin = chkPrompt(('** Address for {0} in CIDR format (can be an IPv4 or IPv6 address; ' +
@ -331,7 +339,7 @@ class aifgen(object):
'enabled': False}} 'enabled': False}}
chkdefs = chkPrompt(('* Would you like to review the default repository configuration ' + chkdefs = chkPrompt(('* Would you like to review the default repository configuration ' +
'(and possibly edit it)? ({0}y{1}/n) ').format(color.BOLD, color.END), repohelp) '(and possibly edit it)? ({0}y{1}/n) ').format(color.BOLD, color.END), repohelp)
fmtstr = '{0} {1:<20} {2:^10} {3:^10} {4}' # ('#', 'REPO', 'ENABLED', 'SIGLEVEL', 'URI') fmtstr = '\t{0} {1:<20} {2:^10} {3:^10} {4}' # ('#', 'REPO', 'ENABLED', 'SIGLEVEL', 'URI')
if not re.match('^no?$', chkdefs.lower()): if not re.match('^no?$', chkdefs.lower()):
print('{0}{1}{2}'.format(color.BOLD, fmtstr.format('#', 'REPO', 'ENABLED', 'SIGLEVEL', 'URI'), color.END)) print('{0}{1}{2}'.format(color.BOLD, fmtstr.format('#', 'REPO', 'ENABLED', 'SIGLEVEL', 'URI'), color.END))
rcnt = 1 rcnt = 1
@ -491,12 +499,12 @@ class aifgen(object):
return(scrpts) return(scrpts)
conf = {} conf = {}
print('[{0}] Beginning configuration...'.format(datetime.datetime.now())) print('[{0}] Beginning configuration...'.format(datetime.datetime.now()))
print('You may reply with \'wikihelp\' on the first prompt of a question for the relevant link(s) in the Arch wiki ' + print('\n\tYou may reply with \'wikihelp\' on the first prompt of a question for the relevant link(s) in the Arch wiki ' +
'(and other resources).') '(and other resources).')
# https://aif.square-r00t.net/#code_disk_code # https://aif.square-r00t.net/#code_disk_code
diskhelp = ['https://wiki.archlinux.org/index.php/installation_guide#Partition_the_disks'] diskhelp = ['https://wiki.archlinux.org/index.php/installation_guide#Partition_the_disks']
print('{0}= DISKS ={1}'.format(color.BOLD, color.END)) print('{0}= DISKS ={1}'.format(color.BOLD, color.END))
diskin = chkPrompt('\n* What disk(s) would you like to be configured on the target system?\n' + diskin = chkPrompt('* What disk(s) would you like to be configured on the target system?\n' +
'\tIf you have multiple disks, separate with a comma (e.g. \'/dev/sda,/dev/sdb\'): ', diskhelp) '\tIf you have multiple disks, separate with a comma (e.g. \'/dev/sda,/dev/sdb\'): ', diskhelp)
# NOTE: the following is a dict of fstype codes to their description. # NOTE: the following is a dict of fstype codes to their description.
fstypes = {'0700': 'Microsoft basic data', '0c01': 'Microsoft reserved', '2700': 'Windows RE', '3000': 'ONIE config', '3900': 'Plan 9', '4100': 'PowerPC PReP boot', '4200': 'Windows LDM data', '4201': 'Windows LDM metadata', '4202': 'Windows Storage Spaces', '7501': 'IBM GPFS', '7f00': 'ChromeOS kernel', '7f01': 'ChromeOS root', '7f02': 'ChromeOS reserved', '8200': 'Linux swap', '8300': 'Linux filesystem', '8301': 'Linux reserved', '8302': 'Linux /home', '8303': 'Linux x86 root (/)', '8304': 'Linux x86-64 root (/', '8305': 'Linux ARM64 root (/)', '8306': 'Linux /srv', '8307': 'Linux ARM32 root (/)', '8400': 'Intel Rapid Start', '8e00': 'Linux LVM', 'a500': 'FreeBSD disklabel', 'a501': 'FreeBSD boot', 'a502': 'FreeBSD swap', 'a503': 'FreeBSD UFS', 'a504': 'FreeBSD ZFS', 'a505': 'FreeBSD Vinum/RAID', 'a580': 'Midnight BSD data', 'a581': 'Midnight BSD boot', 'a582': 'Midnight BSD swap', 'a583': 'Midnight BSD UFS', 'a584': 'Midnight BSD ZFS', 'a585': 'Midnight BSD Vinum', 'a600': 'OpenBSD disklabel', 'a800': 'Apple UFS', 'a901': 'NetBSD swap', 'a902': 'NetBSD FFS', 'a903': 'NetBSD LFS', 'a904': 'NetBSD concatenated', 'a905': 'NetBSD encrypted', 'a906': 'NetBSD RAID', 'ab00': 'Recovery HD', 'af00': 'Apple HFS/HFS+', 'af01': 'Apple RAID', 'af02': 'Apple RAID offline', 'af03': 'Apple label', 'af04': 'AppleTV recovery', 'af05': 'Apple Core Storage', 'bc00': 'Acronis Secure Zone', 'be00': 'Solaris boot', 'bf00': 'Solaris root', 'bf01': 'Solaris /usr & Mac ZFS', 'bf02': 'Solaris swap', 'bf03': 'Solaris backup', 'bf04': 'Solaris /var', 'bf05': 'Solaris /home', 'bf06': 'Solaris alternate sector', 'bf07': 'Solaris Reserved 1', 'bf08': 'Solaris Reserved 2', 'bf09': 'Solaris Reserved 3', 'bf0a': 'Solaris Reserved 4', 'bf0b': 'Solaris Reserved 5', 'c001': 'HP-UX data', 'c002': 'HP-UX service', 'ea00': 'Freedesktop $BOOT', 'eb00': 'Haiku BFS', 'ed00': 'Sony system partition', 'ed01': 'Lenovo system partition', 'ef00': 'EFI System', 'ef01': 'MBR partition scheme', 'ef02': 'BIOS boot partition', 'f800': 'Ceph OSD', 'f801': 'Ceph dm-crypt OSD', 'f802': 'Ceph journal', 'f803': 'Ceph dm-crypt journal', 'f804': 'Ceph disk in creation', 'f805': 'Ceph dm-crypt disk in creation', 'fb00': 'VMWare VMFS', 'fb01': 'VMWare reserved', 'fc00': 'VMWare kcore crash protection', 'fd00': 'Linux RAID'} fstypes = {'0700': 'Microsoft basic data', '0c01': 'Microsoft reserved', '2700': 'Windows RE', '3000': 'ONIE config', '3900': 'Plan 9', '4100': 'PowerPC PReP boot', '4200': 'Windows LDM data', '4201': 'Windows LDM metadata', '4202': 'Windows Storage Spaces', '7501': 'IBM GPFS', '7f00': 'ChromeOS kernel', '7f01': 'ChromeOS root', '7f02': 'ChromeOS reserved', '8200': 'Linux swap', '8300': 'Linux filesystem', '8301': 'Linux reserved', '8302': 'Linux /home', '8303': 'Linux x86 root (/)', '8304': 'Linux x86-64 root (/', '8305': 'Linux ARM64 root (/)', '8306': 'Linux /srv', '8307': 'Linux ARM32 root (/)', '8400': 'Intel Rapid Start', '8e00': 'Linux LVM', 'a500': 'FreeBSD disklabel', 'a501': 'FreeBSD boot', 'a502': 'FreeBSD swap', 'a503': 'FreeBSD UFS', 'a504': 'FreeBSD ZFS', 'a505': 'FreeBSD Vinum/RAID', 'a580': 'Midnight BSD data', 'a581': 'Midnight BSD boot', 'a582': 'Midnight BSD swap', 'a583': 'Midnight BSD UFS', 'a584': 'Midnight BSD ZFS', 'a585': 'Midnight BSD Vinum', 'a600': 'OpenBSD disklabel', 'a800': 'Apple UFS', 'a901': 'NetBSD swap', 'a902': 'NetBSD FFS', 'a903': 'NetBSD LFS', 'a904': 'NetBSD concatenated', 'a905': 'NetBSD encrypted', 'a906': 'NetBSD RAID', 'ab00': 'Recovery HD', 'af00': 'Apple HFS/HFS+', 'af01': 'Apple RAID', 'af02': 'Apple RAID offline', 'af03': 'Apple label', 'af04': 'AppleTV recovery', 'af05': 'Apple Core Storage', 'bc00': 'Acronis Secure Zone', 'be00': 'Solaris boot', 'bf00': 'Solaris root', 'bf01': 'Solaris /usr & Mac ZFS', 'bf02': 'Solaris swap', 'bf03': 'Solaris backup', 'bf04': 'Solaris /var', 'bf05': 'Solaris /home', 'bf06': 'Solaris alternate sector', 'bf07': 'Solaris Reserved 1', 'bf08': 'Solaris Reserved 2', 'bf09': 'Solaris Reserved 3', 'bf0a': 'Solaris Reserved 4', 'bf0b': 'Solaris Reserved 5', 'c001': 'HP-UX data', 'c002': 'HP-UX service', 'ea00': 'Freedesktop $BOOT', 'eb00': 'Haiku BFS', 'ed00': 'Sony system partition', 'ed01': 'Lenovo system partition', 'ef00': 'EFI System', 'ef01': 'MBR partition scheme', 'ef02': 'BIOS boot partition', 'f800': 'Ceph OSD', 'f801': 'Ceph dm-crypt OSD', 'f802': 'Ceph journal', 'f803': 'Ceph dm-crypt journal', 'f804': 'Ceph disk in creation', 'f805': 'Ceph dm-crypt disk in creation', 'fb00': 'VMWare VMFS', 'fb01': 'VMWare reserved', 'fc00': 'VMWare kcore crash protection', 'fd00': 'Linux RAID'}
@ -546,18 +554,19 @@ class aifgen(object):
exit(' !! ERROR: {0} is not a valid filesystem type.'.format(fstypein)) exit(' !! ERROR: {0} is not a valid filesystem type.'.format(fstypein))
else: else:
print('\t(Selected {0})'.format(fstypes[fstypein])) print('\t(Selected {0})'.format(fstypes[fstypein]))
conf['disks'][disk]['parts'][partn]['fstype'] = fstypein
mnthelp = ['https://wiki.archlinux.org/index.php/installation_guide#Mount_the_file_systems', mnthelp = ['https://wiki.archlinux.org/index.php/installation_guide#Mount_the_file_systems',
'https://aif.square-r00t.net/#code_mount_code'] 'https://aif.square-r00t.net/#code_mount_code']
print('{0}= MOUNTS ={1}'.format(color.BOLD, color.END)) print('\n{0}= MOUNTS ={1}'.format(color.BOLD, color.END))
mntin = chkPrompt('\n* What mountpoint(s) would you like to be configured on the target system?\n' + mntin = chkPrompt('* What mountpoint(s) would you like to be configured on the target system?\n' +
'\tIf you have multiple mountpoints, separate with a comma (e.g. \'/mnt/aif,/mnt/aif/boot\').\n' + '\tIf you have multiple mountpoints, separate with a comma (e.g. \'/mnt/aif,/mnt/aif/boot\').\n' +
'\t(NOTE: Can be \'swap\' for swapspace.): ', mnthelp) '\t(NOTE: Can be \'swap\' for swapspace.): ', mnthelp)
conf['mounts'] = {} conf['mounts'] = {}
for m in mntin.split(','): for m in mntin.split(','):
mount = m.strip() mount = m.strip()
if not re.match('^(/([^/\x00\s]+(/)?)+|swap)$', mount): if not re.match('^(/([^/\x00\s]+(/)?)+|swap)$', mount):
exit('!! ERROR: Mountpoint {0} does not seem to be a valid path/specifier.'.format(mount)) exit('!! ERROR: Mountpoint {0} does not seem to be a valid path/specifier.'.format(mount))
print('\n{0}==MOUNT {1}=={2}'.format(color.BOLD, mount, color.END)) print('\n{0}== MOUNT: {1} =={2}'.format(color.BOLD, mount, color.END))
dvcin = chkPrompt('* What device/partition should be mounted here? ', mnthelp) dvcin = chkPrompt('* What device/partition should be mounted here? ', mnthelp)
if not re.match('^/dev/[A-Za-z0]+', dvcin): if not re.match('^/dev/[A-Za-z0]+', dvcin):
exit(' !! ERROR: Must be a full path to a device/partition.') exit(' !! ERROR: Must be a full path to a device/partition.')
@ -717,10 +726,13 @@ class aifgen(object):
scrptsin = chkPrompt('* Do you have any hook scripts you\'d like to add? (y/{0}n{1}) '.format(color.BOLD, color.END), scrpthlp) scrptsin = chkPrompt('* Do you have any hook scripts you\'d like to add? (y/{0}n{1}) '.format(color.BOLD, color.END), scrpthlp)
if re.match('^y(es)?$', scrptsin.lower()): if re.match('^y(es)?$', scrptsin.lower()):
conf['scripts'] = scrptPrompt(scrpthlp) conf['scripts'] = scrptPrompt(scrpthlp)
print('\n\n{0}ALL DONE!{1} Whew. You can find your configuration file at: {2}{3}{1}\n'.format(color.BOLD, else:
color.END, conf['scripts'] = False
color.BLUE, print('\n\n[{0}] {1}ALL DONE!{2} Whew. You can find your configuration file at: {3}{4}{2}\n'.format(datetime.datetime.now(),
self.args['cfgfile'])) color.BOLD,
color.END,
color.BLUE,
self.args['cfgfile']))
if self.args['verbose']: if self.args['verbose']:
import pprint import pprint
pprint.pprint(conf) pprint.pprint(conf)
@ -739,7 +751,9 @@ class aifgen(object):
def validateXML(self): def validateXML(self):
# First we validate the XSD. # First we validate the XSD.
if not lxml_avail: if not lxml_avail:
exit('\nXML validation is only supported by LXML.\nIf you want to validate the XML, install the lxml python module (python-lxml) and try again.\n') exit('\nXML validation is only supported by LXML.\n' +
'If you want to validate the XML, install the lxml python module (python-lxml) ' +
'and run:\n\t{0} validate -f {1}.\n'.format(sys.argv[0], self.args['cfgfile']))
try: try:
xsd = etree.XMLSchema(self.getXSD()) xsd = etree.XMLSchema(self.getXSD())
print('\nXSD: {0}PASSED{1}'.format(color.BOLD, color.END)) print('\nXSD: {0}PASSED{1}'.format(color.BOLD, color.END))
@ -753,11 +767,174 @@ class aifgen(object):
print('XML: {0}FAILED{1}: {2}\n'.format(color.BOLD, color.END, e)) print('XML: {0}FAILED{1}: {2}\n'.format(color.BOLD, color.END, e))


def genXMLFile(self, conf): def genXMLFile(self, conf):
namespaces = {'aif': 'http://aif.square-r00t.net/', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}
xsi = {'{http://www.w3.org/2001/XMLSchema-instance}schemaLocation' : 'http://aif.square-r00t.net aif.xsd'}
#for ns in namespaces.keys():
# etree.register_namespace(ns, namespaces[ns])
if lxml_avail: if lxml_avail:
root = etree.Element('aif') genname = 'LXML (http://lxml.de/)'
root = etree.Element('aif', nsmap = namespaces, attrib = xsi)
#xml = etree.ElementTree(root)
else: else:
root = etree.ElementTree.Element('aif') genname = 'Python stdlib "xml" module'
pass for ns in namespaces.keys():
etree.register_namespace(ns, namespaces[ns])
root = etree.Element('aif')
if self.args['oper'] == 'convert':
fromstr = self.args['inputfile']
else:
fromstr = 'interactive commandline'
root.append(etree.Comment('Generated by {0} on {1} from {2} via {3}'.format(sys.argv[0], datetime.datetime.now(), fromstr, genname)))
root.append(etree.Comment('THIS FILE CONTAINS SENSITIVE INFORMATION. SHARE/SCRUB WISELY.'))
# /aif/ required sections
for e in ('storage', 'network', 'system', 'pacman', 'bootloader'):
root.append(etree.Element(e))
# /aif/ optional sections
if conf['scripts']:
root.append(etree.Element('scripts'))
# /aif/storage
strg = root.find('storage')
for d in conf['disks'].keys():
# /aif/storage/disk
disk = etree.Element('disk', device = d, diskfmt = conf['disks'][d]['fmt'])
for p in conf['disks'][d]['parts'].keys():
# /aif/storage/disk/part
start = conf['disks'][d]['parts'][p]['start']
stop = conf['disks'][d]['parts'][p]['stop']
fstype = conf['disks'][d]['parts'][p]['fstype']
disk.append(etree.Element('part', num = p, start = start, stop = stop, fstype = fstype))
strg.append(disk)
# /aif/storage/mount
for m in conf['mounts'].keys():
mnt = {}
mnt['order'] = m
mnt['source'] = conf['mounts'][m]['device']
mnt['target'] = conf['mounts'][m]['target']
# These are optional, hence the splat and mnt dict.
for o in ('fstype', 'opts'):
if o in conf['mounts'][m].keys() and conf['mounts'][m][o]:
mnt[o] = conf['mounts'][m][o]
mount = etree.Element('mount', **mnt)
strg.append(mount)
# /aif/network
ntwk = root.find('network')
ntwk.set('hostname', conf['network']['hostname'])
for i in conf['network']['ifaces'].keys():
# /aif/network/iface
optmap = {'gw': 'gateway', 'proto': 'netproto', 'resolvers': 'resolvers'}
iface = {}
iface['device'] = i
iface['address'] = conf['network']['ifaces'][i]['address']
for o in optmap.keys():
if conf['network']['ifaces'][i][o]:
if o == 'resolvers':
iface[optmap[o]] = ','.join(conf['network']['ifaces'][i][o])
else:
iface[optmap[o]] = conf['network']['ifaces'][i][o]
interface = etree.Element('iface', **iface)
ntwk.append(interface)
# /aif/system
systm = root.find('system')
for a in ('timezone', 'locale', 'chrootpath', 'kbd', 'reboot'):
if isinstance(conf['system'][a], bool):
val = str(conf['system'][a]).lower()
else:
val = conf['system'][a]
systm.set(a, val)
# /aif/system/users
usrs = etree.Element('users', rootpass = conf['system']['rootpass'])
subs = ('home', 'xgroups')
optional = ('uid', 'group', 'gid')
if conf['system']['users']:
for u in conf['system']['users'].keys():
# /aif/system/users/user
o = {}
o['name'] = u
for i in conf['system']['users'][u].keys():
if isinstance(conf['system']['users'][u][i], bool):
val = str(conf['system']['users'][u][i]).lower()
else:
val = conf['system']['users'][u][i]
if i not in subs: # we handle "subs" as subelements
if i in optional: # and we only add optional attribs if they're populated
if conf['system']['users'][u][i]:
o[i] = val
else:
o[i] = val
user = etree.Element('user', **o)
# /aif/system/users/user/home
if conf['system']['users'][u]['home']:
o = {}
o['create'] = str(conf['system']['users'][u]['home']['create']).lower()
if 'path' in conf['system']['users'][u]['home'].keys():
o['path'] = conf['system']['users'][u]['home']['path']
home = etree.Element('home', **o)
user.append(home)
# /aig/system/users/user/xgroup
if conf['system']['users'][u]['xgroups']:
for g in conf['system']['users'][u]['xgroups'].keys():
o = {}
o['name'] = g
o['create'] = str(conf['system']['users'][u]['xgroups'][g]['create']).lower()
if 'gid' in conf['system']['users'][u]['xgroups'][g].keys() and conf['system']['users'][u]['xgroups'][g]['gid']:
o['gid'] = conf['system']['users'][u]['xgroups'][g]['gid']
xgrp = etree.Element('xgroup', **o)
user.append(xgrp)
usrs.append(user)
systm.append(usrs)
# /aif/system/service
if conf['system']['services']:
for s in conf['system']['services'].keys():
o = {}
o['name'] = s
o['status'] = str(conf['system']['services'][s]).lower()
svc = etree.Element('service', **o)
systm.append(svc)
# /aif/pacman
pcmn = root.find('pacman')
if conf['software']['pkgr']:
pcmn.set('command', conf['software']['pkgr'])
# /aif/pacman/repo
repos = etree.Element('repos')
for r in conf['software']['repos'].keys():
o = {}
o['name'] = r
o['enabled'] = str(conf['software']['repos'][r]['enabled']).lower()
o['siglevel'] = conf['software']['repos'][r]['siglevel']
o['mirror'] = conf['software']['repos'][r]['mirror']
repo = etree.Element('repo', **o)
repos.append(repo)
pcmn.append(repos)
# debugging
if lxml_avail:
# LXML
#print(etree.tostring(root).decode('utf-8'))
print(etree.tostring(root, xml_declaration = True, encoding = 'utf-8', pretty_print = True).decode('utf-8'))
else:
# XML
import xml.dom.minidom
xmlstr = etree.tostring(root, encoding = 'utf-8')
# holy cats, the xml module sucks.
nsstr = ''
for ns in namespaces.keys():
nsstr += ' xmlns:{0}="{1}"'.format(ns, namespaces[ns])
for x in xsi.keys():
xsiname = x.split('}')[1]
nsstr += ' xsi:{0}="{1}"'.format(xsiname, xsi[x])
outstr = xml.dom.minidom.parseString(xmlstr).toprettyxml(indent = ' ').splitlines()
outstr[0] = '<?xml version=\'1.0\' encoding=\'utf-8\'?>'
outstr[1] = '<aif{0}>'.format(nsstr)
print('\n'.join(outstr))
# end debugging
# https://stackoverflow.com/questions/4886189/python-namespaces-in-xml-elementtree-or-lxml
#if lxml_avail:
#xml.write(..., xml_declaration = True, encoding='utf-8')
#else:
#import xml.dom.minidom
#xmlstr = etree.tostring(root, encoding = 'utf-8')
#with open(self.args['cfgfile'], 'w') as f: # TODO: test this. print() wrap it necessary?
#f.write(xml.dom.minidom.parseString(xmlstr).toprettyxml(indent = ' '))
return()


def main(self): def main(self):
if self.args['oper'] == 'create': if self.args['oper'] == 'create':

View File

@ -5,8 +5,8 @@
- how to support mdadm, lvm? - how to support mdadm, lvm?
- support serverside "autoconfig"- a mechanism to let servers automatically generate xml build configs. e.g.: - support serverside "autoconfig"- a mechanism to let servers automatically generate xml build configs. e.g.:
kernel ... aif_url="https://build.domain.tld/aif-ng.php" auto=yes kernel ... aif_url="https://build.domain.tld/aif-ng.php" auto=yes
would yield the *client* sending info via URL params, e.g. would yield the *client* sending info via URL params (actually, this might be better as a JSON POST, since we already have a way to generate JSON. sort of.),
https://build.domain.tld/aif-ng.php?disk[]=sda&disk[]=sdb&disk[sda]=300GB&disk[sdb]=500GB e.g. https://build.domain.tld/aif-ng.php?disk[]=sda&disk[]=sdb&disk[sda]=300GB&disk[sdb]=500GB (can have it so that the autoconfig is only supported clientside if pyyaml is installed)
or something like that. or something like that.
- parser: make sure to use https://mikeknoop.com/lxml-xxe-exploit/ fix - parser: make sure to use https://mikeknoop.com/lxml-xxe-exploit/ fix
- convert use of confobj or whatever to maybe be suitable to use webFetch instead. LOTS of duplicated code there. - convert use of confobj or whatever to maybe be suitable to use webFetch instead. LOTS of duplicated code there.
@ -23,13 +23,14 @@
run on /mnt/aif/run type tmpfs (rw,nosuid,nodev,relatime,mode=755) run on /mnt/aif/run type tmpfs (rw,nosuid,nodev,relatime,mode=755)
tmp on /mnt/aif/tmp type tmpfs (rw,nosuid,nodev) tmp on /mnt/aif/tmp type tmpfs (rw,nosuid,nodev)


DOCUMENTATION: aif-config.py (and note sample yaml as well) DOCUMENTATION: aif-config.py (and note sample json as well)
also need to add users, xgroups, etc. etc. etc. into the getOpts -finish genXML() or whatever i call it
-add <mirrorlist><mirror><mirror/><mirrorlist/> support- to both the config run and the XML generator


also create: also create:
-create boot media with bdisk since default arch doesn't even have python 3 -create boot media with bdisk since default arch doesn't even have python 3
-- this is.. sort of? done. but iPXE/mini build is failing, need to investigate why -- this is.. sort of? done. but iPXE/mini build is failing, need to investigate why

-- i tihnk i fixed iPXE but i need to generate another one once 1.5 is released
docs: docs:
http://lxml.de/parsing.html http://lxml.de/parsing.html
https://www.w3.org/2001/XMLSchema.xsd https://www.w3.org/2001/XMLSchema.xsd

View File

@ -8,10 +8,12 @@
"fmt": "gpt", "fmt": "gpt",
"parts": { "parts": {
"1": { "1": {
"fstype": "8300",
"start": "0%", "start": "0%",
"stop": "95%" "stop": "95%"
}, },
"2": { "2": {
"fstype": "ef00",
"start": "95%", "start": "95%",
"stop": "100%" "stop": "100%"
} }
@ -21,14 +23,17 @@
"fmt": "gpt", "fmt": "gpt",
"parts": { "parts": {
"1": { "1": {
"fstype": "8300",
"start": "0%", "start": "0%",
"stop": "47%" "stop": "47%"
}, },
"2": { "2": {
"fstype": "8300",
"start": "47%", "start": "47%",
"stop": "95%" "stop": "95%"
}, },
"3": { "3": {
"fstype": "8200",
"start": "95%", "start": "95%",
"stop": "100%" "stop": "100%"
} }
@ -87,6 +92,7 @@
} }
} }
}, },
"scripts": false,
"software": { "software": {
"packages": { "packages": {
"openssh": "None" "openssh": "None"
@ -130,7 +136,7 @@
"kbd": "US", "kbd": "US",
"locale": "en_US.UTF-8", "locale": "en_US.UTF-8",
"reboot": true, "reboot": true,
"rootpass": "$6$0jk/xhwahQHTi5QP$VWTgGlHNdSBDbQmJXUwJPZqajfL3JqYYF7Ghxk3ZSKi12WWXb49KsjR7q0bigvgBBBk5A/mvYES3/qareytFS0", "rootpass": "$6$OeSE5pp4BLWZUn6H$9Y.NO/2cUliOr.apu8qSmgmL4EbGei0u22cw1IANs0h6ek45t8bpHveY7rlHAlljd8PKIxvIRtY9bRCzV24h50",
"services": { "services": {
"sshd": true "sshd": true
}, },
@ -141,7 +147,7 @@
"gid": false, "gid": false,
"group": false, "group": false,
"home": false, "home": false,
"password": "$6$IlEwDkNmZRuTrT97$vKHjREGspspApBd8aQ/y1S43yRmGMjAzqOmdjNRLWaZyNKqGPrIjMHV9CJc7BzQgU12pRz3cwC6yyc8BDFARu/", "password": "$6$RCL/E8zPTHoYjITS$MsBQ9DXibdRvjE8a0ak8F2OCzShcRg3vKXSyLAipokaIJvTwFWwlLda1MQr6zTzUxlFui.9Ep4k3B8vdRyBX6.",
"sudo": true, "sudo": true,
"uid": false, "uid": false,
"xgroups": { "xgroups": {
@ -153,4 +159,4 @@
} }
} }
} }
} }

View File

@ -1,11 +1,21 @@
{'boot': {'efi': True, 'target': '/boot'}, {'boot': {'efi': True, 'target': '/boot'},
'disks': {'/dev/sda': {'fmt': 'gpt', 'disks': {'/dev/sda': {'fmt': 'gpt',
'parts': {1: {'start': '0%', 'stop': '95%'}, 'parts': {1: {'fstype': '8300',
2: {'start': '95%', 'stop': '100%'}}}, 'start': '0%',
'stop': '95%'},
2: {'fstype': 'ef00',
'start': '95%',
'stop': '100%'}}},
'/dev/sdb': {'fmt': 'gpt', '/dev/sdb': {'fmt': 'gpt',
'parts': {1: {'start': '0%', 'stop': '47%'}, 'parts': {1: {'fstype': '8300',
2: {'start': '47%', 'stop': '95%'}, 'start': '0%',
3: {'start': '95%', 'stop': '100%'}}}}, 'stop': '47%'},
2: {'fstype': '8300',
'start': '47%',
'stop': '95%'},
3: {'fstype': '8200',
'start': '95%',
'stop': '100%'}}}},
'mounts': {1: {'device': '/dev/sda1', 'mounts': {1: {'device': '/dev/sda1',
'fstype': 'ext4', 'fstype': 'ext4',
'opts': 'defaults', 'opts': 'defaults',
@ -35,7 +45,8 @@
'gw': '192.168.1.1', 'gw': '192.168.1.1',
'proto': 'ipv4', 'proto': 'ipv4',
'resolvers': ['4.2.2.1', '4.2.2.2']}}}, 'resolvers': ['4.2.2.1', '4.2.2.2']}}},
'software': {'packages': {'openssh': 'None'}, 'scripts': False,
'software': {'packages': {'openssh': None},
'pkgr': False, 'pkgr': False,
'repos': {'community': {'enabled': True, 'repos': {'community': {'enabled': True,
'mirror': 'file:///etc/pacman.d/mirrorlist', 'mirror': 'file:///etc/pacman.d/mirrorlist',
@ -59,14 +70,14 @@
'kbd': 'US', 'kbd': 'US',
'locale': 'en_US.UTF-8', 'locale': 'en_US.UTF-8',
'reboot': True, 'reboot': True,
'rootpass': '$6$0jk/xhwahQHTi5QP$VWTgGlHNdSBDbQmJXUwJPZqajfL3JqYYF7Ghxk3ZSKi12WWXb49KsjR7q0bigvgBBBk5A/mvYES3/qareytFS0', 'rootpass': '$6$OeSE5pp4BLWZUn6H$9Y.NO/2cUliOr.apu8qSmgmL4EbGei0u22cw1IANs0h6ek45t8bpHveY7rlHAlljd8PKIxvIRtY9bRCzV24h50',
'services': {'sshd': True}, 'services': {'sshd': True},
'timezone': 'UTC', 'timezone': 'UTC',
'users': {'aifusr': {'comment': 'A Test User', 'users': {'aifusr': {'comment': 'A Test User',
'gid': False, 'gid': False,
'group': False, 'group': False,
'home': False, 'home': False,
'password': '$6$IlEwDkNmZRuTrT97$vKHjREGspspApBd8aQ/y1S43yRmGMjAzqOmdjNRLWaZyNKqGPrIjMHV9CJc7BzQgU12pRz3cwC6yyc8BDFARu/', 'password': '$6$RCL/E8zPTHoYjITS$MsBQ9DXibdRvjE8a0ak8F2OCzShcRg3vKXSyLAipokaIJvTwFWwlLda1MQr6zTzUxlFui.9Ep4k3B8vdRyBX6.',
'sudo': True, 'sudo': True,
'uid': False, 'uid': False,
'xgroups': {'users': {'create': False, 'xgroups': {'users': {'create': False,

View File

@ -14,7 +14,8 @@ if {$force_conservative} {
#set send_slow {10 .001} #set send_slow {10 .001}


set timeout -1 set timeout -1
spawn ./aif-config.py create -v:r -f /tmp/aif.xml #spawn ./aif-config.py create -v:r -f /tmp/aif.xml
spawn ./aif-config.py create -v -f /tmp/aif.xml
## disks ## disks
send -- "/dev/sda,/dev/sdb\r" send -- "/dev/sda,/dev/sdb\r"
# sda # sda