beginnings of a conf generator

This commit is contained in:
brent s 2017-05-07 23:50:11 -04:00
parent 479c6e65bc
commit bbb37c3c29

177
aif-config.py Executable file
View File

@ -0,0 +1,177 @@
#!/usr/bin/env python3

try:
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
import argparse
import datetime
import errno
import ipaddress
import os
import pydoc # a dirty hack we use for pagination
import re
import shlex
import socket
import sys
import urllib.request as urlrequest
import urllib.parse as urlparse
import urllib.response as urlresponse
from ftplib import FTP_TLS

xsd = 'https://aif.square-r00t.net/aif.xsd'

class aifgen(object):
def __init__(self, args):
self.args = args

def getXSD(self):
pass
def getXML(self):
pass
def getOpts(self):
def chkPrompt(prompt, urls):
txtin = None
txtin = input(prompt)
if txtin in ('wikihelp', ''):
print('\n Articles/pages that you may find helpful for this option are:')
for h in urls:
print(' * {0}'.format(h))
print()
txtin = input(prompt)
else:
return(txtin)
conf = {}
print('[{0}] Beginning configuration...'.format(datetime.datetime.now()))
print('You may reply with \'wikihelp\' for the relevant link(s) in the Arch wiki ' +
'(and other resources).\n')
# https://aif.square-r00t.net/#code_disk_code
diskhelp = ['https://wiki.archlinux.org/index.php/installation_guide#Partition_the_disks']
diskin = chkPrompt('\nWhat disk(s) would you like to be configured on the target system?\n' +
'If you have multiple disks, separate with a comma (e.g. \'/dev/sda,/dev/sdb\').\n', diskhelp)
conf['disks'] = {}
for d in diskin.split(','):
disk = d.strip()
if not re.match('^/dev/[A-Za-z0]+', disk):
exit('!! ERROR: Disk {0} does not seem to be a valid device path.'.format(disk))
conf['disks'][disk] = {}
print('\nConfiguring disk {0} ...'.format(disk))
fmtin = chkPrompt('* What format should this disk use (gpt/bios)? ', diskhelp)
fmt = fmtin.lower()
if fmt not in ('gpt', 'bios'):
exit(' !! ERROR: Must be one of \'gpt\' or \'bios\'.')
conf['disks'][disk]['fmt'] = fmt
if fmt == 'gpt':
maxpart = '256'
else:
maxpart = '4'
partnumsin = chkPrompt('* How many partitions should this disk have? (Maximum: {0}) '.format(maxpart), diskhelp)
if not isinstance(partnumsin, int):
exit(' !! ERROR: Must be an integer.')
if partnumsin < 1:
exit(' !! ERROR: Must be a positive integer.')
if partnumsin > int(maxpart):
exit(' !! ERROR: Must be less than {0}'.format(maxpart))
parthelp = diskhelp + ['https://wiki.archlinux.org/index.php/installation_guide#Format_the_partitions',
'https://aif.square-r00t.net/#code_part_code',
'https://aif.square-r00t.net/#fstypes']
for partn in range(1, partnumsin + 1):
startsize = chkPrompt(('** Where should partition {0} start? Can be percentage [n%] ' +
'or size [(+/-)n(K/M/G/T/P)]: ').format(partn), parthelp)
startn = re.sub('[%\-+KMGTP])', '', startsize)
if int(startn) not in range(0, 100):
exit()
# https://aif.square-r00t.net/#code_part_code
parthelp.append('https://aif.square-r00t.net/#code_part_code')

def validateXML(self):
pass
def main(self):
if self.args['oper'] == 'create':
self.getOpts()
if self.args['oper'] in ('create', 'view'):
self.validateXML()

def parseArgs():
args = argparse.ArgumentParser(description = 'AIF-NG Configuration Generator',
epilog = 'TIP: this program has context-specific help. e.g. try "%(prog)s create --help"')
commonargs = argparse.ArgumentParser(add_help = False)
commonargs.add_argument('-f',
'--file',
dest = 'cfgfile',
help = 'The file to create/validate/view. If not specified, defaults to ./aif.xml',
default = '{0}/aif.xml'.format(os.getcwd()))
subparsers = args.add_subparsers(help = 'Operation to perform',
dest = 'oper')
createargs = subparsers.add_parser('create',
help = 'Create an AIF-NG XML configuration file.',
parents = [commonargs])
validateargs = subparsers.add_parser('validate',
help = 'Validate an AIF-NG XML configuration file.',
parents = [commonargs])
viewargs = subparsers.add_parser('view',
help = 'View an AIF-NG XML configuration file.',
parents = [commonargs])
return(args)
def verifyArgs(args):
args['cfgfile'] = os.path.normpath(os.path.abspath(os.path.expanduser(args['cfgfile'])))
args['cfgfile'] = re.sub('^/+', '/', args['cfgfile'])
# Path/file handling - make sure we can create the parent dir if it doesn't exist,
# check that we can write to the file, etc.
if args['oper'] == 'create':
args['cfgbak'] = '{0}.bak.{1}'.format(args['cfgfile'], int(datetime.datetime.utcnow().timestamp()))
try:
temp = True
#mtime = None
#atime = None
if os.path.lexists(args['cfgfile']):
temp = False
#mtime = os.stat(args['cfgfile']).st_mtime
#atime = os.stat(args['cfgfile']).st_atime
os.makedirs(os.path.dirname(args['cfgfile']), exist_ok = True)
with open(args['cfgfile'], 'a') as f:
f.write('')
if temp:
os.remove(args['cfgfile'])
#else:
# WE WERE NEVER HERE.
# I lied; ctime will still be modified, but I think this is playing it safely enough.
# Turns out, though, f.write('') does no modifications but WILL throw the perm error we want.
# Good.
#os.utime(args['cfgfile'], times = (atime, mtime))
except OSError as e:
print('\nERROR: {0}: {1}'.format(e.strerror, e.filename))
exit(('\nWe encountered an error when trying to use path {0}.\n' +
'Please review the output and address any issues present.').format(args['cfgfile']))
elif args['oper'] == 'view':
try:
with open(args['cfgfile'], 'r') as f:
f.read()
except OSError as e:
print('\nERROR: {0}: {1}'.format(e.strerror, e.filename))
exit(('\nWe encountered an error when trying to use path {0}.\n' +
'Please review the output and address any issues present.').format(args['cfgfile']))
return(args)

def main():
args = vars(parseArgs().parse_args())
if not args['oper']:
parseArgs().print_help()
else:
# verifyArgs(args)
aif = aifgen(verifyArgs(args))
if args['oper'] == 'create':
aif.getOpts()
import pprint # DEBUGGING
print(args) # DEBUGGING

if __name__ == '__main__':
main()