aif-config is... done?

This commit is contained in:
brent s 2017-05-15 12:38:10 -04:00
parent 372b51b1a6
commit aea4f1b8e3
4 changed files with 198 additions and 40 deletions

View File

@ -1,8 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3


xmldebug = True xmldebug = False
stdlibxmldebug = False


if not xmldebug: if not stdlibxmldebug:
try: try:
from lxml import etree from lxml import etree
lxml_avail = True lxml_avail = True
@ -431,6 +432,26 @@ class aifgen(object):
if not re.match('^y(es)?$', morereposin.lower()): if not re.match('^y(es)?$', morereposin.lower()):
addrepos = False addrepos = False
return(repos) return(repos)
def mirrorPrompt(mirrorhelp):
moremirrors = False
mirrors = False
mirrorchk = chkPrompt('* Would you like to replace the default mirrorlist? (y/{0}n{1}) '.format(color.BOLD, color.END), mirrorhelp)
if re.match('^y(es)?$', mirrorchk.lower()):
moremirrors = True
while moremirrors:
if not isinstance(mirrors, list):
mirrors = []
mirrorin = chkPrompt('** What is the URI for the mirror you would like to add?\n' +
'\tCan be one of the following types of URIs:\n' +
'\thttp://, https://, or file:// (for directories on the newly-installed system): ', mirrorhelp)
if mirrorin == '':
exit(' !! ERROR: You cannot specify a blank mirror URI.')
else:
mirrors.append(mirrorin)
moremirrorschk = chkPrompt('* Would you like to add another mirror? (y/{0}n{1}) '.format(color.BOLD, color.END), mirrorhelp)
if not re.match('^y(es)?$', moremirrorschk.lower()):
moremirrors = False
return(mirrors)
def pkgsPrompt(repohelp): def pkgsPrompt(repohelp):
pkgs = {} pkgs = {}
morepkgs = True morepkgs = True
@ -466,33 +487,33 @@ class aifgen(object):
'\tMust be a unique integer ' + '\tMust be a unique integer ' +
'(lower numbers execute before higher numbers): ').format(hook), scrpthlp) '(lower numbers execute before higher numbers): ').format(hook), scrpthlp)
try: try:
order = int(ordrin) orderint = int(orderin)
except: except:
exit(' !! ERROR: Must be an integer') exit(' !! ERROR: Must be an integer')
if order in scrpts[hook].keys(): if order in scrpts[hook].keys():
exit(' !! ERROR: You already have a {0} script at that order number.'.format(order)) exit(' !! ERROR: You already have a {0} script at that order number.'.format(hook))
scrpts[hook][order] = {'uri': scrptin} scrpts[hook][orderint] = {'uri': scrptin}
if re.match('^(https?|ftps?)://', scriptin.lower()): if re.match('^(https?|ftps?)://', scrptin.lower()):
authin = chkPrompt('** Does this script URI require auth? (y/{0}n{1}) '.format(color.BOLD, color.END), scrpthlp) authin = chkPrompt('** Does this script URI require auth? (y/{0}n{1}) '.format(color.BOLD, color.END), scrpthlp)
if re.match('^y(es)?$', authin.lower()): if re.match('^y(es)?$', authin.lower()):
if re.match('^https?://', scriptin.lower()): if re.match('^https?://', scrptin.lower()):
authtype = chkPrompt(('*** What type of auth does this URI require? ' + authtype = chkPrompt(('*** What type of auth does this URI require? ' +
'({0}basic{1}/digest) ').format(color.BOLD, color.END), scrpthlp) '({0}basic{1}/digest) ').format(color.BOLD, color.END), scrpthlp)
if authtype == '': if authtype == '':
scrpts[hook][order]['auth'] = 'basic' scrpts[hook][orderint]['auth'] = 'basic'
elif not re.match('^(basic|digest)$', authtype.lower()): elif re.match('^(basic|digest)$', authtype.lower()):
scrpts[hook][order]['auth'] = authtype.lower() scrpts[hook][orderint]['auth'] = authtype.lower()
else: else:
exit(' !! ERROR: That is not a valid auth type.') exit(' !! ERROR: That is not a valid auth type.')
if authtype.lower() == 'digest': if authtype.lower() == 'digest':
realmin = chkPrompt('*** Do you know the realm needed for authentication?\n' + realmin = chkPrompt('*** Do you know the realm needed for authentication?\n' +
'\tIf not, just leave this blank and AIF-NG will try to guess: ', scrpthlp) '\tIf not, just leave this blank and AIF-NG will try to guess: ', scrpthlp)
if realmin != '': if realmin != '':
scrpts[hook][order]['realm'] = realmin scrpts[hook][orderint]['realm'] = realmin
scrpts[hook][order]['user'] = chkPrompt('*** What user should we use for auth? ', scrpthlp) scrpts[hook][orderint]['user'] = chkPrompt('*** What user should we use for auth? ', scrpthlp)
scrpts[hook][order]['password'] = chkPrompt('*** What password should we use for auth? ', scrpthlp) scrpts[hook][orderint]['password'] = chkPrompt('*** What password should we use for auth? ', scrpthlp)
else: else:
scrpts[hook][order][auth] = False scrpts[hook][orderint][auth] = False
morescrptsin = chkPrompt('* Would you like to add another hook script? (y/{0}n{1}) '.format(color.BOLD, color.END), scrpthlp) morescrptsin = chkPrompt('* Would you like to add another hook script? (y/{0}n{1}) '.format(color.BOLD, color.END), scrpthlp)
if not re.match('^y(es)?$', morescrptsin.lower()): if not re.match('^y(es)?$', morescrptsin.lower()):
morescrpts = False morescrpts = False
@ -685,6 +706,10 @@ class aifgen(object):
print('\n{0}=== REPOSITORIES/PACKAGES ==={1}'.format(color.BOLD, color.END)) print('\n{0}=== REPOSITORIES/PACKAGES ==={1}'.format(color.BOLD, color.END))
repohelp = ['https://aif.square-r00t.net/#code_repos_code'] repohelp = ['https://aif.square-r00t.net/#code_repos_code']
conf['software']['repos'] = repoPrompt(repohelp) conf['software']['repos'] = repoPrompt(repohelp)
mirrorhelp = ['https://wiki.archlinux.org/index.php/installation_guide#Select_the_mirrors',
'https://aif.square-r00t.net/#code_mirrorlist_code',
'https://aif.square-r00t.net/#code_mirror_code']
conf['software']['mirrors'] = mirrorPrompt(mirrorhelp)
if pkgrcmd == '': if pkgrcmd == '':
pkgrcmd = 'pacman --needed --noconfirm -S' pkgrcmd = 'pacman --needed --noconfirm -S'
pkgsin = chkPrompt(('* Would you like to install extra packages?\n' + pkgsin = chkPrompt(('* Would you like to install extra packages?\n' +
@ -704,7 +729,7 @@ class aifgen(object):
btldrin = 'grub' btldrin = 'grub'
elif not re.match('^(grub|systemd)$', btldrin.lower()): elif not re.match('^(grub|systemd)$', btldrin.lower()):
exit(' !! ERROR: You must choose a bootloader between grub or systemd.') exit(' !! ERROR: You must choose a bootloader between grub or systemd.')
else:
conf['boot']['bootloader'] = btldrin.lower() conf['boot']['bootloader'] = btldrin.lower()
bttgtstr = 'boot partition/disk' bttgtstr = 'boot partition/disk'
btrgx = re.compile('^/dev/[A-Za-z0]+') btrgx = re.compile('^/dev/[A-Za-z0]+')
@ -790,7 +815,7 @@ class aifgen(object):
for e in ('storage', 'network', 'system', 'pacman', 'bootloader'): for e in ('storage', 'network', 'system', 'pacman', 'bootloader'):
root.append(etree.Element(e)) root.append(etree.Element(e))
# /aif/ optional sections # /aif/ optional sections
if conf['scripts']: if 'scripts' in conf.keys() and conf['scripts']:
root.append(etree.Element('scripts')) root.append(etree.Element('scripts'))
# /aif/storage # /aif/storage
strg = root.find('storage') strg = root.find('storage')
@ -905,10 +930,63 @@ class aifgen(object):
repo = etree.Element('repo', **o) repo = etree.Element('repo', **o)
repos.append(repo) repos.append(repo)
pcmn.append(repos) pcmn.append(repos)
# /aif/pacman/mirrorlist
if 'mirrors' in conf['software'].keys() and conf['software']['mirrors']:
mrlst = etree.Element('mirrorlist')
for m in conf['software']['mirrors']:
# /aif/pacman/mirrorlist/mirror
mirror = etree.Element('mirror')
mirror.text = m
mrlst.append(mirror)
pcmn.append(mrlst)
# /aif/pacman/software
if 'packages' in conf['software'].keys() and conf['software']['packages']:
sftwr = etree.Element('software')
for p in conf['software']['packages'].keys():
# /aif/pacman/software/package
pkg = etree.Element('package')
pkg.set('name', p)
if conf['software']['packages'][p]:
if conf['software']['packages'][p] not in (None, 'None'): # fix JSON not parsing "None"
pkg.set('repo', conf['software']['packages'][p])
sftwr.append(pkg)
pcmn.append(sftwr)
# /aif/bootloader
btldr = root.find('bootloader')
optmap = {'bttype': 'type', 'efi': 'efi', 'bttgt': 'target'}
opts = {}
opts['bttype'] = conf['boot']['bootloader']
opts['efi'] = str(conf['boot']['efi']).lower()
opts['bttgt'] = conf['boot']['target']
for k in optmap.keys():
btldr.set(optmap[k], opts[k])
# /aif/scripts
if 'scripts' in conf.keys() and conf['scripts']:
scrpts = root.find('scripts')
# /aif/scripts/script@execution
for t in ('pre', 'pkg', 'post'):
# /aif/scripts/script@order
if t in conf['scripts'].keys() and conf['scripts'][t]:
for n in conf['scripts'][t].keys():
# /aif/scripts/script@uri
uri = conf['scripts'][t][n]['uri']
scrpt = etree.Element('script', execution = t, order = n, uri = uri)
# /aif/scripts/script@authtype
if 'auth' in conf['scripts'][t][n].keys() and conf['scripts'][t][n]['auth']:
scrpt.set('authtype', conf['scripts'][t][n]['auth'])
# /aif/scripts/script@realm
if conf['scripts'][t][n]['auth'] == 'digest':
if 'realm' in conf['scripts'][t][n].keys():
scrpt.set('realm', conf['scripts'][t][n]['realm'])
# /aif/scripts/script@user
scrpt.set('user', conf['scripts'][t][n]['user'])
# /aif/scripts/script@password
scrpt.set('password', conf['scripts'][t][n]['password'])
scrpts.append(scrpt)
# debugging # debugging
if xmldebug:
if lxml_avail: if lxml_avail:
# LXML # LXML
#print(etree.tostring(root).decode('utf-8'))
print(etree.tostring(root, xml_declaration = True, encoding = 'utf-8', pretty_print = True).decode('utf-8')) print(etree.tostring(root, xml_declaration = True, encoding = 'utf-8', pretty_print = True).decode('utf-8'))
else: else:
# XML # XML
@ -927,14 +1005,26 @@ class aifgen(object):
print('\n'.join(outstr)) print('\n'.join(outstr))
# end debugging # end debugging
# https://stackoverflow.com/questions/4886189/python-namespaces-in-xml-elementtree-or-lxml # https://stackoverflow.com/questions/4886189/python-namespaces-in-xml-elementtree-or-lxml
#if lxml_avail: if lxml_avail:
#xml.write(..., xml_declaration = True, encoding='utf-8') xml = etree.ElementTree(root)
#else: with open(self.args['cfgfile'], 'wb') as f:
#import xml.dom.minidom xml.write(f, xml_declaration = True, encoding='utf-8', pretty_print = True)
#xmlstr = etree.tostring(root, encoding = 'utf-8') else:
#with open(self.args['cfgfile'], 'w') as f: # TODO: test this. print() wrap it necessary? import xml.dom.minidom
#f.write(xml.dom.minidom.parseString(xmlstr).toprettyxml(indent = ' ')) xmlstr = etree.tostring(root, encoding = 'utf-8')
return() # 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)
with open(self.args['cfgfile'], 'w') as f: # TODO: test this. print() wrap it necessary?
f.write('\n'.join(outstr))
return(root)


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

View File

@ -1,5 +1,6 @@
{ {
"boot": { "boot": {
"bootloader": "grub",
"efi": true, "efi": true,
"target": "/boot" "target": "/boot"
}, },
@ -92,8 +93,28 @@
} }
} }
}, },
"scripts": false, "scripts": {
"pkg": false,
"post": {
"1": {
"auth": "digest",
"password": "password",
"realm": "realmname",
"uri": "https://aif.square-r00t.net/sample-scripts/post/first.sh",
"user": "test"
}
},
"pre": false
},
"software": { "software": {
"mirrors": [
"http://mirrors.advancedhosters.com/archlinux/$repo/os/$arch",
"http://mirror.us.leaseweb.net/archlinux/$repo/os/$arch",
"http://arch.mirror.constant.com/$repo/os/$arch",
"http://mirror.vtti.vt.edu/archlinux/$repo/os/$arch",
"http://arch.mirrors.pair.com/$repo/os/$arch",
"http://mirror.yellowfiber.net/archlinux/$repo/os/$arch"
],
"packages": { "packages": {
"openssh": "None" "openssh": "None"
}, },
@ -136,7 +157,7 @@
"kbd": "US", "kbd": "US",
"locale": "en_US.UTF-8", "locale": "en_US.UTF-8",
"reboot": true, "reboot": true,
"rootpass": "$6$OeSE5pp4BLWZUn6H$9Y.NO/2cUliOr.apu8qSmgmL4EbGei0u22cw1IANs0h6ek45t8bpHveY7rlHAlljd8PKIxvIRtY9bRCzV24h50", "rootpass": "$6$aIK0xvxLa/9BTEDu$xFskR0cQcEi273I8dgUtyO7WjjhHUZOfyS6NemelPgfMJORxbjgI6QCW6wEcCh7NVA1qGDpS0Lyg9vDCaRnA9/",
"services": { "services": {
"sshd": true "sshd": true
}, },
@ -147,7 +168,7 @@
"gid": false, "gid": false,
"group": false, "group": false,
"home": false, "home": false,
"password": "$6$RCL/E8zPTHoYjITS$MsBQ9DXibdRvjE8a0ak8F2OCzShcRg3vKXSyLAipokaIJvTwFWwlLda1MQr6zTzUxlFui.9Ep4k3B8vdRyBX6.", "password": "$6$arRyKn/VsusyJNQo$huX4aa1aJPzRMyyqeEw6IxC1KC1EKKJ8RXdQp6W68Yt7SVdHjwU/fEDvPb3xD3lUHOQ6ysLKWLkEXFNYxLpMf1",
"sudo": true, "sudo": true,
"uid": false, "uid": false,
"xgroups": { "xgroups": {

View File

@ -1,4 +1,4 @@
{'boot': {'efi': True, 'target': '/boot'}, {'boot': {'bootloader': 'grub', 'efi': True, 'target': '/boot'},
'disks': {'/dev/sda': {'fmt': 'gpt', 'disks': {'/dev/sda': {'fmt': 'gpt',
'parts': {1: {'fstype': '8300', 'parts': {1: {'fstype': '8300',
'start': '0%', 'start': '0%',
@ -45,8 +45,20 @@
'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']}}},
'scripts': False, 'scripts': {'pkg': False,
'software': {'packages': {'openssh': None}, 'post': {1: {'auth': 'digest',
'password': 'password',
'realm': 'realmname',
'uri': 'https://aif.square-r00t.net/sample-scripts/post/first.sh',
'user': 'test'}},
'pre': False},
'software': {'mirrors': ['http://mirrors.advancedhosters.com/archlinux/$repo/os/$arch',
'http://mirror.us.leaseweb.net/archlinux/$repo/os/$arch',
'http://arch.mirror.constant.com/$repo/os/$arch',
'http://mirror.vtti.vt.edu/archlinux/$repo/os/$arch',
'http://arch.mirrors.pair.com/$repo/os/$arch',
'http://mirror.yellowfiber.net/archlinux/$repo/os/$arch'],
'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',
@ -70,14 +82,14 @@
'kbd': 'US', 'kbd': 'US',
'locale': 'en_US.UTF-8', 'locale': 'en_US.UTF-8',
'reboot': True, 'reboot': True,
'rootpass': '$6$OeSE5pp4BLWZUn6H$9Y.NO/2cUliOr.apu8qSmgmL4EbGei0u22cw1IANs0h6ek45t8bpHveY7rlHAlljd8PKIxvIRtY9bRCzV24h50', 'rootpass': '$6$aIK0xvxLa/9BTEDu$xFskR0cQcEi273I8dgUtyO7WjjhHUZOfyS6NemelPgfMJORxbjgI6QCW6wEcCh7NVA1qGDpS0Lyg9vDCaRnA9/',
'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$RCL/E8zPTHoYjITS$MsBQ9DXibdRvjE8a0ak8F2OCzShcRg3vKXSyLAipokaIJvTwFWwlLda1MQr6zTzUxlFui.9Ep4k3B8vdRyBX6.', 'password': '$6$arRyKn/VsusyJNQo$huX4aa1aJPzRMyyqeEw6IxC1KC1EKKJ8RXdQp6W68Yt7SVdHjwU/fEDvPb3xD3lUHOQ6ysLKWLkEXFNYxLpMf1',
'sudo': True, 'sudo': True,
'uid': False, 'uid': False,
'xgroups': {'users': {'create': False, 'xgroups': {'users': {'create': False,

View File

@ -154,6 +154,22 @@ send -- "\r"
send -- "\r" send -- "\r"
# add additional repositories? default is no # add additional repositories? default is no
send -- "\r" send -- "\r"
# modify default mirrorlist?
send -- "y\r"
# URI for mirror
send -- "http://mirrors.advancedhosters.com/archlinux/\$repo/os/\$arch\r"
# add another?
send -- "y\r"
send -- "http://mirror.us.leaseweb.net/archlinux/\$repo/os/\$arch\r"
send -- "y\r"
send -- "http://arch.mirror.constant.com/\$repo/os/\$arch\r"
send -- "y\r"
send -- "http://mirror.vtti.vt.edu/archlinux/\$repo/os/\$arch\r"
send -- "y\r"
send -- "http://arch.mirrors.pair.com/\$repo/os/\$arch\r"
send -- "y\r"
send -- "http://mirror.yellowfiber.net/archlinux/\$repo/os/\$arch\r"
send -- "\r"
# install extra software? # install extra software?
send -- "y\r" send -- "y\r"
# software # software
@ -169,5 +185,24 @@ send -- "\r"
# ESP/EFI system partition # ESP/EFI system partition
send -- "/boot\r" send -- "/boot\r"
# any hook scripts? default is no # any hook scripts? default is no
send -- "y\r"
# pre, pkg, or post
send -- "post\r"
# script URI
send -- "https://aif.square-r00t.net/sample-scripts/post/first.sh\r"
# order for the execution run
send -- "1\r"
# auth required?
send -- "y\r"
# basic/digest? default is basic
send -- "digest\r"
# if digest, realm
send -- "realmname\r"
# user
send -- "test\r"
# password
send -- "password\r"
# would you like to add another script? default is no
send -- "\r" send -- "\r"
interact
expect eof expect eof