holy cats. xml generation's almost done
This commit is contained in:
parent
3f8c626fca
commit
372b51b1a6
211
aif-config.py
211
aif-config.py
@ -1,11 +1,19 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
try:
|
xmldebug = True
|
||||||
|
|
||||||
|
if not xmldebug:
|
||||||
|
try:
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
lxml_avail = True
|
lxml_avail = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import xml.etree.ElementTree as etree # https://docs.python.org/3/library/xml.etree.elementtree.html
|
import xml.etree.ElementTree as etree # https://docs.python.org/3/library/xml.etree.elementtree.html
|
||||||
lxml_avail = False
|
lxml_avail = False
|
||||||
|
else:
|
||||||
|
# debugging
|
||||||
|
import xml.etree.ElementTree as etree
|
||||||
|
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,10 +554,11 @@ 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'] = {}
|
||||||
@ -557,7 +566,7 @@ class aifgen(object):
|
|||||||
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,7 +726,10 @@ 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:
|
||||||
|
conf['scripts'] = False
|
||||||
|
print('\n\n[{0}] {1}ALL DONE!{2} Whew. You can find your configuration file at: {3}{4}{2}\n'.format(datetime.datetime.now(),
|
||||||
|
color.BOLD,
|
||||||
color.END,
|
color.END,
|
||||||
color.BLUE,
|
color.BLUE,
|
||||||
self.args['cfgfile']))
|
self.args['cfgfile']))
|
||||||
@ -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':
|
||||||
|
11
docs/TODO
11
docs/TODO
@ -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
|
||||||
|
@ -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": {
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user